diff --git a/wire/msgtx.go b/wire/msgtx.go index 7705504cc8f..62ab2696828 100644 --- a/wire/msgtx.go +++ b/wire/msgtx.go @@ -6,6 +6,7 @@ package wire import ( "bytes" + "encoding/hex" "errors" "fmt" "io" @@ -366,6 +367,29 @@ func (msg *MsgTx) TxHash() chainhash.Hash { return chainhash.DoubleHashH(buf.Bytes()) } +// TxIdFromMsgTxHash generates the transaction ID (txid) of the transaction from +// the double hash of the transaction. +func TxIdFromMsgTxHash(txHash chainhash.Hash) string { + // Reverse the bytes of the hash. + revBytes := txHash + size := chainhash.HashSize + for i := 0; i < size/2; i++ { + revBytes[i], revBytes[size-1-i] = revBytes[size-1-i], revBytes[i] + } + + // Hex encode the reversed bytes. + return hex.EncodeToString(revBytes[:]) +} + +// TxID generates the transaction ID of the transaction. +func (msg *MsgTx) TxID() string { + // Encode the transaction and calculate the double sha256 hash of the + // result. + txHash := msg.TxHash() + + return TxIdFromMsgTxHash(txHash) +} + // WitnessHash generates the hash of the transaction serialized according to // the new witness serialization defined in BIP0141 and BIP0144. The final // output is used within the Segregated Witness commitment of all the witnesses diff --git a/wire/msgtx_test.go b/wire/msgtx_test.go index 5ec753b62d8..4dbc87cb957 100644 --- a/wire/msgtx_test.go +++ b/wire/msgtx_test.go @@ -756,6 +756,38 @@ func TestTxSerializeSizeStripped(t *testing.T) { } } +// TestTxID performs tests to ensure the serialize size for +// various transactions is accurate. +func TestTxID(t *testing.T) { + // Empty tx message. + noTx := NewMsgTx(1) + noTx.Version = 1 + + tests := []struct { + in *MsgTx // Tx to encode. + txid string // Expected transaction ID. + }{ + // No inputs or outputs. + {noTx, "d21633ba23f70118185227be58a63527675641ad37967e2aa461559f577aec43"}, + + // Transaction with an input and an output. + {multiTx, "0100d15a522ff38de05c164ca0a56379a1b77dd1e4805a6534dc9b3d88290e9d"}, + + // Transaction with an input which includes witness data, and + // one output. + {multiWitnessTx, "0f167d1385a84d1518cfee208b653fc9163b605ccf1b75347e2850b3e2eb19f3"}, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + txid := test.in.TxID() + if txid != test.txid { + t.Errorf("MsgTx.TxID: #%d got: %s, want: %s", i, txid, test.txid) + continue + } + } +} + // TestTxWitnessSize performs tests to ensure that the serialized size for // various types of transactions that include witness data is accurate. func TestTxWitnessSize(t *testing.T) {