mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
core/vm: fix opEOFCreate, correct initcode stuff
This commit is contained in:
parent
abe9f28845
commit
e9ad878b90
5 changed files with 45 additions and 24 deletions
|
|
@ -72,6 +72,7 @@ type RefTests struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type EOFTest struct {
|
type EOFTest struct {
|
||||||
|
IsInitCode bool `json:"isInitCode"`
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
Results map[string]etResult `json:"results"`
|
Results map[string]etResult `json:"results"`
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +85,7 @@ type etResult struct {
|
||||||
func eofParser(ctx *cli.Context) error {
|
func eofParser(ctx *cli.Context) error {
|
||||||
// If `--hex` is set, parse and validate the hex string argument.
|
// If `--hex` is set, parse and validate the hex string argument.
|
||||||
if ctx.IsSet(HexFlag.Name) {
|
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 {
|
if err2 := errors.Unwrap(err); err2 != nil {
|
||||||
err = err2
|
err = err2
|
||||||
}
|
}
|
||||||
|
|
@ -143,7 +144,7 @@ func eofParser(ctx *cli.Context) error {
|
||||||
if len(t) == 0 || t[0] == '#' {
|
if len(t) == 0 || t[0] == '#' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, err := parseAndValidate(t); err != nil {
|
if _, err := parseAndValidate(t, false); err != nil {
|
||||||
if err2 := errors.Unwrap(err); err2 != nil {
|
if err2 := errors.Unwrap(err); err2 != nil {
|
||||||
err = err2
|
err = err2
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +167,7 @@ func ExecuteTest(src []byte) (int, int, error) {
|
||||||
total++
|
total++
|
||||||
// TODO(matt): all tests currently run against
|
// TODO(matt): all tests currently run against
|
||||||
// shanghai EOF, add support for custom forks.
|
// shanghai EOF, add support for custom forks.
|
||||||
_, err := parseAndValidate(tt.Code)
|
_, err := parseAndValidate(tt.Code, tt.IsInitCode)
|
||||||
if err2 := errors.Unwrap(err); err2 != nil {
|
if err2 := errors.Unwrap(err); err2 != nil {
|
||||||
err = err2
|
err = err2
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +194,7 @@ func ExecuteTest(src []byte) (int, int, error) {
|
||||||
return passed, total, nil
|
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") {
|
if len(s) >= 2 && strings.HasPrefix(s, "0x") {
|
||||||
s = s[2:]
|
s = s[2:]
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +203,7 @@ func parseAndValidate(s string) (*vm.Container, error) {
|
||||||
return nil, fmt.Errorf("unable to decode data: %w", err)
|
return nil, fmt.Errorf("unable to decode data: %w", err)
|
||||||
}
|
}
|
||||||
var c vm.Container
|
var c vm.Container
|
||||||
if err := c.UnmarshalBinary(b); err != nil {
|
if err := c.UnmarshalBinary(b, isInitCode); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := c.ValidateCode(&jt); err != nil {
|
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)
|
return fmt.Errorf("unable to decode data: %w", err)
|
||||||
}
|
}
|
||||||
var c vm.Container
|
var c vm.Container
|
||||||
if err := c.UnmarshalBinary(b); err != nil {
|
if err := c.UnmarshalBinary(b, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Print(c.String())
|
fmt.Print(c.String())
|
||||||
|
|
|
||||||
|
|
@ -297,7 +297,7 @@ func applyEOFChecks(prestate *Prestate, chainConfig *params.ChainConfig) error {
|
||||||
c vm.Container
|
c vm.Container
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
err = c.UnmarshalBinary(acc.Code)
|
err = c.UnmarshalBinary(acc.Code, false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
jt := vm.NewPragueEOFInstructionSetForTesting()
|
jt := vm.NewPragueEOFInstructionSetForTesting()
|
||||||
err = c.ValidateCode(&jt)
|
err = c.ValidateCode(&jt)
|
||||||
|
|
|
||||||
|
|
@ -882,7 +882,6 @@ func opEOFCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
||||||
salt = scope.Stack.pop()
|
salt = scope.Stack.pop()
|
||||||
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
offset, size = scope.Stack.pop(), scope.Stack.pop()
|
||||||
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
|
input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
|
||||||
gas = scope.Contract.Gas
|
|
||||||
)
|
)
|
||||||
if int(idx) >= len(scope.Contract.Container.ContainerSections) {
|
if int(idx) >= len(scope.Contract.Container.ContainerSections) {
|
||||||
return nil, fmt.Errorf("invalid subcontainer")
|
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 {
|
if ok := scope.Contract.UseGas(hashingCharge, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified); !ok {
|
||||||
return nil, ErrGasUintOverflow
|
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
|
// Reuse last popped value from stack
|
||||||
stackvalue := size
|
stackvalue := size
|
||||||
// Apply EIP150
|
// Apply EIP150
|
||||||
|
|
@ -996,6 +1001,18 @@ func opReturnContract(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
|
||||||
if len(deployedCode) == 0 {
|
if len(deployedCode) == 0 {
|
||||||
return nil, errors.New("nonexistant subcontainer")
|
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
|
// Restore context
|
||||||
var (
|
var (
|
||||||
last = len(scope.ReturnStack) - 1
|
last = len(scope.ReturnStack) - 1
|
||||||
|
|
@ -1004,7 +1021,9 @@ func opReturnContract(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
|
||||||
scope.ReturnStack = scope.ReturnStack[:last]
|
scope.ReturnStack = scope.ReturnStack[:last]
|
||||||
scope.CodeSection = retCtx.Section
|
scope.CodeSection = retCtx.Section
|
||||||
*pc = retCtx.Pc - 1
|
*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) {
|
func opDataLoad(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ func (c *Container) MarshalBinary() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalBinary decodes an EOF container.
|
// UnmarshalBinary decodes an EOF container.
|
||||||
func (c *Container) UnmarshalBinary(b []byte) error {
|
func (c *Container) UnmarshalBinary(b []byte, isInitcode bool) error {
|
||||||
if !hasEOFMagic(b) {
|
if !hasEOFMagic(b) {
|
||||||
return fmt.Errorf("%w: want %x", ErrInvalidMagic, eofMagic)
|
return fmt.Errorf("%w: want %x", ErrInvalidMagic, eofMagic)
|
||||||
}
|
}
|
||||||
|
|
@ -224,7 +224,11 @@ func (c *Container) UnmarshalBinary(b []byte) error {
|
||||||
if len(containerSizes) != 0 {
|
if len(containerSizes) != 0 {
|
||||||
expectedSize += sum(containerSizes)
|
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)
|
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)
|
c := new(Container)
|
||||||
end := min(idx+size, len(b))
|
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)
|
return fmt.Errorf("%w for section %d", err, i)
|
||||||
}
|
}
|
||||||
container = append(container, c)
|
container = append(container, c)
|
||||||
|
|
@ -291,7 +295,10 @@ func (c *Container) UnmarshalBinary(b []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse data section.
|
// 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]
|
c.Data = b[idx:end]
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -487,7 +487,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
if isInitcodeEOF {
|
if isInitcodeEOF {
|
||||||
// If the initcode is EOF, verify it is well-formed.
|
// If the initcode is EOF, verify it is well-formed.
|
||||||
var c Container
|
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)
|
return nil, common.Address{}, gas, fmt.Errorf("%w: %v", ErrInvalidEOFInitcode, err)
|
||||||
}
|
}
|
||||||
if err := c.ValidateCode(evm.interpreter.tableEOF); err != nil {
|
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.
|
// Reject code starting with 0xEF if EIP-3541 is enabled.
|
||||||
if err == nil && len(ret) >= 1 && HasEOFByte(ret) {
|
if err == nil && len(ret) >= 1 && HasEOFByte(ret) {
|
||||||
if evm.chainRules.IsShanghai {
|
if evm.chainRules.IsShanghai {
|
||||||
var c Container
|
// Don't reject EOF contracts after Shanghai
|
||||||
if err = c.UnmarshalBinary(ret); err == nil {
|
|
||||||
err = c.ValidateCode(evm.interpreter.tableEOF)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("%w: %v", ErrInvalidEOF, err)
|
|
||||||
}
|
|
||||||
} else if evm.chainRules.IsLondon {
|
} else if evm.chainRules.IsLondon {
|
||||||
err = ErrInvalidCode
|
err = ErrInvalidCode
|
||||||
}
|
}
|
||||||
|
|
@ -691,7 +685,7 @@ func (evm *EVM) GetVMContext() *tracing.VMContext {
|
||||||
func (evm *EVM) parseContainer(b []byte) *Container {
|
func (evm *EVM) parseContainer(b []byte) *Container {
|
||||||
if evm.chainRules.IsPrague {
|
if evm.chainRules.IsPrague {
|
||||||
var c Container
|
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
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
// Code was already validated, so no other errors should be possible.
|
// Code was already validated, so no other errors should be possible.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue