mirror of
https://github.com/btcsuite/btcd.git
synced 2025-02-22 14:22:49 +01:00
Merge pull request #2073 from Roasbeef/wire-opts
wire: only borrow/return binaryFreeList buffers at the message level
This commit is contained in:
commit
16684f6cbc
26 changed files with 1289 additions and 370 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
"bytes"
|
||||
"compress/bzip2"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
|
@ -63,38 +64,48 @@ var genesisCoinbaseTx = MsgTx{
|
|||
// BenchmarkWriteVarInt1 performs a benchmark on how long it takes to write
|
||||
// a single byte variable length integer.
|
||||
func BenchmarkWriteVarInt1(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteVarInt(ioutil.Discard, 0, 1)
|
||||
WriteVarInt(io.Discard, 0, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkWriteVarInt3 performs a benchmark on how long it takes to write
|
||||
// a three byte variable length integer.
|
||||
func BenchmarkWriteVarInt3(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteVarInt(ioutil.Discard, 0, 65535)
|
||||
WriteVarInt(io.Discard, 0, 65535)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkWriteVarInt5 performs a benchmark on how long it takes to write
|
||||
// a five byte variable length integer.
|
||||
func BenchmarkWriteVarInt5(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteVarInt(ioutil.Discard, 0, 4294967295)
|
||||
WriteVarInt(io.Discard, 0, 4294967295)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkWriteVarInt9 performs a benchmark on how long it takes to write
|
||||
// a nine byte variable length integer.
|
||||
func BenchmarkWriteVarInt9(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteVarInt(ioutil.Discard, 0, 18446744073709551615)
|
||||
WriteVarInt(io.Discard, 0, 18446744073709551615)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkReadVarInt1 performs a benchmark on how long it takes to read
|
||||
// a single byte variable length integer.
|
||||
func BenchmarkReadVarInt1(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := []byte{0x01}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -106,6 +117,8 @@ func BenchmarkReadVarInt1(b *testing.B) {
|
|||
// BenchmarkReadVarInt3 performs a benchmark on how long it takes to read
|
||||
// a three byte variable length integer.
|
||||
func BenchmarkReadVarInt3(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := []byte{0x0fd, 0xff, 0xff}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -117,6 +130,8 @@ func BenchmarkReadVarInt3(b *testing.B) {
|
|||
// BenchmarkReadVarInt5 performs a benchmark on how long it takes to read
|
||||
// a five byte variable length integer.
|
||||
func BenchmarkReadVarInt5(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := []byte{0xfe, 0xff, 0xff, 0xff, 0xff}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -128,6 +143,8 @@ func BenchmarkReadVarInt5(b *testing.B) {
|
|||
// BenchmarkReadVarInt9 performs a benchmark on how long it takes to read
|
||||
// a nine byte variable length integer.
|
||||
func BenchmarkReadVarInt9(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -136,9 +153,119 @@ func BenchmarkReadVarInt9(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
// BenchmarkWriteVarIntBuf1 performs a benchmark on how long it takes to write
|
||||
// a single byte variable length integer.
|
||||
func BenchmarkWriteVarIntBuf1(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteVarIntBuf(io.Discard, 0, 1, buffer)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkWriteVarIntBuf3 performs a benchmark on how long it takes to write
|
||||
// a three byte variable length integer.
|
||||
func BenchmarkWriteVarIntBuf3(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteVarIntBuf(io.Discard, 0, 65535, buffer)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkWriteVarIntBuf5 performs a benchmark on how long it takes to write
|
||||
// a five byte variable length integer.
|
||||
func BenchmarkWriteVarIntBuf5(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteVarIntBuf(io.Discard, 0, 4294967295, buffer)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkWriteVarIntBuf9 performs a benchmark on how long it takes to write
|
||||
// a nine byte variable length integer.
|
||||
func BenchmarkWriteVarIntBuf9(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteVarIntBuf(io.Discard, 0, 18446744073709551615, buffer)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkReadVarIntBuf1 performs a benchmark on how long it takes to read
|
||||
// a single byte variable length integer.
|
||||
func BenchmarkReadVarIntBuf1(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
buf := []byte{0x01}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
ReadVarIntBuf(r, 0, buffer)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkReadVarIntBuf3 performs a benchmark on how long it takes to read
|
||||
// a three byte variable length integer.
|
||||
func BenchmarkReadVarIntBuf3(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
buf := []byte{0x0fd, 0xff, 0xff}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
ReadVarIntBuf(r, 0, buffer)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkReadVarIntBuf5 performs a benchmark on how long it takes to read
|
||||
// a five byte variable length integer.
|
||||
func BenchmarkReadVarIntBuf5(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
buf := []byte{0xfe, 0xff, 0xff, 0xff, 0xff}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
ReadVarIntBuf(r, 0, buffer)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkReadVarIntBuf9 performs a benchmark on how long it takes to read
|
||||
// a nine byte variable length integer.
|
||||
func BenchmarkReadVarIntBuf9(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
buf := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
ReadVarIntBuf(r, 0, buffer)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkReadVarStr4 performs a benchmark on how long it takes to read a
|
||||
// four byte variable length string.
|
||||
func BenchmarkReadVarStr4(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := []byte{0x04, 't', 'e', 's', 't'}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -150,6 +277,8 @@ func BenchmarkReadVarStr4(b *testing.B) {
|
|||
// BenchmarkReadVarStr10 performs a benchmark on how long it takes to read a
|
||||
// ten byte variable length string.
|
||||
func BenchmarkReadVarStr10(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := []byte{0x0a, 't', 'e', 's', 't', '0', '1', '2', '3', '4', '5'}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -161,22 +290,83 @@ func BenchmarkReadVarStr10(b *testing.B) {
|
|||
// BenchmarkWriteVarStr4 performs a benchmark on how long it takes to write a
|
||||
// four byte variable length string.
|
||||
func BenchmarkWriteVarStr4(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteVarString(ioutil.Discard, 0, "test")
|
||||
WriteVarString(io.Discard, 0, "test")
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkWriteVarStr10 performs a benchmark on how long it takes to write a
|
||||
// ten byte variable length string.
|
||||
func BenchmarkWriteVarStr10(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteVarString(ioutil.Discard, 0, "test012345")
|
||||
WriteVarString(io.Discard, 0, "test012345")
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkReadVarStrBuf4 performs a benchmark on how long it takes to read a
|
||||
// four byte variable length string.
|
||||
func BenchmarkReadVarStrBuf4(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
buf := []byte{0x04, 't', 'e', 's', 't'}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
readVarStringBuf(r, 0, buffer)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkReadVarStrBuf10 performs a benchmark on how long it takes to read a
|
||||
// ten byte variable length string.
|
||||
func BenchmarkReadVarStrBuf10(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
buf := []byte{0x0a, 't', 'e', 's', 't', '0', '1', '2', '3', '4', '5'}
|
||||
r := bytes.NewReader(buf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
readVarStringBuf(r, 0, buf)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkWriteVarStrBuf4 performs a benchmark on how long it takes to write a
|
||||
// four byte variable length string.
|
||||
func BenchmarkWriteVarStrBuf4(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := binarySerializer.Borrow()
|
||||
for i := 0; i < b.N; i++ {
|
||||
writeVarStringBuf(io.Discard, 0, "test", buf)
|
||||
}
|
||||
binarySerializer.Return(buf)
|
||||
}
|
||||
|
||||
// BenchmarkWriteVarStrBuf10 performs a benchmark on how long it takes to write
|
||||
// a ten byte variable length string.
|
||||
func BenchmarkWriteVarStrBuf10(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := binarySerializer.Borrow()
|
||||
for i := 0; i < b.N; i++ {
|
||||
writeVarStringBuf(io.Discard, 0, "test012345", buf)
|
||||
}
|
||||
binarySerializer.Return(buf)
|
||||
}
|
||||
|
||||
// BenchmarkReadOutPoint performs a benchmark on how long it takes to read a
|
||||
// transaction output point.
|
||||
func BenchmarkReadOutPoint(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
buf := []byte{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
@ -188,25 +378,46 @@ func BenchmarkReadOutPoint(b *testing.B) {
|
|||
var op OutPoint
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
readOutPoint(r, 0, 0, &op)
|
||||
readOutPointBuf(r, 0, 0, &op, buffer)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkWriteOutPoint performs a benchmark on how long it takes to write a
|
||||
// transaction output point.
|
||||
func BenchmarkWriteOutPoint(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
op := &OutPoint{
|
||||
Hash: chainhash.Hash{},
|
||||
Index: 0,
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteOutPoint(ioutil.Discard, 0, 0, op)
|
||||
WriteOutPoint(io.Discard, 0, 0, op)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkWriteOutPointBuf performs a benchmark on how long it takes to write a
|
||||
// transaction output point.
|
||||
func BenchmarkWriteOutPointBuf(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := binarySerializer.Borrow()
|
||||
op := &OutPoint{
|
||||
Hash: chainhash.Hash{},
|
||||
Index: 0,
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
writeOutPointBuf(io.Discard, 0, 0, op, buf)
|
||||
}
|
||||
binarySerializer.Return(buf)
|
||||
}
|
||||
|
||||
// BenchmarkReadTxOut performs a benchmark on how long it takes to read a
|
||||
// transaction output.
|
||||
func BenchmarkReadTxOut(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := []byte{
|
||||
0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount
|
||||
0x43, // Varint for length of pk script
|
||||
|
@ -227,22 +438,74 @@ func BenchmarkReadTxOut(b *testing.B) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
ReadTxOut(r, 0, 0, &txOut)
|
||||
scriptPool.Return(txOut.PkScript)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkReadTxOutBuf performs a benchmark on how long it takes to read a
|
||||
// transaction output.
|
||||
func BenchmarkReadTxOutBuf(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
scriptBuffer := scriptPool.Borrow()
|
||||
sbuf := scriptBuffer[:]
|
||||
buffer := binarySerializer.Borrow()
|
||||
buf := []byte{
|
||||
0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount
|
||||
0x43, // Varint for length of pk script
|
||||
0x41, // OP_DATA_65
|
||||
0x04, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c,
|
||||
0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16,
|
||||
0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c,
|
||||
0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c,
|
||||
0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4,
|
||||
0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6,
|
||||
0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e,
|
||||
0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58,
|
||||
0xee, // 65-byte signature
|
||||
0xac, // OP_CHECKSIG
|
||||
}
|
||||
r := bytes.NewReader(buf)
|
||||
var txOut TxOut
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
readTxOutBuf(r, 0, 0, &txOut, buffer, sbuf)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
scriptPool.Return(scriptBuffer)
|
||||
}
|
||||
|
||||
// BenchmarkWriteTxOut performs a benchmark on how long it takes to write
|
||||
// a transaction output.
|
||||
func BenchmarkWriteTxOut(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
txOut := blockOne.Transactions[0].TxOut[0]
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteTxOut(ioutil.Discard, 0, 0, txOut)
|
||||
WriteTxOut(io.Discard, 0, 0, txOut)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkWriteTxOutBuf performs a benchmark on how long it takes to write
|
||||
// a transaction output.
|
||||
func BenchmarkWriteTxOutBuf(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := binarySerializer.Borrow()
|
||||
txOut := blockOne.Transactions[0].TxOut[0]
|
||||
for i := 0; i < b.N; i++ {
|
||||
WriteTxOutBuf(io.Discard, 0, 0, txOut, buf)
|
||||
}
|
||||
binarySerializer.Return(buf)
|
||||
}
|
||||
|
||||
// BenchmarkReadTxIn performs a benchmark on how long it takes to read a
|
||||
// transaction input.
|
||||
func BenchmarkReadTxIn(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
scriptBuffer := scriptPool.Borrow()
|
||||
sbuf := scriptBuffer[:]
|
||||
buffer := binarySerializer.Borrow()
|
||||
buf := []byte{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
@ -257,18 +520,23 @@ func BenchmarkReadTxIn(b *testing.B) {
|
|||
var txIn TxIn
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
readTxIn(r, 0, 0, &txIn)
|
||||
scriptPool.Return(txIn.SignatureScript)
|
||||
readTxInBuf(r, 0, 0, &txIn, buffer, sbuf)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
scriptPool.Return(scriptBuffer)
|
||||
}
|
||||
|
||||
// BenchmarkWriteTxIn performs a benchmark on how long it takes to write
|
||||
// a transaction input.
|
||||
func BenchmarkWriteTxIn(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := binarySerializer.Borrow()
|
||||
txIn := blockOne.Transactions[0].TxIn[0]
|
||||
for i := 0; i < b.N; i++ {
|
||||
writeTxIn(ioutil.Discard, 0, 0, txIn)
|
||||
writeTxInBuf(io.Discard, 0, 0, txIn, buf)
|
||||
}
|
||||
binarySerializer.Return(buf)
|
||||
}
|
||||
|
||||
// BenchmarkDeserializeTx performs a benchmark on how long it takes to
|
||||
|
@ -302,6 +570,9 @@ func BenchmarkDeserializeTxSmall(b *testing.B) {
|
|||
0x00, 0x00, 0x00, 0x00, // Lock time
|
||||
}
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
r := bytes.NewReader(buf)
|
||||
var tx MsgTx
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -313,6 +584,7 @@ func BenchmarkDeserializeTxSmall(b *testing.B) {
|
|||
// BenchmarkDeserializeTxLarge performs a benchmark on how long it takes to
|
||||
// deserialize a very large transaction.
|
||||
func BenchmarkDeserializeTxLarge(b *testing.B) {
|
||||
|
||||
// tx bb41a757f405890fb0f5856228e23b715702d714d59bf2b1feb70d8b2b4e3e08
|
||||
// from the main block chain.
|
||||
fi, err := os.Open("testdata/megatx.bin.bz2")
|
||||
|
@ -325,6 +597,9 @@ func BenchmarkDeserializeTxLarge(b *testing.B) {
|
|||
b.Fatalf("Failed to read transaction data: %v", err)
|
||||
}
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
r := bytes.NewReader(buf)
|
||||
var tx MsgTx
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -333,19 +608,132 @@ func BenchmarkDeserializeTxLarge(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkDeserializeBlock(b *testing.B) {
|
||||
buf, err := os.ReadFile(
|
||||
"testdata/block-00000000000000000021868c2cefc52a480d173c849412fe81c4e5ab806f94ab.blk",
|
||||
)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to read block data: %v", err)
|
||||
}
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
r := bytes.NewReader(buf)
|
||||
var block MsgBlock
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
block.Deserialize(r)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSerializeBlock(b *testing.B) {
|
||||
buf, err := os.ReadFile(
|
||||
"testdata/block-00000000000000000021868c2cefc52a480d173c849412fe81c4e5ab806f94ab.blk",
|
||||
)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to read block data: %v", err)
|
||||
}
|
||||
|
||||
var block MsgBlock
|
||||
err = block.Deserialize(bytes.NewReader(buf))
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
block.Serialize(io.Discard)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkSerializeTx performs a benchmark on how long it takes to serialize
|
||||
// a transaction.
|
||||
func BenchmarkSerializeTx(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
tx := blockOne.Transactions[0]
|
||||
for i := 0; i < b.N; i++ {
|
||||
tx.Serialize(ioutil.Discard)
|
||||
tx.Serialize(io.Discard)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkSerializeTxSmall performs a benchmark on how long it takes to
|
||||
// serialize a transaction.
|
||||
func BenchmarkSerializeTxSmall(b *testing.B) {
|
||||
buf := []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
|
||||
0x07, // Varint for length of signature script
|
||||
0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, // Signature script
|
||||
0xff, 0xff, 0xff, 0xff, // Sequence
|
||||
0x01, // 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, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c,
|
||||
0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16,
|
||||
0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c,
|
||||
0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c,
|
||||
0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4,
|
||||
0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6,
|
||||
0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e,
|
||||
0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58,
|
||||
0xee, // 65-byte signature
|
||||
0xac, // OP_CHECKSIG
|
||||
0x00, 0x00, 0x00, 0x00, // Lock time
|
||||
}
|
||||
|
||||
var tx MsgTx
|
||||
tx.Deserialize(bytes.NewReader(buf))
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
tx.Serialize(io.Discard)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkSerializeTxLarge performs a benchmark on how long it takes to
|
||||
// serialize a transaction.
|
||||
func BenchmarkSerializeTxLarge(b *testing.B) {
|
||||
// tx bb41a757f405890fb0f5856228e23b715702d714d59bf2b1feb70d8b2b4e3e08
|
||||
// from the main block chain.
|
||||
fi, err := os.Open("testdata/megatx.bin.bz2")
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to read transaction data: %v", err)
|
||||
}
|
||||
defer fi.Close()
|
||||
buf, err := ioutil.ReadAll(bzip2.NewReader(fi))
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to read transaction data: %v", err)
|
||||
}
|
||||
|
||||
var tx MsgTx
|
||||
tx.Deserialize(bytes.NewReader(buf))
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
tx.Serialize(io.Discard)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkReadBlockHeader performs a benchmark on how long it takes to
|
||||
// deserialize a block header.
|
||||
func BenchmarkReadBlockHeader(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := []byte{
|
||||
0x01, 0x00, 0x00, 0x00, // Version 1
|
||||
0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72,
|
||||
|
@ -369,18 +757,65 @@ func BenchmarkReadBlockHeader(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
// BenchmarkReadBlockHeaderBuf performs a benchmark on how long it takes to
|
||||
// deserialize a block header.
|
||||
func BenchmarkReadBlockHeaderBuf(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buffer := binarySerializer.Borrow()
|
||||
buf := []byte{
|
||||
0x01, 0x00, 0x00, 0x00, // Version 1
|
||||
0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72,
|
||||
0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f,
|
||||
0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c,
|
||||
0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, // PrevBlock
|
||||
0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2,
|
||||
0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76, 0x8f, 0x61,
|
||||
0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32,
|
||||
0x3a, 0x9f, 0xb8, 0xaa, 0x4b, 0x1e, 0x5e, 0x4a, // MerkleRoot
|
||||
0x29, 0xab, 0x5f, 0x49, // Timestamp
|
||||
0xff, 0xff, 0x00, 0x1d, // Bits
|
||||
0xf3, 0xe0, 0x01, 0x00, // Nonce
|
||||
0x00, // TxnCount Varint
|
||||
}
|
||||
r := bytes.NewReader(buf)
|
||||
var header BlockHeader
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, 0)
|
||||
readBlockHeaderBuf(r, 0, &header, buffer)
|
||||
}
|
||||
binarySerializer.Return(buffer)
|
||||
}
|
||||
|
||||
// BenchmarkWriteBlockHeader performs a benchmark on how long it takes to
|
||||
// serialize a block header.
|
||||
func BenchmarkWriteBlockHeader(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
header := blockOne.Header
|
||||
for i := 0; i < b.N; i++ {
|
||||
writeBlockHeader(ioutil.Discard, 0, &header)
|
||||
writeBlockHeader(io.Discard, 0, &header)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkWriteBlockHeaderBuf performs a benchmark on how long it takes to
|
||||
// serialize a block header.
|
||||
func BenchmarkWriteBlockHeaderBuf(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
buf := binarySerializer.Borrow()
|
||||
header := blockOne.Header
|
||||
for i := 0; i < b.N; i++ {
|
||||
writeBlockHeaderBuf(io.Discard, 0, &header, buf)
|
||||
}
|
||||
binarySerializer.Return(buf)
|
||||
}
|
||||
|
||||
// BenchmarkDecodeGetHeaders performs a benchmark on how long it takes to
|
||||
// decode a getheaders message with the maximum number of block locator hashes.
|
||||
func BenchmarkDecodeGetHeaders(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
// Create a message with the maximum number of block locators.
|
||||
pver := ProtocolVersion
|
||||
var m MsgGetHeaders
|
||||
|
@ -411,6 +846,8 @@ func BenchmarkDecodeGetHeaders(b *testing.B) {
|
|||
// BenchmarkDecodeHeaders performs a benchmark on how long it takes to
|
||||
// decode a headers message with the maximum number of headers.
|
||||
func BenchmarkDecodeHeaders(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
// Create a message with the maximum number of headers.
|
||||
pver := ProtocolVersion
|
||||
var m MsgHeaders
|
||||
|
@ -441,6 +878,8 @@ func BenchmarkDecodeHeaders(b *testing.B) {
|
|||
// BenchmarkDecodeGetBlocks performs a benchmark on how long it takes to
|
||||
// decode a getblocks message with the maximum number of block locator hashes.
|
||||
func BenchmarkDecodeGetBlocks(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
// Create a message with the maximum number of block locators.
|
||||
pver := ProtocolVersion
|
||||
var m MsgGetBlocks
|
||||
|
@ -471,6 +910,8 @@ func BenchmarkDecodeGetBlocks(b *testing.B) {
|
|||
// BenchmarkDecodeAddr performs a benchmark on how long it takes to decode an
|
||||
// addr message with the maximum number of addresses.
|
||||
func BenchmarkDecodeAddr(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
// Create a message with the maximum number of addresses.
|
||||
pver := ProtocolVersion
|
||||
ip := net.ParseIP("127.0.0.1")
|
||||
|
@ -516,6 +957,9 @@ func BenchmarkDecodeInv(b *testing.B) {
|
|||
}
|
||||
buf := bb.Bytes()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
r := bytes.NewReader(buf)
|
||||
var msg MsgInv
|
||||
b.ResetTimer()
|
||||
|
@ -528,6 +972,8 @@ func BenchmarkDecodeInv(b *testing.B) {
|
|||
// BenchmarkDecodeNotFound performs a benchmark on how long it takes to decode
|
||||
// a notfound message with the maximum number of entries.
|
||||
func BenchmarkDecodeNotFound(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
// Create a message with the maximum number of entries.
|
||||
pver := ProtocolVersion
|
||||
var m MsgNotFound
|
||||
|
@ -558,6 +1004,8 @@ func BenchmarkDecodeNotFound(b *testing.B) {
|
|||
// BenchmarkDecodeMerkleBlock performs a benchmark on how long it takes to
|
||||
// decode a reasonably sized merkleblock message.
|
||||
func BenchmarkDecodeMerkleBlock(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
// Create a message with random data.
|
||||
pver := ProtocolVersion
|
||||
var m MsgMerkleBlock
|
||||
|
@ -596,6 +1044,8 @@ func BenchmarkDecodeMerkleBlock(b *testing.B) {
|
|||
// BenchmarkTxHash performs a benchmark on how long it takes to hash a
|
||||
// transaction.
|
||||
func BenchmarkTxHash(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
genesisCoinbaseTx.TxHash()
|
||||
}
|
||||
|
@ -604,6 +1054,8 @@ func BenchmarkTxHash(b *testing.B) {
|
|||
// BenchmarkDoubleHashB performs a benchmark on how long it takes to perform a
|
||||
// double hash returning a byte slice.
|
||||
func BenchmarkDoubleHashB(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := genesisCoinbaseTx.Serialize(&buf); err != nil {
|
||||
b.Errorf("Serialize: unexpected error: %v", err)
|
||||
|
@ -620,6 +1072,8 @@ func BenchmarkDoubleHashB(b *testing.B) {
|
|||
// BenchmarkDoubleHashH performs a benchmark on how long it takes to perform
|
||||
// a double hash returning a chainhash.Hash.
|
||||
func BenchmarkDoubleHashH(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := genesisCoinbaseTx.Serialize(&buf); err != nil {
|
||||
b.Errorf("Serialize: unexpected error: %v", err)
|
||||
|
|
|
@ -107,16 +107,109 @@ func NewBlockHeader(version int32, prevHash, merkleRootHash *chainhash.Hash,
|
|||
// readBlockHeader reads a bitcoin block header from r. See Deserialize for
|
||||
// decoding block headers stored to disk, such as in a database, as opposed to
|
||||
// decoding from the wire.
|
||||
//
|
||||
// DEPRECATED: Use readBlockHeaderBuf instead.
|
||||
func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error {
|
||||
return readElements(r, &bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
|
||||
(*uint32Time)(&bh.Timestamp), &bh.Bits, &bh.Nonce)
|
||||
buf := binarySerializer.Borrow()
|
||||
err := readBlockHeaderBuf(r, pver, bh, buf)
|
||||
binarySerializer.Return(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// readBlockHeaderBuf reads a bitcoin block header from r. See Deserialize for
|
||||
// decoding block headers stored to disk, such as in a database, as opposed to
|
||||
// decoding from the wire.
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func readBlockHeaderBuf(r io.Reader, pver uint32, bh *BlockHeader,
|
||||
buf []byte) error {
|
||||
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
bh.Version = int32(littleEndian.Uint32(buf[:4]))
|
||||
|
||||
if _, err := io.ReadFull(r, bh.PrevBlock[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(r, bh.MerkleRoot[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
bh.Timestamp = time.Unix(int64(littleEndian.Uint32(buf[:4])), 0)
|
||||
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
bh.Bits = littleEndian.Uint32(buf[:4])
|
||||
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
bh.Nonce = littleEndian.Uint32(buf[:4])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeBlockHeader writes a bitcoin block header to w. See Serialize for
|
||||
// encoding block headers to be stored to disk, such as in a database, as
|
||||
// opposed to encoding for the wire.
|
||||
//
|
||||
// DEPRECATED: Use writeBlockHeaderBuf instead.
|
||||
func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error {
|
||||
sec := uint32(bh.Timestamp.Unix())
|
||||
return writeElements(w, bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
|
||||
sec, bh.Bits, bh.Nonce)
|
||||
buf := binarySerializer.Borrow()
|
||||
err := writeBlockHeaderBuf(w, pver, bh, buf)
|
||||
binarySerializer.Return(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// writeBlockHeaderBuf writes a bitcoin block header to w. See Serialize for
|
||||
// encoding block headers to be stored to disk, such as in a database, as
|
||||
// opposed to encoding for the wire.
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func writeBlockHeaderBuf(w io.Writer, pver uint32, bh *BlockHeader,
|
||||
buf []byte) error {
|
||||
|
||||
littleEndian.PutUint32(buf[:4], uint32(bh.Version))
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := w.Write(bh.PrevBlock[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := w.Write(bh.MerkleRoot[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
littleEndian.PutUint32(buf[:4], uint32(bh.Timestamp.Unix()))
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
littleEndian.PutUint32(buf[:4], bh.Bits)
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
littleEndian.PutUint32(buf[:4], bh.Nonce)
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
211
wire/common.go
211
wire/common.go
|
@ -73,12 +73,13 @@ func (l binaryFreeList) Return(buf []byte) {
|
|||
// free list and returns it as a uint8.
|
||||
func (l binaryFreeList) Uint8(r io.Reader) (uint8, error) {
|
||||
buf := l.Borrow()[:1]
|
||||
defer l.Return(buf)
|
||||
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
l.Return(buf)
|
||||
return 0, err
|
||||
}
|
||||
rv := buf[0]
|
||||
l.Return(buf)
|
||||
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
|
@ -87,12 +88,13 @@ func (l binaryFreeList) Uint8(r io.Reader) (uint8, error) {
|
|||
// the resulting uint16.
|
||||
func (l binaryFreeList) Uint16(r io.Reader, byteOrder binary.ByteOrder) (uint16, error) {
|
||||
buf := l.Borrow()[:2]
|
||||
defer l.Return(buf)
|
||||
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
l.Return(buf)
|
||||
return 0, err
|
||||
}
|
||||
rv := byteOrder.Uint16(buf)
|
||||
l.Return(buf)
|
||||
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
|
@ -101,12 +103,13 @@ func (l binaryFreeList) Uint16(r io.Reader, byteOrder binary.ByteOrder) (uint16,
|
|||
// the resulting uint32.
|
||||
func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) {
|
||||
buf := l.Borrow()[:4]
|
||||
defer l.Return(buf)
|
||||
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
l.Return(buf)
|
||||
return 0, err
|
||||
}
|
||||
rv := byteOrder.Uint32(buf)
|
||||
l.Return(buf)
|
||||
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
|
@ -115,12 +118,13 @@ func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32,
|
|||
// the resulting uint64.
|
||||
func (l binaryFreeList) Uint64(r io.Reader, byteOrder binary.ByteOrder) (uint64, error) {
|
||||
buf := l.Borrow()[:8]
|
||||
defer l.Return(buf)
|
||||
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
l.Return(buf)
|
||||
return 0, err
|
||||
}
|
||||
rv := byteOrder.Uint64(buf)
|
||||
l.Return(buf)
|
||||
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
|
@ -128,9 +132,11 @@ func (l binaryFreeList) Uint64(r io.Reader, byteOrder binary.ByteOrder) (uint64,
|
|||
// writes the resulting byte to the given writer.
|
||||
func (l binaryFreeList) PutUint8(w io.Writer, val uint8) error {
|
||||
buf := l.Borrow()[:1]
|
||||
defer l.Return(buf)
|
||||
|
||||
buf[0] = val
|
||||
_, err := w.Write(buf)
|
||||
l.Return(buf)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -139,9 +145,11 @@ func (l binaryFreeList) PutUint8(w io.Writer, val uint8) error {
|
|||
// writer.
|
||||
func (l binaryFreeList) PutUint16(w io.Writer, byteOrder binary.ByteOrder, val uint16) error {
|
||||
buf := l.Borrow()[:2]
|
||||
defer l.Return(buf)
|
||||
|
||||
byteOrder.PutUint16(buf, val)
|
||||
_, err := w.Write(buf)
|
||||
l.Return(buf)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -150,9 +158,11 @@ func (l binaryFreeList) PutUint16(w io.Writer, byteOrder binary.ByteOrder, val u
|
|||
// writer.
|
||||
func (l binaryFreeList) PutUint32(w io.Writer, byteOrder binary.ByteOrder, val uint32) error {
|
||||
buf := l.Borrow()[:4]
|
||||
defer l.Return(buf)
|
||||
|
||||
byteOrder.PutUint32(buf, val)
|
||||
_, err := w.Write(buf)
|
||||
l.Return(buf)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -161,9 +171,11 @@ func (l binaryFreeList) PutUint32(w io.Writer, byteOrder binary.ByteOrder, val u
|
|||
// writer.
|
||||
func (l binaryFreeList) PutUint64(w io.Writer, byteOrder binary.ByteOrder, val uint64) error {
|
||||
buf := l.Borrow()[:8]
|
||||
defer l.Return(buf)
|
||||
|
||||
byteOrder.PutUint64(buf, val)
|
||||
_, err := w.Write(buf)
|
||||
l.Return(buf)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -474,19 +486,30 @@ func writeElements(w io.Writer, elements ...interface{}) error {
|
|||
|
||||
// ReadVarInt reads a variable length integer from r and returns it as a uint64.
|
||||
func ReadVarInt(r io.Reader, pver uint32) (uint64, error) {
|
||||
discriminant, err := binarySerializer.Uint8(r)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
n, err := ReadVarIntBuf(r, pver, buf)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// ReadVarIntBuf reads a variable length integer from r using a preallocated
|
||||
// scratch buffer and returns it as a uint64.
|
||||
//
|
||||
// NOTE: buf MUST at least an 8-byte slice.
|
||||
func ReadVarIntBuf(r io.Reader, pver uint32, buf []byte) (uint64, error) {
|
||||
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
discriminant := buf[0]
|
||||
|
||||
var rv uint64
|
||||
switch discriminant {
|
||||
case 0xff:
|
||||
sv, err := binarySerializer.Uint64(r, littleEndian)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
rv = sv
|
||||
rv = littleEndian.Uint64(buf)
|
||||
|
||||
// The encoding is not canonical if the value could have been
|
||||
// encoded using fewer bytes.
|
||||
|
@ -497,11 +520,10 @@ func ReadVarInt(r io.Reader, pver uint32) (uint64, error) {
|
|||
}
|
||||
|
||||
case 0xfe:
|
||||
sv, err := binarySerializer.Uint32(r, littleEndian)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
rv = uint64(sv)
|
||||
rv = uint64(littleEndian.Uint32(buf[:4]))
|
||||
|
||||
// The encoding is not canonical if the value could have been
|
||||
// encoded using fewer bytes.
|
||||
|
@ -512,11 +534,10 @@ func ReadVarInt(r io.Reader, pver uint32) (uint64, error) {
|
|||
}
|
||||
|
||||
case 0xfd:
|
||||
sv, err := binarySerializer.Uint16(r, littleEndian)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf[:2]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
rv = uint64(sv)
|
||||
rv = uint64(littleEndian.Uint16(buf[:2]))
|
||||
|
||||
// The encoding is not canonical if the value could have been
|
||||
// encoded using fewer bytes.
|
||||
|
@ -536,31 +557,46 @@ func ReadVarInt(r io.Reader, pver uint32) (uint64, error) {
|
|||
// WriteVarInt serializes val to w using a variable number of bytes depending
|
||||
// on its value.
|
||||
func WriteVarInt(w io.Writer, pver uint32, val uint64) error {
|
||||
if val < 0xfd {
|
||||
return binarySerializer.PutUint8(w, uint8(val))
|
||||
}
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
if val <= math.MaxUint16 {
|
||||
err := binarySerializer.PutUint8(w, 0xfd)
|
||||
if err != nil {
|
||||
err := WriteVarIntBuf(w, pver, val, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteVarIntBuf serializes val to w using a variable number of bytes depending
|
||||
// on its value using a preallocated scratch buffer.
|
||||
//
|
||||
// NOTE: buf MUST at least an 8-byte slice.
|
||||
func WriteVarIntBuf(w io.Writer, pver uint32, val uint64, buf []byte) error {
|
||||
switch {
|
||||
case val < 0xfd:
|
||||
buf[0] = uint8(val)
|
||||
_, err := w.Write(buf[:1])
|
||||
return err
|
||||
|
||||
case val <= math.MaxUint16:
|
||||
buf[0] = 0xfd
|
||||
littleEndian.PutUint16(buf[1:3], uint16(val))
|
||||
_, err := w.Write(buf[:3])
|
||||
return err
|
||||
|
||||
case val <= math.MaxUint32:
|
||||
buf[0] = 0xfe
|
||||
littleEndian.PutUint32(buf[1:5], uint32(val))
|
||||
_, err := w.Write(buf[:5])
|
||||
return err
|
||||
|
||||
default:
|
||||
buf[0] = 0xff
|
||||
if _, err := w.Write(buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
return binarySerializer.PutUint16(w, littleEndian, uint16(val))
|
||||
}
|
||||
|
||||
if val <= math.MaxUint32 {
|
||||
err := binarySerializer.PutUint8(w, 0xfe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return binarySerializer.PutUint32(w, littleEndian, uint32(val))
|
||||
}
|
||||
|
||||
err := binarySerializer.PutUint8(w, 0xff)
|
||||
if err != nil {
|
||||
littleEndian.PutUint64(buf, val)
|
||||
_, err := w.Write(buf)
|
||||
return err
|
||||
}
|
||||
return binarySerializer.PutUint64(w, littleEndian, val)
|
||||
}
|
||||
|
||||
// VarIntSerializeSize returns the number of bytes it would take to serialize
|
||||
|
@ -593,7 +629,27 @@ func VarIntSerializeSize(val uint64) int {
|
|||
// maximum block payload size since it helps protect against memory exhaustion
|
||||
// attacks and forced panics through malformed messages.
|
||||
func ReadVarString(r io.Reader, pver uint32) (string, error) {
|
||||
count, err := ReadVarInt(r, pver)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
str, err := readVarStringBuf(r, pver, buf)
|
||||
return str, err
|
||||
}
|
||||
|
||||
// readVarStringBuf reads a variable length string from r and returns it as a Go
|
||||
// string. A variable length string is encoded as a variable length integer
|
||||
// containing the length of the string followed by the bytes that represent the
|
||||
// string itself. An error is returned if the length is greater than the
|
||||
// maximum block payload size since it helps protect against memory exhaustion
|
||||
// attacks and forced panics through malformed messages.
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func readVarStringBuf(r io.Reader, pver uint32, buf []byte) (string, error) {
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -607,22 +663,40 @@ func ReadVarString(r io.Reader, pver uint32) (string, error) {
|
|||
return "", messageError("ReadVarString", str)
|
||||
}
|
||||
|
||||
buf := make([]byte, count)
|
||||
_, err = io.ReadFull(r, buf)
|
||||
str := make([]byte, count)
|
||||
_, err = io.ReadFull(r, str)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(buf), nil
|
||||
return string(str), nil
|
||||
}
|
||||
|
||||
// WriteVarString serializes str to w as a variable length integer containing
|
||||
// the length of the string followed by the bytes that represent the string
|
||||
// itself.
|
||||
func WriteVarString(w io.Writer, pver uint32, str string) error {
|
||||
err := WriteVarInt(w, pver, uint64(len(str)))
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := writeVarStringBuf(w, pver, str, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// writeVarStringBuf serializes str to w as a variable length integer containing
|
||||
// the length of the string followed by the bytes that represent the string
|
||||
// itself.
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func writeVarStringBuf(w io.Writer, pver uint32, str string, buf []byte) error {
|
||||
err := WriteVarIntBuf(w, pver, uint64(len(str)), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = w.Write([]byte(str))
|
||||
return err
|
||||
}
|
||||
|
@ -637,7 +711,26 @@ func WriteVarString(w io.Writer, pver uint32, str string) error {
|
|||
func ReadVarBytes(r io.Reader, pver uint32, maxAllowed uint32,
|
||||
fieldName string) ([]byte, error) {
|
||||
|
||||
count, err := ReadVarInt(r, pver)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
b, err := ReadVarBytesBuf(r, pver, buf, maxAllowed, fieldName)
|
||||
return b, err
|
||||
}
|
||||
|
||||
// ReadVarBytesBuf reads a variable length byte array. A byte array is encoded
|
||||
// as a varInt containing the length of the array followed by the bytes
|
||||
// themselves. An error is returned if the length is greater than the
|
||||
// passed maxAllowed parameter which helps protect against memory exhaustion
|
||||
// attacks and forced panics through malformed messages. The fieldName
|
||||
// parameter is only used for the error message so it provides more context in
|
||||
// the error. If b is non-nil, the provided buffer will be used for serializing
|
||||
// small values. Otherwise a buffer will be drawn from the binarySerializer's
|
||||
// pool and return when the method finishes.
|
||||
func ReadVarBytesBuf(r io.Reader, pver uint32, buf []byte, maxAllowed uint32,
|
||||
fieldName string) ([]byte, error) {
|
||||
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -651,19 +744,33 @@ func ReadVarBytes(r io.Reader, pver uint32, maxAllowed uint32,
|
|||
return nil, messageError("ReadVarBytes", str)
|
||||
}
|
||||
|
||||
b := make([]byte, count)
|
||||
_, err = io.ReadFull(r, b)
|
||||
bytes := make([]byte, count)
|
||||
_, err = io.ReadFull(r, bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
// WriteVarBytes serializes a variable length byte array to w as a varInt
|
||||
// containing the number of bytes, followed by the bytes themselves.
|
||||
func WriteVarBytes(w io.Writer, pver uint32, bytes []byte) error {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := WriteVarBytesBuf(w, pver, bytes, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteVarBytesBuf serializes a variable length byte array to w as a varInt
|
||||
// containing the number of bytes, followed by the bytes themselves. If b is
|
||||
// non-nil, the provided buffer will be used for serializing small values.
|
||||
// Otherwise a buffer will be drawn from the binarySerializer's pool and return
|
||||
// when the method finishes.
|
||||
func WriteVarBytesBuf(w io.Writer, pver uint32, bytes, buf []byte) error {
|
||||
slen := uint64(len(bytes))
|
||||
err := WriteVarInt(w, pver, slen)
|
||||
|
||||
err := WriteVarIntBuf(w, pver, slen, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -74,13 +74,37 @@ func NewInvVect(typ InvType, hash *chainhash.Hash) *InvVect {
|
|||
}
|
||||
}
|
||||
|
||||
// readInvVect reads an encoded InvVect from r depending on the protocol
|
||||
// readInvVectBuf reads an encoded InvVect from r depending on the protocol
|
||||
// version.
|
||||
func readInvVect(r io.Reader, pver uint32, iv *InvVect) error {
|
||||
return readElements(r, &iv.Type, &iv.Hash)
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func readInvVectBuf(r io.Reader, pver uint32, iv *InvVect, buf []byte) error {
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
iv.Type = InvType(littleEndian.Uint32(buf[:4]))
|
||||
|
||||
_, err := io.ReadFull(r, iv.Hash[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// writeInvVect serializes an InvVect to w depending on the protocol version.
|
||||
func writeInvVect(w io.Writer, pver uint32, iv *InvVect) error {
|
||||
return writeElements(w, iv.Type, &iv.Hash)
|
||||
// writeInvVectBuf serializes an InvVect to w depending on the protocol version.
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func writeInvVectBuf(w io.Writer, pver uint32, iv *InvVect, buf []byte) error {
|
||||
littleEndian.PutUint32(buf[:4], uint32(iv.Type))
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := w.Write(iv.Hash[:])
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -238,10 +238,11 @@ func TestInvVectWire(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Logf("Running %d tests", len(tests))
|
||||
var b [8]byte
|
||||
for i, test := range tests {
|
||||
// Encode to wire format.
|
||||
var buf bytes.Buffer
|
||||
err := writeInvVect(&buf, test.pver, &test.in)
|
||||
err := writeInvVectBuf(&buf, test.pver, &test.in, b[:])
|
||||
if err != nil {
|
||||
t.Errorf("writeInvVect #%d error %v", i, err)
|
||||
continue
|
||||
|
@ -255,7 +256,7 @@ func TestInvVectWire(t *testing.T) {
|
|||
// Decode the message from wire format.
|
||||
var iv InvVect
|
||||
rbuf := bytes.NewReader(test.buf)
|
||||
err = readInvVect(rbuf, test.pver, &iv)
|
||||
err = readInvVectBuf(rbuf, test.pver, &iv, b[:])
|
||||
if err != nil {
|
||||
t.Errorf("readInvVect #%d error %v", i, err)
|
||||
continue
|
||||
|
|
|
@ -62,12 +62,15 @@ func (msg *MsgBlock) ClearTransactions() {
|
|||
// See Deserialize for decoding blocks stored to disk, such as in a database, as
|
||||
// opposed to decoding blocks from the wire.
|
||||
func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
||||
err := readBlockHeader(r, pver, &msg.Header)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := readBlockHeaderBuf(r, pver, &msg.Header, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txCount, err := ReadVarInt(r, pver)
|
||||
txCount, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -81,10 +84,13 @@ func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) er
|
|||
return messageError("MsgBlock.BtcDecode", str)
|
||||
}
|
||||
|
||||
scriptBuf := scriptPool.Borrow()
|
||||
defer scriptPool.Return(scriptBuf)
|
||||
|
||||
msg.Transactions = make([]*MsgTx, 0, txCount)
|
||||
for i := uint64(0); i < txCount; i++ {
|
||||
tx := MsgTx{}
|
||||
err := tx.BtcDecode(r, pver, enc)
|
||||
err := tx.btcDecode(r, pver, enc, buf, scriptBuf[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -129,15 +135,18 @@ func (msg *MsgBlock) DeserializeNoWitness(r io.Reader) error {
|
|||
func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
|
||||
fullLen := r.Len()
|
||||
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
// At the current time, there is no difference between the wire encoding
|
||||
// at protocol version 0 and the stable long-term storage format. As
|
||||
// a result, make use of existing wire protocol functions.
|
||||
err := readBlockHeader(r, 0, &msg.Header)
|
||||
err := readBlockHeaderBuf(r, 0, &msg.Header, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txCount, err := ReadVarInt(r, 0)
|
||||
txCount, err := ReadVarIntBuf(r, 0, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -151,6 +160,9 @@ func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
|
|||
return nil, messageError("MsgBlock.DeserializeTxLoc", str)
|
||||
}
|
||||
|
||||
scriptBuf := scriptPool.Borrow()
|
||||
defer scriptPool.Return(scriptBuf)
|
||||
|
||||
// Deserialize each transaction while keeping track of its location
|
||||
// within the byte stream.
|
||||
msg.Transactions = make([]*MsgTx, 0, txCount)
|
||||
|
@ -158,7 +170,7 @@ func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
|
|||
for i := uint64(0); i < txCount; i++ {
|
||||
txLocs[i].TxStart = fullLen - r.Len()
|
||||
tx := MsgTx{}
|
||||
err := tx.Deserialize(r)
|
||||
err := tx.btcDecode(r, 0, WitnessEncoding, buf, scriptBuf[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -174,18 +186,21 @@ func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
|
|||
// See Serialize for encoding blocks to be stored to disk, such as in a
|
||||
// database, as opposed to encoding blocks for the wire.
|
||||
func (msg *MsgBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
|
||||
err := writeBlockHeader(w, pver, &msg.Header)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := writeBlockHeaderBuf(w, pver, &msg.Header, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = WriteVarInt(w, pver, uint64(len(msg.Transactions)))
|
||||
err = WriteVarIntBuf(w, pver, uint64(len(msg.Transactions)), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, tx := range msg.Transactions {
|
||||
err = tx.BtcEncode(w, pver, enc)
|
||||
err = tx.btcEncode(w, pver, enc, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -52,20 +52,22 @@ func (msg *MsgCFCheckpt) AddCFHeader(header *chainhash.Hash) error {
|
|||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
// Read filter type
|
||||
err := readElement(r, &msg.FilterType)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.FilterType = FilterType(buf[0])
|
||||
|
||||
// Read stop hash
|
||||
err = readElement(r, &msg.StopHash)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, msg.StopHash[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read number of filter headers
|
||||
count, err := ReadVarInt(r, pver)
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -80,7 +82,7 @@ func (msg *MsgCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding)
|
|||
msg.FilterHeaders = make([]*chainhash.Hash, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
var cfh chainhash.Hash
|
||||
err := readElement(r, &cfh)
|
||||
_, err := io.ReadFull(r, cfh[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -93,27 +95,29 @@ func (msg *MsgCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding)
|
|||
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgCFCheckpt) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
// Write filter type
|
||||
err := writeElement(w, msg.FilterType)
|
||||
if err != nil {
|
||||
buf[0] = byte(msg.FilterType)
|
||||
if _, err := w.Write(buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write stop hash
|
||||
err = writeElement(w, msg.StopHash)
|
||||
if err != nil {
|
||||
if _, err := w.Write(msg.StopHash[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write length of FilterHeaders slice
|
||||
count := len(msg.FilterHeaders)
|
||||
err = WriteVarInt(w, pver, uint64(count))
|
||||
err := WriteVarIntBuf(w, pver, uint64(count), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, cfh := range msg.FilterHeaders {
|
||||
err := writeElement(w, cfh)
|
||||
_, err := w.Write(cfh[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -48,26 +48,27 @@ func (msg *MsgCFHeaders) AddCFHash(hash *chainhash.Hash) error {
|
|||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
// Read filter type
|
||||
err := readElement(r, &msg.FilterType)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.FilterType = FilterType(buf[0])
|
||||
|
||||
// Read stop hash
|
||||
err = readElement(r, &msg.StopHash)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, msg.StopHash[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read prev filter header
|
||||
err = readElement(r, &msg.PrevFilterHeader)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, msg.PrevFilterHeader[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read number of filter headers
|
||||
count, err := ReadVarInt(r, pver)
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -85,7 +86,7 @@ func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding)
|
|||
msg.FilterHashes = make([]*chainhash.Hash, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
var cfh chainhash.Hash
|
||||
err := readElement(r, &cfh)
|
||||
_, err := io.ReadFull(r, cfh[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -98,25 +99,6 @@ func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding)
|
|||
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
||||
// Write filter type
|
||||
err := writeElement(w, msg.FilterType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write stop hash
|
||||
err = writeElement(w, msg.StopHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write prev filter header
|
||||
err = writeElement(w, msg.PrevFilterHeader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Limit to max committed headers per message.
|
||||
count := len(msg.FilterHashes)
|
||||
if count > MaxCFHeadersPerMsg {
|
||||
str := fmt.Sprintf("too many committed filter headers for "+
|
||||
|
@ -125,13 +107,32 @@ func (msg *MsgCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding)
|
|||
return messageError("MsgCFHeaders.BtcEncode", str)
|
||||
}
|
||||
|
||||
err = WriteVarInt(w, pver, uint64(count))
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
// Write filter type
|
||||
buf[0] = byte(msg.FilterType)
|
||||
if _, err := w.Write(buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write stop hash
|
||||
if _, err := w.Write(msg.StopHash[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write prev filter header
|
||||
if _, err := w.Write(msg.PrevFilterHeader[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := WriteVarIntBuf(w, pver, uint64(count), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, cfh := range msg.FilterHashes {
|
||||
err := writeElement(w, cfh)
|
||||
_, err := w.Write(cfh[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -38,19 +38,22 @@ type MsgCFilter struct {
|
|||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgCFilter) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||
// Read filter type
|
||||
err := readElement(r, &msg.FilterType)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.FilterType = FilterType(buf[0])
|
||||
|
||||
// Read the hash of the filter's block
|
||||
err = readElement(r, &msg.BlockHash)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, msg.BlockHash[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read filter data
|
||||
msg.Data, err = ReadVarBytes(r, pver, MaxCFilterDataSize,
|
||||
var err error
|
||||
msg.Data, err = ReadVarBytesBuf(r, pver, buf, MaxCFilterDataSize,
|
||||
"cfilter data")
|
||||
return err
|
||||
}
|
||||
|
@ -65,17 +68,20 @@ func (msg *MsgCFilter) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) er
|
|||
return messageError("MsgCFilter.BtcEncode", str)
|
||||
}
|
||||
|
||||
err := writeElement(w, msg.FilterType)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
buf[0] = byte(msg.FilterType)
|
||||
if _, err := w.Write(buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writeElement(w, msg.BlockHash)
|
||||
if err != nil {
|
||||
if _, err := w.Write(msg.BlockHash[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return WriteVarBytes(w, pver, msg.Data)
|
||||
err := WriteVarBytesBuf(w, pver, msg.Data, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// Deserialize decodes a filter from r into the receiver using a format that is
|
||||
|
|
|
@ -51,16 +51,20 @@ func (msg *MsgGetBlocks) AddBlockLocatorHash(hash *chainhash.Hash) error {
|
|||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgGetBlocks) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
||||
err := readElement(r, &msg.ProtocolVersion)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.ProtocolVersion = littleEndian.Uint32(buf[:4])
|
||||
|
||||
// Read num block locator hashes and limit to max.
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read num block locator hashes and limit to max.
|
||||
count, err := ReadVarInt(r, pver)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > MaxBlockLocatorsPerMsg {
|
||||
str := fmt.Sprintf("too many block locator hashes for message "+
|
||||
"[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
|
||||
|
@ -73,14 +77,15 @@ func (msg *MsgGetBlocks) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding
|
|||
msg.BlockLocatorHashes = make([]*chainhash.Hash, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
hash := &locatorHashes[i]
|
||||
err := readElement(r, hash)
|
||||
_, err := io.ReadFull(r, hash[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg.AddBlockLocatorHash(hash)
|
||||
}
|
||||
|
||||
return readElement(r, &msg.HashStop)
|
||||
_, err = io.ReadFull(r, msg.HashStop[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||
|
@ -93,24 +98,28 @@ func (msg *MsgGetBlocks) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding
|
|||
return messageError("MsgGetBlocks.BtcEncode", str)
|
||||
}
|
||||
|
||||
err := writeElement(w, msg.ProtocolVersion)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
littleEndian.PutUint32(buf[:4], msg.ProtocolVersion)
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = WriteVarInt(w, pver, uint64(count))
|
||||
err := WriteVarIntBuf(w, pver, uint64(count), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, hash := range msg.BlockLocatorHashes {
|
||||
err = writeElement(w, hash)
|
||||
_, err := w.Write(hash[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return writeElement(w, &msg.HashStop)
|
||||
_, err = w.Write(msg.HashStop[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
|
|
|
@ -21,23 +21,31 @@ type MsgGetCFCheckpt struct {
|
|||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgGetCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||
err := readElement(r, &msg.FilterType)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.FilterType = FilterType(buf[0])
|
||||
|
||||
return readElement(r, &msg.StopHash)
|
||||
_, err := io.ReadFull(r, msg.StopHash[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgGetCFCheckpt) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
||||
err := writeElement(w, msg.FilterType)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
buf[0] = byte(msg.FilterType)
|
||||
if _, err := w.Write(buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeElement(w, &msg.StopHash)
|
||||
_, err := w.Write(msg.StopHash[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
|
|
|
@ -22,33 +22,41 @@ type MsgGetCFHeaders struct {
|
|||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgGetCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||
err := readElement(r, &msg.FilterType)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.FilterType = FilterType(buf[0])
|
||||
|
||||
err = readElement(r, &msg.StartHeight)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.StartHeight = littleEndian.Uint32(buf[:4])
|
||||
|
||||
return readElement(r, &msg.StopHash)
|
||||
_, err := io.ReadFull(r, msg.StopHash[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgGetCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
||||
err := writeElement(w, msg.FilterType)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
buf[0] = byte(msg.FilterType)
|
||||
if _, err := w.Write(buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writeElement(w, &msg.StartHeight)
|
||||
if err != nil {
|
||||
littleEndian.PutUint32(buf[:4], msg.StartHeight)
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeElement(w, &msg.StopHash)
|
||||
_, err := w.Write(msg.StopHash[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
|
|
|
@ -26,33 +26,41 @@ type MsgGetCFilters struct {
|
|||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgGetCFilters) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||
err := readElement(r, &msg.FilterType)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.FilterType = FilterType(buf[0])
|
||||
|
||||
err = readElement(r, &msg.StartHeight)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.StartHeight = littleEndian.Uint32(buf[:4])
|
||||
|
||||
return readElement(r, &msg.StopHash)
|
||||
_, err := io.ReadFull(r, msg.StopHash[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgGetCFilters) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
||||
err := writeElement(w, msg.FilterType)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
buf[0] = byte(msg.FilterType)
|
||||
if _, err := w.Write(buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writeElement(w, &msg.StartHeight)
|
||||
if err != nil {
|
||||
littleEndian.PutUint32(buf[:4], msg.StartHeight)
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return writeElement(w, &msg.StopHash)
|
||||
_, err := w.Write(msg.StopHash[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
|
|
|
@ -38,7 +38,10 @@ func (msg *MsgGetData) AddInvVect(iv *InvVect) error {
|
|||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgGetData) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
||||
count, err := ReadVarInt(r, pver)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -55,7 +58,7 @@ func (msg *MsgGetData) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding)
|
|||
msg.InvList = make([]*InvVect, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
iv := &invList[i]
|
||||
err := readInvVect(r, pver, iv)
|
||||
err := readInvVectBuf(r, pver, iv, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -75,13 +78,16 @@ func (msg *MsgGetData) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding)
|
|||
return messageError("MsgGetData.BtcEncode", str)
|
||||
}
|
||||
|
||||
err := WriteVarInt(w, pver, uint64(count))
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := WriteVarIntBuf(w, pver, uint64(count), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, iv := range msg.InvList {
|
||||
err := writeInvVect(w, pver, iv)
|
||||
err := writeInvVectBuf(w, pver, iv, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -48,16 +48,20 @@ func (msg *MsgGetHeaders) AddBlockLocatorHash(hash *chainhash.Hash) error {
|
|||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgGetHeaders) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
||||
err := readElement(r, &msg.ProtocolVersion)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.ProtocolVersion = littleEndian.Uint32(buf[:4])
|
||||
|
||||
// Read num block locator hashes and limit to max.
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read num block locator hashes and limit to max.
|
||||
count, err := ReadVarInt(r, pver)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > MaxBlockLocatorsPerMsg {
|
||||
str := fmt.Sprintf("too many block locator hashes for message "+
|
||||
"[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
|
||||
|
@ -70,14 +74,15 @@ func (msg *MsgGetHeaders) BtcDecode(r io.Reader, pver uint32, enc MessageEncodin
|
|||
msg.BlockLocatorHashes = make([]*chainhash.Hash, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
hash := &locatorHashes[i]
|
||||
err := readElement(r, hash)
|
||||
_, err := io.ReadFull(r, hash[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg.AddBlockLocatorHash(hash)
|
||||
}
|
||||
|
||||
return readElement(r, &msg.HashStop)
|
||||
_, err = io.ReadFull(r, msg.HashStop[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||
|
@ -91,24 +96,28 @@ func (msg *MsgGetHeaders) BtcEncode(w io.Writer, pver uint32, enc MessageEncodin
|
|||
return messageError("MsgGetHeaders.BtcEncode", str)
|
||||
}
|
||||
|
||||
err := writeElement(w, msg.ProtocolVersion)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
littleEndian.PutUint32(buf[:4], msg.ProtocolVersion)
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = WriteVarInt(w, pver, uint64(count))
|
||||
err := WriteVarIntBuf(w, pver, uint64(count), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, hash := range msg.BlockLocatorHashes {
|
||||
err := writeElement(w, hash)
|
||||
_, err := w.Write(hash[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return writeElement(w, &msg.HashStop)
|
||||
_, err = w.Write(msg.HashStop[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
|
|
|
@ -37,7 +37,10 @@ func (msg *MsgHeaders) AddBlockHeader(bh *BlockHeader) error {
|
|||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
||||
count, err := ReadVarInt(r, pver)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -55,12 +58,12 @@ func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding)
|
|||
msg.Headers = make([]*BlockHeader, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
bh := &headers[i]
|
||||
err := readBlockHeader(r, pver, bh)
|
||||
err := readBlockHeaderBuf(r, pver, bh, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txCount, err := ReadVarInt(r, pver)
|
||||
txCount, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -88,13 +91,16 @@ func (msg *MsgHeaders) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding)
|
|||
return messageError("MsgHeaders.BtcEncode", str)
|
||||
}
|
||||
|
||||
err := WriteVarInt(w, pver, uint64(count))
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := WriteVarIntBuf(w, pver, uint64(count), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, bh := range msg.Headers {
|
||||
err := writeBlockHeader(w, pver, bh)
|
||||
err := writeBlockHeaderBuf(w, pver, bh, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -103,7 +109,7 @@ func (msg *MsgHeaders) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding)
|
|||
// of transactions on header messages. This is really just an
|
||||
// artifact of the way the original implementation serializes
|
||||
// block headers, but it is required.
|
||||
err = WriteVarInt(w, pver, 0)
|
||||
err = WriteVarIntBuf(w, pver, 0, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -46,7 +46,10 @@ func (msg *MsgInv) AddInvVect(iv *InvVect) error {
|
|||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgInv) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
||||
count, err := ReadVarInt(r, pver)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -63,7 +66,7 @@ func (msg *MsgInv) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) erro
|
|||
msg.InvList = make([]*InvVect, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
iv := &invList[i]
|
||||
err := readInvVect(r, pver, iv)
|
||||
err := readInvVectBuf(r, pver, iv, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -83,13 +86,16 @@ func (msg *MsgInv) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) erro
|
|||
return messageError("MsgInv.BtcEncode", str)
|
||||
}
|
||||
|
||||
err := WriteVarInt(w, pver, uint64(count))
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := WriteVarIntBuf(w, pver, uint64(count), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, iv := range msg.InvList {
|
||||
err := writeInvVect(w, pver, iv)
|
||||
err := writeInvVectBuf(w, pver, iv, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -49,18 +49,21 @@ func (msg *MsgMerkleBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncodi
|
|||
return messageError("MsgMerkleBlock.BtcDecode", str)
|
||||
}
|
||||
|
||||
err := readBlockHeader(r, pver, &msg.Header)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := readBlockHeaderBuf(r, pver, &msg.Header, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = readElement(r, &msg.Transactions)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.Transactions = littleEndian.Uint32(buf[:4])
|
||||
|
||||
// Read num block locator hashes and limit to max.
|
||||
count, err := ReadVarInt(r, pver)
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -76,14 +79,14 @@ func (msg *MsgMerkleBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncodi
|
|||
msg.Hashes = make([]*chainhash.Hash, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
hash := &hashes[i]
|
||||
err := readElement(r, hash)
|
||||
_, err := io.ReadFull(r, hash[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg.AddTxHash(hash)
|
||||
}
|
||||
|
||||
msg.Flags, err = ReadVarBytes(r, pver, maxFlagsPerMerkleBlock,
|
||||
msg.Flags, err = ReadVarBytesBuf(r, pver, buf, maxFlagsPerMerkleBlock,
|
||||
"merkle block flags size")
|
||||
return err
|
||||
}
|
||||
|
@ -111,28 +114,32 @@ func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncodi
|
|||
return messageError("MsgMerkleBlock.BtcDecode", str)
|
||||
}
|
||||
|
||||
err := writeBlockHeader(w, pver, &msg.Header)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := writeBlockHeaderBuf(w, pver, &msg.Header, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writeElement(w, msg.Transactions)
|
||||
if err != nil {
|
||||
littleEndian.PutUint32(buf[:4], msg.Transactions)
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = WriteVarInt(w, pver, uint64(numHashes))
|
||||
err = WriteVarIntBuf(w, pver, uint64(numHashes), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, hash := range msg.Hashes {
|
||||
err = writeElement(w, hash)
|
||||
_, err := w.Write(hash[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return WriteVarBytes(w, pver, msg.Flags)
|
||||
err = WriteVarBytesBuf(w, pver, msg.Flags, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
|
|
|
@ -35,7 +35,10 @@ func (msg *MsgNotFound) AddInvVect(iv *InvVect) error {
|
|||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||
// This is part of the Message interface implementation.
|
||||
func (msg *MsgNotFound) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
||||
count, err := ReadVarInt(r, pver)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -52,7 +55,7 @@ func (msg *MsgNotFound) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding)
|
|||
msg.InvList = make([]*InvVect, 0, count)
|
||||
for i := uint64(0); i < count; i++ {
|
||||
iv := &invList[i]
|
||||
err := readInvVect(r, pver, iv)
|
||||
err := readInvVectBuf(r, pver, iv, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -72,13 +75,16 @@ func (msg *MsgNotFound) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding)
|
|||
return messageError("MsgNotFound.BtcEncode", str)
|
||||
}
|
||||
|
||||
err := WriteVarInt(w, pver, uint64(count))
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := WriteVarIntBuf(w, pver, uint64(count), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, iv := range msg.InvList {
|
||||
err := writeInvVect(w, pver, iv)
|
||||
err := writeInvVectBuf(w, pver, iv, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -32,10 +32,11 @@ func (msg *MsgPing) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) err
|
|||
// NOTE: > is not a mistake here. The BIP0031 was defined as AFTER
|
||||
// the version unlike most others.
|
||||
if pver > BIP0031Version {
|
||||
err := readElement(r, &msg.Nonce)
|
||||
nonce, err := binarySerializer.Uint64(r, littleEndian)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg.Nonce = nonce
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -48,7 +49,7 @@ func (msg *MsgPing) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) err
|
|||
// NOTE: > is not a mistake here. The BIP0031 was defined as AFTER
|
||||
// the version unlike most others.
|
||||
if pver > BIP0031Version {
|
||||
err := writeElement(w, msg.Nonce)
|
||||
err := binarySerializer.PutUint64(w, littleEndian, msg.Nonce)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -31,7 +31,13 @@ func (msg *MsgPong) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) err
|
|||
return messageError("MsgPong.BtcDecode", str)
|
||||
}
|
||||
|
||||
return readElement(r, &msg.Nonce)
|
||||
nonce, err := binarySerializer.Uint64(r, littleEndian)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg.Nonce = nonce
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||
|
@ -45,7 +51,7 @@ func (msg *MsgPong) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) err
|
|||
return messageError("MsgPong.BtcEncode", str)
|
||||
}
|
||||
|
||||
return writeElement(w, msg.Nonce)
|
||||
return binarySerializer.PutUint64(w, littleEndian, msg.Nonce)
|
||||
}
|
||||
|
||||
// Command returns the protocol command string for the message. This is part
|
||||
|
|
|
@ -81,21 +81,24 @@ func (msg *MsgReject) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) e
|
|||
}
|
||||
|
||||
// Command that was rejected.
|
||||
cmd, err := ReadVarString(r, pver)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
cmd, err := readVarStringBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg.Cmd = cmd
|
||||
|
||||
// Code indicating why the command was rejected.
|
||||
err = readElement(r, &msg.Code)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.Code = RejectCode(buf[0])
|
||||
|
||||
// Human readable string with specific details (over and above the
|
||||
// reject code above) about why the command was rejected.
|
||||
reason, err := ReadVarString(r, pver)
|
||||
reason, err := readVarStringBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -104,7 +107,7 @@ func (msg *MsgReject) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) e
|
|||
// CmdBlock and CmdTx messages have an additional hash field that
|
||||
// identifies the specific block or transaction.
|
||||
if msg.Cmd == CmdBlock || msg.Cmd == CmdTx {
|
||||
err := readElement(r, &msg.Hash)
|
||||
_, err := io.ReadFull(r, msg.Hash[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -123,20 +126,23 @@ func (msg *MsgReject) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) e
|
|||
}
|
||||
|
||||
// Command that was rejected.
|
||||
err := WriteVarString(w, pver, msg.Cmd)
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := writeVarStringBuf(w, pver, msg.Cmd, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Code indicating why the command was rejected.
|
||||
err = writeElement(w, msg.Code)
|
||||
if err != nil {
|
||||
buf[0] = byte(msg.Code)
|
||||
if _, err := w.Write(buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Human readable string with specific details (over and above the
|
||||
// reject code above) about why the command was rejected.
|
||||
err = WriteVarString(w, pver, msg.Reason)
|
||||
err = writeVarStringBuf(w, pver, msg.Reason, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -144,7 +150,7 @@ func (msg *MsgReject) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) e
|
|||
// CmdBlock and CmdTx messages have an additional hash field that
|
||||
// identifies the specific block or transaction.
|
||||
if msg.Cmd == CmdBlock || msg.Cmd == CmdTx {
|
||||
err := writeElement(w, &msg.Hash)
|
||||
_, err := w.Write(msg.Hash[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
314
wire/msgtx.go
314
wire/msgtx.go
|
@ -93,7 +93,7 @@ const (
|
|||
// scripts per transaction being simultaneously deserialized by 125
|
||||
// peers. Thus, the peak usage of the free list is 12,500 * 512 =
|
||||
// 6,400,000 bytes.
|
||||
freeListMaxItems = 12500
|
||||
freeListMaxItems = 125
|
||||
|
||||
// maxWitnessItemsPerInput is the maximum number of witness items to
|
||||
// be read for the witness data for a single TxIn. This number is
|
||||
|
@ -146,6 +146,10 @@ const (
|
|||
WitnessFlag TxFlag = 0x01
|
||||
)
|
||||
|
||||
const scriptSlabSize = 1 << 22
|
||||
|
||||
type scriptSlab [scriptSlabSize]byte
|
||||
|
||||
// scriptFreeList defines a free list of byte slices (up to the maximum number
|
||||
// defined by the freeListMaxItems constant) that have a cap according to the
|
||||
// freeListMaxScriptSize constant. It is used to provide temporary buffers for
|
||||
|
@ -154,7 +158,7 @@ const (
|
|||
//
|
||||
// The caller can obtain a buffer from the free list by calling the Borrow
|
||||
// function and should return it via the Return function when done using it.
|
||||
type scriptFreeList chan []byte
|
||||
type scriptFreeList chan *scriptSlab
|
||||
|
||||
// Borrow returns a byte slice from the free list with a length according the
|
||||
// provided size. A new buffer is allocated if there are any items available.
|
||||
|
@ -163,18 +167,14 @@ type scriptFreeList chan []byte
|
|||
// a new buffer of the appropriate size is allocated and returned. It is safe
|
||||
// to attempt to return said buffer via the Return function as it will be
|
||||
// ignored and allowed to go the garbage collector.
|
||||
func (c scriptFreeList) Borrow(size uint64) []byte {
|
||||
if size > freeListMaxScriptSize {
|
||||
return make([]byte, size)
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
func (c scriptFreeList) Borrow() *scriptSlab {
|
||||
var buf *scriptSlab
|
||||
select {
|
||||
case buf = <-c:
|
||||
default:
|
||||
buf = make([]byte, freeListMaxScriptSize)
|
||||
buf = new(scriptSlab)
|
||||
}
|
||||
return buf[:size]
|
||||
return buf
|
||||
}
|
||||
|
||||
// Return puts the provided byte slice back on the free list when it has a cap
|
||||
|
@ -182,13 +182,7 @@ func (c scriptFreeList) Borrow(size uint64) []byte {
|
|||
// the Borrow function. Any slices that are not of the appropriate size, such
|
||||
// as those whose size is greater than the largest allowed free list item size
|
||||
// are simply ignored so they can go to the garbage collector.
|
||||
func (c scriptFreeList) Return(buf []byte) {
|
||||
// Ignore any buffers returned that aren't the expected size for the
|
||||
// free list.
|
||||
if cap(buf) != freeListMaxScriptSize {
|
||||
return
|
||||
}
|
||||
|
||||
func (c scriptFreeList) Return(buf *scriptSlab) {
|
||||
// Return the buffer to the free list when it's not full. Otherwise let
|
||||
// it be garbage collected.
|
||||
select {
|
||||
|
@ -201,7 +195,7 @@ func (c scriptFreeList) Return(buf []byte) {
|
|||
// Create the concurrent safe free list to use for script deserialization. As
|
||||
// previously described, this free list is maintained to significantly reduce
|
||||
// the number of allocations.
|
||||
var scriptPool scriptFreeList = make(chan []byte, freeListMaxItems)
|
||||
var scriptPool = make(scriptFreeList, freeListMaxItems)
|
||||
|
||||
// OutPoint defines a bitcoin data type that is used to track previous
|
||||
// transaction outputs.
|
||||
|
@ -452,13 +446,25 @@ func (msg *MsgTx) Copy() *MsgTx {
|
|||
// See Deserialize for decoding transactions stored to disk, such as in a
|
||||
// database, as opposed to decoding transactions from the wire.
|
||||
func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
||||
version, err := binarySerializer.Uint32(r, littleEndian)
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
sbuf := scriptPool.Borrow()
|
||||
defer scriptPool.Return(sbuf)
|
||||
|
||||
err := msg.btcDecode(r, pver, enc, buf, sbuf[:])
|
||||
return err
|
||||
}
|
||||
|
||||
func (msg *MsgTx) btcDecode(r io.Reader, pver uint32, enc MessageEncoding,
|
||||
buf, sbuf []byte) error {
|
||||
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.Version = int32(version)
|
||||
msg.Version = int32(littleEndian.Uint32(buf[:4]))
|
||||
|
||||
count, err := ReadVarInt(r, pver)
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -482,7 +488,7 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
|||
|
||||
// With the Segregated Witness specific fields decoded, we can
|
||||
// now read in the actual txin count.
|
||||
count, err = ReadVarInt(r, pver)
|
||||
count, err = ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -498,35 +504,6 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
|||
return messageError("MsgTx.BtcDecode", str)
|
||||
}
|
||||
|
||||
// returnScriptBuffers is a closure that returns any script buffers that
|
||||
// were borrowed from the pool when there are any deserialization
|
||||
// errors. This is only valid to call before the final step which
|
||||
// replaces the scripts with the location in a contiguous buffer and
|
||||
// returns them.
|
||||
returnScriptBuffers := func() {
|
||||
for _, txIn := range msg.TxIn {
|
||||
if txIn == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if txIn.SignatureScript != nil {
|
||||
scriptPool.Return(txIn.SignatureScript)
|
||||
}
|
||||
|
||||
for _, witnessElem := range txIn.Witness {
|
||||
if witnessElem != nil {
|
||||
scriptPool.Return(witnessElem)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, txOut := range msg.TxOut {
|
||||
if txOut == nil || txOut.PkScript == nil {
|
||||
continue
|
||||
}
|
||||
scriptPool.Return(txOut.PkScript)
|
||||
}
|
||||
}
|
||||
|
||||
// Deserialize the inputs.
|
||||
var totalScriptSize uint64
|
||||
txIns := make([]TxIn, count)
|
||||
|
@ -536,17 +513,16 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
|||
// and needs to be returned to the pool on error.
|
||||
ti := &txIns[i]
|
||||
msg.TxIn[i] = ti
|
||||
err = readTxIn(r, pver, msg.Version, ti)
|
||||
err = readTxInBuf(r, pver, msg.Version, ti, buf, sbuf)
|
||||
if err != nil {
|
||||
returnScriptBuffers()
|
||||
return err
|
||||
}
|
||||
totalScriptSize += uint64(len(ti.SignatureScript))
|
||||
sbuf = sbuf[len(ti.SignatureScript):]
|
||||
}
|
||||
|
||||
count, err = ReadVarInt(r, pver)
|
||||
count, err = ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
returnScriptBuffers()
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -554,7 +530,6 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
|||
// message. It would be possible to cause memory exhaustion and panics
|
||||
// without a sane upper bound on this count.
|
||||
if count > uint64(maxTxOutPerMessage) {
|
||||
returnScriptBuffers()
|
||||
str := fmt.Sprintf("too many output transactions to fit into "+
|
||||
"max message size [count %d, max %d]", count,
|
||||
maxTxOutPerMessage)
|
||||
|
@ -569,12 +544,12 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
|||
// and needs to be returned to the pool on error.
|
||||
to := &txOuts[i]
|
||||
msg.TxOut[i] = to
|
||||
err = ReadTxOut(r, pver, msg.Version, to)
|
||||
err = readTxOutBuf(r, pver, msg.Version, to, buf, sbuf)
|
||||
if err != nil {
|
||||
returnScriptBuffers()
|
||||
return err
|
||||
}
|
||||
totalScriptSize += uint64(len(to.PkScript))
|
||||
sbuf = sbuf[len(to.PkScript):]
|
||||
}
|
||||
|
||||
// If the transaction's flag byte isn't 0x00 at this point, then one or
|
||||
|
@ -584,16 +559,14 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
|||
// For each input, the witness is encoded as a stack
|
||||
// with one or more items. Therefore, we first read a
|
||||
// varint which encodes the number of stack items.
|
||||
witCount, err := ReadVarInt(r, pver)
|
||||
witCount, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
returnScriptBuffers()
|
||||
return err
|
||||
}
|
||||
|
||||
// Prevent a possible memory exhaustion attack by
|
||||
// limiting the witCount value to a sane upper bound.
|
||||
if witCount > maxWitnessItemsPerInput {
|
||||
returnScriptBuffers()
|
||||
str := fmt.Sprintf("too many witness items to fit "+
|
||||
"into max message size [count %d, max %d]",
|
||||
witCount, maxWitnessItemsPerInput)
|
||||
|
@ -605,23 +578,23 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
|||
// item itself.
|
||||
txin.Witness = make([][]byte, witCount)
|
||||
for j := uint64(0); j < witCount; j++ {
|
||||
txin.Witness[j], err = readScript(
|
||||
r, pver, maxWitnessItemSize, "script witness item",
|
||||
txin.Witness[j], err = readScriptBuf(
|
||||
r, pver, buf, sbuf, maxWitnessItemSize,
|
||||
"script witness item",
|
||||
)
|
||||
if err != nil {
|
||||
returnScriptBuffers()
|
||||
return err
|
||||
}
|
||||
totalScriptSize += uint64(len(txin.Witness[j]))
|
||||
sbuf = sbuf[len(txin.Witness[j]):]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg.LockTime, err = binarySerializer.Uint32(r, littleEndian)
|
||||
if err != nil {
|
||||
returnScriptBuffers()
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.LockTime = littleEndian.Uint32(buf[:4])
|
||||
|
||||
// Create a single allocation to house all of the scripts and set each
|
||||
// input signature script and output public key script to the
|
||||
|
@ -652,9 +625,6 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
|||
msg.TxIn[i].SignatureScript = scripts[offset:end:end]
|
||||
offset += scriptSize
|
||||
|
||||
// Return the temporary script buffer to the pool.
|
||||
scriptPool.Return(signatureScript)
|
||||
|
||||
for j := 0; j < len(msg.TxIn[i].Witness); j++ {
|
||||
// Copy each item within the witness stack for this
|
||||
// input into the contiguous buffer at the appropriate
|
||||
|
@ -668,10 +638,6 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
|||
end := offset + witnessElemSize
|
||||
msg.TxIn[i].Witness[j] = scripts[offset:end:end]
|
||||
offset += witnessElemSize
|
||||
|
||||
// Return the temporary buffer used for the witness stack
|
||||
// item to the pool.
|
||||
scriptPool.Return(witnessElem)
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(msg.TxOut); i++ {
|
||||
|
@ -686,9 +652,6 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
|||
end := offset + scriptSize
|
||||
msg.TxOut[i].PkScript = scripts[offset:end:end]
|
||||
offset += scriptSize
|
||||
|
||||
// Return the temporary script buffer to the pool.
|
||||
scriptPool.Return(pkScript)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -724,8 +687,18 @@ func (msg *MsgTx) DeserializeNoWitness(r io.Reader) error {
|
|||
// See Serialize for encoding transactions to be stored to disk, such as in a
|
||||
// database, as opposed to encoding transactions for the wire.
|
||||
func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
|
||||
err := binarySerializer.PutUint32(w, littleEndian, uint32(msg.Version))
|
||||
if err != nil {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := msg.btcEncode(w, pver, enc, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
func (msg *MsgTx) btcEncode(w io.Writer, pver uint32, enc MessageEncoding,
|
||||
buf []byte) error {
|
||||
|
||||
littleEndian.PutUint32(buf[:4], uint32(msg.Version))
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -745,26 +718,26 @@ func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error
|
|||
}
|
||||
|
||||
count := uint64(len(msg.TxIn))
|
||||
err = WriteVarInt(w, pver, count)
|
||||
err := WriteVarIntBuf(w, pver, count, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, ti := range msg.TxIn {
|
||||
err = writeTxIn(w, pver, msg.Version, ti)
|
||||
err = writeTxInBuf(w, pver, msg.Version, ti, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
count = uint64(len(msg.TxOut))
|
||||
err = WriteVarInt(w, pver, count)
|
||||
err = WriteVarIntBuf(w, pver, count, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, to := range msg.TxOut {
|
||||
err = WriteTxOut(w, pver, msg.Version, to)
|
||||
err = WriteTxOutBuf(w, pver, msg.Version, to, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -775,14 +748,16 @@ func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error
|
|||
// within the transaction.
|
||||
if doWitness {
|
||||
for _, ti := range msg.TxIn {
|
||||
err = writeTxWitness(w, pver, msg.Version, ti.Witness)
|
||||
err = writeTxWitnessBuf(w, pver, msg.Version, ti.Witness, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return binarySerializer.PutUint32(w, littleEndian, msg.LockTime)
|
||||
littleEndian.PutUint32(buf[:4], msg.LockTime)
|
||||
_, err = w.Write(buf[:4])
|
||||
return err
|
||||
}
|
||||
|
||||
// HasWitness returns false if none of the inputs within the transaction
|
||||
|
@ -939,26 +914,58 @@ func NewMsgTx(version int32) *MsgTx {
|
|||
}
|
||||
}
|
||||
|
||||
// readOutPoint reads the next sequence of bytes from r as an OutPoint.
|
||||
func readOutPoint(r io.Reader, pver uint32, version int32, op *OutPoint) error {
|
||||
// readOutPointBuf reads the next sequence of bytes from r as an OutPoint.
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func readOutPointBuf(r io.Reader, pver uint32, version int32, op *OutPoint,
|
||||
buf []byte) error {
|
||||
|
||||
_, err := io.ReadFull(r, op.Hash[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op.Index, err = binarySerializer.Uint32(r, littleEndian)
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
op.Index = littleEndian.Uint32(buf[:4])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteOutPoint encodes op to the bitcoin protocol encoding for an OutPoint to
|
||||
// w.
|
||||
func WriteOutPoint(w io.Writer, pver uint32, version int32, op *OutPoint) error {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := writeOutPointBuf(w, pver, version, op, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteOutPoint encodes op to the bitcoin protocol encoding for an OutPoint
|
||||
// writeOutPointBuf encodes op to the bitcoin protocol encoding for an OutPoint
|
||||
// to w.
|
||||
func WriteOutPoint(w io.Writer, pver uint32, version int32, op *OutPoint) error {
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func writeOutPointBuf(w io.Writer, pver uint32, version int32, op *OutPoint,
|
||||
buf []byte) error {
|
||||
|
||||
_, err := w.Write(op.Hash[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return binarySerializer.PutUint32(w, littleEndian, op.Index)
|
||||
littleEndian.PutUint32(buf[:4], op.Index)
|
||||
_, err = w.Write(buf[:4])
|
||||
return err
|
||||
}
|
||||
|
||||
// readScript reads a variable length byte array that represents a transaction
|
||||
|
@ -968,8 +975,16 @@ func WriteOutPoint(w io.Writer, pver uint32, version int32, op *OutPoint) error
|
|||
// memory exhaustion attacks and forced panics through malformed messages. The
|
||||
// fieldName parameter is only used for the error message so it provides more
|
||||
// context in the error.
|
||||
func readScript(r io.Reader, pver uint32, maxAllowed uint32, fieldName string) ([]byte, error) {
|
||||
count, err := ReadVarInt(r, pver)
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func readScriptBuf(r io.Reader, pver uint32, buf, s []byte,
|
||||
maxAllowed uint32, fieldName string) ([]byte, error) {
|
||||
|
||||
count, err := ReadVarIntBuf(r, pver, buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -983,58 +998,96 @@ func readScript(r io.Reader, pver uint32, maxAllowed uint32, fieldName string) (
|
|||
return nil, messageError("readScript", str)
|
||||
}
|
||||
|
||||
b := scriptPool.Borrow(count)
|
||||
_, err = io.ReadFull(r, b)
|
||||
_, err = io.ReadFull(r, s[:count])
|
||||
if err != nil {
|
||||
scriptPool.Return(b)
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
return s[:count], nil
|
||||
}
|
||||
|
||||
// readTxIn reads the next sequence of bytes from r as a transaction input
|
||||
// readTxInBuf reads the next sequence of bytes from r as a transaction input
|
||||
// (TxIn).
|
||||
func readTxIn(r io.Reader, pver uint32, version int32, ti *TxIn) error {
|
||||
err := readOutPoint(r, pver, version, &ti.PreviousOutPoint)
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func readTxInBuf(r io.Reader, pver uint32, version int32, ti *TxIn,
|
||||
buf, s []byte) error {
|
||||
|
||||
err := readOutPointBuf(r, pver, version, &ti.PreviousOutPoint, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ti.SignatureScript, err = readScript(r, pver, MaxMessagePayload,
|
||||
ti.SignatureScript, err = readScriptBuf(r, pver, buf, s, MaxMessagePayload,
|
||||
"transaction input signature script")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return readElement(r, &ti.Sequence)
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ti.Sequence = littleEndian.Uint32(buf[:4])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeTxIn encodes ti to the bitcoin protocol encoding for a transaction
|
||||
// input (TxIn) to w.
|
||||
func writeTxIn(w io.Writer, pver uint32, version int32, ti *TxIn) error {
|
||||
err := WriteOutPoint(w, pver, version, &ti.PreviousOutPoint)
|
||||
// writeTxInBuf encodes ti to the bitcoin protocol encoding for a transaction
|
||||
// input (TxIn) to w. If b is non-nil, the provided buffer will be used for
|
||||
// serializing small values. Otherwise a buffer will be drawn from the
|
||||
// binarySerializer's pool and return when the method finishes.
|
||||
func writeTxInBuf(w io.Writer, pver uint32, version int32, ti *TxIn,
|
||||
buf []byte) error {
|
||||
|
||||
err := writeOutPointBuf(w, pver, version, &ti.PreviousOutPoint, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = WriteVarBytes(w, pver, ti.SignatureScript)
|
||||
err = WriteVarBytesBuf(w, pver, ti.SignatureScript, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return binarySerializer.PutUint32(w, littleEndian, ti.Sequence)
|
||||
littleEndian.PutUint32(buf[:4], ti.Sequence)
|
||||
_, err = w.Write(buf[:4])
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// ReadTxOut reads the next sequence of bytes from r as a transaction output
|
||||
// (TxOut).
|
||||
func ReadTxOut(r io.Reader, pver uint32, version int32, to *TxOut) error {
|
||||
err := readElement(r, &to.Value)
|
||||
var s scriptSlab
|
||||
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := readTxOutBuf(r, pver, version, to, buf, s[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// readTxOutBuf reads the next sequence of bytes from r as a transaction output
|
||||
// (TxOut). If b is non-nil, the provided buffer will be used for serializing
|
||||
// small values. Otherwise a buffer will be drawn from the binarySerializer's
|
||||
// pool and return when the method finishes.
|
||||
func readTxOutBuf(r io.Reader, pver uint32, version int32, to *TxOut,
|
||||
buf, s []byte) error {
|
||||
|
||||
_, err := io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
to.Value = int64(littleEndian.Uint64(buf))
|
||||
|
||||
to.PkScript, err = readScript(r, pver, MaxMessagePayload,
|
||||
"transaction output public key script")
|
||||
to.PkScript, err = readScriptBuf(
|
||||
r, pver, buf, s, MaxMessagePayload,
|
||||
"transaction output public key script",
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -1044,26 +1097,49 @@ func ReadTxOut(r io.Reader, pver uint32, version int32, to *TxOut) error {
|
|||
// NOTE: This function is exported in order to allow txscript to compute the
|
||||
// new sighashes for witness transactions (BIP0143).
|
||||
func WriteTxOut(w io.Writer, pver uint32, version int32, to *TxOut) error {
|
||||
err := binarySerializer.PutUint64(w, littleEndian, uint64(to.Value))
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := WriteTxOutBuf(w, pver, version, to, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteTxOutBuf encodes to into the bitcoin protocol encoding for a transaction
|
||||
// output (TxOut) to w. If b is non-nil, the provided buffer will be used for
|
||||
// serializing small values. Otherwise a buffer will be drawn from the
|
||||
// binarySerializer's pool and return when the method finishes.
|
||||
//
|
||||
// NOTE: This function is exported in order to allow txscript to compute the
|
||||
// new sighashes for witness transactions (BIP0143).
|
||||
func WriteTxOutBuf(w io.Writer, pver uint32, version int32, to *TxOut,
|
||||
buf []byte) error {
|
||||
|
||||
littleEndian.PutUint64(buf, uint64(to.Value))
|
||||
_, err := w.Write(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return WriteVarBytes(w, pver, to.PkScript)
|
||||
return WriteVarBytesBuf(w, pver, to.PkScript, buf)
|
||||
}
|
||||
|
||||
// writeTxWitness encodes the bitcoin protocol encoding for a transaction
|
||||
// input's witness into to w.
|
||||
func writeTxWitness(w io.Writer, pver uint32, version int32, wit [][]byte) error {
|
||||
err := WriteVarInt(w, pver, uint64(len(wit)))
|
||||
// writeTxWitnessBuf encodes the bitcoin protocol encoding for a transaction
|
||||
// input's witness into to w. If b is non-nil, the provided buffer will be used
|
||||
// for serializing small values. Otherwise a buffer will be drawn from the
|
||||
// binarySerializer's pool and return when the method finishes.
|
||||
func writeTxWitnessBuf(w io.Writer, pver uint32, version int32, wit [][]byte,
|
||||
buf []byte) error {
|
||||
|
||||
err := WriteVarIntBuf(w, pver, uint64(len(wit)), buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range wit {
|
||||
err = WriteVarBytes(w, pver, item)
|
||||
err = WriteVarBytesBuf(w, pver, item, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
package wire
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
@ -89,31 +88,60 @@ func NewNetAddress(addr *net.TCPAddr, services ServiceFlag) *NetAddress {
|
|||
// version and whether or not the timestamp is included per ts. Some messages
|
||||
// like version do not include the timestamp.
|
||||
func readNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error {
|
||||
var ip [16]byte
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
|
||||
err := readNetAddressBuf(r, pver, na, ts, buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// readNetAddressBuf reads an encoded NetAddress from r depending on the
|
||||
// protocol version and whether or not the timestamp is included per ts. Some
|
||||
// messages like version do not include the timestamp.
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func readNetAddressBuf(r io.Reader, pver uint32, na *NetAddress, ts bool,
|
||||
buf []byte) error {
|
||||
|
||||
var (
|
||||
timestamp time.Time
|
||||
services ServiceFlag
|
||||
ip [16]byte
|
||||
port uint16
|
||||
)
|
||||
|
||||
// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
|
||||
// stop working somewhere around 2106. Also timestamp wasn't added until
|
||||
// protocol version >= NetAddressTimeVersion
|
||||
if ts && pver >= NetAddressTimeVersion {
|
||||
err := readElement(r, (*uint32Time)(&na.Timestamp))
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
timestamp = time.Unix(int64(littleEndian.Uint32(buf[:4])), 0)
|
||||
}
|
||||
|
||||
err := readElements(r, &na.Services, &ip)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
services = ServiceFlag(littleEndian.Uint64(buf))
|
||||
|
||||
if _, err := io.ReadFull(r, ip[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sigh. Bitcoin protocol mixes little and big endian.
|
||||
port, err := binarySerializer.Uint16(r, bigEndian)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(r, buf[:2]); err != nil {
|
||||
return err
|
||||
}
|
||||
port = bigEndian.Uint16(buf[:2])
|
||||
|
||||
*na = NetAddress{
|
||||
Timestamp: na.Timestamp,
|
||||
Services: na.Services,
|
||||
Timestamp: timestamp,
|
||||
Services: services,
|
||||
IP: net.IP(ip[:]),
|
||||
Port: port,
|
||||
}
|
||||
|
@ -124,26 +152,50 @@ func readNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error {
|
|||
// version and whether or not the timestamp is included per ts. Some messages
|
||||
// like version do not include the timestamp.
|
||||
func writeNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) error {
|
||||
buf := binarySerializer.Borrow()
|
||||
defer binarySerializer.Return(buf)
|
||||
err := writeNetAddressBuf(w, pver, na, ts, buf)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// writeNetAddressBuf serializes a NetAddress to w depending on the protocol
|
||||
// version and whether or not the timestamp is included per ts. Some messages
|
||||
// like version do not include the timestamp.
|
||||
//
|
||||
// If b is non-nil, the provided buffer will be used for serializing small
|
||||
// values. Otherwise a buffer will be drawn from the binarySerializer's pool
|
||||
// and return when the method finishes.
|
||||
//
|
||||
// NOTE: b MUST either be nil or at least an 8-byte slice.
|
||||
func writeNetAddressBuf(w io.Writer, pver uint32, na *NetAddress, ts bool, buf []byte) error {
|
||||
// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
|
||||
// stop working somewhere around 2106. Also timestamp wasn't added until
|
||||
// until protocol version >= NetAddressTimeVersion.
|
||||
if ts && pver >= NetAddressTimeVersion {
|
||||
err := writeElement(w, uint32(na.Timestamp.Unix()))
|
||||
if err != nil {
|
||||
littleEndian.PutUint32(buf[:4], uint32(na.Timestamp.Unix()))
|
||||
if _, err := w.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
littleEndian.PutUint64(buf, uint64(na.Services))
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure to always write 16 bytes even if the ip is nil.
|
||||
var ip [16]byte
|
||||
if na.IP != nil {
|
||||
copy(ip[:], na.IP.To16())
|
||||
}
|
||||
err := writeElements(w, na.Services, ip)
|
||||
if err != nil {
|
||||
if _, err := w.Write(ip[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sigh. Bitcoin protocol mixes little and big endian.
|
||||
return binary.Write(w, bigEndian, na.Port)
|
||||
bigEndian.PutUint16(buf[:2], na.Port)
|
||||
_, err := w.Write(buf[:2])
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
BIN
wire/testdata/block-0000000000000000001602407ac49862a7bca9d00f7f402db20b7be2f5de59d2.blk
vendored
Normal file
BIN
wire/testdata/block-0000000000000000001602407ac49862a7bca9d00f7f402db20b7be2f5de59d2.blk
vendored
Normal file
Binary file not shown.
BIN
wire/testdata/block-00000000000000000021868c2cefc52a480d173c849412fe81c4e5ab806f94ab.blk
vendored
Normal file
BIN
wire/testdata/block-00000000000000000021868c2cefc52a480d173c849412fe81c4e5ab806f94ab.blk
vendored
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue