github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/protocol/vm/ops_test.go (about) 1 package vm 2 3 import ( 4 "fmt" 5 "reflect" 6 "testing" 7 8 "github.com/bytom/bytom/errors" 9 "github.com/bytom/bytom/math/checked" 10 "github.com/bytom/bytom/testutil" 11 ) 12 13 func TestParseOp(t *testing.T) { 14 cases := []struct { 15 prog []byte 16 pc uint32 17 want Instruction 18 wantErr error 19 }{{ 20 prog: []byte{byte(OP_ADD)}, 21 want: Instruction{Op: OP_ADD, Len: 1}, 22 }, { 23 prog: []byte{byte(OP_16)}, 24 want: Instruction{Op: OP_16, Data: []byte{16}, Len: 1}, 25 }, { 26 prog: []byte{byte(OP_DATA_5), 1, 1, 1, 1, 1}, 27 want: Instruction{Op: OP_DATA_5, Data: []byte{1, 1, 1, 1, 1}, Len: 6}, 28 }, { 29 prog: []byte{byte(OP_DATA_5), 1, 1, 1, 1, 1, 255}, 30 want: Instruction{Op: OP_DATA_5, Data: []byte{1, 1, 1, 1, 1}, Len: 6}, 31 }, { 32 prog: []byte{byte(OP_PUSHDATA1), 1, 1}, 33 want: Instruction{Op: OP_PUSHDATA1, Data: []byte{1}, Len: 3}, 34 }, { 35 prog: []byte{byte(OP_PUSHDATA1), 1, 1, 255}, 36 want: Instruction{Op: OP_PUSHDATA1, Data: []byte{1}, Len: 3}, 37 }, { 38 prog: []byte{byte(OP_PUSHDATA2), 1, 0, 1}, 39 want: Instruction{Op: OP_PUSHDATA2, Data: []byte{1}, Len: 4}, 40 }, { 41 prog: []byte{byte(OP_PUSHDATA2), 1, 0, 1, 255}, 42 want: Instruction{Op: OP_PUSHDATA2, Data: []byte{1}, Len: 4}, 43 }, { 44 prog: []byte{byte(OP_PUSHDATA4), 1, 0, 0, 0, 1}, 45 want: Instruction{Op: OP_PUSHDATA4, Data: []byte{1}, Len: 6}, 46 }, { 47 prog: []byte{byte(OP_PUSHDATA4), 1, 0, 0, 0, 1, 255}, 48 want: Instruction{Op: OP_PUSHDATA4, Data: []byte{1}, Len: 6}, 49 }, { 50 prog: []byte{}, 51 wantErr: ErrShortProgram, 52 }, { 53 prog: []byte{byte(OP_0)}, 54 pc: 1, 55 wantErr: ErrShortProgram, 56 }, { 57 prog: []byte{byte(OP_DATA_1)}, 58 wantErr: ErrShortProgram, 59 }, { 60 prog: []byte{byte(OP_PUSHDATA1)}, 61 wantErr: ErrShortProgram, 62 }, { 63 prog: []byte{byte(OP_PUSHDATA1), 1}, 64 wantErr: ErrShortProgram, 65 }, { 66 prog: []byte{byte(OP_PUSHDATA2)}, 67 wantErr: ErrShortProgram, 68 }, { 69 prog: []byte{byte(OP_PUSHDATA2), 1, 0}, 70 wantErr: ErrShortProgram, 71 }, { 72 prog: []byte{byte(OP_PUSHDATA4)}, 73 wantErr: ErrShortProgram, 74 }, { 75 prog: []byte{byte(OP_PUSHDATA4), 1, 0, 0, 0}, 76 wantErr: ErrShortProgram, 77 }, { 78 pc: 71, 79 prog: []byte{0x6d, 0x6b, 0xaa, 0x20, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x0, 0x0, 0x4e, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, 80 wantErr: checked.ErrOverflow, 81 }} 82 83 for _, c := range cases { 84 t.Run(fmt.Sprintf("%d: %x", c.pc, c.prog), func(t *testing.T) { 85 got, gotErr := ParseOp(c.prog, c.pc) 86 87 if errors.Root(gotErr) != c.wantErr { 88 t.Errorf("ParseOp(%x, %d) error = %v want %v", c.prog, c.pc, gotErr, c.wantErr) 89 } 90 91 if c.wantErr != nil { 92 return 93 } 94 95 if !testutil.DeepEqual(got, c.want) { 96 t.Errorf("ParseOp(%x, %d) = %+v want %+v", c.prog, c.pc, got, c.want) 97 } 98 }) 99 } 100 } 101 102 func TestParseProgram(t *testing.T) { 103 cases := []struct { 104 prog []byte 105 want []Instruction 106 wantErr error 107 }{ 108 { 109 prog: []byte{byte(OP_2), byte(OP_3), byte(OP_ADD), byte(OP_5), byte(OP_NUMEQUAL)}, 110 want: []Instruction{ 111 {Op: OP_2, Data: []byte{0x02}, Len: 1}, 112 {Op: OP_3, Data: []byte{0x03}, Len: 1}, 113 {Op: OP_ADD, Len: 1}, 114 {Op: OP_5, Data: []byte{0x05}, Len: 1}, 115 {Op: OP_NUMEQUAL, Len: 1}, 116 }, 117 }, 118 { 119 prog: []byte{255}, 120 want: []Instruction{ 121 {Op: 255, Len: 1}, 122 }, 123 }, 124 } 125 126 for _, c := range cases { 127 got, gotErr := ParseProgram(c.prog) 128 129 if errors.Root(gotErr) != c.wantErr { 130 t.Errorf("ParseProgram(%x) error = %v want %v", c.prog, gotErr, c.wantErr) 131 } 132 133 if c.wantErr != nil { 134 continue 135 } 136 137 if !testutil.DeepEqual(got, c.want) { 138 t.Errorf("ParseProgram(%x) = %+v want %+v", c.prog, got, c.want) 139 } 140 } 141 } 142 143 func TestIsPushData(t *testing.T) { 144 cases := []struct { 145 want Instruction 146 wantErr error 147 }{ 148 { 149 want: Instruction{Op: OP_16, Data: []byte{16}, Len: 1}, 150 }, 151 { 152 want: Instruction{Op: OP_DATA_32, Data: []byte{16}, Len: 1}, 153 }, 154 { 155 want: Instruction{Op: OP_FALSE, Data: []byte{}, Len: 1}, 156 }, 157 { 158 want: Instruction{Op: OP_TRUE, Data: []byte{1}, Len: 1}, 159 }, 160 { 161 want: Instruction{Op: OP_JUMP, Data: []byte{0x00000000}, Len: 1}, 162 wantErr: ErrShortProgram, 163 }, 164 { 165 want: Instruction{Op: OP_ADD, Data: []byte{0x12, 0x56}, Len: 2}, 166 wantErr: ErrShortProgram, 167 }, 168 } 169 170 for _, c := range cases { 171 if c.want.IsPushdata() { 172 t.Logf("check success") 173 } else if c.wantErr != nil { 174 t.Logf("check err success") 175 } else { 176 t.Errorf("check false: %v -- %v", reflect.ValueOf(ops[OP_1].fn), reflect.ValueOf(ops[c.want.Op].fn)) 177 } 178 } 179 }