Expose new SerializeSize API for transactions.
This commit adds a new function named SerializeSize to the public API for MsgTx, TxOut, and TxIn which can be used to determine how many bytes the serialized data would take without having to actually serialize it. The following benchmark shows the difference between using the new function to get the serialize size for a typical transaction and serializing into a temporary buffer and taking the length of it: Bufffer: BenchmarkTxSerializeSizeBuffer 200000 7050 ns/op New: BenchmarkTxSerializeSizeNew 100000000 18 ns/op This is part of the ongoing effort to optimize serialization as noted in conformal/btcd#27.
This commit is contained in:
parent
cbf648a02f
commit
26cb71d805
2 changed files with 60 additions and 0 deletions
23
common.go
23
common.go
|
@ -111,6 +111,29 @@ func writeVarInt(w io.Writer, pver uint32, val uint64) error {
|
|||
return writeElements(w, []byte{0xff}, uint64(val))
|
||||
}
|
||||
|
||||
// varIntSerializeSize returns the number of bytes it would take to serialize
|
||||
// val as a variable length integer.
|
||||
func varIntSerializeSize(val uint64) int {
|
||||
// The value is small enough to be represented by itself, so it's
|
||||
// just 1 byte.
|
||||
if val < 0xfd {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Discriminant 1 byte plus 2 bytes for the uint16.
|
||||
if val <= math.MaxUint16 {
|
||||
return 3
|
||||
}
|
||||
|
||||
// Discriminant 1 byte plus 4 bytes for the uint32.
|
||||
if val <= math.MaxUint32 {
|
||||
return 5
|
||||
}
|
||||
|
||||
// Discriminant 1 byte plus 8 bytes for the uint64.
|
||||
return 9
|
||||
}
|
||||
|
||||
// readVarString reads a variable length string from r and returns it as a Go
|
||||
// string. A varString is encoded as a varInt containing the length of the
|
||||
// string, and the bytes that represent the string itself. An error is returned
|
||||
|
|
37
msgtx.go
37
msgtx.go
|
@ -75,6 +75,16 @@ type TxIn struct {
|
|||
Sequence uint32
|
||||
}
|
||||
|
||||
// SerializeSize returns the number of bytes it would take to serialize the
|
||||
// the transaction input.
|
||||
func (t *TxIn) SerializeSize() int {
|
||||
// Outpoint Hash 32 bytes + Outpoint Index 4 bytes + Sequence 4 bytes +
|
||||
// serialized varint size for the length of SignatureScript +
|
||||
// SignatureScript bytes.
|
||||
return 40 + varIntSerializeSize(uint64(len(t.SignatureScript))) +
|
||||
len(t.SignatureScript)
|
||||
}
|
||||
|
||||
// NewTxIn returns a new bitcoin transaction input with the provided
|
||||
// previous outpoint point and signature script with a default sequence of
|
||||
// MaxTxInSequenceNum.
|
||||
|
@ -92,6 +102,14 @@ type TxOut struct {
|
|||
PkScript []byte
|
||||
}
|
||||
|
||||
// SerializeSize returns the number of bytes it would take to serialize the
|
||||
// the transaction output.
|
||||
func (t *TxOut) SerializeSize() int {
|
||||
// Value 8 bytes + serialized varint size for the length of PkScript +
|
||||
// PkScript bytes.
|
||||
return 8 + varIntSerializeSize(uint64(len(t.PkScript))) + len(t.PkScript)
|
||||
}
|
||||
|
||||
// NewTxOut returns a new bitcoin transaction output with the provided
|
||||
// transaction value and public key script.
|
||||
func NewTxOut(value int64, pkScript []byte) *TxOut {
|
||||
|
@ -352,6 +370,25 @@ func (msg *MsgTx) Serialize(w io.Writer) error {
|
|||
|
||||
}
|
||||
|
||||
// SerializeSize returns the number of bytes it would take to serialize the
|
||||
// the transaction.
|
||||
func (msg *MsgTx) SerializeSize() int {
|
||||
// Version 4 bytes + LockTime 4 bytes + Serialized varint size for the
|
||||
// number of transaction inputs and outputs.
|
||||
n := 8 + varIntSerializeSize(uint64(len(msg.TxIn))) +
|
||||
varIntSerializeSize(uint64(len(msg.TxOut)))
|
||||
|
||||
for _, txIn := range msg.TxIn {
|
||||
n += txIn.SerializeSize()
|
||||
}
|
||||
|
||||
for _, txOut := range msg.TxOut {
|
||||
n += txOut.SerializeSize()
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
// of the Message interface implementation.
|
||||
func (msg *MsgTx) Command() string {
|
||||
|
|
Loading…
Reference in a new issue