core/vm: parse containers on call
This commit is contained in:
parent
44125c2e45
commit
d744516b74
|
@ -53,6 +53,7 @@ type Contract struct {
|
||||||
analysis bitvec // Locally cached result of JUMPDEST analysis
|
analysis bitvec // Locally cached result of JUMPDEST analysis
|
||||||
|
|
||||||
Code []byte
|
Code []byte
|
||||||
|
Container *Container
|
||||||
CodeHash common.Hash
|
CodeHash common.Hash
|
||||||
CodeAddr *common.Address
|
CodeAddr *common.Address
|
||||||
Input []byte
|
Input []byte
|
||||||
|
@ -144,11 +145,12 @@ func (c *Contract) AsDelegate() *Contract {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOp returns the n'th element in the contract's byte array
|
// GetOp returns the n'th element in the contract's byte array
|
||||||
func (c *Contract) GetOp(n uint64) OpCode {
|
func (c *Contract) GetOp(n uint64, s uint64) OpCode {
|
||||||
if n < uint64(len(c.Code)) {
|
if c.IsEOF() && n < uint64(len(c.Container.codeSections[s])) {
|
||||||
|
return OpCode(c.Container.codeSections[s][n])
|
||||||
|
} else if n < uint64(len(c.Code)) {
|
||||||
return OpCode(c.Code[n])
|
return OpCode(c.Code[n])
|
||||||
}
|
}
|
||||||
|
|
||||||
return STOP
|
return STOP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,10 +195,23 @@ func (c *Contract) Value() *uint256.Int {
|
||||||
return c.value
|
return c.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsEOF returns whether the contract is EOF.
|
||||||
|
func (c *Contract) IsEOF() bool {
|
||||||
|
return c.Container != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Contract) CodeAt(section uint64) []byte {
|
||||||
|
if c.Container == nil {
|
||||||
|
return c.Code
|
||||||
|
}
|
||||||
|
return c.Container.codeSections[section]
|
||||||
|
}
|
||||||
|
|
||||||
// SetCallCode sets the code of the contract and address of the backing data
|
// SetCallCode sets the code of the contract and address of the backing data
|
||||||
// object
|
// object
|
||||||
func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) {
|
func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte, container *Container) {
|
||||||
c.Code = code
|
c.Code = code
|
||||||
|
c.Container = container
|
||||||
c.CodeHash = hash
|
c.CodeHash = hash
|
||||||
c.CodeAddr = addr
|
c.CodeAddr = addr
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,9 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
@ -223,7 +225,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||||
// If the account has no code, we can abort here
|
// If the account has no code, we can abort here
|
||||||
// The depth-check is already done, and precompiles handled above
|
// The depth-check is already done, and precompiles handled above
|
||||||
contract := NewContract(caller, AccountRef(addrCopy), value, gas)
|
contract := NewContract(caller, AccountRef(addrCopy), value, gas)
|
||||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code)
|
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code, evm.parseContainer(code))
|
||||||
ret, err = evm.interpreter.Run(contract, input, false)
|
ret, err = evm.interpreter.Run(contract, input, false)
|
||||||
gas = contract.Gas
|
gas = contract.Gas
|
||||||
}
|
}
|
||||||
|
@ -286,7 +288,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||||
if witness := evm.StateDB.Witness(); witness != nil {
|
if witness := evm.StateDB.Witness(); witness != nil {
|
||||||
witness.AddCode(evm.StateDB.GetCode(addrCopy))
|
witness.AddCode(evm.StateDB.GetCode(addrCopy))
|
||||||
}
|
}
|
||||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
code := evm.StateDB.GetCode(addrCopy)
|
||||||
|
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code, evm.parseContainer(code))
|
||||||
ret, err = evm.interpreter.Run(contract, input, false)
|
ret, err = evm.interpreter.Run(contract, input, false)
|
||||||
gas = contract.Gas
|
gas = contract.Gas
|
||||||
}
|
}
|
||||||
|
@ -336,7 +339,8 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||||
if witness := evm.StateDB.Witness(); witness != nil {
|
if witness := evm.StateDB.Witness(); witness != nil {
|
||||||
witness.AddCode(evm.StateDB.GetCode(addrCopy))
|
witness.AddCode(evm.StateDB.GetCode(addrCopy))
|
||||||
}
|
}
|
||||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
code := evm.StateDB.GetCode(addrCopy)
|
||||||
|
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code, evm.parseContainer(code))
|
||||||
ret, err = evm.interpreter.Run(contract, input, false)
|
ret, err = evm.interpreter.Run(contract, input, false)
|
||||||
gas = contract.Gas
|
gas = contract.Gas
|
||||||
}
|
}
|
||||||
|
@ -394,7 +398,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||||
if witness := evm.StateDB.Witness(); witness != nil {
|
if witness := evm.StateDB.Witness(); witness != nil {
|
||||||
witness.AddCode(evm.StateDB.GetCode(addrCopy))
|
witness.AddCode(evm.StateDB.GetCode(addrCopy))
|
||||||
}
|
}
|
||||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
code := evm.StateDB.GetCode(addrCopy)
|
||||||
|
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code, evm.parseContainer(code))
|
||||||
// When an error was returned by the EVM or when setting the creation code
|
// 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
|
// 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.
|
// when we're in Homestead this also counts for code storage gas errors.
|
||||||
|
@ -617,3 +622,18 @@ func (evm *EVM) GetVMContext() *tracing.VMContext {
|
||||||
StateDB: evm.StateDB,
|
StateDB: evm.StateDB,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseContainer tries to parse an EOF container if the Shanghai fork is active. It expects the code to already be validated.
|
||||||
|
func (evm *EVM) parseContainer(b []byte) *Container {
|
||||||
|
if evm.chainRules.IsPrague {
|
||||||
|
var c Container
|
||||||
|
if err := c.UnmarshalBinary(b, false); err != nil && strings.HasPrefix(err.Error(), "invalid magic") {
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
// Code was already validated, so no other errors should be possible.
|
||||||
|
panic(fmt.Sprintf("unexpected error: %v\ncode: %s\n", err, common.Bytes2Hex(b)))
|
||||||
|
}
|
||||||
|
return &c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue