mirror of
https://github.com/FlipsideCrypto/dcrd.git
synced 2026-02-06 10:56:47 +00:00
223 lines
6.0 KiB
Go
223 lines
6.0 KiB
Go
// Copyright (c) 2013-2016 The btcsuite developers
|
|
// Copyright (c) 2015-2017 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package dcrutil
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/decred/dcrd/chaincfg/chainhash"
|
|
"github.com/decred/dcrd/wire"
|
|
)
|
|
|
|
// assertTransactionImmutability throws a panic when a transaction has been
|
|
// mutated.
|
|
var assertTransactionImmutability = false
|
|
|
|
// TxIndexUnknown is the value returned for a transaction index that is unknown.
|
|
// This is typically because the transaction has not been inserted into a block
|
|
// yet.
|
|
const TxIndexUnknown = -1
|
|
|
|
// Tx defines a transaction that provides easier and more efficient manipulation
|
|
// of raw transactions. It also memoizes the hash for the transaction on its
|
|
// first access so subsequent accesses don't have to repeat the relatively
|
|
// expensive hashing operations.
|
|
type Tx struct {
|
|
hash chainhash.Hash // Cached transaction hash
|
|
msgTx *wire.MsgTx // Underlying MsgTx
|
|
txTree int8 // Indicates which tx tree the tx is found in
|
|
txIndex int // Position within a block or TxIndexUnknown
|
|
}
|
|
|
|
// MsgTx returns the underlying wire.MsgTx for the transaction.
|
|
func (t *Tx) MsgTx() *wire.MsgTx {
|
|
// Return the cached transaction.
|
|
return t.msgTx
|
|
}
|
|
|
|
// Hash returns the hash of the transaction. This is equivalent to
|
|
// calling TxHash on the underlying wire.MsgTx, however it caches the
|
|
// result so subsequent calls are more efficient.
|
|
func (t *Tx) Hash() *chainhash.Hash {
|
|
if assertTransactionImmutability {
|
|
hash := t.msgTx.TxHash()
|
|
if !hash.IsEqual(&t.hash) {
|
|
str := fmt.Sprintf("ASSERT: mutated util.tx detected, old hash %v, "+
|
|
"new hash %v",
|
|
t.hash,
|
|
hash)
|
|
panic(str)
|
|
}
|
|
}
|
|
return &t.hash
|
|
}
|
|
|
|
// Index returns the saved index of the transaction within a block. This value
|
|
// will be TxIndexUnknown if it hasn't already explicitly been set.
|
|
func (t *Tx) Index() int {
|
|
return t.txIndex
|
|
}
|
|
|
|
// SetIndex sets the index of the transaction in within a block.
|
|
func (t *Tx) SetIndex(index int) {
|
|
t.txIndex = index
|
|
}
|
|
|
|
// Tree returns the saved tree of the transaction within a block. This value
|
|
// will be TxTreeUnknown if it hasn't already explicitly been set.
|
|
func (t *Tx) Tree() int8 {
|
|
return t.txTree
|
|
}
|
|
|
|
// SetTree sets the tree of the transaction in within a block.
|
|
func (t *Tx) SetTree(tree int8) {
|
|
t.txTree = tree
|
|
}
|
|
|
|
// 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,
|
|
}
|
|
}
|
|
|
|
// NewTxDeep returns a new instance of a transaction given an underlying
|
|
// wire.MsgTx. Until NewTx, it completely copies the data in the msgTx
|
|
// so that there are new memory allocations, in case you were to somewhere
|
|
// else modify the data assigned to these pointers.
|
|
func NewTxDeep(msgTx *wire.MsgTx) *Tx {
|
|
txIns := make([]*wire.TxIn, len(msgTx.TxIn))
|
|
txOuts := make([]*wire.TxOut, len(msgTx.TxOut))
|
|
|
|
for i, txin := range msgTx.TxIn {
|
|
sigScript := make([]byte, len(txin.SignatureScript))
|
|
copy(sigScript[:], txin.SignatureScript[:])
|
|
|
|
txIns[i] = &wire.TxIn{
|
|
PreviousOutPoint: wire.OutPoint{
|
|
Hash: txin.PreviousOutPoint.Hash,
|
|
Index: txin.PreviousOutPoint.Index,
|
|
Tree: txin.PreviousOutPoint.Tree,
|
|
},
|
|
Sequence: txin.Sequence,
|
|
ValueIn: txin.ValueIn,
|
|
BlockHeight: txin.BlockHeight,
|
|
BlockIndex: txin.BlockIndex,
|
|
SignatureScript: sigScript,
|
|
}
|
|
}
|
|
|
|
for i, txout := range msgTx.TxOut {
|
|
pkScript := make([]byte, len(txout.PkScript))
|
|
copy(pkScript[:], txout.PkScript[:])
|
|
|
|
txOuts[i] = &wire.TxOut{
|
|
Value: txout.Value,
|
|
Version: txout.Version,
|
|
PkScript: pkScript,
|
|
}
|
|
}
|
|
|
|
mtx := &wire.MsgTx{
|
|
CachedHash: nil,
|
|
SerType: msgTx.SerType,
|
|
Version: msgTx.Version,
|
|
TxIn: txIns,
|
|
TxOut: txOuts,
|
|
LockTime: msgTx.LockTime,
|
|
Expiry: msgTx.Expiry,
|
|
}
|
|
|
|
return &Tx{
|
|
hash: mtx.TxHash(),
|
|
msgTx: mtx,
|
|
txTree: wire.TxTreeUnknown,
|
|
txIndex: TxIndexUnknown,
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
|
|
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,
|
|
}
|
|
}
|
|
|
|
// NewTxFromBytes returns a new instance of a transaction given the
|
|
// serialized bytes. See Tx.
|
|
func NewTxFromBytes(serializedTx []byte) (*Tx, error) {
|
|
br := bytes.NewReader(serializedTx)
|
|
return NewTxFromReader(br)
|
|
}
|
|
|
|
// 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
|
|
}
|