// TestForVMFailure feeds random scripts to the VMs to check and see if it // crashes. Try increasing the number of iterations or the length of the // byte string to sample a greater space. func TestForVMFailure(t *testing.T) { numTests := 2 bsLength := 11 for i := 0; i < numTests; i++ { tests := randByteSliceSlice(65536, bsLength, i) for j := range tests { if j == 0 { continue } msgTx := new(wire.MsgTx) msgTx.AddTxIn(&wire.TxIn{ PreviousOutPoint: wire.OutPoint{}, SignatureScript: tests[j-1], Sequence: 0xFFFFFFFF, }) msgTx.AddTxOut(&wire.TxOut{ Value: 0x00FFFFFF00000000, PkScript: []byte{0x01}, }) flags := StandardVerifyFlags engine, err := NewEngine(tests[j], msgTx, 0, flags, 0, nil) if err == nil { engine.Execute() } } } }
// NewTxDeepTxIns is used to deep copy a transaction, maintaining the old // pointers to the TxOuts while replacing the old pointers to the TxIns with // deep copies. This is to prevent races when the fraud proofs for the // transactions are set by the miner. func NewTxDeepTxIns(msgTx *wire.MsgTx) *Tx { if msgTx == nil { return nil } newMsgTx := new(wire.MsgTx) // Copy the fixed fields. newMsgTx.Version = msgTx.Version newMsgTx.LockTime = msgTx.LockTime newMsgTx.Expiry = msgTx.Expiry // Copy the TxIns deeply. for _, txIn := range msgTx.TxIn { sigScrLen := len(txIn.SignatureScript) sigScrCopy := make([]byte, sigScrLen, sigScrLen) txInCopy := new(wire.TxIn) txInCopy.PreviousOutPoint.Hash = txIn.PreviousOutPoint.Hash txInCopy.PreviousOutPoint.Index = txIn.PreviousOutPoint.Index txInCopy.PreviousOutPoint.Tree = txIn.PreviousOutPoint.Tree txInCopy.Sequence = txIn.Sequence txInCopy.ValueIn = txIn.ValueIn txInCopy.BlockHeight = txIn.BlockHeight txInCopy.BlockIndex = txIn.BlockIndex txInCopy.SignatureScript = sigScrCopy newMsgTx.AddTxIn(txIn) } // Shallow copy the TxOuts. for _, txOut := range msgTx.TxOut { newMsgTx.AddTxOut(txOut) } return &Tx{ hash: msgTx.TxHash(), msgTx: msgTx, txTree: wire.TxTreeUnknown, txIndex: TxIndexUnknown, } }
func Test_dupTx(t *testing.T) { // Ignore db remove errors since it means we didn't have an old one. dbname := fmt.Sprintf("tstdbdup0") dbnamever := dbname + ".ver" _ = os.RemoveAll(dbname) _ = os.RemoveAll(dbnamever) db, err := database.CreateDB("leveldb", dbname) if err != nil { t.Errorf("Failed to open test database %v", err) return } defer os.RemoveAll(dbname) defer os.RemoveAll(dbnamever) defer func() { if err := db.Close(); err != nil { t.Errorf("Close: unexpected error: %v", err) } }() testdatafile := filepath.Join("../", "../blockchain/testdata", "blocks0to168.bz2") blocks, err := loadBlocks(t, testdatafile) if err != nil { t.Errorf("Unable to load blocks from test data for: %v", err) return } var lastSha *chainhash.Hash // Populate with the fisrt 256 blocks, so we have blocks to 'mess with' err = nil out: for height := int64(0); height < int64(len(blocks)); height++ { block := blocks[height] if height != 0 { // except for NoVerify which does not allow lookups check inputs mblock := block.MsgBlock() //t.Errorf("%v", blockchain.DebugBlockString(block)) parentBlock := blocks[height-1] mParentBlock := parentBlock.MsgBlock() var txneededList []*chainhash.Hash opSpentInBlock := make(map[wire.OutPoint]struct{}) if dcrutil.IsFlagSet16(dcrutil.BlockValid, mParentBlock.Header.VoteBits) { for _, tx := range mParentBlock.Transactions { for _, txin := range tx.TxIn { if txin.PreviousOutPoint.Index == uint32(4294967295) { continue } if existsInOwnBlockRegTree(mParentBlock, txin.PreviousOutPoint.Hash) { _, used := opSpentInBlock[txin.PreviousOutPoint] if !used { // Origin tx is in the block and so hasn't been // added yet, continue opSpentInBlock[txin.PreviousOutPoint] = struct{}{} continue } else { t.Errorf("output ref %v attempted double spend of previously spend output", txin.PreviousOutPoint) } } origintxsha := &txin.PreviousOutPoint.Hash txneededList = append(txneededList, origintxsha) exists, err := db.ExistsTxSha(origintxsha) if err != nil { t.Errorf("ExistsTxSha: unexpected error %v ", err) } if !exists { t.Errorf("referenced tx not found %v (height %v)", origintxsha, height) } _, err = db.FetchTxBySha(origintxsha) if err != nil { t.Errorf("referenced tx not found %v err %v ", origintxsha, err) } } } } for _, stx := range mblock.STransactions { for _, txin := range stx.TxIn { if txin.PreviousOutPoint.Index == uint32(4294967295) { continue } if existsInOwnBlockRegTree(mParentBlock, txin.PreviousOutPoint.Hash) { _, used := opSpentInBlock[txin.PreviousOutPoint] if !used { // Origin tx is in the block and so hasn't been // added yet, continue opSpentInBlock[txin.PreviousOutPoint] = struct{}{} continue } else { t.Errorf("output ref %v attempted double spend of previously spend output", txin.PreviousOutPoint) } } origintxsha := &txin.PreviousOutPoint.Hash txneededList = append(txneededList, origintxsha) exists, err := db.ExistsTxSha(origintxsha) if err != nil { t.Errorf("ExistsTxSha: unexpected error %v ", err) } if !exists { t.Errorf("referenced tx not found %v", origintxsha) } _, err = db.FetchTxBySha(origintxsha) if err != nil { t.Errorf("referenced tx not found %v err %v ", origintxsha, err) } } } txlist := db.FetchUnSpentTxByShaList(txneededList) for _, txe := range txlist { if txe.Err != nil { t.Errorf("tx list fetch failed %v err %v ", txe.Sha, txe.Err) break out } } } newheight, err := db.InsertBlock(block) if err != nil { t.Errorf("failed to insert block %v err %v", height, err) break out } if newheight != height { t.Errorf("height mismatch expect %v returned %v", height, newheight) break out } newSha, blkid, err := db.NewestSha() if err != nil { t.Errorf("failed to obtain latest sha %v %v", height, err) } if blkid != height { t.Errorf("height doe not match latest block height %v %v %v", blkid, height, err) } blkSha := block.Sha() if *newSha != *blkSha { t.Errorf("Newest block sha does not match freshly inserted one %v %v %v ", newSha, blkSha, err) } lastSha = blkSha } // generate a new block based on the last sha // these block are not verified, so there are a bunch of garbage fields // in the 'generated' block. var bh wire.BlockHeader bh.Version = 0 bh.PrevBlock = *lastSha // Bits, Nonce are not filled in mblk := wire.NewMsgBlock(&bh) hash, _ := chainhash.NewHashFromStr("c23953c56cb2ef8e4698e3ed3b0fc4c837754d3cd16485192d893e35f32626b4") po := wire.NewOutPoint(hash, 0, dcrutil.TxTreeRegular) txI := wire.NewTxIn(po, []byte("garbage")) txO := wire.NewTxOut(50000000, []byte("garbageout")) var tx wire.MsgTx tx.AddTxIn(txI) tx.AddTxOut(txO) mblk.AddTransaction(&tx) blk := dcrutil.NewBlock(mblk) fetchList := []*chainhash.Hash{hash} listReply := db.FetchUnSpentTxByShaList(fetchList) for _, lr := range listReply { if lr.Err != nil { t.Errorf("sha %v spent %v err %v\n", lr.Sha, lr.TxSpent, lr.Err) } } _, err = db.InsertBlock(blk) if err != nil { t.Errorf("failed to insert phony block %v", err) } // ok, did it 'spend' the tx ? listReply = db.FetchUnSpentTxByShaList(fetchList) for _, lr := range listReply { if lr.Err != nil && lr.Err != database.ErrTxShaMissing { t.Errorf("sha %v spent %v err %v\n", lr.Sha, lr.TxSpent, lr.Err) } } txlist := blk.Transactions() for _, tx := range txlist { txsha := tx.Sha() txReply, err := db.FetchTxBySha(txsha) if err != nil { t.Errorf("fully spent lookup %v err %v\n", hash, err) } else { for _, lr := range txReply { if lr.Err != nil { t.Errorf("stx %v spent %v err %v\n", lr.Sha, lr.TxSpent, lr.Err) } } } } err = db.DropAfterBlockBySha(lastSha) if err != nil { t.Errorf("failed to drop spending block %v", err) } }
func TestNewlyEnabledOpCodes(t *testing.T) { sigScriptMath := []byte{ 0x04, 0xff, 0xff, 0xff, 0x7f, 0x04, 0xee, 0xee, 0xee, 0x6e, } sigScriptShift := []byte{ 0x04, 0xff, 0xff, 0xff, 0x7f, 0x53, } sigScriptRot := []byte{ 0x04, 0x21, 0x12, 0x34, 0x56, 0x53, } sigScriptInv := []byte{ 0x04, 0xff, 0x00, 0xf0, 0x0f, } sigScriptLogic := []byte{ 0x04, 0x21, 0x12, 0x34, 0x56, 0x04, 0x0f, 0xf0, 0x00, 0xff, } sigScriptCat := []byte{ 0x06, 0x21, 0x12, 0x34, 0x56, 0x44, 0x55, 0x06, 0x0f, 0xf0, 0x00, 0xff, 0x88, 0x99, } lotsOf01s := bytes.Repeat([]byte{0x01}, 2050) builder := NewScriptBuilder() builder.AddData(lotsOf01s).AddData(lotsOf01s) sigScriptCatOverflow, _ := builder.Script() sigScriptSubstr := []byte{ 0x08, 0x21, 0x12, 0x34, 0x56, 0x59, 0x32, 0x40, 0x21, 0x56, 0x52, } sigScriptLR := []byte{ 0x08, 0x21, 0x12, 0x34, 0x56, 0x59, 0x32, 0x40, 0x21, 0x54, } tests := []struct { name string pkScript []byte sigScript []byte expected bool }{ { name: "add", pkScript: []byte{ 0x93, // OP_ADD 0x05, // Expected result push 0xed, 0xee, 0xee, 0xee, 0x00, 0x87, // OP_EQUAL }, sigScript: sigScriptMath, expected: true, }, { name: "sub", pkScript: []byte{ 0x94, // OP_SUB 0x04, // Expected result push 0x11, 0x11, 0x11, 0x11, 0x87, // OP_EQUAL }, sigScript: sigScriptMath, expected: true, }, { name: "mul", pkScript: []byte{ 0x95, // OP_MUL 0x04, // Expected result push 0xee, 0xee, 0xee, 0xee, 0x87, // OP_EQUAL }, sigScript: sigScriptMath, expected: true, }, { name: "div", pkScript: []byte{ 0x96, // OP_DIV 0x51, // Expected result push 0x87, // OP_EQUAL }, sigScript: sigScriptMath, expected: true, }, { name: "mod", pkScript: []byte{ 0x97, // OP_MOD 0x04, // Expected result push 0x11, 0x11, 0x11, 0x11, 0x87, // OP_EQUAL }, sigScript: sigScriptMath, expected: true, }, { name: "lshift", pkScript: []byte{ 0x98, // OP_LSHIFT 0x01, // Expected result push 0x88, 0x87, // OP_EQUAL }, sigScript: sigScriptShift, expected: true, }, { name: "rshift", pkScript: []byte{ 0x99, // OP_RSHIFT 0x04, // Expected result push 0xff, 0xff, 0xff, 0x0f, 0x87, // OP_EQUAL }, sigScript: sigScriptShift, expected: true, }, { name: "rotr", pkScript: []byte{ 0x89, // OP_ROTR 0x04, // Expected result push 0x44, 0x82, 0xc6, 0x2a, 0x87, // OP_EQUAL }, sigScript: sigScriptRot, expected: true, }, { name: "rotl", pkScript: []byte{ 0x8a, // OP_ROTL 0x04, // Expected result push 0xf6, 0x6e, 0x5f, 0xce, 0x87, // OP_EQUAL }, sigScript: sigScriptRot, expected: true, }, { name: "inv", pkScript: []byte{ 0x83, // OP_INV 0x04, // Expected result push 0x00, 0x01, 0xf0, 0x8f, 0x87, // OP_EQUAL }, sigScript: sigScriptInv, expected: true, }, { name: "and", pkScript: []byte{ 0x84, // OP_AND 0x03, // Expected result push 0x21, 0x02, 0x34, 0x87, // OP_EQUAL }, sigScript: sigScriptLogic, expected: true, }, { name: "or", pkScript: []byte{ 0x85, // OP_OR 0x04, // Expected result push 0x0f, 0xe0, 0x00, 0xa9, 0x87, // OP_EQUAL }, sigScript: sigScriptLogic, expected: true, }, { name: "xor", pkScript: []byte{ 0x86, // OP_XOR 0x04, // Expected result push 0x30, 0xe2, 0x34, 0xa9, 0x87, // OP_EQUAL }, sigScript: sigScriptLogic, expected: true, }, { name: "cat", pkScript: []byte{ 0x7e, // OP_CAT 0x0c, // Expected result push 0x21, 0x12, 0x34, 0x56, 0x44, 0x55, 0x0f, 0xf0, 0x00, 0xff, 0x88, 0x99, 0x87, // OP_EQUAL }, sigScript: sigScriptCat, expected: true, }, { name: "catoverflow", pkScript: []byte{ 0x7e, // OP_CAT 0x0c, // Expected result push 0x21, 0x12, 0x34, 0x56, 0x44, 0x55, 0x0f, 0xf0, 0x00, 0xff, 0x88, 0x99, 0x87, // OP_EQUAL }, sigScript: sigScriptCatOverflow, expected: false, }, { name: "substr", pkScript: []byte{ 0x7f, // OP_SUBSTR 0x04, // Expected result push 0x34, 0x56, 0x59, 0x32, 0x87, // OP_EQUAL }, sigScript: sigScriptSubstr, expected: true, }, { name: "left", pkScript: []byte{ 0x80, // OP_LEFT 0x04, // Expected result push 0x21, 0x12, 0x34, 0x56, 0x87, // OP_EQUAL }, sigScript: sigScriptLR, expected: true, }, { name: "right", pkScript: []byte{ 0x81, // OP_RIGHT 0x04, // Expected result push 0x59, 0x32, 0x40, 0x21, 0x87, // OP_EQUAL }, sigScript: sigScriptLR, expected: true, }, } for _, test := range tests { msgTx := new(wire.MsgTx) msgTx.AddTxIn(&wire.TxIn{ PreviousOutPoint: wire.OutPoint{}, SignatureScript: test.sigScript, Sequence: 0xFFFFFFFF, }) msgTx.AddTxOut(&wire.TxOut{ Value: 0x00FFFFFF00000000, PkScript: []byte{0x01}, }) flags := StandardVerifyFlags engine, err := NewEngine(test.pkScript, msgTx, 0, flags, 0, nil) if err != nil { t.Errorf("Bad script result for test %v because of error: %v", test.name, err.Error()) continue } err = engine.Execute() if err != nil && test.expected { t.Errorf("Bad script exec for test %v because of error: %v", test.name, err.Error()) } } }
// TestCalcSignatureHash does some rudimentary testing of msg hash calculation. func TestCalcSignatureHash(t *testing.T) { tx := new(wire.MsgTx) for i := 0; i < 3; i++ { txIn := new(wire.TxIn) txIn.Sequence = 0xFFFFFFFF txIn.PreviousOutPoint.Hash = chainhash.HashFuncH([]byte{byte(i)}) txIn.PreviousOutPoint.Index = uint32(i) txIn.PreviousOutPoint.Tree = int8(0) tx.AddTxIn(txIn) } for i := 0; i < 2; i++ { txOut := new(wire.TxOut) txOut.PkScript = []byte{0x01, 0x01, 0x02, 0x03} txOut.Value = 0x0000FF00FF00FF00 tx.AddTxOut(txOut) } want, _ := hex.DecodeString("d09285b6f60c71329323bc2e76c48" + "a462cde4e1032aa8f59c55823f1722c7f4a") pops, _ := txscript.TstParseScript([]byte{0x01, 0x01, 0x02, 0x03}) // Test prefix caching. msg1, err := txscript.CalcSignatureHash(pops, txscript.SigHashAll, tx, 0, nil) if err != nil { t.Fatalf("unexpected error %v", err.Error()) } prefixHash := tx.TxSha() msg2, err := txscript.CalcSignatureHash(pops, txscript.SigHashAll, tx, 0, &prefixHash) if err != nil { t.Fatalf("unexpected error %v", err.Error()) } if !bytes.Equal(msg1, want) { t.Errorf("for sighash all sig noncached wrong msg %x given, want %x", msg1, want) } if !bytes.Equal(msg2, want) { t.Errorf("for sighash all sig cached wrong msg %x given, want %x", msg1, want) } if !bytes.Equal(msg1, msg2) { t.Errorf("for sighash all sig non-equivalent msgs %x and %x were "+ "returned when using a cached prefix", msg1, msg2) } // Move the index and make sure that we get a whole new hash, despite // using the same TxOuts. msg3, err := txscript.CalcSignatureHash(pops, txscript.SigHashAll, tx, 1, &prefixHash) if err != nil { t.Fatalf("unexpected error %v", err.Error()) } if bytes.Equal(msg1, msg3) { t.Errorf("for sighash all sig equivalent msgs %x and %x were "+ "returned when using a cached prefix but different indices", msg1, msg3) } }