// SignRawTransaction2Async returns an instance of a type that can be used to // get the result of the RPC at some future time by invoking the Receive // function on the returned instance. // // See SignRawTransaction2 for the blocking version and more details. func (c *Client) SignRawTransaction2Async(tx *wire.MsgTx, inputs []dcrjson.RawTxInput) FutureSignRawTransactionResult { txHex := "" if tx != nil { // Serialize the transaction and convert to hex string. buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize())) if err := tx.Serialize(buf); err != nil { return newFutureError(err) } txHex = hex.EncodeToString(buf.Bytes()) } cmd := dcrjson.NewSignRawTransactionCmd(txHex, &inputs, nil, nil) return c.sendCmd(cmd) }
// dbFetchTx looks up the passed transaction hash in the transaction index and // loads it from the database. func dbFetchTx(dbTx database.Tx, hash chainhash.Hash) (*wire.MsgTx, error) { // Look up the location of the transaction. blockRegion, err := dbFetchTxIndexEntry(dbTx, hash) if err != nil { return nil, err } if blockRegion == nil { return nil, fmt.Errorf("transaction %v not found in the txindex", hash) } // Load the raw transaction bytes from the database. txBytes, err := dbTx.FetchBlockRegion(blockRegion) if err != nil { return nil, err } // Deserialize the transaction. var msgTx wire.MsgTx err = msgTx.Deserialize(bytes.NewReader(txBytes)) if err != nil { return nil, err } return &msgTx, nil }
// calcPriority returns a transaction priority given a transaction and the sum // of each of its input values multiplied by their age (# of confirmations). // Thus, the final formula for the priority is: // sum(inputValue * inputAge) / adjustedTxSize func calcPriority(tx *wire.MsgTx, utxoView *blockchain.UtxoViewpoint, nextBlockHeight int64) float64 { // In order to encourage spending multiple old unspent transaction // outputs thereby reducing the total set, don't count the constant // overhead for each input as well as enough bytes of the signature // script to cover a pay-to-script-hash redemption with a compressed // pubkey. This makes additional inputs free by boosting the priority // of the transaction accordingly. No more incentive is given to avoid // encouraging gaming future transactions through the use of junk // outputs. This is the same logic used in the reference // implementation. // // The constant overhead for a txin is 41 bytes since the previous // outpoint is 36 bytes + 4 bytes for the sequence + 1 byte the // signature script length. // // A compressed pubkey pay-to-script-hash redemption with a maximum len // signature is of the form: // [OP_DATA_73 <73-byte sig> + OP_DATA_35 + {OP_DATA_33 // <33 byte compresed pubkey> + OP_CHECKSIG}] // // Thus 1 + 73 + 1 + 1 + 33 + 1 = 110 overhead := 0 for _, txIn := range tx.TxIn { // Max inputs + size can't possibly overflow here. overhead += 41 + minInt(110, len(txIn.SignatureScript)) } serializedTxSize := tx.SerializeSize() if overhead >= serializedTxSize { return 0.0 } inputValueAge := calcInputValueAge(tx, utxoView, nextBlockHeight) return inputValueAge / float64(serializedTxSize-overhead) }
// Receive waits for the response promised by the future and returns the // signed transaction as well as whether or not all inputs are now signed. func (r FutureSignRawTransactionResult) Receive() (*wire.MsgTx, bool, error) { res, err := receiveFuture(r) if err != nil { return nil, false, err } // Unmarshal as a signrawtransaction result. var signRawTxResult dcrjson.SignRawTransactionResult err = json.Unmarshal(res, &signRawTxResult) if err != nil { return nil, false, err } // Decode the serialized transaction hex to raw bytes. serializedTx, err := hex.DecodeString(signRawTxResult.Hex) if err != nil { return nil, false, err } // Deserialize the transaction and return it. var msgTx wire.MsgTx if err := msgTx.Deserialize(bytes.NewReader(serializedTx)); err != nil { return nil, false, err } return &msgTx, signRawTxResult.Complete, nil }
// fetchTxDataByLoc returns several pieces of data regarding the given tx // located by the block/offset/size location func (db *LevelDb) fetchTxDataByLoc(blkHeight int64, txOff int, txLen int, txspent []byte) (rtx *wire.MsgTx, rblksha *chainhash.Hash, rheight int64, rtxspent []byte, err error) { var blksha *chainhash.Hash var blkbuf []byte blksha, blkbuf, err = db.getBlkByHeight(blkHeight) if err != nil { if err == leveldb.ErrNotFound { err = database.ErrTxShaMissing } return } if len(blkbuf) < txOff+txLen { log.Warnf("block buffer overrun while looking for tx: "+ "block %v %v txoff %v txlen %v", blkHeight, blksha, txOff, txLen) err = database.ErrDbInconsistency return } rbuf := bytes.NewReader(blkbuf[txOff : txOff+txLen]) var tx wire.MsgTx err = tx.Deserialize(rbuf) if err != nil { log.Warnf("unable to decode tx block %v %v txoff %v txlen %v", blkHeight, blksha, txOff, txLen) err = database.ErrDbInconsistency return } return &tx, blksha, blkHeight, txspent, nil }
// Receive waits for the response promised by the future and returns a // transaction given its hash. func (r FutureGetRawTransactionResult) Receive() (*dcrutil.Tx, error) { res, err := receiveFuture(r) if err != nil { return nil, err } // Unmarshal result as a string. var txHex string err = json.Unmarshal(res, &txHex) if err != nil { return nil, err } // Decode the serialized transaction hex to raw bytes. serializedTx, err := hex.DecodeString(txHex) if err != nil { return nil, err } // Deserialize the transaction and return it. var msgTx wire.MsgTx if err := msgTx.Deserialize(bytes.NewReader(serializedTx)); err != nil { return nil, err } return dcrutil.NewTx(&msgTx), nil }
// Receive waits for the response promised by the future and returns the // found raw transactions. func (r FutureSearchRawTransactionsResult) Receive() ([]*wire.MsgTx, error) { res, err := receiveFuture(r) if err != nil { return nil, err } // Unmarshal as an array of strings. var searchRawTxnsResult []string err = json.Unmarshal(res, &searchRawTxnsResult) if err != nil { return nil, err } // Decode and deserialize each transaction. msgTxns := make([]*wire.MsgTx, 0, len(searchRawTxnsResult)) for _, hexTx := range searchRawTxnsResult { // Decode the serialized transaction hex to raw bytes. serializedTx, err := hex.DecodeString(hexTx) if err != nil { return nil, err } // Deserialize the transaction and add it to the result slice. var msgTx wire.MsgTx err = msgTx.Deserialize(bytes.NewReader(serializedTx)) if err != nil { return nil, err } msgTxns = append(msgTxns, &msgTx) } return msgTxns, nil }
// 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() } } } }
// deserializeSStxRecord deserializes the passed serialized tx record information. func deserializeSStxRecord(serializedSStxRecord []byte) (*sstxRecord, error) { record := new(sstxRecord) curPos := 0 // Read MsgTx size (as a uint64). msgTxLen := int(byteOrder.Uint64( serializedSStxRecord[curPos : curPos+int64Size])) curPos += int64Size // Pretend to read the pkScrLoc for the 0th output pkScript. curPos += int32Size // Read the intended voteBits and extended voteBits length (uint8). record.voteBitsSet = false voteBitsLen := uint8(serializedSStxRecord[curPos]) if voteBitsLen != 0 { record.voteBitsSet = true } curPos += int8Size // Read the assumed 2 byte VoteBits as well as the extended // votebits (75 bytes max). record.voteBits = byteOrder.Uint16( serializedSStxRecord[curPos : curPos+int16Size]) curPos += int16Size record.voteBitsExt = make([]byte, int(voteBitsLen)-int16Size) copy(record.voteBitsExt[:], serializedSStxRecord[curPos:curPos+int(voteBitsLen)-int16Size]) curPos += stake.MaxSingleBytePushLength - int16Size // Prepare a buffer for the msgTx. buf := bytes.NewBuffer(serializedSStxRecord[curPos : curPos+msgTxLen]) curPos += msgTxLen // Deserialize transaction. msgTx := new(wire.MsgTx) err := msgTx.Deserialize(buf) if err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } return nil, err } // Create and save the dcrutil.Tx of the read MsgTx and set its index. tx := dcrutil.NewTx((*wire.MsgTx)(msgTx)) tx.SetIndex(dcrutil.TxIndexUnknown) tx.SetTree(dcrutil.TxTreeStake) record.tx = tx // Read received unix time (int64). received := int64(byteOrder.Uint64( serializedSStxRecord[curPos : curPos+int64Size])) curPos += int64Size record.ts = time.Unix(received, 0) return record, nil }
// NewTx returns a new instance of a transaction given an underlying // wire.MsgTx. See Tx. func NewTx(msgTx *wire.MsgTx) *Tx { return &Tx{ hash: msgTx.TxHash(), msgTx: msgTx, txTree: wire.TxTreeUnknown, txIndex: TxIndexUnknown, } }
func spendOutput(txHash *chainhash.Hash, index uint32, outputValues ...int64) *wire.MsgTx { tx := wire.MsgTx{ TxIn: []*wire.TxIn{ &wire.TxIn{ PreviousOutPoint: wire.OutPoint{Hash: *txHash, Index: index}, }, }, } for _, val := range outputValues { tx.TxOut = append(tx.TxOut, &wire.TxOut{Value: val}) } return &tx }
func newCoinBase(outputValues ...int64) *wire.MsgTx { tx := wire.MsgTx{ TxIn: []*wire.TxIn{ &wire.TxIn{ PreviousOutPoint: wire.OutPoint{Index: ^uint32(0)}, }, }, } for _, val := range outputValues { tx.TxOut = append(tx.TxOut, &wire.TxOut{Value: val}) } return &tx }
// SendRawTransactionAsync returns an instance of a type that can be used to get // the result of the RPC at some future time by invoking the Receive function on // the returned instance. // // See SendRawTransaction for the blocking version and more details. func (c *Client) SendRawTransactionAsync(tx *wire.MsgTx, allowHighFees bool) FutureSendRawTransactionResult { txHex := "" if tx != nil { // Serialize the transaction and convert to hex string. buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize())) if err := tx.Serialize(buf); err != nil { return newFutureError(err) } txHex = hex.EncodeToString(buf.Bytes()) } cmd := dcrjson.NewSendRawTransactionCmd(txHex, &allowHighFees) return c.sendCmd(cmd) }
func equalTxs(t *testing.T, got, exp *wire.MsgTx) { var bufGot, bufExp bytes.Buffer err := got.Serialize(&bufGot) if err != nil { t.Fatal(err) } err = exp.Serialize(&bufExp) if err != nil { t.Fatal(err) } if !bytes.Equal(bufGot.Bytes(), bufExp.Bytes()) { t.Errorf("Found unexpected wire.MsgTx:") t.Errorf("Got: %x", bufGot.Bytes()) t.Errorf("Expected: %x", bufExp.Bytes()) } }
// NewTxFromReader returns a new instance of a transaction given a // Reader to deserialize the transaction. See Tx. func NewTxFromReader(r io.Reader) (*Tx, error) { // Deserialize the bytes into a MsgTx. var msgTx wire.MsgTx err := msgTx.Deserialize(r) if err != nil { return nil, err } t := Tx{ hash: msgTx.TxHash(), msgTx: &msgTx, txTree: wire.TxTreeUnknown, txIndex: TxIndexUnknown, } return &t, nil }
// BUGS: // - The transaction is not inspected to be relevant before publishing using // sendrawtransaction, so connection errors to dcrd could result in the tx // never being added to the wallet database. // - Once the above bug is fixed, wallet will require a way to purge invalid // transactions from the database when they are rejected by the network, other // than double spending them. func (s *walletServer) PublishTransaction(ctx context.Context, req *pb.PublishTransactionRequest) ( *pb.PublishTransactionResponse, error) { var msgTx wire.MsgTx err := msgTx.Deserialize(bytes.NewReader(req.SignedTransaction)) if err != nil { return nil, grpc.Errorf(codes.InvalidArgument, "Bytes do not represent a valid raw transaction: %v", err) } txHash, err := s.wallet.PublishTransaction(&msgTx) if err != nil { return nil, translateError(err) } return &pb.PublishTransactionResponse{TransactionHash: txHash[:]}, nil }
// 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, } }
// BUGS: // - InputIndexes request field is ignored. func (s *walletServer) SignTransaction(ctx context.Context, req *pb.SignTransactionRequest) ( *pb.SignTransactionResponse, error) { defer zero.Bytes(req.Passphrase) var tx wire.MsgTx err := tx.Deserialize(bytes.NewReader(req.SerializedTransaction)) if err != nil { return nil, grpc.Errorf(codes.InvalidArgument, "Bytes do not represent a valid raw transaction: %v", err) } lock := make(chan time.Time, 1) defer func() { lock <- time.Time{} // send matters, not the value }() err = s.wallet.Unlock(req.Passphrase, lock) if err != nil { return nil, translateError(err) } invalidSigs, err := s.wallet.SignTransaction(&tx, txscript.SigHashAll, nil, nil, nil) if err != nil { return nil, translateError(err) } invalidInputIndexes := make([]uint32, len(invalidSigs)) for i, e := range invalidSigs { invalidInputIndexes[i] = e.InputIndex } var serializedTransaction bytes.Buffer serializedTransaction.Grow(tx.SerializeSize()) err = tx.Serialize(&serializedTransaction) if err != nil { return nil, translateError(err) } resp := &pb.SignTransactionResponse{ Transaction: serializedTransaction.Bytes(), UnsignedInputIndexes: invalidInputIndexes, } return resp, nil }
func TestStakeInvalidationOfTip(t *testing.T) { db, s, teardown, err := setup() defer teardown() if err != nil { t.Fatal(err) } g := makeBlockGenerator() block1Header := g.generate(dcrutil.BlockValid) block2Header := g.generate(dcrutil.BlockValid) block3Header := g.generate(0) block1Tx := wire.MsgTx{ TxOut: []*wire.TxOut{{Value: 2e8}}, } block2Tx := wire.MsgTx{ TxIn: []*wire.TxIn{ {PreviousOutPoint: wire.OutPoint{Hash: block1Tx.TxSha(), Index: 0, Tree: 0}}, }, TxOut: []*wire.TxOut{{Value: 1e8}}, } block1TxRec, err := NewTxRecordFromMsgTx(&block1Tx, time.Time{}) if err != nil { t.Fatal(err) } block2TxRec, err := NewTxRecordFromMsgTx(&block2Tx, time.Time{}) if err != nil { t.Fatal(err) } const balanceFlag = BFBalanceSpendable err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error { ns := tx.ReadWriteBucket(wtxmgrNamespaceKey) addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey) err := s.InsertMemPoolTx(ns, block1TxRec) if err != nil { return err } err = s.AddCredit(ns, block1TxRec, nil, 0, false, 0) if err != nil { return err } err = s.InsertMemPoolTx(ns, block2TxRec) if err != nil { return err } err = s.AddCredit(ns, block2TxRec, nil, 0, false, 0) if err != nil { return err } bal, err := s.Balance(ns, addrmgrNs, 0, balanceFlag, false, 0) if err != nil { return err } if bal != 1e8 { t.Errorf("Wrong balance before mining either transaction: %v", bal) } headerData := makeHeaderDataSlice(block1Header, block2Header) err = s.InsertMainChainHeaders(ns, addrmgrNs, headerData) if err != nil { return err } err = s.InsertMinedTx(ns, addrmgrNs, block1TxRec, &headerData[0].BlockHash) if err != nil { return err } err = s.InsertMinedTx(ns, addrmgrNs, block2TxRec, &headerData[1].BlockHash) if err != nil { return err } // At this point there should only be one credit for the tx in block 2. bal, err = s.Balance(ns, addrmgrNs, 1, balanceFlag, false, 0) if err != nil { return err } if bal != dcrutil.Amount(block2Tx.TxOut[0].Value) { t.Errorf("Wrong balance: expected %v got %v", dcrutil.Amount(block2Tx.TxOut[0].Value), bal) } credits, err := s.UnspentOutputs(ns) if err != nil { return err } if len(credits) != 1 { t.Errorf("Expected only 1 credit, got %v", len(credits)) return nil } if credits[0].Hash != block2Tx.TxSha() { t.Errorf("Credit hash does match tx from block 2") return nil } if credits[0].Amount != dcrutil.Amount(block2Tx.TxOut[0].Value) { t.Errorf("Credit value does not match tx output 0 from block 2") return nil } // Add the next block header which invalidates the regular tx tree of // block 2. t.Log("Invalidating block 2") headerData = makeHeaderDataSlice(block3Header) err = s.InsertMainChainHeaders(ns, addrmgrNs, headerData) if err != nil { return err } /* d := makeHeaderData(block3Header) err = s.ExtendMainChain(ns, &d) if err != nil { return err } */ // Now the transaction in block 2 is invalidated. There should only be // one unspent output, from block 1. bal, err = s.Balance(ns, addrmgrNs, 1, balanceFlag, false, 0) if err != nil { return err } if bal != dcrutil.Amount(block1Tx.TxOut[0].Value) { t.Errorf("Wrong balance: expected %v got %v", dcrutil.Amount(block1Tx.TxOut[0].Value), bal) } credits, err = s.UnspentOutputs(ns) if err != nil { return err } if len(credits) != 1 { t.Errorf("Expected only 1 credit, got %v", len(credits)) return nil } if credits[0].Hash != block1Tx.TxSha() { t.Errorf("Credit hash does not match tx from block 1") return nil } if credits[0].Amount != dcrutil.Amount(block1Tx.TxOut[0].Value) { t.Errorf("Credit value does not match tx output 0 from block 1") return nil } return nil }) if err != nil { t.Error(err) } }
var genesisCoinbaseTxLegacy = wire.MsgTx{ Version: 1, TxIn: []*wire.TxIn{ { PreviousOutPoint: wire.OutPoint{ Hash: chainhash.Hash{}, Index: 0xffffffff, }, SignatureScript: []byte{ 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, /* |.......E| */ 0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, /* |The Time| */ 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, /* |s 03/Jan| */ 0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x68, /* |/2009 Ch| */ 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x72, /* |ancellor| */ 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, /* | on brin| */ 0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x63, /* |k of sec|*/ 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, /* |ond bail| */ 0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, /* |out for |*/ 0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ }, Sequence: 0xffffffff, }, }, TxOut: []*wire.TxOut{ { Value: 0x00000000, PkScript: []byte{ 0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, /* |A.g....U| */ 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, /* |H'.g..q0| */ 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, /* |..\..(.9| */ 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, /* |..yb...a| */ 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, /* |..I..?L.| */ 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, /* |8..U....| */ 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, /* |..\8M...| */ 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, /* |.W.Lp+k.| */ 0x1d, 0x5f, 0xac, /* |._.| */ }, }, }, LockTime: 0, Expiry: 0, }
// TestTxSerializeWitnessValueSigning tests MsgTx serialize and deserialize. func TestTxSerializeWitnessValueSigning(t *testing.T) { noTx := wire.NewMsgTx() noTx.Version = 262145 noTxEncoded := []byte{ 0x01, 0x00, 0x04, 0x00, // Version 0x00, // Varint for number of input signatures } tests := []struct { in *wire.MsgTx // Message to encode out *wire.MsgTx // Expected decoded message buf []byte // Serialized data pkScriptLocs []int // Expected output script locations }{ // No transactions. { noTx, noTx, noTxEncoded, nil, }, // Multiple transactions. { multiTxWitnessValueSigning, multiTxWitnessValueSigning, multiTxWitnessValueSigningEncoded, nil, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Serialize the transaction. var buf bytes.Buffer err := test.in.Serialize(&buf) if err != nil { t.Errorf("Serialize #%d error %v", i, err) continue } if !bytes.Equal(buf.Bytes(), test.buf) { t.Errorf("Serialize #%d\n got: %s want: %s", i, spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) continue } // Test SerializeSize. sz := test.in.SerializeSize() actualSz := len(buf.Bytes()) if sz != actualSz { t.Errorf("Wrong serialize size #%d\n got: %s want: %s", i, sz, actualSz) } // Deserialize the transaction. var tx wire.MsgTx rbuf := bytes.NewReader(test.buf) err = tx.Deserialize(rbuf) if err != nil { t.Errorf("Deserialize #%d error %v", i, err) continue } if !reflect.DeepEqual(&tx, test.out) { t.Errorf("Deserialize #%d\n got: %s want: %s", i, spew.Sdump(&tx), spew.Sdump(test.out)) continue } // Ensure the public key script locations are accurate. pkScriptLocs := test.in.PkScriptLocs() if !reflect.DeepEqual(pkScriptLocs, test.pkScriptLocs) { t.Errorf("PkScriptLocs #%d\n got: %s want: %s", i, spew.Sdump(pkScriptLocs), spew.Sdump(test.pkScriptLocs)) continue } for j, loc := range pkScriptLocs { wantPkScript := test.in.TxOut[j].PkScript gotPkScript := test.buf[loc : loc+len(wantPkScript)] if !bytes.Equal(gotPkScript, wantPkScript) { t.Errorf("PkScriptLocs #%d:%d\n unexpected "+ "script got: %s want: %s", i, j, spew.Sdump(gotPkScript), spew.Sdump(wantPkScript)) } } } }
// TestTxSerializeErrors performs negative tests against wire encode and decode // of MsgTx to confirm error paths work correctly. func TestTxSerializeErrors(t *testing.T) { tests := []struct { in *wire.MsgTx // Value to encode buf []byte // Serialized data max int // Max size of fixed buffer to induce errors writeErr error // Expected write error readErr error // Expected read error }{ // Force error in version. {multiTx, multiTxEncoded, 0, io.ErrShortWrite, io.EOF}, // Force error in number of transaction inputs. {multiTx, multiTxEncoded, 4, io.ErrShortWrite, io.EOF}, // Force error in transaction input previous block hash. {multiTx, multiTxEncoded, 5, io.ErrShortWrite, io.EOF}, // Force error in transaction input previous block output index. {multiTx, multiTxEncoded, 37, io.ErrShortWrite, io.EOF}, // Force error in transaction input previous block output tree. {multiTx, multiTxEncoded, 41, io.ErrShortWrite, io.EOF}, // Force error in transaction input sequence. {multiTx, multiTxEncoded, 42, io.ErrShortWrite, io.EOF}, // Force error in number of transaction outputs. {multiTx, multiTxEncoded, 46, io.ErrShortWrite, io.EOF}, // Force error in transaction output value. {multiTx, multiTxEncoded, 47, io.ErrShortWrite, io.EOF}, // Force error in transaction output version. {multiTx, multiTxEncoded, 55, io.ErrShortWrite, io.EOF}, // Force error in transaction output pk script length. {multiTx, multiTxEncoded, 57, io.ErrShortWrite, io.EOF}, // Force error in transaction output pk script. {multiTx, multiTxEncoded, 58, io.ErrShortWrite, io.EOF}, // Force error in transaction lock time. {multiTx, multiTxEncoded, 203, io.ErrShortWrite, io.EOF}, // Force error in transaction expiry. {multiTx, multiTxEncoded, 207, io.ErrShortWrite, io.EOF}, // Force error in transaction num sig varint. {multiTx, multiTxEncoded, 211, io.ErrShortWrite, io.EOF}, // Force error in transaction sig 0 ValueIn. {multiTx, multiTxEncoded, 212, io.ErrShortWrite, io.EOF}, // Force error in transaction sig 0 BlockHeight. {multiTx, multiTxEncoded, 220, io.ErrShortWrite, io.EOF}, // Force error in transaction sig 0 BlockIndex. {multiTx, multiTxEncoded, 224, io.ErrShortWrite, io.EOF}, // Force error in transaction sig 0 length. {multiTx, multiTxEncoded, 228, io.ErrShortWrite, io.EOF}, // Force error in transaction sig 0 signature script. {multiTx, multiTxEncoded, 229, io.ErrShortWrite, io.EOF}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Serialize the transaction. w := newFixedWriter(test.max) err := test.in.Serialize(w) if err != test.writeErr { t.Errorf("Serialize #%d wrong error got: %v, want: %v", i, err, test.writeErr) continue } // Deserialize the transaction. var tx wire.MsgTx r := newFixedReader(test.max, test.buf) err = tx.Deserialize(r) if err != test.readErr { t.Errorf("Deserialize #%d wrong error got: %v, want: %v", i, err, test.readErr) continue } } }
// TestTxOverflowErrors performs tests to ensure deserializing transactions // which are intentionally crafted to use large values for the variable number // of inputs and outputs are handled properly. This could otherwise potentially // be used as an attack vector. func TestTxOverflowErrors(t *testing.T) { // Use protocol version 1 and transaction version 1 specifically // here instead of the latest values because the test data is using // bytes encoded with those versions. pver := uint32(1) txVer := wire.DefaultMsgTxVersion() tests := []struct { buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding version int32 // Transaction version err error // Expected error }{ // Transaction that claims to have ~uint64(0) inputs. [0] { []byte{ 0x01, 0x00, 0x00, 0x00, // Version 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Varint for number of input transactions }, pver, txVer, &wire.MessageError{}, }, // Transaction that claims to have ~uint64(0) outputs. [1] { []byte{ 0x01, 0x00, 0x00, 0x00, // Version 0x00, // Varint for number of input transactions 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Varint for number of output transactions }, pver, txVer, &wire.MessageError{}, }, // Transaction that has an input with a signature script that [2] // claims to have ~uint64(0) length. { []byte{ 0x01, 0x00, 0x00, 0x00, // Version 0x01, // Varint for number of input transactions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash 0xff, 0xff, 0xff, 0xff, // Previous output index 0x00, // Previous output tree 0x00, // Varint for length of signature script 0xff, 0xff, 0xff, 0xff, // Sequence 0x02, // Varint for number of output transactions 0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount 0x43, // Varint for length of pk script 0x41, // OP_DATA_65 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, 0xa6, // 65-byte signature 0xac, // OP_CHECKSIG 0x00, 0xe1, 0xf5, 0x05, 0x00, 0x00, 0x00, 0x00, // Transaction amount 0x43, // Varint for length of pk script 0x41, // OP_DATA_65 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, 0xa6, // 65-byte signature 0xac, // OP_CHECKSIG 0x00, 0x00, 0x00, 0x00, // Lock time 0x00, 0x00, 0x00, 0x00, // Expiry 0x01, // Varint for number of input signature 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Varint for sig script length (overflows) }, pver, txVer, &wire.MessageError{}, }, // Transaction that has an output with a public key script [3] // that claims to have ~uint64(0) length. { []byte{ 0x01, 0x00, 0x00, 0x00, // Version 0x01, // Varint for number of input transactions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash 0xff, 0xff, 0xff, 0xff, // Prevous output index 0x00, // Previous output tree 0x00, // Varint for length of signature script 0xff, 0xff, 0xff, 0xff, // Sequence 0x01, // Varint for number of output transactions 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Transaction amount 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // Varint for length of public key script }, pver, txVer, &wire.MessageError{}, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Decode from wire format. var msg wire.MsgTx r := bytes.NewReader(test.buf) err := msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { t.Errorf("BtcDecode #%d wrong error got: %v, want: %v", i, err, reflect.TypeOf(test.err)) } // Decode from wire format. r = bytes.NewReader(test.buf) err = msg.Deserialize(r) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { t.Errorf("Deserialize #%d wrong error got: %v, want: %v", i, err, reflect.TypeOf(test.err)) continue } } }
// DebugMsgTxString dumps a verbose message containing information about the // contents of a transaction. func DebugMsgTxString(msgTx *wire.MsgTx) string { tx := dcrutil.NewTx(msgTx) isSStx, _ := stake.IsSStx(tx) isSSGen, _ := stake.IsSSGen(tx) var sstxType []bool var sstxPkhs [][]byte var sstxAmts []int64 var sstxRules [][]bool var sstxLimits [][]uint16 if isSStx { sstxType, sstxPkhs, sstxAmts, _, sstxRules, sstxLimits = stake.GetSStxStakeOutputInfo(tx) } var buffer bytes.Buffer hash := msgTx.TxSha() str := fmt.Sprintf("Transaction hash: %v, Version %v, Locktime: %v, "+ "Expiry %v\n\n", hash, msgTx.Version, msgTx.LockTime, msgTx.Expiry) buffer.WriteString(str) str = fmt.Sprintf("==INPUTS==\nNumber of inputs: %v\n\n", len(msgTx.TxIn)) buffer.WriteString(str) for i, input := range msgTx.TxIn { str = fmt.Sprintf("Input number: %v\n", i) buffer.WriteString(str) str = fmt.Sprintf("Previous outpoint hash: %v, ", input.PreviousOutPoint.Hash) buffer.WriteString(str) str = fmt.Sprintf("Previous outpoint index: %v, ", input.PreviousOutPoint.Index) buffer.WriteString(str) str = fmt.Sprintf("Previous outpoint tree: %v \n", input.PreviousOutPoint.Tree) buffer.WriteString(str) str = fmt.Sprintf("Sequence: %v \n", input.Sequence) buffer.WriteString(str) str = fmt.Sprintf("ValueIn: %v \n", input.ValueIn) buffer.WriteString(str) str = fmt.Sprintf("BlockHeight: %v \n", input.BlockHeight) buffer.WriteString(str) str = fmt.Sprintf("BlockIndex: %v \n", input.BlockIndex) buffer.WriteString(str) str = fmt.Sprintf("Raw signature script: %x \n", input.SignatureScript) buffer.WriteString(str) sigScr, _ := txscript.DisasmString(input.SignatureScript) str = fmt.Sprintf("Disasmed signature script: %v \n\n", sigScr) buffer.WriteString(str) } str = fmt.Sprintf("==OUTPUTS==\nNumber of outputs: %v\n\n", len(msgTx.TxOut)) buffer.WriteString(str) for i, output := range msgTx.TxOut { str = fmt.Sprintf("Output number: %v\n", i) buffer.WriteString(str) coins := float64(output.Value) / 1e8 str = fmt.Sprintf("Output amount: %v atoms or %v coins\n", output.Value, coins) buffer.WriteString(str) // SStx OP_RETURNs, dump pkhs and amts committed if isSStx && i != 0 && i%2 == 1 { coins := float64(sstxAmts[i/2]) / 1e8 str = fmt.Sprintf("SStx commit amount: %v atoms or %v coins\n", sstxAmts[i/2], coins) buffer.WriteString(str) str = fmt.Sprintf("SStx commit address: %x\n", sstxPkhs[i/2]) buffer.WriteString(str) str = fmt.Sprintf("SStx address type is P2SH: %v\n", sstxType[i/2]) buffer.WriteString(str) str = fmt.Sprintf("SStx all address types is P2SH: %v\n", sstxType) buffer.WriteString(str) str = fmt.Sprintf("Voting is fee limited: %v\n", sstxLimits[i/2][0]) buffer.WriteString(str) if sstxRules[i/2][0] { str = fmt.Sprintf("Voting limit imposed: %v\n", sstxLimits[i/2][0]) buffer.WriteString(str) } str = fmt.Sprintf("Revoking is fee limited: %v\n", sstxRules[i/2][1]) buffer.WriteString(str) if sstxRules[i/2][1] { str = fmt.Sprintf("Voting limit imposed: %v\n", sstxLimits[i/2][1]) buffer.WriteString(str) } } // SSGen block/block height OP_RETURN. if isSSGen && i == 0 { blkHash, blkHeight, _ := stake.GetSSGenBlockVotedOn(tx) str = fmt.Sprintf("SSGen block hash voted on: %v, height: %v\n", blkHash, blkHeight) buffer.WriteString(str) } if isSSGen && i == 1 { vb := stake.GetSSGenVoteBits(tx) str = fmt.Sprintf("SSGen vote bits: %v\n", vb) buffer.WriteString(str) } str = fmt.Sprintf("Raw script: %x \n", output.PkScript) buffer.WriteString(str) scr, _ := txscript.DisasmString(output.PkScript) str = fmt.Sprintf("Disasmed script: %v \n\n", scr) buffer.WriteString(str) } return buffer.String() }
// calcSignatureHash will, given a script and hash type for the current script // engine instance, calculate the signature hash to be used for signing and // verification. func calcSignatureHash(script []parsedOpcode, hashType SigHashType, tx *wire.MsgTx, idx int, cachedPrefix *chainhash.Hash) ([]byte, error) { // The SigHashSingle signature type signs only the corresponding input // and output (the output with the same index number as the input). // // Since transactions can have more inputs than outputs, this means it // is improper to use SigHashSingle on input indices that don't have a // corresponding output. // // A bug in the original Satoshi client implementation means specifying // an index that is out of range results in a signature hash of 1 (as a // uint256 little endian). The original intent appeared to be to // indicate failure, but unfortunately, it was never checked and thus is // treated as the actual signature hash. This buggy behavior is now // part of the consensus and a hard fork would be required to fix it. // // Due to this, care must be taken by software that creates transactions // which make use of SigHashSingle because it can lead to an extremely // dangerous situation where the invalid inputs will end up signing a // hash of 1. This in turn presents an opportunity for attackers to // cleverly construct transactions which can steal those coins provided // they can reuse signatures. // // Decred mitigates this by actually returning an error instead. if hashType&sigHashMask == SigHashSingle && idx >= len(tx.TxOut) { return nil, ErrSighashSingleIdx } // Remove all instances of OP_CODESEPARATOR from the script. script = removeOpcode(script, OP_CODESEPARATOR) // Make a deep copy of the transaction, zeroing out the script for all // inputs that are not currently being processed. txCopy := tx.Copy() for i := range txCopy.TxIn { if i == idx { // UnparseScript cannot fail here because removeOpcode // above only returns a valid script. sigScript, _ := unparseScript(script) txCopy.TxIn[idx].SignatureScript = sigScript } else { txCopy.TxIn[i].SignatureScript = nil } } switch hashType & sigHashMask { case SigHashNone: txCopy.TxOut = txCopy.TxOut[0:0] // Empty slice. for i := range txCopy.TxIn { if i != idx { txCopy.TxIn[i].Sequence = 0 } } case SigHashSingle: // Resize output array to up to and including requested index. txCopy.TxOut = txCopy.TxOut[:idx+1] // All but current output get zeroed out. for i := 0; i < idx; i++ { txCopy.TxOut[i].Value = -1 txCopy.TxOut[i].PkScript = nil } // Sequence on all other inputs is 0, too. for i := range txCopy.TxIn { if i != idx { txCopy.TxIn[i].Sequence = 0 } } default: // Consensus treats undefined hashtypes like normal SigHashAll // for purposes of hash generation. fallthrough case SigHashOld: fallthrough case SigHashAllValue: fallthrough case SigHashAll: // Nothing special here. } if hashType&SigHashAnyOneCanPay != 0 { txCopy.TxIn = txCopy.TxIn[idx : idx+1] idx = 0 } // The final hash (message to sign) is the hash of: // 1) hash of the prefix || // 2) hash of the witness for signing || // 3) the hash type (encoded as a 4-byte little-endian value) var wbuf bytes.Buffer binary.Write(&wbuf, binary.LittleEndian, uint32(hashType)) // Optimization for SIGHASH_ALL. In this case, the prefix hash is // the same as the transaction hash because only the inputs have // been modified, so don't bother to do the wasteful O(N^2) extra // hash here. // The caching only works if the "anyone can pay flag" is also // disabled. var prefixHash chainhash.Hash if cachedPrefix != nil && (hashType&sigHashMask == SigHashAll) && (hashType&SigHashAnyOneCanPay == 0) && chaincfg.SigHashOptimization { prefixHash = *cachedPrefix } else { prefixHash = txCopy.TxSha() } // If the ValueIn is to be included in what we're signing, sign // the witness hash that includes it. Otherwise, just sign the // prefix and signature scripts. var witnessHash chainhash.Hash if hashType&sigHashMask != SigHashAllValue { witnessHash = txCopy.TxShaWitnessSigning() } else { witnessHash = txCopy.TxShaWitnessValueSigning() } wbuf.Write(prefixHash.Bytes()) wbuf.Write(witnessHash.Bytes()) return chainhash.HashFuncB(wbuf.Bytes()), nil }
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()) } } }
var genesisCoinbaseTx = wire.MsgTx{ Version: 1, TxIn: []*wire.TxIn{ { // Fully null. PreviousOutPoint: wire.OutPoint{ Hash: chainhash.Hash{}, Index: 0xffffffff, Tree: 0, }, SignatureScript: []byte{ 0x00, 0x00, }, Sequence: 0xffffffff, BlockHeight: wire.NullBlockHeight, BlockIndex: wire.NullBlockIndex, ValueIn: wire.NullValueIn, }, }, TxOut: []*wire.TxOut{ { Version: 0x0000, Value: 0x00000000, PkScript: []byte{ 0x80, 0x16, 0x79, 0xe9, 0x85, 0x61, 0xad, 0xa9, 0x6c, 0xae, 0xc2, 0x94, 0x9a, 0x5d, 0x41, 0xc4, 0xca, 0xb3, 0x85, 0x1e, 0xb7, 0x40, 0xd9, 0x51, 0xc1, 0x0e, 0xcb, 0xcf, 0x26, 0x5c, 0x1f, 0xd9, }, }, }, LockTime: 0, Expiry: 0, }
func TestStakeInvalidationTxInsert(t *testing.T) { db, s, teardown, err := setup() defer teardown() if err != nil { t.Fatal(err) } g := makeBlockGenerator() block1Header := g.generate(dcrutil.BlockValid) block2Header := g.generate(dcrutil.BlockValid) block3Header := g.generate(0) block1Tx := wire.MsgTx{ TxOut: []*wire.TxOut{{Value: 2e8}}, } block2Tx := wire.MsgTx{ TxIn: []*wire.TxIn{ {PreviousOutPoint: wire.OutPoint{Hash: block1Tx.TxSha(), Index: 0, Tree: 0}}, }, TxOut: []*wire.TxOut{{Value: 1e8}}, } block1TxRec, err := NewTxRecordFromMsgTx(&block1Tx, time.Time{}) if err != nil { t.Fatal(err) } block2TxRec, err := NewTxRecordFromMsgTx(&block2Tx, time.Time{}) if err != nil { t.Fatal(err) } err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error { ns := tx.ReadWriteBucket(wtxmgrNamespaceKey) addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey) headerData := makeHeaderDataSlice(block1Header, block2Header, block3Header) err = s.InsertMainChainHeaders(ns, addrmgrNs, headerData) if err != nil { return err } err = s.InsertMinedTx(ns, addrmgrNs, block1TxRec, &headerData[0].BlockHash) if err != nil { return err } err = s.AddCredit(ns, block1TxRec, makeBlockMeta(block1Header), 0, false, 0) if err != nil { return err } err = s.InsertMinedTx(ns, addrmgrNs, block2TxRec, &headerData[1].BlockHash) if err != nil { return err } err = s.AddCredit(ns, block2TxRec, makeBlockMeta(block2Header), 0, false, 0) if err != nil { return err } // The transaction in block 2 was inserted invalidated. There should // only be one unspent output, from block 1. bal, err := s.Balance(ns, addrmgrNs, 1, BFBalanceFullScan, true, 0) if err != nil { return err } if bal != dcrutil.Amount(block1Tx.TxOut[0].Value) { t.Errorf("Wrong balance: expected %v got %v", dcrutil.Amount(block1Tx.TxOut[0].Value), bal) } bal, err = s.Balance(ns, addrmgrNs, 1, BFBalanceSpendable, true, 0) if err != nil { return err } if bal != dcrutil.Amount(block1Tx.TxOut[0].Value) { t.Errorf("Wrong balance: expected %v got %v", dcrutil.Amount(block1Tx.TxOut[0].Value), bal) } credits, err := s.UnspentOutputs(ns) if err != nil { return err } if len(credits) != 1 { t.Errorf("Expected only 1 credit, got %v", len(credits)) return nil } if credits[0].Hash != block1Tx.TxSha() { t.Errorf("Credit hash does not match tx from block 1") return nil } if credits[0].Amount != dcrutil.Amount(block1Tx.TxOut[0].Value) { t.Errorf("Credit value does not match tx output 0 from block 1") return nil } return nil }) if err != nil { t.Error(err) } }
// TestTxWireErrors performs negative tests against wire encode and decode // of MsgTx to confirm error paths work correctly. func TestTxWireErrors(t *testing.T) { // Use protocol version 60002 specifically here instead of the latest // because the test data is using bytes encoded with that protocol // version. pver := uint32(60002) tests := []struct { in *wire.MsgTx // Value to encode buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding max int // Max size of fixed buffer to induce errors writeErr error // Expected write error readErr error // Expected read error }{ // Force error in version. {multiTx, multiTxEncoded, pver, 0, io.ErrShortWrite, io.EOF}, // 0 // Force error in number of transaction inputs. {multiTx, multiTxEncoded, pver, 4, io.ErrShortWrite, io.EOF}, // 1 // Force error in transaction input previous block hash. {multiTx, multiTxEncoded, pver, 5, io.ErrShortWrite, io.EOF}, // 2 // Force error in transaction input previous block output index. {multiTx, multiTxEncoded, pver, 37, io.ErrShortWrite, io.EOF}, // 3 // Force error in transaction input previous block output tree. {multiTx, multiTxEncoded, pver, 41, io.ErrShortWrite, io.EOF}, // 4 // Force error in transaction input sequence. {multiTx, multiTxEncoded, pver, 42, io.ErrShortWrite, io.EOF}, // 5 // Force error in number of transaction outputs. {multiTx, multiTxEncoded, pver, 46, io.ErrShortWrite, io.EOF}, // 6 // Force error in transaction output value. {multiTx, multiTxEncoded, pver, 47, io.ErrShortWrite, io.EOF}, // 7 // Force error in transaction output script version. {multiTx, multiTxEncoded, pver, 55, io.ErrShortWrite, io.EOF}, // 8 // Force error in transaction output pk script length. {multiTx, multiTxEncoded, pver, 57, io.ErrShortWrite, io.EOF}, // 9 // Force error in transaction output pk script. {multiTx, multiTxEncoded, pver, 58, io.ErrShortWrite, io.EOF}, // 10 // Force error in transaction output lock time. {multiTx, multiTxEncoded, pver, 203, io.ErrShortWrite, io.EOF}, // 11 // Force error in transaction output expiry. {multiTx, multiTxEncoded, pver, 207, io.ErrShortWrite, io.EOF}, // 12 // Force error in transaction num sig varint. {multiTx, multiTxEncoded, pver, 211, io.ErrShortWrite, io.EOF}, // 13 // Force error in transaction sig 0 AmountIn. {multiTx, multiTxEncoded, pver, 212, io.ErrShortWrite, io.EOF}, // 14 // Force error in transaction sig 0 BlockHeight. {multiTx, multiTxEncoded, pver, 220, io.ErrShortWrite, io.EOF}, // 15 // Force error in transaction sig 0 BlockIndex. {multiTx, multiTxEncoded, pver, 224, io.ErrShortWrite, io.EOF}, // 16 // Force error in transaction sig 0 length. {multiTx, multiTxEncoded, pver, 228, io.ErrShortWrite, io.EOF}, // 17 // Force error in transaction sig 0 signature script. {multiTx, multiTxEncoded, pver, 229, io.ErrShortWrite, io.EOF}, // 18 } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Encode to wire format. w := newFixedWriter(test.max) err := test.in.BtcEncode(w, test.pver) if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, want: %v", i, err, test.writeErr) continue } // Decode from wire format. var msg wire.MsgTx r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, want: %v", i, err, test.readErr) continue } } }