core/vm: fix opEOFCreate, correct initcode stuff

This commit is contained in:
Marius van der Wijden 2024-07-02 11:37:00 +02:00
parent abe9f28845
commit e9ad878b90
5 changed files with 45 additions and 24 deletions

View file

@ -72,6 +72,7 @@ type RefTests struct {
}
type EOFTest struct {
IsInitCode bool `json:"isInitCode"`
Code string `json:"code"`
Results map[string]etResult `json:"results"`
}
@ -84,7 +85,7 @@ type etResult struct {
func eofParser(ctx *cli.Context) error {
// If `--hex` is set, parse and validate the hex string argument.
if ctx.IsSet(HexFlag.Name) {
if _, err := parseAndValidate(ctx.String(HexFlag.Name)); err != nil {
if _, err := parseAndValidate(ctx.String(HexFlag.Name), false); err != nil {
if err2 := errors.Unwrap(err); err2 != nil {
err = err2
}
@ -143,7 +144,7 @@ func eofParser(ctx *cli.Context) error {
if len(t) == 0 || t[0] == '#' {
continue
}
if _, err := parseAndValidate(t); err != nil {
if _, err := parseAndValidate(t, false); err != nil {
if err2 := errors.Unwrap(err); err2 != nil {
err = err2
}
@ -166,7 +167,7 @@ func ExecuteTest(src []byte) (int, int, error) {
total++
// TODO(matt): all tests currently run against
// shanghai EOF, add support for custom forks.
_, err := parseAndValidate(tt.Code)
_, err := parseAndValidate(tt.Code, tt.IsInitCode)
if err2 := errors.Unwrap(err); err2 != nil {
err = err2
}
@ -193,7 +194,7 @@ func ExecuteTest(src []byte) (int, int, error) {
return passed, total, nil
}
func parseAndValidate(s string) (*vm.Container, error) {
func parseAndValidate(s string, isInitCode bool) (*vm.Container, error) {
if len(s) >= 2 && strings.HasPrefix(s, "0x") {
s = s[2:]
}
@ -202,7 +203,7 @@ func parseAndValidate(s string) (*vm.Container, error) {
return nil, fmt.Errorf("unable to decode data: %w", err)
}
var c vm.Container
if err := c.UnmarshalBinary(b); err != nil {
if err := c.UnmarshalBinary(b, isInitCode); err != nil {
return nil, err
}
if err := c.ValidateCode(&jt); err != nil {
@ -223,7 +224,7 @@ func eofDump(ctx *cli.Context) error {
return fmt.Errorf("unable to decode data: %w", err)
}
var c vm.Container
if err := c.UnmarshalBinary(b); err != nil {
if err := c.UnmarshalBinary(b, false); err != nil {
return err
}
fmt.Print(c.String())

View file

@ -297,7 +297,7 @@ func applyEOFChecks(prestate *Prestate, chainConfig *params.ChainConfig) error {
c vm.Container
err error
)
err = c.UnmarshalBinary(acc.Code)
err = c.UnmarshalBinary(acc.Code, false)
if err == nil {
jt := vm.NewPragueEOFInstructionSetForTesting()
err = c.ValidateCode(&jt)

View file

@ -882,7 +882,6 @@ func opEOFCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
salt = scope.Stack.pop()
offset, size = scope.Stack.pop(), scope.Stack.pop()
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
gas = scope.Contract.Gas
)
if int(idx) >= len(scope.Contract.Container.ContainerSections) {
return nil, fmt.Errorf("invalid subcontainer")
@ -895,6 +894,12 @@ func opEOFCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
if ok := scope.Contract.UseGas(hashingCharge, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified); !ok {
return nil, ErrGasUintOverflow
}
if interpreter.evm.Config.Tracer != nil {
if interpreter.evm.Config.Tracer != nil {
interpreter.evm.Config.Tracer.OnOpcode(*pc, byte(EOFCREATE), 0, hashingCharge, scope, interpreter.returnData, interpreter.evm.depth, nil)
}
}
gas := scope.Contract.Gas
// Reuse last popped value from stack
stackvalue := size
// Apply EIP150
@ -996,6 +1001,18 @@ func opReturnContract(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
if len(deployedCode) == 0 {
return nil, errors.New("nonexistant subcontainer")
}
// Validate the subcontainer
var c Container
if err := c.UnmarshalBinary(deployedCode, true); err != nil {
panic(fmt.Sprintf("%x", deployedCode))
}
if err := c.ValidateCode(interpreter.tableEOF); err != nil {
return nil, err
}
if len(c.Data) < c.DataSize {
return nil, errors.New("invalid subcontainer")
}
c.DataSize = len(c.Data)
// Restore context
var (
last = len(scope.ReturnStack) - 1
@ -1004,7 +1021,9 @@ func opReturnContract(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
scope.ReturnStack = scope.ReturnStack[:last]
scope.CodeSection = retCtx.Section
*pc = retCtx.Pc - 1
return deployedCode, errStopToken
fmt.Printf("%v", c.MarshalBinary())
fmt.Printf("%v", deployedCode)
return c.MarshalBinary(), errStopToken
}
func opDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {

View file

@ -142,7 +142,7 @@ func (c *Container) MarshalBinary() []byte {
}
// UnmarshalBinary decodes an EOF container.
func (c *Container) UnmarshalBinary(b []byte) error {
func (c *Container) UnmarshalBinary(b []byte, isInitcode bool) error {
if !hasEOFMagic(b) {
return fmt.Errorf("%w: want %x", ErrInvalidMagic, eofMagic)
}
@ -224,7 +224,11 @@ func (c *Container) UnmarshalBinary(b []byte) error {
if len(containerSizes) != 0 {
expectedSize += sum(containerSizes)
}
if len(b) < expectedSize-dataSize || len(b) > expectedSize {
if len(b) < expectedSize-dataSize {
return fmt.Errorf("%w: have %d, want %d", ErrInvalidContainerSize, len(b), expectedSize)
}
// Only check that the expected size is not exceed on non-initcode
if !isInitcode && len(b) > expectedSize {
return fmt.Errorf("%w: have %d, want %d", ErrInvalidContainerSize, len(b), expectedSize)
}
@ -278,7 +282,7 @@ func (c *Container) UnmarshalBinary(b []byte) error {
}
c := new(Container)
end := min(idx+size, len(b))
if err := c.UnmarshalBinary(b[idx:end]); err != nil {
if err := c.UnmarshalBinary(b[idx:end], isInitcode); err != nil {
return fmt.Errorf("%w for section %d", err, i)
}
container = append(container, c)
@ -291,7 +295,10 @@ func (c *Container) UnmarshalBinary(b []byte) error {
}
// Parse data section.
end := min(idx+dataSize, len(b))
end := len(b)
if !isInitcode {
end = min(idx+dataSize, len(b))
}
c.Data = b[idx:end]
return nil

View file

@ -487,7 +487,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
if isInitcodeEOF {
// If the initcode is EOF, verify it is well-formed.
var c Container
if err := c.UnmarshalBinary(codeAndHash.code); err != nil {
if err := c.UnmarshalBinary(codeAndHash.code, isInitcodeEOF); err != nil {
return nil, common.Address{}, gas, fmt.Errorf("%w: %v", ErrInvalidEOFInitcode, err)
}
if err := c.ValidateCode(evm.interpreter.tableEOF); err != nil {
@ -568,13 +568,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// Reject code starting with 0xEF if EIP-3541 is enabled.
if err == nil && len(ret) >= 1 && HasEOFByte(ret) {
if evm.chainRules.IsShanghai {
var c Container
if err = c.UnmarshalBinary(ret); err == nil {
err = c.ValidateCode(evm.interpreter.tableEOF)
}
if err != nil {
err = fmt.Errorf("%w: %v", ErrInvalidEOF, err)
}
// Don't reject EOF contracts after Shanghai
} else if evm.chainRules.IsLondon {
err = ErrInvalidCode
}
@ -691,7 +685,7 @@ func (evm *EVM) GetVMContext() *tracing.VMContext {
func (evm *EVM) parseContainer(b []byte) *Container {
if evm.chainRules.IsPrague {
var c Container
if err := c.UnmarshalBinary(b); err != nil && strings.HasPrefix(err.Error(), "invalid magic") {
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.