core/vm: precompiles into interpreter, 0-size alloc intpool,prealloc receipts

This commit is contained in:
Martin Holst Swende 2018-04-07 23:22:58 +02:00
parent 40a2c52397
commit f26087d3a6
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
5 changed files with 39 additions and 18 deletions

View file

@ -66,13 +66,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
misc.ApplyDAOHardFork(statedb)
}
// Iterate over and process the individual transactions
receipts = make([]*types.Receipt, len(block.Transactions()))
for i, tx := range block.Transactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg)
if err != nil {
return nil, nil, 0, err
}
receipts = append(receipts, receipt)
receipts[i] = receipt
allLogs = append(allLogs, receipt.Logs...)
}
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)

View file

@ -41,11 +41,7 @@ type (
// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
if contract.CodeAddr != nil {
precompiles := PrecompiledContractsHomestead
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
precompiles = PrecompiledContractsByzantium
}
if p := precompiles[*contract.CodeAddr]; p != nil {
if p := evm.interpreter.precompiles[*contract.CodeAddr]; p != nil {
return RunPrecompiledContract(p, input, contract)
}
}
@ -155,11 +151,8 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
snapshot = evm.StateDB.Snapshot()
)
if !evm.StateDB.Exist(addr) {
precompiles := PrecompiledContractsHomestead
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
precompiles = PrecompiledContractsByzantium
}
if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
if evm.interpreter.precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
// Calling a non existing account, don't do antything, but ping the tracer
if evm.vmConfig.Debug && evm.depth == 0 {
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
@ -171,10 +164,21 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
}
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
code := evm.StateDB.GetCode(addr)
codeHash := evm.StateDB.GetCodeHash(addr)
_, isPrecompile := evm.interpreter.precompiles[addr]
if !isPrecompile && len(code) == 0 {
// Shortcut execution if there is no code,
// but make sure to set returndata to nil
evm.interpreter.returnData = nil
return nil, gas, nil
}
// Initialise a new contract and set the code that is to be used by the EVM.
// The contract is a scoped environment for this execution context only.
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
contract.SetCallCode(&addr, codeHash, code)
start := time.Now()

View file

@ -20,6 +20,7 @@ import (
"fmt"
"sync/atomic"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/params"
)
@ -53,6 +54,7 @@ type Interpreter struct {
readOnly bool // Whether to throw on stateful modifications
returnData []byte // Last CALL's return data for subsequent reuse
precompiles map[common.Address]PrecompiledContract
}
// NewInterpreter returns a new instance of the Interpreter.
@ -73,11 +75,17 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
}
}
precompiles := PrecompiledContractsHomestead
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
precompiles = PrecompiledContractsByzantium
}
return &Interpreter{
evm: evm,
cfg: cfg,
gasTable: evm.ChainConfig().GasTable(evm.BlockNumber),
intPool: newIntPool(),
intPool: newZerosizeIntPool(),
precompiles: precompiles,
}
}

View file

@ -32,6 +32,10 @@ func newIntPool() *intPool {
return &intPool{pool: newstack()}
}
func newZerosizeIntPool() *intPool {
return &intPool{pool: newZeroSizeStack()}
}
// get retrieves a big int from the pool, allocating one if the pool is empty.
// Note, the returned int's value is arbitrary and will not be zeroed!
func (p *intPool) get() *big.Int {

View file

@ -32,6 +32,10 @@ func newstack() *Stack {
return &Stack{data: make([]*big.Int, 0, 1024)}
}
func newZeroSizeStack() *Stack {
return &Stack{data: make([]*big.Int, 0)}
}
func (st *Stack) Data() []*big.Int {
return st.data
}