Skip to content

Commit 4b5d15e

Browse files
authored
Merge pull request #2604 from CortexFoundation/dev
fix PC increment
2 parents 39f7ed1 + 6be1d43 commit 4b5d15e

2 files changed

Lines changed: 276 additions & 0 deletions

File tree

core/vm/instructions.go

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

1170+
func decodeSingle(x byte) int {
1171+
if x <= 90 {
1172+
return int(x) + 17
1173+
}
1174+
return int(x) - 20
1175+
}
1176+
1177+
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+
}
1184+
q, r := k/16, k%16
1185+
if q < r {
1186+
return q + 1, r + 1
1187+
}
1188+
return r + 1, 29 - q
1189+
}
1190+
1191+
func opDupN(pc *uint64, evm *CVM, scope *ScopeContext) ([]byte, error) {
1192+
code := scope.Contract.Code
1193+
i := *pc + 1
1194+
1195+
// Ensure an immediate byte exists after DUPN
1196+
if i >= uint64(len(code)) {
1197+
return nil, &ErrInvalidOpCode{opcode: INVALID}
1198+
}
1199+
x := code[i]
1200+
1201+
// This range is excluded to preserve compatibility with existing opcodes.
1202+
if x > 90 && x < 128 {
1203+
return nil, &ErrInvalidOpCode{opcode: OpCode(x)}
1204+
}
1205+
n := decodeSingle(x)
1206+
1207+
// DUPN duplicates the n'th stack item, so the stack must contain at least n elements.
1208+
if scope.Stack.len() < n {
1209+
return nil, &ErrStackUnderflow{stackLen: scope.Stack.len(), required: n}
1210+
}
1211+
1212+
//The n‘th stack item is duplicated at the top of the stack.
1213+
scope.Stack.push(scope.Stack.Back(n - 1))
1214+
*pc += 1
1215+
return nil, nil
1216+
}
1217+
1218+
func opSwapN(pc *uint64, evm *CVM, scope *ScopeContext) ([]byte, error) {
1219+
code := scope.Contract.Code
1220+
i := *pc + 1
1221+
1222+
// Ensure an immediate byte exists after SWAPN
1223+
if i >= uint64(len(code)) {
1224+
return nil, &ErrInvalidOpCode{opcode: INVALID}
1225+
}
1226+
x := code[i]
1227+
1228+
// This range is excluded to preserve compatibility with existing opcodes.
1229+
if x > 90 && x < 128 {
1230+
return nil, &ErrInvalidOpCode{opcode: OpCode(x)}
1231+
}
1232+
n := decodeSingle(x)
1233+
1234+
// SWAPN operates on the top and n+1 stack items, so the stack must contain at least n+1 elements.
1235+
if scope.Stack.len() < n+1 {
1236+
return nil, &ErrStackUnderflow{stackLen: scope.Stack.len(), required: n + 1}
1237+
}
1238+
1239+
// The (n+1)‘th stack item is swapped with the top of the stack.
1240+
indexTop := scope.Stack.len() - 1
1241+
indexN := scope.Stack.len() - 1 - n
1242+
scope.Stack.data[indexTop], scope.Stack.data[indexN] = scope.Stack.data[indexN], scope.Stack.data[indexTop]
1243+
*pc += 1
1244+
return nil, nil
1245+
}
1246+
1247+
func opExchange(pc *uint64, evm *CVM, scope *ScopeContext) ([]byte, error) {
1248+
code := scope.Contract.Code
1249+
i := *pc + 1
1250+
1251+
// Ensure an immediate byte exists after EXCHANGE
1252+
if i >= uint64(len(code)) {
1253+
return nil, &ErrInvalidOpCode{opcode: INVALID}
1254+
}
1255+
x := code[i]
1256+
1257+
// 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 {
1260+
return nil, &ErrInvalidOpCode{opcode: OpCode(x)}
1261+
}
1262+
n, m := decodePair(x)
1263+
need := max(n, m) + 1
1264+
1265+
// EXCHANGE operates on the (n+1)'th and (m+1)'th stack items,
1266+
// so the stack must contain at least max(n, m)+1 elements.
1267+
if scope.Stack.len() < need {
1268+
return nil, &ErrStackUnderflow{stackLen: scope.Stack.len(), required: need}
1269+
}
1270+
1271+
// The (n+1)‘th stack item is swapped with the (m+1)‘th stack item.
1272+
indexN := scope.Stack.len() - 1 - n
1273+
indexM := scope.Stack.len() - 1 - m
1274+
scope.Stack.data[indexN], scope.Stack.data[indexM] = scope.Stack.data[indexM], scope.Stack.data[indexN]
1275+
*pc += 1
1276+
return nil, nil
1277+
}
1278+
1279+
// following functions are used by the instruction jump table
1280+
11701281
// make log instruction function
11711282
func makeLog(size int) executionFunc {
11721283
return func(pc *uint64, cvm *CVM, scope *ScopeContext) ([]byte, error) {

core/vm/instructions_test.go

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,3 +758,168 @@ func TestOpCLZ(t *testing.T) {
758758
}
759759
}
760760
}
761+
762+
func TestEIP8024_Execution(t *testing.T) {
763+
evm := NewCVM(BlockContext{}, nil, params.TestChainConfig, Config{})
764+
765+
tests := []struct {
766+
name string
767+
codeHex string
768+
wantErr bool
769+
wantVals []uint64
770+
}{
771+
{
772+
name: "DUPN",
773+
codeHex: "60016000808080808080808080808080808080e600",
774+
wantVals: []uint64{
775+
1,
776+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
777+
1,
778+
},
779+
},
780+
{
781+
name: "SWAPN",
782+
codeHex: "600160008080808080808080808080808080806002e700",
783+
wantVals: []uint64{
784+
1,
785+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
786+
2,
787+
},
788+
},
789+
{
790+
name: "EXCHANGE",
791+
codeHex: "600060016002e801",
792+
wantVals: []uint64{2, 0, 1},
793+
},
794+
{
795+
name: "INVALID_SWAPN_LOW",
796+
codeHex: "e75b",
797+
wantErr: true,
798+
},
799+
{
800+
name: "JUMP over INVALID_DUPN",
801+
codeHex: "600456e65b",
802+
wantErr: false,
803+
},
804+
// Additional test cases
805+
{
806+
name: "INVALID_DUPN_LOW",
807+
codeHex: "e65b",
808+
wantErr: true,
809+
},
810+
{
811+
name: "INVALID_EXCHANGE_LOW",
812+
codeHex: "e850",
813+
wantErr: true,
814+
},
815+
{
816+
name: "INVALID_DUPN_HIGH",
817+
codeHex: "e67f",
818+
wantErr: true,
819+
},
820+
{
821+
name: "INVALID_SWAPN_HIGH",
822+
codeHex: "e77f",
823+
wantErr: true,
824+
},
825+
{
826+
name: "INVALID_EXCHANGE_HIGH",
827+
codeHex: "e87f",
828+
wantErr: true,
829+
},
830+
{
831+
name: "UNDERFLOW_DUPN",
832+
codeHex: "5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe600", // (n=17, need 17 items, have 16)
833+
wantErr: true,
834+
},
835+
{
836+
name: "UNDERFLOW_SWAPN",
837+
codeHex: "5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5f5fe700", // (n=17, need 18 items, have 17)
838+
wantErr: true,
839+
},
840+
{
841+
name: "UNDERFLOW_EXCHANGE",
842+
codeHex: "60016002e801", // (n,m)=(1,2), need 3 items, have 2
843+
wantErr: true,
844+
},
845+
{
846+
name: "MISSING_IMMEDIATE_DUPN",
847+
codeHex: "e6", // no operand
848+
wantErr: true,
849+
},
850+
{
851+
name: "MISSING_IMMEDIATE_SWAPN",
852+
codeHex: "e7", // no operand
853+
wantErr: true,
854+
},
855+
{
856+
name: "MISSING_IMMEDIATE_EXCHANGE",
857+
codeHex: "e8", // no operand
858+
wantErr: true,
859+
},
860+
{
861+
name: "PC_INCREMENT",
862+
codeHex: "600060006000e80115",
863+
wantVals: []uint64{1, 0, 0},
864+
},
865+
}
866+
867+
for _, tc := range tests {
868+
t.Run(tc.name, func(t *testing.T) {
869+
code := common.FromHex(tc.codeHex)
870+
stack := newstack()
871+
pc := uint64(0)
872+
scope := &ScopeContext{Stack: stack, Contract: &Contract{Code: code}}
873+
var err error
874+
for pc < uint64(len(code)) && err == nil {
875+
op := code[pc]
876+
switch op {
877+
case 0x00:
878+
return
879+
case 0x60:
880+
_, err = opPush1(&pc, evm, scope)
881+
case 0x80:
882+
dup1 := makeDup(1)
883+
_, err = dup1(&pc, evm, scope)
884+
case 0x56:
885+
_, err = opJump(&pc, evm, scope)
886+
case 0x5b:
887+
_, err = opJumpdest(&pc, evm, scope)
888+
case 0x15:
889+
_, err = opIszero(&pc, evm, scope)
890+
case 0xe6:
891+
_, err = opDupN(&pc, evm, scope)
892+
case 0xe7:
893+
_, err = opSwapN(&pc, evm, scope)
894+
case 0xe8:
895+
_, err = opExchange(&pc, evm, scope)
896+
default:
897+
err = &ErrInvalidOpCode{opcode: OpCode(op)}
898+
}
899+
pc++
900+
}
901+
if tc.wantErr {
902+
if err == nil {
903+
t.Fatalf("expected error, got nil")
904+
}
905+
return
906+
}
907+
if err != nil {
908+
t.Fatalf("unexpected error: %v", err)
909+
}
910+
got := make([]uint64, 0, stack.len())
911+
for i := stack.len() - 1; i >= 0; i-- {
912+
got = append(got, stack.data[i].Uint64())
913+
}
914+
if len(got) != len(tc.wantVals) {
915+
t.Fatalf("stack len=%d; want %d", len(got), len(tc.wantVals))
916+
}
917+
for i := range got {
918+
if got[i] != tc.wantVals[i] {
919+
t.Fatalf("[%s] stack[%d]=%d; want %d\nstack=%v",
920+
tc.name, i, got[i], tc.wantVals[i], got)
921+
}
922+
}
923+
})
924+
}
925+
}

0 commit comments

Comments
 (0)