diff --git a/cmd/eofdump/eofparser.go b/cmd/eofdump/eofparser.go index a494a74ede..de5b4e500c 100644 --- a/cmd/eofdump/eofparser.go +++ b/cmd/eofdump/eofparser.go @@ -72,8 +72,9 @@ type RefTests struct { } type EOFTest struct { - Code string `json:"code"` - Results map[string]etResult `json:"results"` + IsInitCode bool `json:"isInitCode"` + Code string `json:"code"` + Results map[string]etResult `json:"results"` } type etResult struct { @@ -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()) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index d4946d2545..dfa27f3871 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -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) diff --git a/core/vm/eips.go b/core/vm/eips.go index 0489c25eb9..d26eb9e60c 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -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) { diff --git a/core/vm/eof.go b/core/vm/eof.go index e968683d3d..349ca4d5f7 100644 --- a/core/vm/eof.go +++ b/core/vm/eof.go @@ -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 diff --git a/core/vm/evm.go b/core/vm/evm.go index 286e160e0d..19e24f6e23 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -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.