mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-03-04 10:25:04 +00:00
core/vm: Switch to branchless normalization and extend EXCHANGE (#33869)
For bal-devnet-3 we need to update the EIP-8024 implementation to the latest spec changes: https://github.com/ethereum/EIPs/pull/11306 > Note: I deleted tests not specified in the EIP bc maintaining them through EIP changes is too error prone.
This commit is contained in:
parent
6d99759f01
commit
814edc5308
2 changed files with 48 additions and 83 deletions
|
|
@ -946,24 +946,34 @@ func opSelfdestruct6780(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, erro
|
|||
return nil, errStopToken
|
||||
}
|
||||
|
||||
// decodeSingle decodes the immediate operand of a backward-compatible DUPN or SWAPN instruction (EIP-8024)
|
||||
// https://eips.ethereum.org/EIPS/eip-8024
|
||||
func decodeSingle(x byte) int {
|
||||
if x <= 90 {
|
||||
return int(x) + 17
|
||||
}
|
||||
return int(x) - 20
|
||||
// Depths 1-16 are already covered by the legacy opcodes. The forbidden byte range [91, 127] removes
|
||||
// 37 values from the 256 possible immediates, leaving 219 usable values, so this encoding covers depths
|
||||
// 17 through 235. The immediate is encoded as (x + 111) % 256, where 111 is chosen so that these values
|
||||
// avoid the forbidden range. Decoding is simply the modular inverse (i.e. 111+145=256).
|
||||
return (int(x) + 145) % 256
|
||||
}
|
||||
|
||||
// decodePair decodes the immediate operand of a backward-compatible EXCHANGE
|
||||
// instruction (EIP-8024) into stack indices (n, m) where 1 <= n < m
|
||||
// and n + m <= 30. The forbidden byte range [82, 127] removes 46 values from
|
||||
// the 256 possible immediates, leaving exactly 210 usable bytes.
|
||||
// https://eips.ethereum.org/EIPS/eip-8024
|
||||
func decodePair(x byte) (int, int) {
|
||||
var k int
|
||||
if x <= 79 {
|
||||
k = int(x)
|
||||
} else {
|
||||
k = int(x) - 48
|
||||
}
|
||||
// XOR with 143 remaps the forbidden bytes [82, 127] to an unused corner
|
||||
// of the 16x16 grid below.
|
||||
k := int(x ^ 143)
|
||||
// Split into row q and column r of a 16x16 grid. The 210 valid pairs
|
||||
// occupy two triangles within this grid.
|
||||
q, r := k/16, k%16
|
||||
// Upper triangle (q < r): pairs where m <= 16, encoded directly as
|
||||
// (q+1, r+1).
|
||||
if q < r {
|
||||
return q + 1, r + 1
|
||||
}
|
||||
// Lower triangle: pairs where m > 16, recovered as (r+1, 29-q).
|
||||
return r + 1, 29 - q
|
||||
}
|
||||
|
||||
|
|
@ -1034,8 +1044,8 @@ func opExchange(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
|||
}
|
||||
|
||||
// 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).
|
||||
if x > 79 && x < 128 {
|
||||
// and to keep decode_pair’s 16-aligned arithmetic mapping valid (0–81, 128–255).
|
||||
if x > 81 && x < 128 {
|
||||
return nil, &ErrInvalidOpCode{opcode: OpCode(x)}
|
||||
}
|
||||
n, m := decodePair(x)
|
||||
|
|
|
|||
|
|
@ -1022,16 +1022,7 @@ func TestEIP8024_Execution(t *testing.T) {
|
|||
}{
|
||||
{
|
||||
name: "DUPN",
|
||||
codeHex: "60016000808080808080808080808080808080e600",
|
||||
wantVals: []uint64{
|
||||
1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DUPN_MISSING_IMMEDIATE",
|
||||
codeHex: "60016000808080808080808080808080808080e6",
|
||||
codeHex: "60016000808080808080808080808080808080e680",
|
||||
wantVals: []uint64{
|
||||
1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
|
@ -1040,7 +1031,7 @@ func TestEIP8024_Execution(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "SWAPN",
|
||||
codeHex: "600160008080808080808080808080808080806002e700",
|
||||
codeHex: "600160008080808080808080808080808080806002e780",
|
||||
wantVals: []uint64{
|
||||
1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
|
@ -1048,22 +1039,23 @@ func TestEIP8024_Execution(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "SWAPN_MISSING_IMMEDIATE",
|
||||
codeHex: "600160008080808080808080808080808080806002e7",
|
||||
name: "EXCHANGE_MISSING_IMMEDIATE",
|
||||
codeHex: "600260008080808080600160008080808080808080e8",
|
||||
wantVals: []uint64{
|
||||
1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, // 10th from top
|
||||
0, 0, 0, 0, 0, 0,
|
||||
1, // bottom
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "EXCHANGE",
|
||||
codeHex: "600060016002e801",
|
||||
codeHex: "600060016002e88e",
|
||||
wantVals: []uint64{2, 0, 1},
|
||||
},
|
||||
{
|
||||
name: "EXCHANGE_MISSING_IMMEDIATE",
|
||||
codeHex: "600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060016002e8",
|
||||
name: "EXCHANGE",
|
||||
codeHex: "600080808080808080808080808080808080808080808080808080808060016002e88f",
|
||||
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,
|
||||
|
|
@ -1077,68 +1069,31 @@ func TestEIP8024_Execution(t *testing.T) {
|
|||
wantOpcode: SWAPN,
|
||||
},
|
||||
{
|
||||
name: "JUMP over INVALID_DUPN",
|
||||
name: "JUMP_OVER_INVALID_DUPN",
|
||||
codeHex: "600456e65b",
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
name: "UNDERFLOW_DUPN_1",
|
||||
codeHex: "6000808080808080808080808080808080e600",
|
||||
name: "EXCHANGE",
|
||||
codeHex: "60008080e88e15",
|
||||
wantVals: []uint64{1, 0, 0},
|
||||
},
|
||||
{
|
||||
name: "INVALID_EXCHANGE",
|
||||
codeHex: "e852",
|
||||
wantErr: &ErrInvalidOpCode{},
|
||||
wantOpcode: EXCHANGE,
|
||||
},
|
||||
{
|
||||
name: "UNDERFLOW_DUPN",
|
||||
codeHex: "6000808080808080808080808080808080e680",
|
||||
wantErr: &ErrStackUnderflow{},
|
||||
wantOpcode: DUPN,
|
||||
},
|
||||
// Additional test cases
|
||||
{
|
||||
name: "INVALID_DUPN_LOW",
|
||||
codeHex: "e65b",
|
||||
wantErr: &ErrInvalidOpCode{},
|
||||
wantOpcode: DUPN,
|
||||
},
|
||||
{
|
||||
name: "INVALID_EXCHANGE_LOW",
|
||||
codeHex: "e850",
|
||||
wantErr: &ErrInvalidOpCode{},
|
||||
wantOpcode: EXCHANGE,
|
||||
},
|
||||
{
|
||||
name: "INVALID_DUPN_HIGH",
|
||||
codeHex: "e67f",
|
||||
wantErr: &ErrInvalidOpCode{},
|
||||
wantOpcode: DUPN,
|
||||
},
|
||||
{
|
||||
name: "INVALID_SWAPN_HIGH",
|
||||
codeHex: "e77f",
|
||||
wantErr: &ErrInvalidOpCode{},
|
||||
wantOpcode: SWAPN,
|
||||
},
|
||||
{
|
||||
name: "INVALID_EXCHANGE_HIGH",
|
||||
codeHex: "e87f",
|
||||
wantErr: &ErrInvalidOpCode{},
|
||||
wantOpcode: EXCHANGE,
|
||||
},
|
||||
{
|
||||
name: "UNDERFLOW_DUPN_2",
|
||||
codeHex: "5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe600", // (n=17, need 17 items, have 16)
|
||||
wantErr: &ErrStackUnderflow{},
|
||||
wantOpcode: DUPN,
|
||||
},
|
||||
{
|
||||
name: "UNDERFLOW_SWAPN",
|
||||
codeHex: "5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe700", // (n=17, need 18 items, have 17)
|
||||
wantErr: &ErrStackUnderflow{},
|
||||
wantOpcode: SWAPN,
|
||||
},
|
||||
{
|
||||
name: "UNDERFLOW_EXCHANGE",
|
||||
codeHex: "60016002e801", // (n,m)=(1,2), need 3 items, have 2
|
||||
wantErr: &ErrStackUnderflow{},
|
||||
wantOpcode: EXCHANGE,
|
||||
},
|
||||
{
|
||||
name: "PC_INCREMENT",
|
||||
codeHex: "600060006000e80115",
|
||||
codeHex: "600060006000e88e15",
|
||||
wantVals: []uint64{1, 0, 0},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue