mirror of
https://github.com/btcsuite/btcd.git
synced 2025-02-22 22:25:45 +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"
|
"bytes"
|
||||||
"compress/bzip2"
|
"compress/bzip2"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
@ -63,38 +64,48 @@ var genesisCoinbaseTx = MsgTx{
|
||||||
// BenchmarkWriteVarInt1 performs a benchmark on how long it takes to write
|
// BenchmarkWriteVarInt1 performs a benchmark on how long it takes to write
|
||||||
// a single byte variable length integer.
|
// a single byte variable length integer.
|
||||||
func BenchmarkWriteVarInt1(b *testing.B) {
|
func BenchmarkWriteVarInt1(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkWriteVarInt3 performs a benchmark on how long it takes to write
|
||||||
// a three byte variable length integer.
|
// a three byte variable length integer.
|
||||||
func BenchmarkWriteVarInt3(b *testing.B) {
|
func BenchmarkWriteVarInt3(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkWriteVarInt5 performs a benchmark on how long it takes to write
|
||||||
// a five byte variable length integer.
|
// a five byte variable length integer.
|
||||||
func BenchmarkWriteVarInt5(b *testing.B) {
|
func BenchmarkWriteVarInt5(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkWriteVarInt9 performs a benchmark on how long it takes to write
|
||||||
// a nine byte variable length integer.
|
// a nine byte variable length integer.
|
||||||
func BenchmarkWriteVarInt9(b *testing.B) {
|
func BenchmarkWriteVarInt9(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkReadVarInt1 performs a benchmark on how long it takes to read
|
||||||
// a single byte variable length integer.
|
// a single byte variable length integer.
|
||||||
func BenchmarkReadVarInt1(b *testing.B) {
|
func BenchmarkReadVarInt1(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
buf := []byte{0x01}
|
buf := []byte{0x01}
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkReadVarInt3 performs a benchmark on how long it takes to read
|
||||||
// a three byte variable length integer.
|
// a three byte variable length integer.
|
||||||
func BenchmarkReadVarInt3(b *testing.B) {
|
func BenchmarkReadVarInt3(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
buf := []byte{0x0fd, 0xff, 0xff}
|
buf := []byte{0x0fd, 0xff, 0xff}
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkReadVarInt5 performs a benchmark on how long it takes to read
|
||||||
// a five byte variable length integer.
|
// a five byte variable length integer.
|
||||||
func BenchmarkReadVarInt5(b *testing.B) {
|
func BenchmarkReadVarInt5(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
buf := []byte{0xfe, 0xff, 0xff, 0xff, 0xff}
|
buf := []byte{0xfe, 0xff, 0xff, 0xff, 0xff}
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkReadVarInt9 performs a benchmark on how long it takes to read
|
||||||
// a nine byte variable length integer.
|
// a nine byte variable length integer.
|
||||||
func BenchmarkReadVarInt9(b *testing.B) {
|
func BenchmarkReadVarInt9(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
buf := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
buf := []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkReadVarStr4 performs a benchmark on how long it takes to read a
|
||||||
// four byte variable length string.
|
// four byte variable length string.
|
||||||
func BenchmarkReadVarStr4(b *testing.B) {
|
func BenchmarkReadVarStr4(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
buf := []byte{0x04, 't', 'e', 's', 't'}
|
buf := []byte{0x04, 't', 'e', 's', 't'}
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkReadVarStr10 performs a benchmark on how long it takes to read a
|
||||||
// ten byte variable length string.
|
// ten byte variable length string.
|
||||||
func BenchmarkReadVarStr10(b *testing.B) {
|
func BenchmarkReadVarStr10(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
buf := []byte{0x0a, 't', 'e', 's', 't', '0', '1', '2', '3', '4', '5'}
|
buf := []byte{0x0a, 't', 'e', 's', 't', '0', '1', '2', '3', '4', '5'}
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkWriteVarStr4 performs a benchmark on how long it takes to write a
|
||||||
// four byte variable length string.
|
// four byte variable length string.
|
||||||
func BenchmarkWriteVarStr4(b *testing.B) {
|
func BenchmarkWriteVarStr4(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkWriteVarStr10 performs a benchmark on how long it takes to write a
|
||||||
// ten byte variable length string.
|
// ten byte variable length string.
|
||||||
func BenchmarkWriteVarStr10(b *testing.B) {
|
func BenchmarkWriteVarStr10(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkReadOutPoint performs a benchmark on how long it takes to read a
|
||||||
// transaction output point.
|
// transaction output point.
|
||||||
func BenchmarkReadOutPoint(b *testing.B) {
|
func BenchmarkReadOutPoint(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
|
buffer := binarySerializer.Borrow()
|
||||||
buf := []byte{
|
buf := []byte{
|
||||||
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,
|
||||||
|
@ -188,25 +378,46 @@ func BenchmarkReadOutPoint(b *testing.B) {
|
||||||
var op OutPoint
|
var op OutPoint
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
r.Seek(0, 0)
|
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
|
// BenchmarkWriteOutPoint performs a benchmark on how long it takes to write a
|
||||||
// transaction output point.
|
// transaction output point.
|
||||||
func BenchmarkWriteOutPoint(b *testing.B) {
|
func BenchmarkWriteOutPoint(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
op := &OutPoint{
|
op := &OutPoint{
|
||||||
Hash: chainhash.Hash{},
|
Hash: chainhash.Hash{},
|
||||||
Index: 0,
|
Index: 0,
|
||||||
}
|
}
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkReadTxOut performs a benchmark on how long it takes to read a
|
||||||
// transaction output.
|
// transaction output.
|
||||||
func BenchmarkReadTxOut(b *testing.B) {
|
func BenchmarkReadTxOut(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
buf := []byte{
|
buf := []byte{
|
||||||
0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount
|
0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount
|
||||||
0x43, // Varint for length of pk script
|
0x43, // Varint for length of pk script
|
||||||
|
@ -227,22 +438,74 @@ func BenchmarkReadTxOut(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
r.Seek(0, 0)
|
r.Seek(0, 0)
|
||||||
ReadTxOut(r, 0, 0, &txOut)
|
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
|
// BenchmarkWriteTxOut performs a benchmark on how long it takes to write
|
||||||
// a transaction output.
|
// a transaction output.
|
||||||
func BenchmarkWriteTxOut(b *testing.B) {
|
func BenchmarkWriteTxOut(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
txOut := blockOne.Transactions[0].TxOut[0]
|
txOut := blockOne.Transactions[0].TxOut[0]
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkReadTxIn performs a benchmark on how long it takes to read a
|
||||||
// transaction input.
|
// transaction input.
|
||||||
func BenchmarkReadTxIn(b *testing.B) {
|
func BenchmarkReadTxIn(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
|
scriptBuffer := scriptPool.Borrow()
|
||||||
|
sbuf := scriptBuffer[:]
|
||||||
|
buffer := binarySerializer.Borrow()
|
||||||
buf := []byte{
|
buf := []byte{
|
||||||
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,
|
||||||
|
@ -257,18 +520,23 @@ func BenchmarkReadTxIn(b *testing.B) {
|
||||||
var txIn TxIn
|
var txIn TxIn
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
r.Seek(0, 0)
|
r.Seek(0, 0)
|
||||||
readTxIn(r, 0, 0, &txIn)
|
readTxInBuf(r, 0, 0, &txIn, buffer, sbuf)
|
||||||
scriptPool.Return(txIn.SignatureScript)
|
|
||||||
}
|
}
|
||||||
|
binarySerializer.Return(buffer)
|
||||||
|
scriptPool.Return(scriptBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BenchmarkWriteTxIn performs a benchmark on how long it takes to write
|
// BenchmarkWriteTxIn performs a benchmark on how long it takes to write
|
||||||
// a transaction input.
|
// a transaction input.
|
||||||
func BenchmarkWriteTxIn(b *testing.B) {
|
func BenchmarkWriteTxIn(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
|
buf := binarySerializer.Borrow()
|
||||||
txIn := blockOne.Transactions[0].TxIn[0]
|
txIn := blockOne.Transactions[0].TxIn[0]
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// 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
|
0x00, 0x00, 0x00, 0x00, // Lock time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
var tx MsgTx
|
var tx MsgTx
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkDeserializeTxLarge performs a benchmark on how long it takes to
|
||||||
// deserialize a very large transaction.
|
// deserialize a very large transaction.
|
||||||
func BenchmarkDeserializeTxLarge(b *testing.B) {
|
func BenchmarkDeserializeTxLarge(b *testing.B) {
|
||||||
|
|
||||||
// tx bb41a757f405890fb0f5856228e23b715702d714d59bf2b1feb70d8b2b4e3e08
|
// tx bb41a757f405890fb0f5856228e23b715702d714d59bf2b1feb70d8b2b4e3e08
|
||||||
// from the main block chain.
|
// from the main block chain.
|
||||||
fi, err := os.Open("testdata/megatx.bin.bz2")
|
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.Fatalf("Failed to read transaction data: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
var tx MsgTx
|
var tx MsgTx
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkSerializeTx performs a benchmark on how long it takes to serialize
|
||||||
// a transaction.
|
// a transaction.
|
||||||
func BenchmarkSerializeTx(b *testing.B) {
|
func BenchmarkSerializeTx(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
tx := blockOne.Transactions[0]
|
tx := blockOne.Transactions[0]
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkReadBlockHeader performs a benchmark on how long it takes to
|
||||||
// deserialize a block header.
|
// deserialize a block header.
|
||||||
func BenchmarkReadBlockHeader(b *testing.B) {
|
func BenchmarkReadBlockHeader(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
buf := []byte{
|
buf := []byte{
|
||||||
0x01, 0x00, 0x00, 0x00, // Version 1
|
0x01, 0x00, 0x00, 0x00, // Version 1
|
||||||
0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72,
|
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
|
// BenchmarkWriteBlockHeader performs a benchmark on how long it takes to
|
||||||
// serialize a block header.
|
// serialize a block header.
|
||||||
func BenchmarkWriteBlockHeader(b *testing.B) {
|
func BenchmarkWriteBlockHeader(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
header := blockOne.Header
|
header := blockOne.Header
|
||||||
for i := 0; i < b.N; i++ {
|
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
|
// BenchmarkDecodeGetHeaders performs a benchmark on how long it takes to
|
||||||
// decode a getheaders message with the maximum number of block locator hashes.
|
// decode a getheaders message with the maximum number of block locator hashes.
|
||||||
func BenchmarkDecodeGetHeaders(b *testing.B) {
|
func BenchmarkDecodeGetHeaders(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
// Create a message with the maximum number of block locators.
|
// Create a message with the maximum number of block locators.
|
||||||
pver := ProtocolVersion
|
pver := ProtocolVersion
|
||||||
var m MsgGetHeaders
|
var m MsgGetHeaders
|
||||||
|
@ -411,6 +846,8 @@ func BenchmarkDecodeGetHeaders(b *testing.B) {
|
||||||
// BenchmarkDecodeHeaders performs a benchmark on how long it takes to
|
// BenchmarkDecodeHeaders performs a benchmark on how long it takes to
|
||||||
// decode a headers message with the maximum number of headers.
|
// decode a headers message with the maximum number of headers.
|
||||||
func BenchmarkDecodeHeaders(b *testing.B) {
|
func BenchmarkDecodeHeaders(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
// Create a message with the maximum number of headers.
|
// Create a message with the maximum number of headers.
|
||||||
pver := ProtocolVersion
|
pver := ProtocolVersion
|
||||||
var m MsgHeaders
|
var m MsgHeaders
|
||||||
|
@ -441,6 +878,8 @@ func BenchmarkDecodeHeaders(b *testing.B) {
|
||||||
// BenchmarkDecodeGetBlocks performs a benchmark on how long it takes to
|
// BenchmarkDecodeGetBlocks performs a benchmark on how long it takes to
|
||||||
// decode a getblocks message with the maximum number of block locator hashes.
|
// decode a getblocks message with the maximum number of block locator hashes.
|
||||||
func BenchmarkDecodeGetBlocks(b *testing.B) {
|
func BenchmarkDecodeGetBlocks(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
// Create a message with the maximum number of block locators.
|
// Create a message with the maximum number of block locators.
|
||||||
pver := ProtocolVersion
|
pver := ProtocolVersion
|
||||||
var m MsgGetBlocks
|
var m MsgGetBlocks
|
||||||
|
@ -471,6 +910,8 @@ func BenchmarkDecodeGetBlocks(b *testing.B) {
|
||||||
// BenchmarkDecodeAddr performs a benchmark on how long it takes to decode an
|
// BenchmarkDecodeAddr performs a benchmark on how long it takes to decode an
|
||||||
// addr message with the maximum number of addresses.
|
// addr message with the maximum number of addresses.
|
||||||
func BenchmarkDecodeAddr(b *testing.B) {
|
func BenchmarkDecodeAddr(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
// Create a message with the maximum number of addresses.
|
// Create a message with the maximum number of addresses.
|
||||||
pver := ProtocolVersion
|
pver := ProtocolVersion
|
||||||
ip := net.ParseIP("127.0.0.1")
|
ip := net.ParseIP("127.0.0.1")
|
||||||
|
@ -516,6 +957,9 @@ func BenchmarkDecodeInv(b *testing.B) {
|
||||||
}
|
}
|
||||||
buf := bb.Bytes()
|
buf := bb.Bytes()
|
||||||
|
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
var msg MsgInv
|
var msg MsgInv
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
@ -528,6 +972,8 @@ func BenchmarkDecodeInv(b *testing.B) {
|
||||||
// BenchmarkDecodeNotFound performs a benchmark on how long it takes to decode
|
// BenchmarkDecodeNotFound performs a benchmark on how long it takes to decode
|
||||||
// a notfound message with the maximum number of entries.
|
// a notfound message with the maximum number of entries.
|
||||||
func BenchmarkDecodeNotFound(b *testing.B) {
|
func BenchmarkDecodeNotFound(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
// Create a message with the maximum number of entries.
|
// Create a message with the maximum number of entries.
|
||||||
pver := ProtocolVersion
|
pver := ProtocolVersion
|
||||||
var m MsgNotFound
|
var m MsgNotFound
|
||||||
|
@ -558,6 +1004,8 @@ func BenchmarkDecodeNotFound(b *testing.B) {
|
||||||
// BenchmarkDecodeMerkleBlock performs a benchmark on how long it takes to
|
// BenchmarkDecodeMerkleBlock performs a benchmark on how long it takes to
|
||||||
// decode a reasonably sized merkleblock message.
|
// decode a reasonably sized merkleblock message.
|
||||||
func BenchmarkDecodeMerkleBlock(b *testing.B) {
|
func BenchmarkDecodeMerkleBlock(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
// Create a message with random data.
|
// Create a message with random data.
|
||||||
pver := ProtocolVersion
|
pver := ProtocolVersion
|
||||||
var m MsgMerkleBlock
|
var m MsgMerkleBlock
|
||||||
|
@ -596,6 +1044,8 @@ func BenchmarkDecodeMerkleBlock(b *testing.B) {
|
||||||
// BenchmarkTxHash performs a benchmark on how long it takes to hash a
|
// BenchmarkTxHash performs a benchmark on how long it takes to hash a
|
||||||
// transaction.
|
// transaction.
|
||||||
func BenchmarkTxHash(b *testing.B) {
|
func BenchmarkTxHash(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
genesisCoinbaseTx.TxHash()
|
genesisCoinbaseTx.TxHash()
|
||||||
}
|
}
|
||||||
|
@ -604,6 +1054,8 @@ func BenchmarkTxHash(b *testing.B) {
|
||||||
// BenchmarkDoubleHashB performs a benchmark on how long it takes to perform a
|
// BenchmarkDoubleHashB performs a benchmark on how long it takes to perform a
|
||||||
// double hash returning a byte slice.
|
// double hash returning a byte slice.
|
||||||
func BenchmarkDoubleHashB(b *testing.B) {
|
func BenchmarkDoubleHashB(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := genesisCoinbaseTx.Serialize(&buf); err != nil {
|
if err := genesisCoinbaseTx.Serialize(&buf); err != nil {
|
||||||
b.Errorf("Serialize: unexpected error: %v", err)
|
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
|
// BenchmarkDoubleHashH performs a benchmark on how long it takes to perform
|
||||||
// a double hash returning a chainhash.Hash.
|
// a double hash returning a chainhash.Hash.
|
||||||
func BenchmarkDoubleHashH(b *testing.B) {
|
func BenchmarkDoubleHashH(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := genesisCoinbaseTx.Serialize(&buf); err != nil {
|
if err := genesisCoinbaseTx.Serialize(&buf); err != nil {
|
||||||
b.Errorf("Serialize: unexpected error: %v", err)
|
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
|
// 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 block headers stored to disk, such as in a database, as opposed to
|
||||||
// decoding from the wire.
|
// decoding from the wire.
|
||||||
|
//
|
||||||
|
// DEPRECATED: Use readBlockHeaderBuf instead.
|
||||||
func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error {
|
func readBlockHeader(r io.Reader, pver uint32, bh *BlockHeader) error {
|
||||||
return readElements(r, &bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
|
buf := binarySerializer.Borrow()
|
||||||
(*uint32Time)(&bh.Timestamp), &bh.Bits, &bh.Nonce)
|
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
|
// 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
|
// encoding block headers to be stored to disk, such as in a database, as
|
||||||
// opposed to encoding for the wire.
|
// opposed to encoding for the wire.
|
||||||
|
//
|
||||||
|
// DEPRECATED: Use writeBlockHeaderBuf instead.
|
||||||
func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error {
|
func writeBlockHeader(w io.Writer, pver uint32, bh *BlockHeader) error {
|
||||||
sec := uint32(bh.Timestamp.Unix())
|
buf := binarySerializer.Borrow()
|
||||||
return writeElements(w, bh.Version, &bh.PrevBlock, &bh.MerkleRoot,
|
err := writeBlockHeaderBuf(w, pver, bh, buf)
|
||||||
sec, bh.Bits, bh.Nonce)
|
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.
|
// free list and returns it as a uint8.
|
||||||
func (l binaryFreeList) Uint8(r io.Reader) (uint8, error) {
|
func (l binaryFreeList) Uint8(r io.Reader) (uint8, error) {
|
||||||
buf := l.Borrow()[:1]
|
buf := l.Borrow()[:1]
|
||||||
|
defer l.Return(buf)
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, buf); err != nil {
|
if _, err := io.ReadFull(r, buf); err != nil {
|
||||||
l.Return(buf)
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
rv := buf[0]
|
rv := buf[0]
|
||||||
l.Return(buf)
|
|
||||||
return rv, nil
|
return rv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,12 +88,13 @@ func (l binaryFreeList) Uint8(r io.Reader) (uint8, error) {
|
||||||
// the resulting uint16.
|
// the resulting uint16.
|
||||||
func (l binaryFreeList) Uint16(r io.Reader, byteOrder binary.ByteOrder) (uint16, error) {
|
func (l binaryFreeList) Uint16(r io.Reader, byteOrder binary.ByteOrder) (uint16, error) {
|
||||||
buf := l.Borrow()[:2]
|
buf := l.Borrow()[:2]
|
||||||
|
defer l.Return(buf)
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, buf); err != nil {
|
if _, err := io.ReadFull(r, buf); err != nil {
|
||||||
l.Return(buf)
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
rv := byteOrder.Uint16(buf)
|
rv := byteOrder.Uint16(buf)
|
||||||
l.Return(buf)
|
|
||||||
return rv, nil
|
return rv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,12 +103,13 @@ func (l binaryFreeList) Uint16(r io.Reader, byteOrder binary.ByteOrder) (uint16,
|
||||||
// the resulting uint32.
|
// the resulting uint32.
|
||||||
func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) {
|
func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32, error) {
|
||||||
buf := l.Borrow()[:4]
|
buf := l.Borrow()[:4]
|
||||||
|
defer l.Return(buf)
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, buf); err != nil {
|
if _, err := io.ReadFull(r, buf); err != nil {
|
||||||
l.Return(buf)
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
rv := byteOrder.Uint32(buf)
|
rv := byteOrder.Uint32(buf)
|
||||||
l.Return(buf)
|
|
||||||
return rv, nil
|
return rv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,12 +118,13 @@ func (l binaryFreeList) Uint32(r io.Reader, byteOrder binary.ByteOrder) (uint32,
|
||||||
// the resulting uint64.
|
// the resulting uint64.
|
||||||
func (l binaryFreeList) Uint64(r io.Reader, byteOrder binary.ByteOrder) (uint64, error) {
|
func (l binaryFreeList) Uint64(r io.Reader, byteOrder binary.ByteOrder) (uint64, error) {
|
||||||
buf := l.Borrow()[:8]
|
buf := l.Borrow()[:8]
|
||||||
|
defer l.Return(buf)
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, buf); err != nil {
|
if _, err := io.ReadFull(r, buf); err != nil {
|
||||||
l.Return(buf)
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
rv := byteOrder.Uint64(buf)
|
rv := byteOrder.Uint64(buf)
|
||||||
l.Return(buf)
|
|
||||||
return rv, nil
|
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.
|
// writes the resulting byte to the given writer.
|
||||||
func (l binaryFreeList) PutUint8(w io.Writer, val uint8) error {
|
func (l binaryFreeList) PutUint8(w io.Writer, val uint8) error {
|
||||||
buf := l.Borrow()[:1]
|
buf := l.Borrow()[:1]
|
||||||
|
defer l.Return(buf)
|
||||||
|
|
||||||
buf[0] = val
|
buf[0] = val
|
||||||
_, err := w.Write(buf)
|
_, err := w.Write(buf)
|
||||||
l.Return(buf)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,9 +145,11 @@ func (l binaryFreeList) PutUint8(w io.Writer, val uint8) error {
|
||||||
// writer.
|
// writer.
|
||||||
func (l binaryFreeList) PutUint16(w io.Writer, byteOrder binary.ByteOrder, val uint16) error {
|
func (l binaryFreeList) PutUint16(w io.Writer, byteOrder binary.ByteOrder, val uint16) error {
|
||||||
buf := l.Borrow()[:2]
|
buf := l.Borrow()[:2]
|
||||||
|
defer l.Return(buf)
|
||||||
|
|
||||||
byteOrder.PutUint16(buf, val)
|
byteOrder.PutUint16(buf, val)
|
||||||
_, err := w.Write(buf)
|
_, err := w.Write(buf)
|
||||||
l.Return(buf)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,9 +158,11 @@ func (l binaryFreeList) PutUint16(w io.Writer, byteOrder binary.ByteOrder, val u
|
||||||
// writer.
|
// writer.
|
||||||
func (l binaryFreeList) PutUint32(w io.Writer, byteOrder binary.ByteOrder, val uint32) error {
|
func (l binaryFreeList) PutUint32(w io.Writer, byteOrder binary.ByteOrder, val uint32) error {
|
||||||
buf := l.Borrow()[:4]
|
buf := l.Borrow()[:4]
|
||||||
|
defer l.Return(buf)
|
||||||
|
|
||||||
byteOrder.PutUint32(buf, val)
|
byteOrder.PutUint32(buf, val)
|
||||||
_, err := w.Write(buf)
|
_, err := w.Write(buf)
|
||||||
l.Return(buf)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,9 +171,11 @@ func (l binaryFreeList) PutUint32(w io.Writer, byteOrder binary.ByteOrder, val u
|
||||||
// writer.
|
// writer.
|
||||||
func (l binaryFreeList) PutUint64(w io.Writer, byteOrder binary.ByteOrder, val uint64) error {
|
func (l binaryFreeList) PutUint64(w io.Writer, byteOrder binary.ByteOrder, val uint64) error {
|
||||||
buf := l.Borrow()[:8]
|
buf := l.Borrow()[:8]
|
||||||
|
defer l.Return(buf)
|
||||||
|
|
||||||
byteOrder.PutUint64(buf, val)
|
byteOrder.PutUint64(buf, val)
|
||||||
_, err := w.Write(buf)
|
_, err := w.Write(buf)
|
||||||
l.Return(buf)
|
|
||||||
return err
|
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.
|
// ReadVarInt reads a variable length integer from r and returns it as a uint64.
|
||||||
func ReadVarInt(r io.Reader, pver uint32) (uint64, error) {
|
func ReadVarInt(r io.Reader, pver uint32) (uint64, error) {
|
||||||
discriminant, err := binarySerializer.Uint8(r)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
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
|
return 0, err
|
||||||
}
|
}
|
||||||
|
discriminant := buf[0]
|
||||||
|
|
||||||
var rv uint64
|
var rv uint64
|
||||||
switch discriminant {
|
switch discriminant {
|
||||||
case 0xff:
|
case 0xff:
|
||||||
sv, err := binarySerializer.Uint64(r, littleEndian)
|
if _, err := io.ReadFull(r, buf); err != nil {
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
rv = sv
|
rv = littleEndian.Uint64(buf)
|
||||||
|
|
||||||
// The encoding is not canonical if the value could have been
|
// The encoding is not canonical if the value could have been
|
||||||
// encoded using fewer bytes.
|
// encoded using fewer bytes.
|
||||||
|
@ -497,11 +520,10 @@ func ReadVarInt(r io.Reader, pver uint32) (uint64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xfe:
|
case 0xfe:
|
||||||
sv, err := binarySerializer.Uint32(r, littleEndian)
|
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
rv = uint64(sv)
|
rv = uint64(littleEndian.Uint32(buf[:4]))
|
||||||
|
|
||||||
// The encoding is not canonical if the value could have been
|
// The encoding is not canonical if the value could have been
|
||||||
// encoded using fewer bytes.
|
// encoded using fewer bytes.
|
||||||
|
@ -512,11 +534,10 @@ func ReadVarInt(r io.Reader, pver uint32) (uint64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xfd:
|
case 0xfd:
|
||||||
sv, err := binarySerializer.Uint16(r, littleEndian)
|
if _, err := io.ReadFull(r, buf[:2]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
rv = uint64(sv)
|
rv = uint64(littleEndian.Uint16(buf[:2]))
|
||||||
|
|
||||||
// The encoding is not canonical if the value could have been
|
// The encoding is not canonical if the value could have been
|
||||||
// encoded using fewer bytes.
|
// 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
|
// WriteVarInt serializes val to w using a variable number of bytes depending
|
||||||
// on its value.
|
// on its value.
|
||||||
func WriteVarInt(w io.Writer, pver uint32, val uint64) error {
|
func WriteVarInt(w io.Writer, pver uint32, val uint64) error {
|
||||||
if val < 0xfd {
|
buf := binarySerializer.Borrow()
|
||||||
return binarySerializer.PutUint8(w, uint8(val))
|
defer binarySerializer.Return(buf)
|
||||||
}
|
|
||||||
|
|
||||||
if val <= math.MaxUint16 {
|
err := WriteVarIntBuf(w, pver, val, buf)
|
||||||
err := binarySerializer.PutUint8(w, 0xfd)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
|
|
||||||
|
// 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 err
|
||||||
}
|
}
|
||||||
return binarySerializer.PutUint16(w, littleEndian, uint16(val))
|
|
||||||
}
|
|
||||||
|
|
||||||
if val <= math.MaxUint32 {
|
littleEndian.PutUint64(buf, val)
|
||||||
err := binarySerializer.PutUint8(w, 0xfe)
|
_, err := w.Write(buf)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return binarySerializer.PutUint32(w, littleEndian, uint32(val))
|
|
||||||
}
|
|
||||||
|
|
||||||
err := binarySerializer.PutUint8(w, 0xff)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return binarySerializer.PutUint64(w, littleEndian, val)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VarIntSerializeSize returns the number of bytes it would take to serialize
|
// 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
|
// maximum block payload size since it helps protect against memory exhaustion
|
||||||
// attacks and forced panics through malformed messages.
|
// attacks and forced panics through malformed messages.
|
||||||
func ReadVarString(r io.Reader, pver uint32) (string, error) {
|
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -607,22 +663,40 @@ func ReadVarString(r io.Reader, pver uint32) (string, error) {
|
||||||
return "", messageError("ReadVarString", str)
|
return "", messageError("ReadVarString", str)
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := make([]byte, count)
|
str := make([]byte, count)
|
||||||
_, err = io.ReadFull(r, buf)
|
_, err = io.ReadFull(r, str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(buf), nil
|
return string(str), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteVarString serializes str to w as a variable length integer containing
|
// WriteVarString serializes str to w as a variable length integer containing
|
||||||
// the length of the string followed by the bytes that represent the string
|
// the length of the string followed by the bytes that represent the string
|
||||||
// itself.
|
// itself.
|
||||||
func WriteVarString(w io.Writer, pver uint32, str string) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = w.Write([]byte(str))
|
_, err = w.Write([]byte(str))
|
||||||
return err
|
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,
|
func ReadVarBytes(r io.Reader, pver uint32, maxAllowed uint32,
|
||||||
fieldName string) ([]byte, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -651,19 +744,33 @@ func ReadVarBytes(r io.Reader, pver uint32, maxAllowed uint32,
|
||||||
return nil, messageError("ReadVarBytes", str)
|
return nil, messageError("ReadVarBytes", str)
|
||||||
}
|
}
|
||||||
|
|
||||||
b := make([]byte, count)
|
bytes := make([]byte, count)
|
||||||
_, err = io.ReadFull(r, b)
|
_, err = io.ReadFull(r, bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return b, nil
|
return bytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteVarBytes serializes a variable length byte array to w as a varInt
|
// WriteVarBytes serializes a variable length byte array to w as a varInt
|
||||||
// containing the number of bytes, followed by the bytes themselves.
|
// containing the number of bytes, followed by the bytes themselves.
|
||||||
func WriteVarBytes(w io.Writer, pver uint32, bytes []byte) error {
|
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))
|
slen := uint64(len(bytes))
|
||||||
err := WriteVarInt(w, pver, slen)
|
|
||||||
|
err := WriteVarIntBuf(w, pver, slen, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
// 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.
|
// writeInvVectBuf 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)
|
// 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))
|
t.Logf("Running %d tests", len(tests))
|
||||||
|
var b [8]byte
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
// Encode to wire format.
|
// Encode to wire format.
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err := writeInvVect(&buf, test.pver, &test.in)
|
err := writeInvVectBuf(&buf, test.pver, &test.in, b[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("writeInvVect #%d error %v", i, err)
|
t.Errorf("writeInvVect #%d error %v", i, err)
|
||||||
continue
|
continue
|
||||||
|
@ -255,7 +256,7 @@ func TestInvVectWire(t *testing.T) {
|
||||||
// Decode the message from wire format.
|
// Decode the message from wire format.
|
||||||
var iv InvVect
|
var iv InvVect
|
||||||
rbuf := bytes.NewReader(test.buf)
|
rbuf := bytes.NewReader(test.buf)
|
||||||
err = readInvVect(rbuf, test.pver, &iv)
|
err = readInvVectBuf(rbuf, test.pver, &iv, b[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("readInvVect #%d error %v", i, err)
|
t.Errorf("readInvVect #%d error %v", i, err)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -62,12 +62,15 @@ func (msg *MsgBlock) ClearTransactions() {
|
||||||
// See Deserialize for decoding blocks stored to disk, such as in a database, as
|
// See Deserialize for decoding blocks stored to disk, such as in a database, as
|
||||||
// opposed to decoding blocks from the wire.
|
// opposed to decoding blocks from the wire.
|
||||||
func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
txCount, err := ReadVarInt(r, pver)
|
txCount, err := ReadVarIntBuf(r, pver, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -81,10 +84,13 @@ func (msg *MsgBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) er
|
||||||
return messageError("MsgBlock.BtcDecode", str)
|
return messageError("MsgBlock.BtcDecode", str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scriptBuf := scriptPool.Borrow()
|
||||||
|
defer scriptPool.Return(scriptBuf)
|
||||||
|
|
||||||
msg.Transactions = make([]*MsgTx, 0, txCount)
|
msg.Transactions = make([]*MsgTx, 0, txCount)
|
||||||
for i := uint64(0); i < txCount; i++ {
|
for i := uint64(0); i < txCount; i++ {
|
||||||
tx := MsgTx{}
|
tx := MsgTx{}
|
||||||
err := tx.BtcDecode(r, pver, enc)
|
err := tx.btcDecode(r, pver, enc, buf, scriptBuf[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -129,15 +135,18 @@ func (msg *MsgBlock) DeserializeNoWitness(r io.Reader) error {
|
||||||
func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
|
func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
|
||||||
fullLen := r.Len()
|
fullLen := r.Len()
|
||||||
|
|
||||||
|
buf := binarySerializer.Borrow()
|
||||||
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
// At the current time, there is no difference between the wire encoding
|
// At the current time, there is no difference between the wire encoding
|
||||||
// at protocol version 0 and the stable long-term storage format. As
|
// at protocol version 0 and the stable long-term storage format. As
|
||||||
// a result, make use of existing wire protocol functions.
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
txCount, err := ReadVarInt(r, 0)
|
txCount, err := ReadVarIntBuf(r, 0, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -151,6 +160,9 @@ func (msg *MsgBlock) DeserializeTxLoc(r *bytes.Buffer) ([]TxLoc, error) {
|
||||||
return nil, messageError("MsgBlock.DeserializeTxLoc", str)
|
return nil, messageError("MsgBlock.DeserializeTxLoc", str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scriptBuf := scriptPool.Borrow()
|
||||||
|
defer scriptPool.Return(scriptBuf)
|
||||||
|
|
||||||
// Deserialize each transaction while keeping track of its location
|
// Deserialize each transaction while keeping track of its location
|
||||||
// within the byte stream.
|
// within the byte stream.
|
||||||
msg.Transactions = make([]*MsgTx, 0, txCount)
|
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++ {
|
for i := uint64(0); i < txCount; i++ {
|
||||||
txLocs[i].TxStart = fullLen - r.Len()
|
txLocs[i].TxStart = fullLen - r.Len()
|
||||||
tx := MsgTx{}
|
tx := MsgTx{}
|
||||||
err := tx.Deserialize(r)
|
err := tx.btcDecode(r, 0, WitnessEncoding, buf, scriptBuf[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// See Serialize for encoding blocks to be stored to disk, such as in a
|
||||||
// database, as opposed to encoding blocks for the wire.
|
// database, as opposed to encoding blocks for the wire.
|
||||||
func (msg *MsgBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = WriteVarInt(w, pver, uint64(len(msg.Transactions)))
|
err = WriteVarIntBuf(w, pver, uint64(len(msg.Transactions)), buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tx := range msg.Transactions {
|
for _, tx := range msg.Transactions {
|
||||||
err = tx.BtcEncode(w, pver, enc)
|
err = tx.btcEncode(w, pver, enc, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||||
|
buf := binarySerializer.Borrow()
|
||||||
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
// Read filter type
|
// Read filter type
|
||||||
err := readElement(r, &msg.FilterType)
|
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
msg.FilterType = FilterType(buf[0])
|
||||||
|
|
||||||
// Read stop hash
|
// Read stop hash
|
||||||
err = readElement(r, &msg.StopHash)
|
if _, err := io.ReadFull(r, msg.StopHash[:]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read number of filter headers
|
// Read number of filter headers
|
||||||
count, err := ReadVarInt(r, pver)
|
count, err := ReadVarIntBuf(r, pver, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -80,7 +82,7 @@ func (msg *MsgCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding)
|
||||||
msg.FilterHeaders = make([]*chainhash.Hash, count)
|
msg.FilterHeaders = make([]*chainhash.Hash, count)
|
||||||
for i := uint64(0); i < count; i++ {
|
for i := uint64(0); i < count; i++ {
|
||||||
var cfh chainhash.Hash
|
var cfh chainhash.Hash
|
||||||
err := readElement(r, &cfh)
|
_, err := io.ReadFull(r, cfh[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgCFCheckpt) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgCFCheckpt) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
||||||
|
buf := binarySerializer.Borrow()
|
||||||
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
// Write filter type
|
// Write filter type
|
||||||
err := writeElement(w, msg.FilterType)
|
buf[0] = byte(msg.FilterType)
|
||||||
if err != nil {
|
if _, err := w.Write(buf[:1]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write stop hash
|
// Write stop hash
|
||||||
err = writeElement(w, msg.StopHash)
|
if _, err := w.Write(msg.StopHash[:]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write length of FilterHeaders slice
|
// Write length of FilterHeaders slice
|
||||||
count := len(msg.FilterHeaders)
|
count := len(msg.FilterHeaders)
|
||||||
err = WriteVarInt(w, pver, uint64(count))
|
err := WriteVarIntBuf(w, pver, uint64(count), buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cfh := range msg.FilterHeaders {
|
for _, cfh := range msg.FilterHeaders {
|
||||||
err := writeElement(w, cfh)
|
_, err := w.Write(cfh[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||||
|
buf := binarySerializer.Borrow()
|
||||||
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
// Read filter type
|
// Read filter type
|
||||||
err := readElement(r, &msg.FilterType)
|
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
msg.FilterType = FilterType(buf[0])
|
||||||
|
|
||||||
// Read stop hash
|
// Read stop hash
|
||||||
err = readElement(r, &msg.StopHash)
|
if _, err := io.ReadFull(r, msg.StopHash[:]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read prev filter header
|
// Read prev filter header
|
||||||
err = readElement(r, &msg.PrevFilterHeader)
|
if _, err := io.ReadFull(r, msg.PrevFilterHeader[:]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read number of filter headers
|
// Read number of filter headers
|
||||||
count, err := ReadVarInt(r, pver)
|
count, err := ReadVarIntBuf(r, pver, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -85,7 +86,7 @@ func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding)
|
||||||
msg.FilterHashes = make([]*chainhash.Hash, 0, count)
|
msg.FilterHashes = make([]*chainhash.Hash, 0, count)
|
||||||
for i := uint64(0); i < count; i++ {
|
for i := uint64(0); i < count; i++ {
|
||||||
var cfh chainhash.Hash
|
var cfh chainhash.Hash
|
||||||
err := readElement(r, &cfh)
|
_, err := io.ReadFull(r, cfh[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
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)
|
count := len(msg.FilterHashes)
|
||||||
if count > MaxCFHeadersPerMsg {
|
if count > MaxCFHeadersPerMsg {
|
||||||
str := fmt.Sprintf("too many committed filter headers for "+
|
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)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cfh := range msg.FilterHashes {
|
for _, cfh := range msg.FilterHashes {
|
||||||
err := writeElement(w, cfh)
|
_, err := w.Write(cfh[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,19 +38,22 @@ type MsgCFilter struct {
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgCFilter) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgCFilter) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||||
// Read filter type
|
// Read filter type
|
||||||
err := readElement(r, &msg.FilterType)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
|
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
msg.FilterType = FilterType(buf[0])
|
||||||
|
|
||||||
// Read the hash of the filter's block
|
// Read the hash of the filter's block
|
||||||
err = readElement(r, &msg.BlockHash)
|
if _, err := io.ReadFull(r, msg.BlockHash[:]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read filter data
|
// Read filter data
|
||||||
msg.Data, err = ReadVarBytes(r, pver, MaxCFilterDataSize,
|
var err error
|
||||||
|
msg.Data, err = ReadVarBytesBuf(r, pver, buf, MaxCFilterDataSize,
|
||||||
"cfilter data")
|
"cfilter data")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -65,17 +68,20 @@ func (msg *MsgCFilter) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) er
|
||||||
return messageError("MsgCFilter.BtcEncode", str)
|
return messageError("MsgCFilter.BtcEncode", str)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := writeElement(w, msg.FilterType)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
|
buf[0] = byte(msg.FilterType)
|
||||||
|
if _, err := w.Write(buf[:1]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeElement(w, msg.BlockHash)
|
if _, err := w.Write(msg.BlockHash[:]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
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
|
// 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.
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgGetBlocks) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read num block locator hashes and limit to max.
|
|
||||||
count, err := ReadVarInt(r, pver)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if count > MaxBlockLocatorsPerMsg {
|
if count > MaxBlockLocatorsPerMsg {
|
||||||
str := fmt.Sprintf("too many block locator hashes for message "+
|
str := fmt.Sprintf("too many block locator hashes for message "+
|
||||||
"[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
|
"[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)
|
msg.BlockLocatorHashes = make([]*chainhash.Hash, 0, count)
|
||||||
for i := uint64(0); i < count; i++ {
|
for i := uint64(0); i < count; i++ {
|
||||||
hash := &locatorHashes[i]
|
hash := &locatorHashes[i]
|
||||||
err := readElement(r, hash)
|
_, err := io.ReadFull(r, hash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
msg.AddBlockLocatorHash(hash)
|
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.
|
// 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)
|
return messageError("MsgGetBlocks.BtcEncode", str)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := writeElement(w, msg.ProtocolVersion)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
|
littleEndian.PutUint32(buf[:4], msg.ProtocolVersion)
|
||||||
|
if _, err := w.Write(buf[:4]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = WriteVarInt(w, pver, uint64(count))
|
err := WriteVarIntBuf(w, pver, uint64(count), buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, hash := range msg.BlockLocatorHashes {
|
for _, hash := range msg.BlockLocatorHashes {
|
||||||
err = writeElement(w, hash)
|
_, err := w.Write(hash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// 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.
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgGetCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgGetCFCheckpt) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||||
err := readElement(r, &msg.FilterType)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
|
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||||
return err
|
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.
|
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgGetCFCheckpt) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgGetCFCheckpt) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
||||||
err := writeElement(w, msg.FilterType)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
|
buf[0] = byte(msg.FilterType)
|
||||||
|
if _, err := w.Write(buf[:1]); err != nil {
|
||||||
return err
|
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
|
// 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.
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgGetCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgGetCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||||
err := readElement(r, &msg.FilterType)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
|
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
msg.FilterType = FilterType(buf[0])
|
||||||
|
|
||||||
err = readElement(r, &msg.StartHeight)
|
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
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.
|
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgGetCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgGetCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
||||||
err := writeElement(w, msg.FilterType)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
|
buf[0] = byte(msg.FilterType)
|
||||||
|
if _, err := w.Write(buf[:1]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeElement(w, &msg.StartHeight)
|
littleEndian.PutUint32(buf[:4], msg.StartHeight)
|
||||||
if err != nil {
|
if _, err := w.Write(buf[:4]); err != nil {
|
||||||
return err
|
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
|
// 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.
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgGetCFilters) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgGetCFilters) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error {
|
||||||
err := readElement(r, &msg.FilterType)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
|
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
msg.FilterType = FilterType(buf[0])
|
||||||
|
|
||||||
err = readElement(r, &msg.StartHeight)
|
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
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.
|
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgGetCFilters) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
func (msg *MsgGetCFilters) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) error {
|
||||||
err := writeElement(w, msg.FilterType)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
|
buf[0] = byte(msg.FilterType)
|
||||||
|
if _, err := w.Write(buf[:1]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeElement(w, &msg.StartHeight)
|
littleEndian.PutUint32(buf[:4], msg.StartHeight)
|
||||||
if err != nil {
|
if _, err := w.Write(buf[:4]); err != nil {
|
||||||
return err
|
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
|
// 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.
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgGetData) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -55,7 +58,7 @@ func (msg *MsgGetData) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding)
|
||||||
msg.InvList = make([]*InvVect, 0, count)
|
msg.InvList = make([]*InvVect, 0, count)
|
||||||
for i := uint64(0); i < count; i++ {
|
for i := uint64(0); i < count; i++ {
|
||||||
iv := &invList[i]
|
iv := &invList[i]
|
||||||
err := readInvVect(r, pver, iv)
|
err := readInvVectBuf(r, pver, iv, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -75,13 +78,16 @@ func (msg *MsgGetData) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding)
|
||||||
return messageError("MsgGetData.BtcEncode", str)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, iv := range msg.InvList {
|
for _, iv := range msg.InvList {
|
||||||
err := writeInvVect(w, pver, iv)
|
err := writeInvVectBuf(w, pver, iv, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgGetHeaders) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read num block locator hashes and limit to max.
|
|
||||||
count, err := ReadVarInt(r, pver)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if count > MaxBlockLocatorsPerMsg {
|
if count > MaxBlockLocatorsPerMsg {
|
||||||
str := fmt.Sprintf("too many block locator hashes for message "+
|
str := fmt.Sprintf("too many block locator hashes for message "+
|
||||||
"[count %v, max %v]", count, MaxBlockLocatorsPerMsg)
|
"[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)
|
msg.BlockLocatorHashes = make([]*chainhash.Hash, 0, count)
|
||||||
for i := uint64(0); i < count; i++ {
|
for i := uint64(0); i < count; i++ {
|
||||||
hash := &locatorHashes[i]
|
hash := &locatorHashes[i]
|
||||||
err := readElement(r, hash)
|
_, err := io.ReadFull(r, hash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
msg.AddBlockLocatorHash(hash)
|
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.
|
// 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)
|
return messageError("MsgGetHeaders.BtcEncode", str)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := writeElement(w, msg.ProtocolVersion)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
defer binarySerializer.Return(buf)
|
||||||
|
|
||||||
|
littleEndian.PutUint32(buf[:4], msg.ProtocolVersion)
|
||||||
|
if _, err := w.Write(buf[:4]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = WriteVarInt(w, pver, uint64(count))
|
err := WriteVarIntBuf(w, pver, uint64(count), buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, hash := range msg.BlockLocatorHashes {
|
for _, hash := range msg.BlockLocatorHashes {
|
||||||
err := writeElement(w, hash)
|
_, err := w.Write(hash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// 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.
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -55,12 +58,12 @@ func (msg *MsgHeaders) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding)
|
||||||
msg.Headers = make([]*BlockHeader, 0, count)
|
msg.Headers = make([]*BlockHeader, 0, count)
|
||||||
for i := uint64(0); i < count; i++ {
|
for i := uint64(0); i < count; i++ {
|
||||||
bh := &headers[i]
|
bh := &headers[i]
|
||||||
err := readBlockHeader(r, pver, bh)
|
err := readBlockHeaderBuf(r, pver, bh, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
txCount, err := ReadVarInt(r, pver)
|
txCount, err := ReadVarIntBuf(r, pver, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -88,13 +91,16 @@ func (msg *MsgHeaders) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding)
|
||||||
return messageError("MsgHeaders.BtcEncode", str)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, bh := range msg.Headers {
|
for _, bh := range msg.Headers {
|
||||||
err := writeBlockHeader(w, pver, bh)
|
err := writeBlockHeaderBuf(w, pver, bh, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// of transactions on header messages. This is really just an
|
||||||
// artifact of the way the original implementation serializes
|
// artifact of the way the original implementation serializes
|
||||||
// block headers, but it is required.
|
// block headers, but it is required.
|
||||||
err = WriteVarInt(w, pver, 0)
|
err = WriteVarIntBuf(w, pver, 0, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,10 @@ func (msg *MsgInv) AddInvVect(iv *InvVect) error {
|
||||||
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgInv) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -63,7 +66,7 @@ func (msg *MsgInv) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) erro
|
||||||
msg.InvList = make([]*InvVect, 0, count)
|
msg.InvList = make([]*InvVect, 0, count)
|
||||||
for i := uint64(0); i < count; i++ {
|
for i := uint64(0); i < count; i++ {
|
||||||
iv := &invList[i]
|
iv := &invList[i]
|
||||||
err := readInvVect(r, pver, iv)
|
err := readInvVectBuf(r, pver, iv, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -83,13 +86,16 @@ func (msg *MsgInv) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) erro
|
||||||
return messageError("MsgInv.BtcEncode", str)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, iv := range msg.InvList {
|
for _, iv := range msg.InvList {
|
||||||
err := writeInvVect(w, pver, iv)
|
err := writeInvVectBuf(w, pver, iv, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,18 +49,21 @@ func (msg *MsgMerkleBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncodi
|
||||||
return messageError("MsgMerkleBlock.BtcDecode", str)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = readElement(r, &msg.Transactions)
|
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
msg.Transactions = littleEndian.Uint32(buf[:4])
|
||||||
|
|
||||||
// Read num block locator hashes and limit to max.
|
// Read num block locator hashes and limit to max.
|
||||||
count, err := ReadVarInt(r, pver)
|
count, err := ReadVarIntBuf(r, pver, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -76,14 +79,14 @@ func (msg *MsgMerkleBlock) BtcDecode(r io.Reader, pver uint32, enc MessageEncodi
|
||||||
msg.Hashes = make([]*chainhash.Hash, 0, count)
|
msg.Hashes = make([]*chainhash.Hash, 0, count)
|
||||||
for i := uint64(0); i < count; i++ {
|
for i := uint64(0); i < count; i++ {
|
||||||
hash := &hashes[i]
|
hash := &hashes[i]
|
||||||
err := readElement(r, hash)
|
_, err := io.ReadFull(r, hash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
msg.AddTxHash(hash)
|
msg.AddTxHash(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.Flags, err = ReadVarBytes(r, pver, maxFlagsPerMerkleBlock,
|
msg.Flags, err = ReadVarBytesBuf(r, pver, buf, maxFlagsPerMerkleBlock,
|
||||||
"merkle block flags size")
|
"merkle block flags size")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -111,28 +114,32 @@ func (msg *MsgMerkleBlock) BtcEncode(w io.Writer, pver uint32, enc MessageEncodi
|
||||||
return messageError("MsgMerkleBlock.BtcDecode", str)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeElement(w, msg.Transactions)
|
littleEndian.PutUint32(buf[:4], msg.Transactions)
|
||||||
if err != nil {
|
if _, err := w.Write(buf[:4]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = WriteVarInt(w, pver, uint64(numHashes))
|
err = WriteVarIntBuf(w, pver, uint64(numHashes), buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, hash := range msg.Hashes {
|
for _, hash := range msg.Hashes {
|
||||||
err = writeElement(w, hash)
|
_, err := w.Write(hash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// 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.
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver.
|
||||||
// This is part of the Message interface implementation.
|
// This is part of the Message interface implementation.
|
||||||
func (msg *MsgNotFound) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -52,7 +55,7 @@ func (msg *MsgNotFound) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding)
|
||||||
msg.InvList = make([]*InvVect, 0, count)
|
msg.InvList = make([]*InvVect, 0, count)
|
||||||
for i := uint64(0); i < count; i++ {
|
for i := uint64(0); i < count; i++ {
|
||||||
iv := &invList[i]
|
iv := &invList[i]
|
||||||
err := readInvVect(r, pver, iv)
|
err := readInvVectBuf(r, pver, iv, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -72,13 +75,16 @@ func (msg *MsgNotFound) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding)
|
||||||
return messageError("MsgNotFound.BtcEncode", str)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, iv := range msg.InvList {
|
for _, iv := range msg.InvList {
|
||||||
err := writeInvVect(w, pver, iv)
|
err := writeInvVectBuf(w, pver, iv, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// NOTE: > is not a mistake here. The BIP0031 was defined as AFTER
|
||||||
// the version unlike most others.
|
// the version unlike most others.
|
||||||
if pver > BIP0031Version {
|
if pver > BIP0031Version {
|
||||||
err := readElement(r, &msg.Nonce)
|
nonce, err := binarySerializer.Uint64(r, littleEndian)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
msg.Nonce = nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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
|
// NOTE: > is not a mistake here. The BIP0031 was defined as AFTER
|
||||||
// the version unlike most others.
|
// the version unlike most others.
|
||||||
if pver > BIP0031Version {
|
if pver > BIP0031Version {
|
||||||
err := writeElement(w, msg.Nonce)
|
err := binarySerializer.PutUint64(w, littleEndian, msg.Nonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,13 @@ func (msg *MsgPong) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) err
|
||||||
return messageError("MsgPong.BtcDecode", str)
|
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.
|
// 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 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
|
// 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.
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
msg.Cmd = cmd
|
msg.Cmd = cmd
|
||||||
|
|
||||||
// Code indicating why the command was rejected.
|
// Code indicating why the command was rejected.
|
||||||
err = readElement(r, &msg.Code)
|
if _, err := io.ReadFull(r, buf[:1]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
msg.Code = RejectCode(buf[0])
|
||||||
|
|
||||||
// Human readable string with specific details (over and above the
|
// Human readable string with specific details (over and above the
|
||||||
// reject code above) about why the command was rejected.
|
// reject code above) about why the command was rejected.
|
||||||
reason, err := ReadVarString(r, pver)
|
reason, err := readVarStringBuf(r, pver, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// CmdBlock and CmdTx messages have an additional hash field that
|
||||||
// identifies the specific block or transaction.
|
// identifies the specific block or transaction.
|
||||||
if msg.Cmd == CmdBlock || msg.Cmd == CmdTx {
|
if msg.Cmd == CmdBlock || msg.Cmd == CmdTx {
|
||||||
err := readElement(r, &msg.Hash)
|
_, err := io.ReadFull(r, msg.Hash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -123,20 +126,23 @@ func (msg *MsgReject) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command that was rejected.
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code indicating why the command was rejected.
|
// Code indicating why the command was rejected.
|
||||||
err = writeElement(w, msg.Code)
|
buf[0] = byte(msg.Code)
|
||||||
if err != nil {
|
if _, err := w.Write(buf[:1]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Human readable string with specific details (over and above the
|
// Human readable string with specific details (over and above the
|
||||||
// reject code above) about why the command was rejected.
|
// 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 {
|
if err != nil {
|
||||||
return err
|
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
|
// CmdBlock and CmdTx messages have an additional hash field that
|
||||||
// identifies the specific block or transaction.
|
// identifies the specific block or transaction.
|
||||||
if msg.Cmd == CmdBlock || msg.Cmd == CmdTx {
|
if msg.Cmd == CmdBlock || msg.Cmd == CmdTx {
|
||||||
err := writeElement(w, &msg.Hash)
|
_, err := w.Write(msg.Hash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
314
wire/msgtx.go
314
wire/msgtx.go
|
@ -93,7 +93,7 @@ const (
|
||||||
// scripts per transaction being simultaneously deserialized by 125
|
// scripts per transaction being simultaneously deserialized by 125
|
||||||
// peers. Thus, the peak usage of the free list is 12,500 * 512 =
|
// peers. Thus, the peak usage of the free list is 12,500 * 512 =
|
||||||
// 6,400,000 bytes.
|
// 6,400,000 bytes.
|
||||||
freeListMaxItems = 12500
|
freeListMaxItems = 125
|
||||||
|
|
||||||
// maxWitnessItemsPerInput is the maximum number of witness items to
|
// maxWitnessItemsPerInput is the maximum number of witness items to
|
||||||
// be read for the witness data for a single TxIn. This number is
|
// be read for the witness data for a single TxIn. This number is
|
||||||
|
@ -146,6 +146,10 @@ const (
|
||||||
WitnessFlag TxFlag = 0x01
|
WitnessFlag TxFlag = 0x01
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const scriptSlabSize = 1 << 22
|
||||||
|
|
||||||
|
type scriptSlab [scriptSlabSize]byte
|
||||||
|
|
||||||
// scriptFreeList defines a free list of byte slices (up to the maximum number
|
// 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
|
// defined by the freeListMaxItems constant) that have a cap according to the
|
||||||
// freeListMaxScriptSize constant. It is used to provide temporary buffers for
|
// 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
|
// 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.
|
// 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
|
// 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.
|
// 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
|
// 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
|
// to attempt to return said buffer via the Return function as it will be
|
||||||
// ignored and allowed to go the garbage collector.
|
// ignored and allowed to go the garbage collector.
|
||||||
func (c scriptFreeList) Borrow(size uint64) []byte {
|
func (c scriptFreeList) Borrow() *scriptSlab {
|
||||||
if size > freeListMaxScriptSize {
|
var buf *scriptSlab
|
||||||
return make([]byte, size)
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf []byte
|
|
||||||
select {
|
select {
|
||||||
case buf = <-c:
|
case buf = <-c:
|
||||||
default:
|
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
|
// 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
|
// 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
|
// 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.
|
// are simply ignored so they can go to the garbage collector.
|
||||||
func (c scriptFreeList) Return(buf []byte) {
|
func (c scriptFreeList) Return(buf *scriptSlab) {
|
||||||
// Ignore any buffers returned that aren't the expected size for the
|
|
||||||
// free list.
|
|
||||||
if cap(buf) != freeListMaxScriptSize {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the buffer to the free list when it's not full. Otherwise let
|
// Return the buffer to the free list when it's not full. Otherwise let
|
||||||
// it be garbage collected.
|
// it be garbage collected.
|
||||||
select {
|
select {
|
||||||
|
@ -201,7 +195,7 @@ func (c scriptFreeList) Return(buf []byte) {
|
||||||
// Create the concurrent safe free list to use for script deserialization. As
|
// Create the concurrent safe free list to use for script deserialization. As
|
||||||
// previously described, this free list is maintained to significantly reduce
|
// previously described, this free list is maintained to significantly reduce
|
||||||
// the number of allocations.
|
// 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
|
// OutPoint defines a bitcoin data type that is used to track previous
|
||||||
// transaction outputs.
|
// transaction outputs.
|
||||||
|
@ -452,13 +446,25 @@ func (msg *MsgTx) Copy() *MsgTx {
|
||||||
// See Deserialize for decoding transactions stored to disk, such as in a
|
// See Deserialize for decoding transactions stored to disk, such as in a
|
||||||
// database, as opposed to decoding transactions from the wire.
|
// database, as opposed to decoding transactions from the wire.
|
||||||
func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error {
|
||||||
version, err := binarySerializer.Uint32(r, littleEndian)
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
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
|
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 {
|
if err != nil {
|
||||||
return err
|
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
|
// With the Segregated Witness specific fields decoded, we can
|
||||||
// now read in the actual txin count.
|
// now read in the actual txin count.
|
||||||
count, err = ReadVarInt(r, pver)
|
count, err = ReadVarIntBuf(r, pver, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -498,35 +504,6 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
||||||
return messageError("MsgTx.BtcDecode", str)
|
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.
|
// Deserialize the inputs.
|
||||||
var totalScriptSize uint64
|
var totalScriptSize uint64
|
||||||
txIns := make([]TxIn, count)
|
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.
|
// and needs to be returned to the pool on error.
|
||||||
ti := &txIns[i]
|
ti := &txIns[i]
|
||||||
msg.TxIn[i] = ti
|
msg.TxIn[i] = ti
|
||||||
err = readTxIn(r, pver, msg.Version, ti)
|
err = readTxInBuf(r, pver, msg.Version, ti, buf, sbuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
returnScriptBuffers()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
totalScriptSize += uint64(len(ti.SignatureScript))
|
totalScriptSize += uint64(len(ti.SignatureScript))
|
||||||
|
sbuf = sbuf[len(ti.SignatureScript):]
|
||||||
}
|
}
|
||||||
|
|
||||||
count, err = ReadVarInt(r, pver)
|
count, err = ReadVarIntBuf(r, pver, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
returnScriptBuffers()
|
|
||||||
return err
|
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
|
// message. It would be possible to cause memory exhaustion and panics
|
||||||
// without a sane upper bound on this count.
|
// without a sane upper bound on this count.
|
||||||
if count > uint64(maxTxOutPerMessage) {
|
if count > uint64(maxTxOutPerMessage) {
|
||||||
returnScriptBuffers()
|
|
||||||
str := fmt.Sprintf("too many output transactions to fit into "+
|
str := fmt.Sprintf("too many output transactions to fit into "+
|
||||||
"max message size [count %d, max %d]", count,
|
"max message size [count %d, max %d]", count,
|
||||||
maxTxOutPerMessage)
|
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.
|
// and needs to be returned to the pool on error.
|
||||||
to := &txOuts[i]
|
to := &txOuts[i]
|
||||||
msg.TxOut[i] = to
|
msg.TxOut[i] = to
|
||||||
err = ReadTxOut(r, pver, msg.Version, to)
|
err = readTxOutBuf(r, pver, msg.Version, to, buf, sbuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
returnScriptBuffers()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
totalScriptSize += uint64(len(to.PkScript))
|
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
|
// 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
|
// For each input, the witness is encoded as a stack
|
||||||
// with one or more items. Therefore, we first read a
|
// with one or more items. Therefore, we first read a
|
||||||
// varint which encodes the number of stack items.
|
// varint which encodes the number of stack items.
|
||||||
witCount, err := ReadVarInt(r, pver)
|
witCount, err := ReadVarIntBuf(r, pver, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
returnScriptBuffers()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent a possible memory exhaustion attack by
|
// Prevent a possible memory exhaustion attack by
|
||||||
// limiting the witCount value to a sane upper bound.
|
// limiting the witCount value to a sane upper bound.
|
||||||
if witCount > maxWitnessItemsPerInput {
|
if witCount > maxWitnessItemsPerInput {
|
||||||
returnScriptBuffers()
|
|
||||||
str := fmt.Sprintf("too many witness items to fit "+
|
str := fmt.Sprintf("too many witness items to fit "+
|
||||||
"into max message size [count %d, max %d]",
|
"into max message size [count %d, max %d]",
|
||||||
witCount, maxWitnessItemsPerInput)
|
witCount, maxWitnessItemsPerInput)
|
||||||
|
@ -605,23 +578,23 @@ func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32, enc MessageEncoding) error
|
||||||
// item itself.
|
// item itself.
|
||||||
txin.Witness = make([][]byte, witCount)
|
txin.Witness = make([][]byte, witCount)
|
||||||
for j := uint64(0); j < witCount; j++ {
|
for j := uint64(0); j < witCount; j++ {
|
||||||
txin.Witness[j], err = readScript(
|
txin.Witness[j], err = readScriptBuf(
|
||||||
r, pver, maxWitnessItemSize, "script witness item",
|
r, pver, buf, sbuf, maxWitnessItemSize,
|
||||||
|
"script witness item",
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
returnScriptBuffers()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
totalScriptSize += uint64(len(txin.Witness[j]))
|
totalScriptSize += uint64(len(txin.Witness[j]))
|
||||||
|
sbuf = sbuf[len(txin.Witness[j]):]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.LockTime, err = binarySerializer.Uint32(r, littleEndian)
|
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||||
if err != nil {
|
|
||||||
returnScriptBuffers()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
msg.LockTime = littleEndian.Uint32(buf[:4])
|
||||||
|
|
||||||
// Create a single allocation to house all of the scripts and set each
|
// Create a single allocation to house all of the scripts and set each
|
||||||
// input signature script and output public key script to the
|
// 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]
|
msg.TxIn[i].SignatureScript = scripts[offset:end:end]
|
||||||
offset += scriptSize
|
offset += scriptSize
|
||||||
|
|
||||||
// Return the temporary script buffer to the pool.
|
|
||||||
scriptPool.Return(signatureScript)
|
|
||||||
|
|
||||||
for j := 0; j < len(msg.TxIn[i].Witness); j++ {
|
for j := 0; j < len(msg.TxIn[i].Witness); j++ {
|
||||||
// Copy each item within the witness stack for this
|
// Copy each item within the witness stack for this
|
||||||
// input into the contiguous buffer at the appropriate
|
// 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
|
end := offset + witnessElemSize
|
||||||
msg.TxIn[i].Witness[j] = scripts[offset:end:end]
|
msg.TxIn[i].Witness[j] = scripts[offset:end:end]
|
||||||
offset += witnessElemSize
|
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++ {
|
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
|
end := offset + scriptSize
|
||||||
msg.TxOut[i].PkScript = scripts[offset:end:end]
|
msg.TxOut[i].PkScript = scripts[offset:end:end]
|
||||||
offset += scriptSize
|
offset += scriptSize
|
||||||
|
|
||||||
// Return the temporary script buffer to the pool.
|
|
||||||
scriptPool.Return(pkScript)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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
|
// See Serialize for encoding transactions to be stored to disk, such as in a
|
||||||
// database, as opposed to encoding transactions for the wire.
|
// database, as opposed to encoding transactions for the wire.
|
||||||
func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
|
func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error {
|
||||||
err := binarySerializer.PutUint32(w, littleEndian, uint32(msg.Version))
|
buf := binarySerializer.Borrow()
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,26 +718,26 @@ func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error
|
||||||
}
|
}
|
||||||
|
|
||||||
count := uint64(len(msg.TxIn))
|
count := uint64(len(msg.TxIn))
|
||||||
err = WriteVarInt(w, pver, count)
|
err := WriteVarIntBuf(w, pver, count, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ti := range msg.TxIn {
|
for _, ti := range msg.TxIn {
|
||||||
err = writeTxIn(w, pver, msg.Version, ti)
|
err = writeTxInBuf(w, pver, msg.Version, ti, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
count = uint64(len(msg.TxOut))
|
count = uint64(len(msg.TxOut))
|
||||||
err = WriteVarInt(w, pver, count)
|
err = WriteVarIntBuf(w, pver, count, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, to := range msg.TxOut {
|
for _, to := range msg.TxOut {
|
||||||
err = WriteTxOut(w, pver, msg.Version, to)
|
err = WriteTxOutBuf(w, pver, msg.Version, to, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -775,14 +748,16 @@ func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32, enc MessageEncoding) error
|
||||||
// within the transaction.
|
// within the transaction.
|
||||||
if doWitness {
|
if doWitness {
|
||||||
for _, ti := range msg.TxIn {
|
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 {
|
if err != nil {
|
||||||
return err
|
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
|
// 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.
|
// readOutPointBuf reads the next sequence of bytes from r as an OutPoint.
|
||||||
func readOutPoint(r io.Reader, 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 readOutPointBuf(r io.Reader, pver uint32, version int32, op *OutPoint,
|
||||||
|
buf []byte) error {
|
||||||
|
|
||||||
_, err := io.ReadFull(r, op.Hash[:])
|
_, err := io.ReadFull(r, op.Hash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
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.
|
// 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[:])
|
_, err := w.Write(op.Hash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// 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
|
// memory exhaustion attacks and forced panics through malformed messages. The
|
||||||
// fieldName parameter is only used for the error message so it provides more
|
// fieldName parameter is only used for the error message so it provides more
|
||||||
// context in the error.
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -983,58 +998,96 @@ func readScript(r io.Reader, pver uint32, maxAllowed uint32, fieldName string) (
|
||||||
return nil, messageError("readScript", str)
|
return nil, messageError("readScript", str)
|
||||||
}
|
}
|
||||||
|
|
||||||
b := scriptPool.Borrow(count)
|
_, err = io.ReadFull(r, s[:count])
|
||||||
_, err = io.ReadFull(r, b)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
scriptPool.Return(b)
|
|
||||||
return nil, err
|
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).
|
// (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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ti.SignatureScript, err = readScript(r, pver, MaxMessagePayload,
|
ti.SignatureScript, err = readScriptBuf(r, pver, buf, s, MaxMessagePayload,
|
||||||
"transaction input signature script")
|
"transaction input signature script")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// writeTxInBuf encodes ti to the bitcoin protocol encoding for a transaction
|
||||||
// input (TxIn) to w.
|
// input (TxIn) to w. If b is non-nil, the provided buffer will be used for
|
||||||
func writeTxIn(w io.Writer, pver uint32, version int32, ti *TxIn) error {
|
// serializing small values. Otherwise a buffer will be drawn from the
|
||||||
err := WriteOutPoint(w, pver, version, &ti.PreviousOutPoint)
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = WriteVarBytes(w, pver, ti.SignatureScript)
|
err = WriteVarBytesBuf(w, pver, ti.SignatureScript, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// ReadTxOut reads the next sequence of bytes from r as a transaction output
|
||||||
// (TxOut).
|
// (TxOut).
|
||||||
func ReadTxOut(r io.Reader, pver uint32, version int32, to *TxOut) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
to.Value = int64(littleEndian.Uint64(buf))
|
||||||
|
|
||||||
to.PkScript, err = readScript(r, pver, MaxMessagePayload,
|
to.PkScript, err = readScriptBuf(
|
||||||
"transaction output public key script")
|
r, pver, buf, s, MaxMessagePayload,
|
||||||
|
"transaction output public key script",
|
||||||
|
)
|
||||||
return err
|
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
|
// NOTE: This function is exported in order to allow txscript to compute the
|
||||||
// new sighashes for witness transactions (BIP0143).
|
// new sighashes for witness transactions (BIP0143).
|
||||||
func WriteTxOut(w io.Writer, pver uint32, version int32, to *TxOut) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return WriteVarBytes(w, pver, to.PkScript)
|
return WriteVarBytesBuf(w, pver, to.PkScript, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeTxWitness encodes the bitcoin protocol encoding for a transaction
|
// writeTxWitnessBuf encodes the bitcoin protocol encoding for a transaction
|
||||||
// input's witness into to w.
|
// input's witness into to w. If b is non-nil, the provided buffer will be used
|
||||||
func writeTxWitness(w io.Writer, pver uint32, version int32, wit [][]byte) error {
|
// for serializing small values. Otherwise a buffer will be drawn from the
|
||||||
err := WriteVarInt(w, pver, uint64(len(wit)))
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, item := range wit {
|
for _, item := range wit {
|
||||||
err = WriteVarBytes(w, pver, item)
|
err = WriteVarBytesBuf(w, pver, item, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package wire
|
package wire
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"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
|
// version and whether or not the timestamp is included per ts. Some messages
|
||||||
// like version do not include the timestamp.
|
// like version do not include the timestamp.
|
||||||
func readNetAddress(r io.Reader, pver uint32, na *NetAddress, ts bool) error {
|
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
|
// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
|
||||||
// stop working somewhere around 2106. Also timestamp wasn't added until
|
// stop working somewhere around 2106. Also timestamp wasn't added until
|
||||||
// protocol version >= NetAddressTimeVersion
|
// protocol version >= NetAddressTimeVersion
|
||||||
if ts && pver >= NetAddressTimeVersion {
|
if ts && pver >= NetAddressTimeVersion {
|
||||||
err := readElement(r, (*uint32Time)(&na.Timestamp))
|
if _, err := io.ReadFull(r, buf[:4]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
timestamp = time.Unix(int64(littleEndian.Uint32(buf[:4])), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := readElements(r, &na.Services, &ip)
|
if _, err := io.ReadFull(r, buf); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
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.
|
// Sigh. Bitcoin protocol mixes little and big endian.
|
||||||
port, err := binarySerializer.Uint16(r, bigEndian)
|
if _, err := io.ReadFull(r, buf[:2]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
port = bigEndian.Uint16(buf[:2])
|
||||||
|
|
||||||
*na = NetAddress{
|
*na = NetAddress{
|
||||||
Timestamp: na.Timestamp,
|
Timestamp: timestamp,
|
||||||
Services: na.Services,
|
Services: services,
|
||||||
IP: net.IP(ip[:]),
|
IP: net.IP(ip[:]),
|
||||||
Port: port,
|
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
|
// version and whether or not the timestamp is included per ts. Some messages
|
||||||
// like version do not include the timestamp.
|
// like version do not include the timestamp.
|
||||||
func writeNetAddress(w io.Writer, pver uint32, na *NetAddress, ts bool) error {
|
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
|
// NOTE: The bitcoin protocol uses a uint32 for the timestamp so it will
|
||||||
// stop working somewhere around 2106. Also timestamp wasn't added until
|
// stop working somewhere around 2106. Also timestamp wasn't added until
|
||||||
// until protocol version >= NetAddressTimeVersion.
|
// until protocol version >= NetAddressTimeVersion.
|
||||||
if ts && pver >= NetAddressTimeVersion {
|
if ts && pver >= NetAddressTimeVersion {
|
||||||
err := writeElement(w, uint32(na.Timestamp.Unix()))
|
littleEndian.PutUint32(buf[:4], uint32(na.Timestamp.Unix()))
|
||||||
if err != nil {
|
if _, err := w.Write(buf[:4]); err != nil {
|
||||||
return err
|
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.
|
// Ensure to always write 16 bytes even if the ip is nil.
|
||||||
var ip [16]byte
|
var ip [16]byte
|
||||||
if na.IP != nil {
|
if na.IP != nil {
|
||||||
copy(ip[:], na.IP.To16())
|
copy(ip[:], na.IP.To16())
|
||||||
}
|
}
|
||||||
err := writeElements(w, na.Services, ip)
|
if _, err := w.Write(ip[:]); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sigh. Bitcoin protocol mixes little and big endian.
|
// 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