wire: Add func to get pkscript locs from a tx.
This commit provides a new function named PkScriptLocs on the MsgTx type which can be used to efficiently retrieve a list of offsets for the public key scripts for the serialized form of the transaction. This is useful for certain applications which store fully serialized transactions and want to be able to quickly index into the serialized transaction to extract a give public key script directly thereby avoiding the need to deserialize the entire transaction.
This commit is contained in:
parent
def0ef6af6
commit
62432a6f90
3 changed files with 100 additions and 7 deletions
|
@ -108,8 +108,9 @@ func (msg *MsgBlock) Deserialize(r io.Reader) error {
|
|||
}
|
||||
|
||||
// DeserializeTxLoc decodes r in the same manner Deserialize does, but it takes
|
||||
// a byte buffer instead of a generic reader and returns a slice containing the start and length of
|
||||
// each transaction within the raw data that is being deserialized.
|
||||
// a byte buffer instead of a generic reader and returns a slice containing the
|
||||
// start and length of each transaction within the raw data that is being
|
||||
// deserialized.
|
||||
func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
|
||||
fullLen := r.Len()
|
||||
|
||||
|
|
|
@ -430,6 +430,43 @@ func (msg *MsgTx) MaxPayloadLength(pver uint32) uint32 {
|
|||
return MaxBlockPayload
|
||||
}
|
||||
|
||||
// PkScriptLocs returns a slice containing the start of each public key script
|
||||
// within the raw serialized transaction. The caller can easily obtain the
|
||||
// length of each script by using len on the script available via the
|
||||
// appropriate transaction output entry.
|
||||
func (msg *MsgTx) PkScriptLocs() []int {
|
||||
numTxOut := len(msg.TxOut)
|
||||
if numTxOut == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// The starting offset in the serialized transaction of the first
|
||||
// transaction output is:
|
||||
//
|
||||
// Version 4 bytes + serialized varint size for the number of
|
||||
// transaction inputs and outputs + serialized size of each transaction
|
||||
// input.
|
||||
n := 4 + VarIntSerializeSize(uint64(len(msg.TxIn))) +
|
||||
VarIntSerializeSize(uint64(numTxOut))
|
||||
for _, txIn := range msg.TxIn {
|
||||
n += txIn.SerializeSize()
|
||||
}
|
||||
|
||||
// Calculate and set the appropriate offset for each public key script.
|
||||
pkScriptLocs := make([]int, numTxOut)
|
||||
for i, txOut := range msg.TxOut {
|
||||
// The offset of the script in the transaction output is:
|
||||
//
|
||||
// Value 8 bytes + serialized varint size for the length of
|
||||
// PkScript.
|
||||
n += 8 + VarIntSerializeSize(uint64(len(txOut.PkScript)))
|
||||
pkScriptLocs[i] = n
|
||||
n += len(txOut.PkScript)
|
||||
}
|
||||
|
||||
return pkScriptLocs
|
||||
}
|
||||
|
||||
// NewMsgTx returns a new bitcoin tx message that conforms to the Message
|
||||
// interface. The return instance has a default version of TxVersion and there
|
||||
// are no transaction inputs or outputs. Also, the lock time is set to zero
|
||||
|
|
|
@ -392,12 +392,14 @@ func TestTxSerialize(t *testing.T) {
|
|||
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.
|
||||
|
@ -405,6 +407,7 @@ func TestTxSerialize(t *testing.T) {
|
|||
multiTx,
|
||||
multiTx,
|
||||
multiTxEncoded,
|
||||
multiTxPkScriptLocs,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -436,6 +439,25 @@ func TestTxSerialize(t *testing.T) {
|
|||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -611,7 +633,7 @@ func TestTxSerializeSize(t *testing.T) {
|
|||
{noTx, 10},
|
||||
|
||||
// Transcaction with an input and an output.
|
||||
{multiTx, 134},
|
||||
{multiTx, 210},
|
||||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
|
@ -657,6 +679,22 @@ var multiTx = &wire.MsgTx{
|
|||
0xac, // OP_CHECKSIG
|
||||
},
|
||||
},
|
||||
{
|
||||
Value: 0x5f5e100,
|
||||
PkScript: []byte{
|
||||
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
|
||||
},
|
||||
},
|
||||
},
|
||||
LockTime: 0,
|
||||
}
|
||||
|
@ -674,7 +712,7 @@ var multiTxEncoded = []byte{
|
|||
0x07, // Varint for length of signature script
|
||||
0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62, // Signature script
|
||||
0xff, 0xff, 0xff, 0xff, // Sequence
|
||||
0x01, // Varint for number of output transactions
|
||||
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
|
||||
|
@ -688,5 +726,22 @@ var multiTxEncoded = []byte{
|
|||
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
|
||||
}
|
||||
|
||||
// multiTxPkScriptLocs is the location information for the public key scripts
|
||||
// located in multiTx.
|
||||
var multiTxPkScriptLocs = []int{63, 139}
|
||||
|
|
Loading…
Reference in a new issue