github.com/dashpay/godash@v0.0.0-20160726055534-e038a21e0e3d/txscript/scriptbuilder_test.go (about) 1 // Copyright (c) 2013-2015 The btcsuite developers 2 // Copyright (c) 2016 The Dash developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package txscript_test 7 8 import ( 9 "bytes" 10 "testing" 11 12 "github.com/dashpay/godash/txscript" 13 ) 14 15 // TestScriptBuilderAddOp tests that pushing opcodes to a script via the 16 // ScriptBuilder API works as expected. 17 func TestScriptBuilderAddOp(t *testing.T) { 18 t.Parallel() 19 20 tests := []struct { 21 name string 22 opcodes []byte 23 expected []byte 24 }{ 25 { 26 name: "push OP_0", 27 opcodes: []byte{txscript.OP_0}, 28 expected: []byte{txscript.OP_0}, 29 }, 30 { 31 name: "push OP_1 OP_2", 32 opcodes: []byte{txscript.OP_1, txscript.OP_2}, 33 expected: []byte{txscript.OP_1, txscript.OP_2}, 34 }, 35 { 36 name: "push OP_HASH160 OP_EQUAL", 37 opcodes: []byte{txscript.OP_HASH160, txscript.OP_EQUAL}, 38 expected: []byte{txscript.OP_HASH160, txscript.OP_EQUAL}, 39 }, 40 } 41 42 builder := txscript.NewScriptBuilder() 43 t.Logf("Running %d tests", len(tests)) 44 for i, test := range tests { 45 builder.Reset() 46 for _, opcode := range test.opcodes { 47 builder.AddOp(opcode) 48 } 49 result, err := builder.Script() 50 if err != nil { 51 t.Errorf("ScriptBuilder.AddOp #%d (%s) unexpected "+ 52 "error: %v", i, test.name, err) 53 continue 54 } 55 if !bytes.Equal(result, test.expected) { 56 t.Errorf("ScriptBuilder.AddOp #%d (%s) wrong result\n"+ 57 "got: %x\nwant: %x", i, test.name, result, 58 test.expected) 59 continue 60 } 61 } 62 } 63 64 // TestScriptBuilderAddInt64 tests that pushing signed integers to a script via 65 // the ScriptBuilder API works as expected. 66 func TestScriptBuilderAddInt64(t *testing.T) { 67 t.Parallel() 68 69 tests := []struct { 70 name string 71 val int64 72 expected []byte 73 }{ 74 {name: "push -1", val: -1, expected: []byte{txscript.OP_1NEGATE}}, 75 {name: "push small int 0", val: 0, expected: []byte{txscript.OP_0}}, 76 {name: "push small int 1", val: 1, expected: []byte{txscript.OP_1}}, 77 {name: "push small int 2", val: 2, expected: []byte{txscript.OP_2}}, 78 {name: "push small int 3", val: 3, expected: []byte{txscript.OP_3}}, 79 {name: "push small int 4", val: 4, expected: []byte{txscript.OP_4}}, 80 {name: "push small int 5", val: 5, expected: []byte{txscript.OP_5}}, 81 {name: "push small int 6", val: 6, expected: []byte{txscript.OP_6}}, 82 {name: "push small int 7", val: 7, expected: []byte{txscript.OP_7}}, 83 {name: "push small int 8", val: 8, expected: []byte{txscript.OP_8}}, 84 {name: "push small int 9", val: 9, expected: []byte{txscript.OP_9}}, 85 {name: "push small int 10", val: 10, expected: []byte{txscript.OP_10}}, 86 {name: "push small int 11", val: 11, expected: []byte{txscript.OP_11}}, 87 {name: "push small int 12", val: 12, expected: []byte{txscript.OP_12}}, 88 {name: "push small int 13", val: 13, expected: []byte{txscript.OP_13}}, 89 {name: "push small int 14", val: 14, expected: []byte{txscript.OP_14}}, 90 {name: "push small int 15", val: 15, expected: []byte{txscript.OP_15}}, 91 {name: "push small int 16", val: 16, expected: []byte{txscript.OP_16}}, 92 {name: "push 17", val: 17, expected: []byte{txscript.OP_DATA_1, 0x11}}, 93 {name: "push 65", val: 65, expected: []byte{txscript.OP_DATA_1, 0x41}}, 94 {name: "push 127", val: 127, expected: []byte{txscript.OP_DATA_1, 0x7f}}, 95 {name: "push 128", val: 128, expected: []byte{txscript.OP_DATA_2, 0x80, 0}}, 96 {name: "push 255", val: 255, expected: []byte{txscript.OP_DATA_2, 0xff, 0}}, 97 {name: "push 256", val: 256, expected: []byte{txscript.OP_DATA_2, 0, 0x01}}, 98 {name: "push 32767", val: 32767, expected: []byte{txscript.OP_DATA_2, 0xff, 0x7f}}, 99 {name: "push 32768", val: 32768, expected: []byte{txscript.OP_DATA_3, 0, 0x80, 0}}, 100 {name: "push -2", val: -2, expected: []byte{txscript.OP_DATA_1, 0x82}}, 101 {name: "push -3", val: -3, expected: []byte{txscript.OP_DATA_1, 0x83}}, 102 {name: "push -4", val: -4, expected: []byte{txscript.OP_DATA_1, 0x84}}, 103 {name: "push -5", val: -5, expected: []byte{txscript.OP_DATA_1, 0x85}}, 104 {name: "push -17", val: -17, expected: []byte{txscript.OP_DATA_1, 0x91}}, 105 {name: "push -65", val: -65, expected: []byte{txscript.OP_DATA_1, 0xc1}}, 106 {name: "push -127", val: -127, expected: []byte{txscript.OP_DATA_1, 0xff}}, 107 {name: "push -128", val: -128, expected: []byte{txscript.OP_DATA_2, 0x80, 0x80}}, 108 {name: "push -255", val: -255, expected: []byte{txscript.OP_DATA_2, 0xff, 0x80}}, 109 {name: "push -256", val: -256, expected: []byte{txscript.OP_DATA_2, 0x00, 0x81}}, 110 {name: "push -32767", val: -32767, expected: []byte{txscript.OP_DATA_2, 0xff, 0xff}}, 111 {name: "push -32768", val: -32768, expected: []byte{txscript.OP_DATA_3, 0x00, 0x80, 0x80}}, 112 } 113 114 builder := txscript.NewScriptBuilder() 115 t.Logf("Running %d tests", len(tests)) 116 for i, test := range tests { 117 builder.Reset().AddInt64(test.val) 118 result, err := builder.Script() 119 if err != nil { 120 t.Errorf("ScriptBuilder.AddInt64 #%d (%s) unexpected "+ 121 "error: %v", i, test.name, err) 122 continue 123 } 124 if !bytes.Equal(result, test.expected) { 125 t.Errorf("ScriptBuilder.AddInt64 #%d (%s) wrong result\n"+ 126 "got: %x\nwant: %x", i, test.name, result, 127 test.expected) 128 continue 129 } 130 } 131 } 132 133 // TestScriptBuilderAddData tests that pushing data to a script via the 134 // ScriptBuilder API works as expected and conforms to BIP0062. 135 func TestScriptBuilderAddData(t *testing.T) { 136 t.Parallel() 137 138 tests := []struct { 139 name string 140 data []byte 141 expected []byte 142 useFull bool // use AddFullData instead of AddData. 143 }{ 144 // BIP0062: Pushing an empty byte sequence must use OP_0. 145 {name: "push empty byte sequence", data: nil, expected: []byte{txscript.OP_0}}, 146 {name: "push 1 byte 0x00", data: []byte{0x00}, expected: []byte{txscript.OP_0}}, 147 148 // BIP0062: Pushing a 1-byte sequence of byte 0x01 through 0x10 must use OP_n. 149 {name: "push 1 byte 0x01", data: []byte{0x01}, expected: []byte{txscript.OP_1}}, 150 {name: "push 1 byte 0x02", data: []byte{0x02}, expected: []byte{txscript.OP_2}}, 151 {name: "push 1 byte 0x03", data: []byte{0x03}, expected: []byte{txscript.OP_3}}, 152 {name: "push 1 byte 0x04", data: []byte{0x04}, expected: []byte{txscript.OP_4}}, 153 {name: "push 1 byte 0x05", data: []byte{0x05}, expected: []byte{txscript.OP_5}}, 154 {name: "push 1 byte 0x06", data: []byte{0x06}, expected: []byte{txscript.OP_6}}, 155 {name: "push 1 byte 0x07", data: []byte{0x07}, expected: []byte{txscript.OP_7}}, 156 {name: "push 1 byte 0x08", data: []byte{0x08}, expected: []byte{txscript.OP_8}}, 157 {name: "push 1 byte 0x09", data: []byte{0x09}, expected: []byte{txscript.OP_9}}, 158 {name: "push 1 byte 0x0a", data: []byte{0x0a}, expected: []byte{txscript.OP_10}}, 159 {name: "push 1 byte 0x0b", data: []byte{0x0b}, expected: []byte{txscript.OP_11}}, 160 {name: "push 1 byte 0x0c", data: []byte{0x0c}, expected: []byte{txscript.OP_12}}, 161 {name: "push 1 byte 0x0d", data: []byte{0x0d}, expected: []byte{txscript.OP_13}}, 162 {name: "push 1 byte 0x0e", data: []byte{0x0e}, expected: []byte{txscript.OP_14}}, 163 {name: "push 1 byte 0x0f", data: []byte{0x0f}, expected: []byte{txscript.OP_15}}, 164 {name: "push 1 byte 0x10", data: []byte{0x10}, expected: []byte{txscript.OP_16}}, 165 166 // BIP0062: Pushing the byte 0x81 must use OP_1NEGATE. 167 {name: "push 1 byte 0x81", data: []byte{0x81}, expected: []byte{txscript.OP_1NEGATE}}, 168 169 // BIP0062: Pushing any other byte sequence up to 75 bytes must 170 // use the normal data push (opcode byte n, with n the number of 171 // bytes, followed n bytes of data being pushed). 172 {name: "push 1 byte 0x11", data: []byte{0x11}, expected: []byte{txscript.OP_DATA_1, 0x11}}, 173 {name: "push 1 byte 0x80", data: []byte{0x80}, expected: []byte{txscript.OP_DATA_1, 0x80}}, 174 {name: "push 1 byte 0x82", data: []byte{0x82}, expected: []byte{txscript.OP_DATA_1, 0x82}}, 175 {name: "push 1 byte 0xff", data: []byte{0xff}, expected: []byte{txscript.OP_DATA_1, 0xff}}, 176 { 177 name: "push data len 17", 178 data: bytes.Repeat([]byte{0x49}, 17), 179 expected: append([]byte{txscript.OP_DATA_17}, bytes.Repeat([]byte{0x49}, 17)...), 180 }, 181 { 182 name: "push data len 75", 183 data: bytes.Repeat([]byte{0x49}, 75), 184 expected: append([]byte{txscript.OP_DATA_75}, bytes.Repeat([]byte{0x49}, 75)...), 185 }, 186 187 // BIP0062: Pushing 76 to 255 bytes must use OP_PUSHDATA1. 188 { 189 name: "push data len 76", 190 data: bytes.Repeat([]byte{0x49}, 76), 191 expected: append([]byte{txscript.OP_PUSHDATA1, 76}, bytes.Repeat([]byte{0x49}, 76)...), 192 }, 193 { 194 name: "push data len 255", 195 data: bytes.Repeat([]byte{0x49}, 255), 196 expected: append([]byte{txscript.OP_PUSHDATA1, 255}, bytes.Repeat([]byte{0x49}, 255)...), 197 }, 198 199 // BIP0062: Pushing 256 to 520 bytes must use OP_PUSHDATA2. 200 { 201 name: "push data len 256", 202 data: bytes.Repeat([]byte{0x49}, 256), 203 expected: append([]byte{txscript.OP_PUSHDATA2, 0, 1}, bytes.Repeat([]byte{0x49}, 256)...), 204 }, 205 { 206 name: "push data len 520", 207 data: bytes.Repeat([]byte{0x49}, 520), 208 expected: append([]byte{txscript.OP_PUSHDATA2, 0x08, 0x02}, bytes.Repeat([]byte{0x49}, 520)...), 209 }, 210 211 // BIP0062: OP_PUSHDATA4 can never be used, as pushes over 520 212 // bytes are not allowed, and those below can be done using 213 // other operators. 214 { 215 name: "push data len 521", 216 data: bytes.Repeat([]byte{0x49}, 521), 217 expected: nil, 218 }, 219 { 220 name: "push data len 32767 (canonical)", 221 data: bytes.Repeat([]byte{0x49}, 32767), 222 expected: nil, 223 }, 224 { 225 name: "push data len 65536 (canonical)", 226 data: bytes.Repeat([]byte{0x49}, 65536), 227 expected: nil, 228 }, 229 230 // Additional tests for the PushFullData function that 231 // intentionally allows data pushes to exceed the limit for 232 // regression testing purposes. 233 234 // 3-byte data push via OP_PUSHDATA_2. 235 { 236 name: "push data len 32767 (non-canonical)", 237 data: bytes.Repeat([]byte{0x49}, 32767), 238 expected: append([]byte{txscript.OP_PUSHDATA2, 255, 127}, bytes.Repeat([]byte{0x49}, 32767)...), 239 useFull: true, 240 }, 241 242 // 5-byte data push via OP_PUSHDATA_4. 243 { 244 name: "push data len 65536 (non-canonical)", 245 data: bytes.Repeat([]byte{0x49}, 65536), 246 expected: append([]byte{txscript.OP_PUSHDATA4, 0, 0, 1, 0}, bytes.Repeat([]byte{0x49}, 65536)...), 247 useFull: true, 248 }, 249 } 250 251 builder := txscript.NewScriptBuilder() 252 t.Logf("Running %d tests", len(tests)) 253 for i, test := range tests { 254 if !test.useFull { 255 builder.Reset().AddData(test.data) 256 } else { 257 builder.Reset().AddFullData(test.data) 258 } 259 result, _ := builder.Script() 260 if !bytes.Equal(result, test.expected) { 261 t.Errorf("ScriptBuilder.AddData #%d (%s) wrong result\n"+ 262 "got: %x\nwant: %x", i, test.name, result, 263 test.expected) 264 continue 265 } 266 } 267 } 268 269 // TestExceedMaxScriptSize ensures that all of the functions that can be used 270 // to add data to a script don't allow the script to exceed the max allowed 271 // size. 272 func TestExceedMaxScriptSize(t *testing.T) { 273 t.Parallel() 274 275 // Start off by constructing a max size script. 276 maxScriptSize := txscript.TstMaxScriptSize 277 builder := txscript.NewScriptBuilder() 278 builder.Reset().AddFullData(make([]byte, maxScriptSize-3)) 279 origScript, err := builder.Script() 280 if err != nil { 281 t.Fatalf("Unexpected error for max size script: %v", err) 282 } 283 284 // Ensure adding data that would exceed the maximum size of the script 285 // does not add the data. 286 script, err := builder.AddData([]byte{0x00}).Script() 287 if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil { 288 t.Fatalf("ScriptBuilder.AddData allowed exceeding max script "+ 289 "size: %v", len(script)) 290 } 291 if !bytes.Equal(script, origScript) { 292 t.Fatalf("ScriptBuilder.AddData unexpected modified script - "+ 293 "got len %d, want len %d", len(script), len(origScript)) 294 } 295 296 // Ensure adding an opcode that would exceed the maximum size of the 297 // script does not add the data. 298 builder.Reset().AddFullData(make([]byte, maxScriptSize-3)) 299 script, err = builder.AddOp(txscript.OP_0).Script() 300 if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil { 301 t.Fatalf("ScriptBuilder.AddOp unexpected modified script - "+ 302 "got len %d, want len %d", len(script), len(origScript)) 303 } 304 if !bytes.Equal(script, origScript) { 305 t.Fatalf("ScriptBuilder.AddOp unexpected modified script - "+ 306 "got len %d, want len %d", len(script), len(origScript)) 307 } 308 309 // Ensure adding an integer that would exceed the maximum size of the 310 // script does not add the data. 311 builder.Reset().AddFullData(make([]byte, maxScriptSize-3)) 312 script, err = builder.AddInt64(0).Script() 313 if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil { 314 t.Fatalf("ScriptBuilder.AddInt64 unexpected modified script - "+ 315 "got len %d, want len %d", len(script), len(origScript)) 316 } 317 if !bytes.Equal(script, origScript) { 318 t.Fatalf("ScriptBuilder.AddInt64 unexpected modified script - "+ 319 "got len %d, want len %d", len(script), len(origScript)) 320 } 321 } 322 323 // TestErroredScript ensures that all of the functions that can be used to add 324 // data to a script don't modify the script once an error has happened. 325 func TestErroredScript(t *testing.T) { 326 t.Parallel() 327 328 // Start off by constructing a near max size script that has enough 329 // space left to add each data type without an error and force an 330 // initial error condition. 331 maxScriptSize := txscript.TstMaxScriptSize 332 builder := txscript.NewScriptBuilder() 333 builder.Reset().AddFullData(make([]byte, maxScriptSize-8)) 334 origScript, err := builder.Script() 335 if err != nil { 336 t.Fatalf("ScriptBuilder.AddFullData unexpected error: %v", err) 337 } 338 script, err := builder.AddData([]byte{0x00, 0x00, 0x00, 0x00, 0x00}).Script() 339 if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil { 340 t.Fatalf("ScriptBuilder.AddData allowed exceeding max script "+ 341 "size: %v", len(script)) 342 } 343 if !bytes.Equal(script, origScript) { 344 t.Fatalf("ScriptBuilder.AddData unexpected modified script - "+ 345 "got len %d, want len %d", len(script), len(origScript)) 346 } 347 348 // Ensure adding data, even using the non-canonical path, to a script 349 // that has errored doesn't succeed. 350 script, err = builder.AddFullData([]byte{0x00}).Script() 351 if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil { 352 t.Fatal("ScriptBuilder.AddFullData succeeded on errored script") 353 } 354 if !bytes.Equal(script, origScript) { 355 t.Fatalf("ScriptBuilder.AddFullData unexpected modified "+ 356 "script - got len %d, want len %d", len(script), 357 len(origScript)) 358 } 359 360 // Ensure adding data to a script that has errored doesn't succeed. 361 script, err = builder.AddData([]byte{0x00}).Script() 362 if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil { 363 t.Fatal("ScriptBuilder.AddData succeeded on errored script") 364 } 365 if !bytes.Equal(script, origScript) { 366 t.Fatalf("ScriptBuilder.AddData unexpected modified "+ 367 "script - got len %d, want len %d", len(script), 368 len(origScript)) 369 } 370 371 // Ensure adding an opcode to a script that has errored doesn't succeed. 372 script, err = builder.AddOp(txscript.OP_0).Script() 373 if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil { 374 t.Fatal("ScriptBuilder.AddOp succeeded on errored script") 375 } 376 if !bytes.Equal(script, origScript) { 377 t.Fatalf("ScriptBuilder.AddOp unexpected modified script - "+ 378 "got len %d, want len %d", len(script), len(origScript)) 379 } 380 381 // Ensure adding an integer to a script that has errored doesn't 382 // succeed. 383 script, err = builder.AddInt64(0).Script() 384 if _, ok := err.(txscript.ErrScriptNotCanonical); !ok || err == nil { 385 t.Fatal("ScriptBuilder.AddInt64 succeeded on errored script") 386 } 387 if !bytes.Equal(script, origScript) { 388 t.Fatalf("ScriptBuilder.AddInt64 unexpected modified script - "+ 389 "got len %d, want len %d", len(script), len(origScript)) 390 } 391 392 // Ensure the error has a message set. 393 if err.Error() == "" { 394 t.Fatal("ErrScriptNotCanonical.Error does not have any text") 395 } 396 }