// 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 }
// 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 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 }
// 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 }
// 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 }
// 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 }
// 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 }
// 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 } } }
// 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 } } }
// 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)) } } } }
// loadTxStore returns a transaction store loaded from a file. func loadTxStore(filename string) (blockchain.TxStore, error) { // The txstore file format is: // <num tx data entries> <tx length> <serialized tx> <blk height> // <num spent bits> <spent bits> // // All num and length fields are little-endian uint32s. The spent bits // field is padded to a byte boundary. filename = filepath.Join("testdata/", filename) fi, err := os.Open(filename) if err != nil { return nil, err } // Choose read based on whether the file is compressed or not. var r io.Reader if strings.HasSuffix(filename, ".bz2") { r = bzip2.NewReader(fi) } else { r = fi } defer fi.Close() // Num of transaction store objects. var numItems uint32 if err := binary.Read(r, binary.LittleEndian, &numItems); err != nil { return nil, err } txStore := make(blockchain.TxStore) var uintBuf uint32 for height := uint32(0); height < numItems; height++ { txD := blockchain.TxData{} // Serialized transaction length. err = binary.Read(r, binary.LittleEndian, &uintBuf) if err != nil { return nil, err } serializedTxLen := uintBuf if serializedTxLen > wire.MaxBlockPayload { return nil, fmt.Errorf("Read serialized transaction "+ "length of %d is larger max allowed %d", serializedTxLen, wire.MaxBlockPayload) } // Transaction. var msgTx wire.MsgTx err = msgTx.Deserialize(r) if err != nil { return nil, err } txD.Tx = dcrutil.NewTx(&msgTx) // Transaction hash. txHash := msgTx.TxSha() txD.Hash = &txHash // Block height the transaction came from. err = binary.Read(r, binary.LittleEndian, &uintBuf) if err != nil { return nil, err } txD.BlockHeight = int64(uintBuf) // Num spent bits. err = binary.Read(r, binary.LittleEndian, &uintBuf) if err != nil { return nil, err } numSpentBits := uintBuf numSpentBytes := numSpentBits / 8 if numSpentBits%8 != 0 { numSpentBytes++ } // Packed spent bytes. spentBytes := make([]byte, numSpentBytes) _, err = io.ReadFull(r, spentBytes) if err != nil { return nil, err } // Populate spent data based on spent bits. txD.Spent = make([]bool, numSpentBits) for byteNum, spentByte := range spentBytes { for bit := 0; bit < 8; bit++ { if uint32((byteNum*8)+bit) < numSpentBits { if spentByte&(1<<uint(bit)) != 0 { txD.Spent[(byteNum*8)+bit] = true } } } } txStore[*txD.Hash] = &txD } return txStore, nil }