diff --git a/core/vm/instructions.go b/core/vm/instructions.go index a7bd7c9624..65d77132b8 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -1192,11 +1192,11 @@ func opDupN(pc *uint64, evm *CVM, scope *ScopeContext) ([]byte, error) { code := scope.Contract.Code i := *pc + 1 - // Ensure an immediate byte exists after DUPN - if i >= uint64(len(code)) { - return nil, &ErrInvalidOpCode{opcode: INVALID} + // If the immediate byte is missing, treat as 0x00 (same convention as PUSHn). + var x byte + if i < uint64(len(code)) { + x = code[i] } - x := code[i] // This range is excluded to preserve compatibility with existing opcodes. if x > 90 && x < 128 { @@ -1219,11 +1219,11 @@ func opSwapN(pc *uint64, evm *CVM, scope *ScopeContext) ([]byte, error) { code := scope.Contract.Code i := *pc + 1 - // Ensure an immediate byte exists after SWAPN - if i >= uint64(len(code)) { - return nil, &ErrInvalidOpCode{opcode: INVALID} + // If the immediate byte is missing, treat as 0x00 (same convention as PUSHn). + var x byte + if i < uint64(len(code)) { + x = code[i] } - x := code[i] // This range is excluded to preserve compatibility with existing opcodes. if x > 90 && x < 128 { @@ -1248,11 +1248,11 @@ func opExchange(pc *uint64, evm *CVM, scope *ScopeContext) ([]byte, error) { code := scope.Contract.Code i := *pc + 1 - // Ensure an immediate byte exists after EXCHANGE - if i >= uint64(len(code)) { - return nil, &ErrInvalidOpCode{opcode: INVALID} + // If the immediate byte is missing, treat as 0x00 (same convention as PUSHn). + var x byte + if i < uint64(len(code)) { + x = code[i] } - x := code[i] // This range is excluded both to preserve compatibility with existing opcodes // and to keep decode_pair’s 16-aligned arithmetic mapping valid (0–79, 128–255). diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 0e7a8be52d..b7ad59d6c8 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -777,6 +777,15 @@ func TestEIP8024_Execution(t *testing.T) { 1, }, }, + { + name: "DUPN_MISSING_IMMEDIATE", + codeHex: "60016000808080808080808080808080808080e6", + wantVals: []uint64{ + 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, + }, + }, { name: "SWAPN", codeHex: "600160008080808080808080808080808080806002e700", @@ -786,11 +795,29 @@ func TestEIP8024_Execution(t *testing.T) { 2, }, }, + { + name: "SWAPN_MISSING_IMMEDIATE", + codeHex: "600160008080808080808080808080808080806002e7", + wantVals: []uint64{ + 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, + }, + }, { name: "EXCHANGE", codeHex: "600060016002e801", wantVals: []uint64{2, 0, 1}, }, + { + name: "EXCHANGE_MISSING_IMMEDIATE", + codeHex: "600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060016002e8", + wantVals: []uint64{ + 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, + }, + }, { name: "INVALID_SWAPN_LOW", codeHex: "e75b", @@ -842,21 +869,6 @@ func TestEIP8024_Execution(t *testing.T) { codeHex: "60016002e801", // (n,m)=(1,2), need 3 items, have 2 wantErr: true, }, - { - name: "MISSING_IMMEDIATE_DUPN", - codeHex: "e6", // no operand - wantErr: true, - }, - { - name: "MISSING_IMMEDIATE_SWAPN", - codeHex: "e7", // no operand - wantErr: true, - }, - { - name: "MISSING_IMMEDIATE_EXCHANGE", - codeHex: "e8", // no operand - wantErr: true, - }, { name: "PC_INCREMENT", codeHex: "600060006000e80115", @@ -873,25 +885,25 @@ func TestEIP8024_Execution(t *testing.T) { var err error for pc < uint64(len(code)) && err == nil { op := code[pc] - switch op { - case 0x00: + switch OpCode(op) { + case STOP: return - case 0x60: + case PUSH1: _, err = opPush1(&pc, evm, scope) - case 0x80: + case DUP1: dup1 := makeDup(1) _, err = dup1(&pc, evm, scope) - case 0x56: + case JUMP: _, err = opJump(&pc, evm, scope) - case 0x5b: + case JUMPDEST: _, err = opJumpdest(&pc, evm, scope) - case 0x15: + case ISZERO: _, err = opIszero(&pc, evm, scope) - case 0xe6: + case DUPN: _, err = opDupN(&pc, evm, scope) - case 0xe7: + case SWAPN: _, err = opSwapN(&pc, evm, scope) - case 0xe8: + case EXCHANGE: _, err = opExchange(&pc, evm, scope) default: err = &ErrInvalidOpCode{opcode: OpCode(op)} diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 6a7f5294f6..03db5e8a72 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -206,6 +206,29 @@ const ( LOG4 ) +// 0xd0 range - eof operations. +const ( + DATALOAD OpCode = 0xd0 + DATALOADN OpCode = 0xd1 + DATASIZE OpCode = 0xd2 + DATACOPY OpCode = 0xd3 +) + +// 0xe0 range - eof operations. +const ( + RJUMP OpCode = 0xe0 + RJUMPI OpCode = 0xe1 + RJUMPV OpCode = 0xe2 + CALLF OpCode = 0xe3 + RETF OpCode = 0xe4 + JUMPF OpCode = 0xe5 + DUPN OpCode = 0xe6 + SWAPN OpCode = 0xe7 + EXCHANGE OpCode = 0xe8 + EOFCREATE OpCode = 0xec + RETURNCONTRACT OpCode = 0xee +) + // 0xf0 range - closures. const ( CREATE OpCode = 0xf0 + iota