mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-20 13:44:31 +00:00
core/vm: less allocations for various call variants (#21222)
This commit is contained in:
parent
a575d731d3
commit
67b5b2bf9a
8 changed files with 188 additions and 132 deletions
|
|
@ -135,12 +135,29 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
|
|||
}
|
||||
|
||||
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
|
||||
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
|
||||
gas := p.RequiredGas(input)
|
||||
if contract.UseGas(gas) {
|
||||
return p.Run(input)
|
||||
// It returns
|
||||
// - the returned bytes,
|
||||
// - the _remaining_ gas,
|
||||
// - any error that occurred
|
||||
func RunPrecompiledContract(evm *EVM, p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) {
|
||||
if evm != nil {
|
||||
if evm.chainConfig.IsTIPXDCXReceiver(evm.Context.BlockNumber) {
|
||||
switch p := p.(type) {
|
||||
case *XDCxEpochPrice:
|
||||
p.SetTradingState(evm.tradingStateDB)
|
||||
case *XDCxLastPrice:
|
||||
p.SetTradingState(evm.tradingStateDB)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, ErrOutOfGas
|
||||
|
||||
gasCost := p.RequiredGas(input)
|
||||
if suppliedGas < gasCost {
|
||||
return nil, 0, ErrOutOfGas
|
||||
}
|
||||
suppliedGas -= gasCost
|
||||
output, err := p.Run(input)
|
||||
return output, suppliedGas, err
|
||||
}
|
||||
|
||||
// ECRECOVER implemented as a native contract.
|
||||
|
|
@ -230,6 +247,7 @@ func (c *dataCopy) Run(in []byte) ([]byte, error) {
|
|||
type bigModExp struct{}
|
||||
|
||||
var (
|
||||
big0 = big.NewInt(0)
|
||||
big1 = big.NewInt(1)
|
||||
big4 = big.NewInt(4)
|
||||
big8 = big.NewInt(8)
|
||||
|
|
|
|||
|
|
@ -23,10 +23,6 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
)
|
||||
|
||||
|
|
@ -496,10 +492,9 @@ var blake2FTests = []precompiledTest{
|
|||
func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
|
||||
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
|
||||
in := common.Hex2Bytes(test.input)
|
||||
contract := NewContract(AccountRef(common.HexToAddress("1337")),
|
||||
nil, new(big.Int), p.RequiredGas(in))
|
||||
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) {
|
||||
if res, err := RunPrecompiledContract(p, in, contract); err != nil {
|
||||
gas := p.RequiredGas(in)
|
||||
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, gas), func(t *testing.T) {
|
||||
if res, _, err := RunPrecompiledContract(nil, p, in, gas); err != nil {
|
||||
t.Error(err)
|
||||
} else if common.Bytes2Hex(res) != test.expected {
|
||||
t.Errorf("Expected %v, got %v", test.expected, common.Bytes2Hex(res))
|
||||
|
|
@ -513,21 +508,12 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
|
|||
}
|
||||
|
||||
func testXDCxPrecompiled(addr string, test precompiledTest, t *testing.T) {
|
||||
db := rawdb.NewMemoryDatabase()
|
||||
stateCache := tradingstate.NewDatabase(db)
|
||||
tradingStateDB, _ := tradingstate.New(common.Hash{}, stateCache)
|
||||
tradingStateDB.SetLastPrice(tradingstate.GetTradingOrderBookHash(common.HexToAddress(BTCAddress), common.HexToAddress(USDTAddress)), BTCUSDTLastPrice)
|
||||
tradingStateDB.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(common.HexToAddress(BTCAddress), common.HexToAddress(USDTAddress)), BTCUSDTEpochPrice)
|
||||
|
||||
evm := NewEVM(BlockContext{BlockNumber: common.Big1}, TxContext{}, nil, tradingStateDB, ¶ms.ChainConfig{ByzantiumBlock: common.Big0}, Config{})
|
||||
contractAddr := common.HexToAddress(addr)
|
||||
p := PrecompiledContractsByzantium[contractAddr]
|
||||
in := common.Hex2Bytes(test.input)
|
||||
contract := NewContract(AccountRef(common.HexToAddress("1337")),
|
||||
nil, new(big.Int), p.RequiredGas(in))
|
||||
contract.SetCallCode(&contractAddr, common.Hash{}, []byte{})
|
||||
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) {
|
||||
if res, err := run(evm, contract, in, false); err != nil {
|
||||
gas := p.RequiredGas(in)
|
||||
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, gas), func(t *testing.T) {
|
||||
if res, _, err := RunPrecompiledContract(nil, p, in, gas); err != nil {
|
||||
t.Error(err)
|
||||
} else if common.Bytes2Hex(res) != test.expected {
|
||||
t.Errorf("Expected %v, got %v", test.expected, common.Bytes2Hex(res))
|
||||
|
|
@ -536,16 +522,12 @@ func testXDCxPrecompiled(addr string, test precompiledTest, t *testing.T) {
|
|||
}
|
||||
|
||||
func testPrecompiledWithEmptyTradingState(addr string, test precompiledTest, t *testing.T) {
|
||||
evm := NewEVM(BlockContext{BlockNumber: common.Big1}, TxContext{}, nil, nil, ¶ms.ChainConfig{ByzantiumBlock: common.Big0}, Config{})
|
||||
|
||||
contractAddr := common.HexToAddress(addr)
|
||||
p := PrecompiledContractsByzantium[contractAddr]
|
||||
in := common.Hex2Bytes(test.input)
|
||||
contract := NewContract(AccountRef(common.HexToAddress("1337")),
|
||||
nil, new(big.Int), p.RequiredGas(in))
|
||||
contract.SetCallCode(&contractAddr, common.Hash{}, []byte{})
|
||||
t.Run(fmt.Sprintf("testPrecompiledWithEmptyTradingState-%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) {
|
||||
if res, err := run(evm, contract, in, false); err != nil {
|
||||
gas := p.RequiredGas(in)
|
||||
t.Run(fmt.Sprintf("testPrecompiledWithEmptyTradingState-%s-Gas=%d", test.name, gas), func(t *testing.T) {
|
||||
if res, _, err := RunPrecompiledContract(nil, p, in, gas); err != nil {
|
||||
t.Error(err)
|
||||
} else if common.Bytes2Hex(res) != test.expected {
|
||||
t.Errorf("Expected %v, got %v", test.expected, common.Bytes2Hex(res))
|
||||
|
|
@ -556,10 +538,10 @@ func testPrecompiledWithEmptyTradingState(addr string, test precompiledTest, t *
|
|||
func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
|
||||
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
|
||||
in := common.Hex2Bytes(test.input)
|
||||
contract := NewContract(AccountRef(common.HexToAddress("1337")),
|
||||
nil, new(big.Int), p.RequiredGas(in)-1)
|
||||
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) {
|
||||
_, err := RunPrecompiledContract(p, in, contract)
|
||||
gas := p.RequiredGas(in) - 1
|
||||
|
||||
t.Run(fmt.Sprintf("%s-Gas=%d", test.name, gas), func(t *testing.T) {
|
||||
_, _, err := RunPrecompiledContract(nil, p, in, gas)
|
||||
if err.Error() != "out of gas" {
|
||||
t.Errorf("Expected error [out of gas], got [%v]", err)
|
||||
}
|
||||
|
|
@ -574,11 +556,9 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
|
|||
func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing.T) {
|
||||
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
|
||||
in := common.Hex2Bytes(test.input)
|
||||
contract := NewContract(AccountRef(common.HexToAddress("31337")),
|
||||
nil, new(big.Int), p.RequiredGas(in))
|
||||
|
||||
gas := p.RequiredGas(in)
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
_, err := RunPrecompiledContract(p, in, contract)
|
||||
_, _, err := RunPrecompiledContract(nil, p, in, gas)
|
||||
if !reflect.DeepEqual(err, test.expectedError) {
|
||||
t.Errorf("Expected error [%v], got [%v]", test.expectedError, err)
|
||||
}
|
||||
|
|
@ -597,8 +577,6 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
|
|||
p := PrecompiledContractsIstanbul[common.HexToAddress(addr)]
|
||||
in := common.Hex2Bytes(test.input)
|
||||
reqGas := p.RequiredGas(in)
|
||||
contract := NewContract(AccountRef(common.HexToAddress("1337")),
|
||||
nil, new(big.Int), reqGas)
|
||||
|
||||
var (
|
||||
res []byte
|
||||
|
|
@ -606,12 +584,11 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
|
|||
data = make([]byte, len(in))
|
||||
)
|
||||
|
||||
bench.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(bench *testing.B) {
|
||||
bench.Run(fmt.Sprintf("%s-Gas=%d", test.name, reqGas), func(bench *testing.B) {
|
||||
bench.ResetTimer()
|
||||
for i := 0; i < bench.N; i++ {
|
||||
contract.Gas = reqGas
|
||||
copy(data, in)
|
||||
res, err = RunPrecompiledContract(p, data, contract)
|
||||
res, _, err = RunPrecompiledContract(nil, p, data, reqGas)
|
||||
}
|
||||
bench.StopTimer()
|
||||
//Check if it is correct
|
||||
|
|
|
|||
156
core/vm/evm.go
156
core/vm/evm.go
|
|
@ -26,6 +26,7 @@ import (
|
|||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// emptyCodeHash is used by create to ensure deployment is disallowed to already
|
||||
|
|
@ -60,19 +61,6 @@ func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
|
|||
|
||||
// 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, readOnly bool) ([]byte, error) {
|
||||
if contract.CodeAddr != nil {
|
||||
if p, isPrecompile := evm.precompile(*contract.CodeAddr); isPrecompile {
|
||||
if evm.chainConfig.IsTIPXDCXReceiver(evm.Context.BlockNumber) {
|
||||
switch p := p.(type) {
|
||||
case *XDCxEpochPrice:
|
||||
p.SetTradingState(evm.tradingStateDB)
|
||||
case *XDCxLastPrice:
|
||||
p.SetTradingState(evm.tradingStateDB)
|
||||
}
|
||||
}
|
||||
return RunPrecompiledContract(p, input, contract)
|
||||
}
|
||||
}
|
||||
if evm.ChainConfig().IsTIPXDCXCancellationFee(evm.Context.BlockNumber) {
|
||||
for _, interpreter := range evm.interpreters {
|
||||
if interpreter.CanRun(contract.Code) {
|
||||
|
|
@ -218,15 +206,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
return nil, gas, ErrDepth
|
||||
}
|
||||
// Fail if we're trying to transfer more than the available balance
|
||||
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||
if value.Sign() != 0 && !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||
return nil, gas, ErrInsufficientBalance
|
||||
}
|
||||
var (
|
||||
to = AccountRef(addr)
|
||||
snapshot = evm.StateDB.Snapshot()
|
||||
)
|
||||
snapshot := evm.StateDB.Snapshot()
|
||||
p, isPrecompile := evm.precompile(addr)
|
||||
|
||||
if !evm.StateDB.Exist(addr) {
|
||||
_, isPrecompile := evm.precompile(addr)
|
||||
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
|
||||
// Calling a non existing account, don't do anything, but ping the tracer
|
||||
if evm.vmConfig.Debug {
|
||||
|
|
@ -242,7 +228,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
}
|
||||
evm.StateDB.CreateAccount(addr)
|
||||
}
|
||||
evm.Context.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
|
||||
evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value)
|
||||
|
||||
// Capture the tracer start/end events in debug mode
|
||||
if evm.vmConfig.Debug {
|
||||
|
|
@ -261,16 +247,24 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
|
||||
// Even if the account has no code, we need to continue because it might be a precompile
|
||||
|
||||
ret, err = run(evm, contract, input, false)
|
||||
gas = contract.Gas
|
||||
|
||||
if isPrecompile {
|
||||
ret, gas, err = RunPrecompiledContract(evm, p, input, gas)
|
||||
} else {
|
||||
// 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.
|
||||
code := evm.StateDB.GetCode(addr)
|
||||
if len(code) == 0 {
|
||||
ret, err = nil, nil // gas is unchanged
|
||||
} else {
|
||||
addrCopy := addr
|
||||
// If the account has no code, we can abort here
|
||||
// The depth-check is already done, and precompiles handled above
|
||||
contract := NewContract(caller, AccountRef(addrCopy), value, gas)
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code)
|
||||
ret, err = run(evm, contract, input, false)
|
||||
gas = contract.Gas
|
||||
}
|
||||
}
|
||||
// When an error was returned by the EVM or when setting the creation code
|
||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||
// when we're in homestead this also counts for code storage gas errors.
|
||||
|
|
@ -279,6 +273,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
if err != ErrExecutionReverted {
|
||||
gas = 0
|
||||
}
|
||||
// TODO: consider clearing up unused snapshots:
|
||||
//} else {
|
||||
// evm.StateDB.DiscardSnapshot(snapshot)
|
||||
}
|
||||
return ret, gas, err
|
||||
}
|
||||
|
|
@ -302,10 +299,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
|||
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||
return nil, gas, ErrInsufficientBalance
|
||||
}
|
||||
var (
|
||||
snapshot = evm.StateDB.Snapshot()
|
||||
to = AccountRef(caller.Address())
|
||||
)
|
||||
var snapshot = evm.StateDB.Snapshot()
|
||||
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.vmConfig.Debug {
|
||||
|
|
@ -315,13 +309,18 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
|||
}(gas)
|
||||
}
|
||||
|
||||
// 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))
|
||||
|
||||
ret, err = run(evm, contract, input, false)
|
||||
gas = contract.Gas
|
||||
// It is allowed to call precompiles, even via delegatecall
|
||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||
ret, gas, err = RunPrecompiledContract(evm, p, input, gas)
|
||||
} else {
|
||||
addrCopy := addr
|
||||
// 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, AccountRef(caller.Address()), value, gas)
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
ret, err = run(evm, contract, input, false)
|
||||
gas = contract.Gas
|
||||
}
|
||||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
|
|
@ -341,10 +340,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, ErrDepth
|
||||
}
|
||||
var (
|
||||
snapshot = evm.StateDB.Snapshot()
|
||||
to = AccountRef(caller.Address())
|
||||
)
|
||||
var snapshot = evm.StateDB.Snapshot()
|
||||
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.vmConfig.Debug {
|
||||
|
|
@ -354,12 +350,17 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||
}(gas)
|
||||
}
|
||||
|
||||
// Initialise a new contract and make initialise the delegate values
|
||||
contract := NewContract(caller, to, nil, gas).AsDelegate()
|
||||
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||
|
||||
ret, err = run(evm, contract, input, false)
|
||||
gas = contract.Gas
|
||||
// It is allowed to call precompiles, even via delegatecall
|
||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||
ret, gas, err = RunPrecompiledContract(evm, p, input, gas)
|
||||
} else {
|
||||
addrCopy := addr
|
||||
// Initialise a new contract and make initialise the delegate values
|
||||
contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate()
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
ret, err = run(evm, contract, input, false)
|
||||
gas = contract.Gas
|
||||
}
|
||||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
|
|
@ -378,22 +379,18 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
|||
if evm.depth > int(params.CallCreateDepth) {
|
||||
return nil, gas, ErrDepth
|
||||
}
|
||||
var (
|
||||
to = AccountRef(addr)
|
||||
snapshot = evm.StateDB.Snapshot()
|
||||
)
|
||||
// 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, new(big.Int), gas)
|
||||
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||
// We take a snapshot here. This is a bit counter-intuitive, and could probably be skipped.
|
||||
// However, even a staticcall is considered a 'touch'. On mainnet, static calls were introduced
|
||||
// after all empty accounts were deleted, so this is not required. However, if we omit this,
|
||||
// then certain tests start failing; stRevertTest/RevertPrecompiledTouchExactOOG.json.
|
||||
// We could change this, but for now it's left for legacy reasons
|
||||
var snapshot = evm.StateDB.Snapshot()
|
||||
|
||||
if evm.ChainConfig().IsTIPXDCXCancellationFee(evm.Context.BlockNumber) {
|
||||
// We do an AddBalance of zero here, just in order to trigger a touch.
|
||||
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,
|
||||
// but is the correct thing to do and matters on other networks, in tests, and potential
|
||||
// future scenarios
|
||||
evm.StateDB.AddBalance(addr, big.NewInt(0))
|
||||
}
|
||||
// We do an AddBalance of zero here, just in order to trigger a touch.
|
||||
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,
|
||||
// but is the correct thing to do and matters on other networks, in tests, and potential
|
||||
// future scenarios
|
||||
evm.StateDB.AddBalance(addr, big0)
|
||||
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.vmConfig.Debug {
|
||||
|
|
@ -403,11 +400,24 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
|||
}(gas)
|
||||
}
|
||||
|
||||
// When an error was returned by the EVM or when setting the creation code
|
||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||
// when we're in Homestead this also counts for code storage gas errors.
|
||||
ret, err = run(evm, contract, input, evm.ChainConfig().IsTIPXDCXCancellationFee(evm.Context.BlockNumber))
|
||||
gas = contract.Gas
|
||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||
ret, gas, err = RunPrecompiledContract(evm, p, input, gas)
|
||||
} else {
|
||||
// At this point, we use a copy of address. If we don't, the go compiler will
|
||||
// leak the 'contract' to the outer scope, and make allocation for 'contract'
|
||||
// even if the actual execution ends on RunPrecompiled above.
|
||||
addrCopy := addr
|
||||
// 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, AccountRef(addrCopy), new(big.Int), gas)
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
// When an error was returned by the EVM or when setting the creation code
|
||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||
// when we're in Homestead this also counts for code storage gas errors.
|
||||
readOnly := evm.ChainConfig().IsTIPXDCXCancellationFee(evm.Context.BlockNumber)
|
||||
ret, err = run(evm, contract, input, readOnly)
|
||||
gas = contract.Gas
|
||||
}
|
||||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
|
|
@ -531,9 +541,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
|||
//
|
||||
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
|
||||
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
|
||||
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
||||
codeAndHash := &codeAndHash{code: code}
|
||||
contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes())
|
||||
contractAddr = crypto.CreateAddress2(caller.Address(), common.Hash(salt.Bytes32()), codeAndHash.Hash().Bytes())
|
||||
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -606,7 +606,13 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
|||
stackvalue := size
|
||||
|
||||
scope.Contract.UseGas(gas)
|
||||
res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract, input, gas, value.ToBig())
|
||||
//TODO: use uint256.Int instead of converting with toBig()
|
||||
var bigVal = big0
|
||||
if !value.IsZero() {
|
||||
bigVal = value.ToBig()
|
||||
}
|
||||
|
||||
res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract, input, gas, bigVal)
|
||||
// Push item on the stack based on the returned error. If the ruleset is
|
||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||
// rule) and treat as an error, if the ruleset is frontier we must
|
||||
|
|
@ -646,8 +652,13 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
|||
scope.Contract.UseGas(gas)
|
||||
// reuse size int for stackvalue
|
||||
stackvalue := size
|
||||
//TODO: use uint256.Int instead of converting with toBig()
|
||||
bigEndowment := big0
|
||||
if !endowment.IsZero() {
|
||||
bigEndowment = endowment.ToBig()
|
||||
}
|
||||
res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract, input, gas,
|
||||
endowment.ToBig(), salt.ToBig())
|
||||
bigEndowment, &salt)
|
||||
// Push item on the stack based on the returned error.
|
||||
if suberr != nil {
|
||||
stackvalue.Clear()
|
||||
|
|
@ -680,10 +691,18 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
|
|||
if interpreter.readOnly && !value.IsZero() {
|
||||
return nil, ErrWriteProtection
|
||||
}
|
||||
|
||||
var bigVal = big0
|
||||
//TODO: use uint256.Int instead of converting with toBig()
|
||||
// By using big0 here, we save an alloc for the most common case (non-ether-transferring contract calls),
|
||||
// but it would make more sense to extend the usage of uint256.Int
|
||||
if !value.IsZero() {
|
||||
gas += params.CallStipend
|
||||
bigVal = value.ToBig()
|
||||
}
|
||||
ret, returnGas, err := interpreter.evm.Call(scope.Contract, toAddr, args, gas, value.ToBig())
|
||||
|
||||
ret, returnGas, err := interpreter.evm.Call(scope.Contract, toAddr, args, gas, bigVal)
|
||||
|
||||
if err != nil {
|
||||
temp.Clear()
|
||||
} else {
|
||||
|
|
@ -712,10 +731,14 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
|||
// Get arguments from the memory.
|
||||
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
|
||||
|
||||
//TODO: use uint256.Int instead of converting with toBig()
|
||||
var bigVal = big0
|
||||
if !value.IsZero() {
|
||||
gas += params.CallStipend
|
||||
bigVal = value.ToBig()
|
||||
}
|
||||
ret, returnGas, err := interpreter.evm.CallCode(scope.Contract, toAddr, args, gas, value.ToBig())
|
||||
|
||||
ret, returnGas, err := interpreter.evm.CallCode(scope.Contract, toAddr, args, gas, bigVal)
|
||||
if err != nil {
|
||||
temp.Clear()
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -186,6 +186,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
logged bool // deferred EVMLogger should ignore already logged steps
|
||||
res []byte // result of the opcode execution function
|
||||
)
|
||||
// Don't move this deferrred function, it's placed before the capturestate-deferred method,
|
||||
// so that it get's executed _after_: the capturestate needs the stacks before
|
||||
// they are returned to the pools
|
||||
defer func() {
|
||||
returnStack(stack)
|
||||
}()
|
||||
contract.Input = input
|
||||
|
||||
if in.cfg.Debug {
|
||||
|
|
|
|||
|
|
@ -52,13 +52,22 @@ type Config struct {
|
|||
func setDefaults(cfg *Config) {
|
||||
if cfg.ChainConfig == nil {
|
||||
cfg.ChainConfig = ¶ms.ChainConfig{
|
||||
ChainId: big.NewInt(1),
|
||||
HomesteadBlock: new(big.Int),
|
||||
DAOForkBlock: new(big.Int),
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: new(big.Int),
|
||||
EIP155Block: new(big.Int),
|
||||
EIP158Block: new(big.Int),
|
||||
ChainId: big.NewInt(1),
|
||||
HomesteadBlock: new(big.Int),
|
||||
DAOForkBlock: new(big.Int),
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: new(big.Int),
|
||||
EIP150Hash: common.Hash{},
|
||||
EIP155Block: new(big.Int),
|
||||
EIP158Block: new(big.Int),
|
||||
ByzantiumBlock: new(big.Int),
|
||||
ConstantinopleBlock: new(big.Int),
|
||||
PetersburgBlock: new(big.Int),
|
||||
IstanbulBlock: new(big.Int),
|
||||
BerlinBlock: new(big.Int),
|
||||
LondonBlock: new(big.Int),
|
||||
MergeBlock: new(big.Int),
|
||||
ShanghaiBlock: new(big.Int),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,9 +17,17 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
var stackPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return &Stack{data: make([]uint256.Int, 0, 16)}
|
||||
},
|
||||
}
|
||||
|
||||
// Stack is an object for basic stack operations. Items popped to the stack are
|
||||
// expected to be changed and modified. stack does not take care of adding newly
|
||||
// initialised objects.
|
||||
|
|
@ -28,7 +36,12 @@ type Stack struct {
|
|||
}
|
||||
|
||||
func newstack() *Stack {
|
||||
return &Stack{data: make([]uint256.Int, 0, 16)}
|
||||
return stackPool.Get().(*Stack)
|
||||
}
|
||||
|
||||
func returnStack(s *Stack) {
|
||||
s.data = s.data[:0]
|
||||
stackPool.Put(s)
|
||||
}
|
||||
|
||||
// Data returns the underlying uint256.Int array.
|
||||
|
|
|
|||
|
|
@ -179,9 +179,9 @@ func (t *SecureTrie) hashKey(key []byte) []byte {
|
|||
h := newHasher(false)
|
||||
h.sha.Reset()
|
||||
h.sha.Write(key)
|
||||
buf := h.sha.Sum(t.hashKeyBuf[:0])
|
||||
h.sha.Read(t.hashKeyBuf[:])
|
||||
returnHasherToPool(h)
|
||||
return buf
|
||||
return t.hashKeyBuf[:]
|
||||
}
|
||||
|
||||
// getSecKeyCache returns the current secure key Cache, creating a new one if
|
||||
|
|
|
|||
Loading…
Reference in a new issue