core/vm: parse containers on call
This commit is contained in:
parent
44125c2e45
commit
d744516b74
|
@ -52,10 +52,11 @@ type Contract struct {
|
|||
jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis.
|
||||
analysis bitvec // Locally cached result of JUMPDEST analysis
|
||||
|
||||
Code []byte
|
||||
CodeHash common.Hash
|
||||
CodeAddr *common.Address
|
||||
Input []byte
|
||||
Code []byte
|
||||
Container *Container
|
||||
CodeHash common.Hash
|
||||
CodeAddr *common.Address
|
||||
Input []byte
|
||||
|
||||
// is the execution frame represented by this object a contract deployment
|
||||
IsDeployment bool
|
||||
|
@ -144,11 +145,12 @@ func (c *Contract) AsDelegate() *Contract {
|
|||
}
|
||||
|
||||
// GetOp returns the n'th element in the contract's byte array
|
||||
func (c *Contract) GetOp(n uint64) OpCode {
|
||||
if n < uint64(len(c.Code)) {
|
||||
func (c *Contract) GetOp(n uint64, s uint64) OpCode {
|
||||
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 STOP
|
||||
}
|
||||
|
||||
|
@ -193,10 +195,23 @@ func (c *Contract) Value() *uint256.Int {
|
|||
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
|
||||
// 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.Container = container
|
||||
c.CodeHash = hash
|
||||
c.CodeAddr = addr
|
||||
}
|
||||
|
|
|
@ -18,7 +18,9 @@ package vm
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"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
|
||||
// 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)
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code, evm.parseContainer(code))
|
||||
ret, err = evm.interpreter.Run(contract, input, false)
|
||||
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 {
|
||||
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)
|
||||
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 {
|
||||
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)
|
||||
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 {
|
||||
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
|
||||
// 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.
|
||||
|
@ -617,3 +622,18 @@ func (evm *EVM) GetVMContext() *tracing.VMContext {
|
|||
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