Skip to content

Commit e11db5a

Browse files
authored
Merge pull request #2670 from CortexFoundation/dev
Switch to branchless normalization and extend EXCHANGE
2 parents e9eadbd + ec1b70d commit e11db5a

File tree

2 files changed

+45
-80
lines changed

2 files changed

+45
-80
lines changed

core/vm/instructions.go

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,24 +1167,34 @@ func opSelfdestruct6780(pc *uint64, cvm *CVM, scope *ScopeContext) ([]byte, erro
11671167
return nil, errStopToken
11681168
}
11691169

1170+
// decodeSingle decodes the immediate operand of a backward-compatible DUPN or SWAPN instruction (EIP-8024)
1171+
// https://eips.ethereum.org/EIPS/eip-8024
11701172
func decodeSingle(x byte) int {
1171-
if x <= 90 {
1172-
return int(x) + 17
1173-
}
1174-
return int(x) - 20
1175-
}
1176-
1173+
// Depths 1-16 are already covered by the legacy opcodes. The forbidden byte range [91, 127] removes
1174+
// 37 values from the 256 possible immediates, leaving 219 usable values, so this encoding covers depths
1175+
// 17 through 235. The immediate is encoded as (x + 111) % 256, where 111 is chosen so that these values
1176+
// avoid the forbidden range. Decoding is simply the modular inverse (i.e. 111+145=256).
1177+
return (int(x) + 145) % 256
1178+
}
1179+
1180+
// decodePair decodes the immediate operand of a backward-compatible EXCHANGE
1181+
// instruction (EIP-8024) into stack indices (n, m) where 1 <= n < m
1182+
// and n + m <= 30. The forbidden byte range [82, 127] removes 46 values from
1183+
// the 256 possible immediates, leaving exactly 210 usable bytes.
1184+
// https://eips.ethereum.org/EIPS/eip-8024
11771185
func decodePair(x byte) (int, int) {
1178-
var k int
1179-
if x <= 79 {
1180-
k = int(x)
1181-
} else {
1182-
k = int(x) - 48
1183-
}
1186+
// XOR with 143 remaps the forbidden bytes [82, 127] to an unused corner
1187+
// of the 16x16 grid below.
1188+
k := int(x ^ 143)
1189+
// Split into row q and column r of a 16x16 grid. The 210 valid pairs
1190+
// occupy two triangles within this grid.
11841191
q, r := k/16, k%16
1192+
// Upper triangle (q < r): pairs where m <= 16, encoded directly as
1193+
// (q+1, r+1).
11851194
if q < r {
11861195
return q + 1, r + 1
11871196
}
1197+
// Lower triangle: pairs where m > 16, recovered as (r+1, 29-q).
11881198
return r + 1, 29 - q
11891199
}
11901200

@@ -1255,8 +1265,8 @@ func opExchange(pc *uint64, evm *CVM, scope *ScopeContext) ([]byte, error) {
12551265
}
12561266

12571267
// This range is excluded both to preserve compatibility with existing opcodes
1258-
// and to keep decode_pair’s 16-aligned arithmetic mapping valid (0–79, 128–255).
1259-
if x > 79 && x < 128 {
1268+
// and to keep decode_pair’s 16-aligned arithmetic mapping valid (0–81, 128–255).
1269+
if x > 81 && x < 128 {
12601270
return nil, &ErrInvalidOpCode{opcode: OpCode(x)}
12611271
}
12621272
n, m := decodePair(x)

core/vm/instructions_test.go

Lines changed: 21 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -772,16 +772,7 @@ func TestEIP8024_Execution(t *testing.T) {
772772
}{
773773
{
774774
name: "DUPN",
775-
codeHex: "60016000808080808080808080808080808080e600",
776-
wantVals: []uint64{
777-
1,
778-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
779-
1,
780-
},
781-
},
782-
{
783-
name: "DUPN_MISSING_IMMEDIATE",
784-
codeHex: "60016000808080808080808080808080808080e6",
775+
codeHex: "60016000808080808080808080808080808080e680",
785776
wantVals: []uint64{
786777
1,
787778
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -790,30 +781,31 @@ func TestEIP8024_Execution(t *testing.T) {
790781
},
791782
{
792783
name: "SWAPN",
793-
codeHex: "600160008080808080808080808080808080806002e700",
784+
codeHex: "600160008080808080808080808080808080806002e780",
794785
wantVals: []uint64{
795786
1,
796787
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
797788
2,
798789
},
799790
},
800791
{
801-
name: "SWAPN_MISSING_IMMEDIATE",
802-
codeHex: "600160008080808080808080808080808080806002e7",
792+
name: "EXCHANGE_MISSING_IMMEDIATE",
793+
codeHex: "600260008080808080600160008080808080808080e8",
803794
wantVals: []uint64{
804-
1,
805-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
806-
2,
795+
0, 0, 0, 0, 0, 0, 0, 0, 0,
796+
2, // 10th from top
797+
0, 0, 0, 0, 0, 0,
798+
1, // bottom
807799
},
808800
},
809801
{
810802
name: "EXCHANGE",
811-
codeHex: "600060016002e801",
803+
codeHex: "600060016002e88e",
812804
wantVals: []uint64{2, 0, 1},
813805
},
814806
{
815-
name: "EXCHANGE_MISSING_IMMEDIATE",
816-
codeHex: "600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060016002e8",
807+
name: "EXCHANGE",
808+
codeHex: "600080808080808080808080808080808080808080808080808080808060016002e88f",
817809
wantVals: []uint64{
818810
2,
819811
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,
@@ -827,68 +819,31 @@ func TestEIP8024_Execution(t *testing.T) {
827819
wantOpcode: SWAPN,
828820
},
829821
{
830-
name: "JUMP over INVALID_DUPN",
822+
name: "JUMP_OVER_INVALID_DUPN",
831823
codeHex: "600456e65b",
832824
wantErr: nil,
833825
},
834826
{
835-
name: "UNDERFLOW_DUPN_1",
836-
codeHex: "6000808080808080808080808080808080e600",
837-
wantErr: &ErrStackUnderflow{},
838-
wantOpcode: DUPN,
839-
},
840-
// Additional test cases
841-
{
842-
name: "INVALID_DUPN_LOW",
843-
codeHex: "e65b",
844-
wantErr: &ErrInvalidOpCode{},
845-
wantOpcode: DUPN,
846-
},
847-
{
848-
name: "INVALID_EXCHANGE_LOW",
849-
codeHex: "e850",
850-
wantErr: &ErrInvalidOpCode{},
851-
wantOpcode: EXCHANGE,
852-
},
853-
{
854-
name: "INVALID_DUPN_HIGH",
855-
codeHex: "e67f",
856-
wantErr: &ErrInvalidOpCode{},
857-
wantOpcode: DUPN,
858-
},
859-
{
860-
name: "INVALID_SWAPN_HIGH",
861-
codeHex: "e77f",
862-
wantErr: &ErrInvalidOpCode{},
863-
wantOpcode: SWAPN,
827+
name: "EXCHANGE",
828+
codeHex: "60008080e88e15",
829+
wantVals: []uint64{1, 0, 0},
864830
},
865831
{
866-
name: "INVALID_EXCHANGE_HIGH",
867-
codeHex: "e87f",
832+
name: "INVALID_EXCHANGE",
833+
codeHex: "e852",
868834
wantErr: &ErrInvalidOpCode{},
869835
wantOpcode: EXCHANGE,
870836
},
871837
{
872-
name: "UNDERFLOW_DUPN_2",
873-
codeHex: "5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe600", // (n=17, need 17 items, have 16)
838+
name: "UNDERFLOW_DUPN",
839+
codeHex: "6000808080808080808080808080808080e680",
874840
wantErr: &ErrStackUnderflow{},
875841
wantOpcode: DUPN,
876842
},
877-
{
878-
name: "UNDERFLOW_SWAPN",
879-
codeHex: "5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe700", // (n=17, need 18 items, have 17)
880-
wantErr: &ErrStackUnderflow{},
881-
wantOpcode: SWAPN,
882-
},
883-
{
884-
name: "UNDERFLOW_EXCHANGE",
885-
codeHex: "60016002e801", // (n,m)=(1,2), need 3 items, have 2
886-
wantErr: &ErrStackUnderflow{},
887-
wantOpcode: EXCHANGE,
888-
},
843+
// Additional test cases
889844
{
890845
name: "PC_INCREMENT",
891-
codeHex: "600060006000e80115",
846+
codeHex: "600060006000e88e15",
892847
wantVals: []uint64{1, 0, 0},
893848
},
894849
}

0 commit comments

Comments
 (0)