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) misc.ApplyDAOHardFork(statedb)
} }
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
receipts = make([]*types.Receipt, len(block.Transactions()))
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
statedb.Prepare(tx.Hash(), block.Hash(), i) statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg) receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg)
if err != nil { if err != nil {
return nil, nil, 0, err return nil, nil, 0, err
} }
receipts = append(receipts, receipt) receipts[i] = receipt
allLogs = append(allLogs, receipt.Logs...) allLogs = append(allLogs, receipt.Logs...)
} }
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards) // 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. // 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) { func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
if contract.CodeAddr != nil { if contract.CodeAddr != nil {
precompiles := PrecompiledContractsHomestead if p := evm.interpreter.precompiles[*contract.CodeAddr]; p != nil {
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
precompiles = PrecompiledContractsByzantium
}
if p := precompiles[*contract.CodeAddr]; p != nil {
return RunPrecompiledContract(p, input, contract) 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() snapshot = evm.StateDB.Snapshot()
) )
if !evm.StateDB.Exist(addr) { if !evm.StateDB.Exist(addr) {
precompiles := PrecompiledContractsHomestead if evm.interpreter.precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
precompiles = PrecompiledContractsByzantium
}
if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
// Calling a non existing account, don't do antything, but ping the tracer // Calling a non existing account, don't do antything, but ping the tracer
if evm.vmConfig.Debug && evm.depth == 0 { if evm.vmConfig.Debug && evm.depth == 0 {
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) 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) 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. // 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. // The contract is a scoped environment for this execution context only.
contract := NewContract(caller, to, value, gas) 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() start := time.Now()

View file

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"sync/atomic" "sync/atomic"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -53,6 +54,7 @@ type Interpreter struct {
readOnly bool // Whether to throw on stateful modifications readOnly bool // Whether to throw on stateful modifications
returnData []byte // Last CALL's return data for subsequent reuse returnData []byte // Last CALL's return data for subsequent reuse
precompiles map[common.Address]PrecompiledContract
} }
// NewInterpreter returns a new instance of the Interpreter. // 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{ return &Interpreter{
evm: evm, evm: evm,
cfg: cfg, cfg: cfg,
gasTable: evm.ChainConfig().GasTable(evm.BlockNumber), 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()} 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. // 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! // Note, the returned int's value is arbitrary and will not be zeroed!
func (p *intPool) get() *big.Int { func (p *intPool) get() *big.Int {

View file

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