Support RelayTx param in ver message for 70001+.

This commit adds support for the version message RelayTx parameter for
protocol version 70001+ as added by BIP0037.
This commit is contained in:
David Hill 2014-03-27 15:19:03 -04:00 committed by Dave Collins
parent 8721348051
commit e9a18fb14c
4 changed files with 186 additions and 10 deletions

View file

@ -60,6 +60,19 @@ func readElement(r io.Reader, element interface{}) error {
*e = binary.LittleEndian.Uint64(b) *e = binary.LittleEndian.Uint64(b)
return nil return nil
case *bool:
b := scratch[0:1]
_, err := io.ReadFull(r, b)
if err != nil {
return err
}
if b[0] == 0x00 {
*e = false
} else {
*e = true
}
return nil
// Message header checksum. // Message header checksum.
case *[4]byte: case *[4]byte:
_, err := io.ReadFull(r, e[:]) _, err := io.ReadFull(r, e[:])
@ -179,6 +192,19 @@ func writeElement(w io.Writer, element interface{}) error {
} }
return nil return nil
case bool:
b := scratch[0:1]
if e == true {
b[0] = 0x01
} else {
b[0] = 0x00
}
_, err := w.Write(b)
if err != nil {
return err
}
return nil
// Message header checksum. // Message header checksum.
case [4]byte: case [4]byte:
_, err := w.Write(e[:]) _, err := w.Write(e[:])

View file

@ -76,7 +76,7 @@ func TestMessage(t *testing.T) {
btcnet btcwire.BitcoinNet // Network to use for wire encoding btcnet btcwire.BitcoinNet // Network to use for wire encoding
bytes int // Expected num bytes read/written bytes int // Expected num bytes read/written
}{ }{
{msgVersion, msgVersion, pver, btcwire.MainNet, 121}, {msgVersion, msgVersion, pver, btcwire.MainNet, 122},
{msgVerack, msgVerack, pver, btcwire.MainNet, 24}, {msgVerack, msgVerack, pver, btcwire.MainNet, 24},
{msgGetAddr, msgGetAddr, pver, btcwire.MainNet, 24}, {msgGetAddr, msgGetAddr, pver, btcwire.MainNet, 24},
{msgAddr, msgAddr, pver, btcwire.MainNet, 25}, {msgAddr, msgAddr, pver, btcwire.MainNet, 25},

View file

@ -49,6 +49,9 @@ type MsgVersion struct {
// Last block seen by the generator of the version message. // Last block seen by the generator of the version message.
LastBlock int32 LastBlock int32
// Announce transactions to peer.
RelayTx bool
} }
// HasService returns whether the specified service is supported by the peer // HasService returns whether the specified service is supported by the peer
@ -129,6 +132,14 @@ func (msg *MsgVersion) BtcDecode(r io.Reader, pver uint32) error {
} }
} }
if pver >= BIP0037Version {
err = readElement(r, &msg.RelayTx)
if err != nil {
// Optional
msg.RelayTx = true
}
}
return nil return nil
} }
@ -172,6 +183,12 @@ func (msg *MsgVersion) BtcEncode(w io.Writer, pver uint32) error {
return err return err
} }
if pver >= BIP0037Version {
err = writeElement(w, msg.RelayTx)
if err != nil {
return err
}
}
return nil return nil
} }
@ -189,8 +206,8 @@ func (msg *MsgVersion) MaxPayloadLength(pver uint32) uint32 {
// Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + remote // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + remote
// and local net addresses + nonce 8 bytes + length of user agent (varInt) + // and local net addresses + nonce 8 bytes + length of user agent (varInt) +
// max allowed useragent length + last block 4 bytes. // max allowed useragent length + last block 4 bytes + relay tx 1 byte.
return 32 + (maxNetAddressPayload(pver) * 2) + MaxVarIntPayload + MaxUserAgentLen return 32 + (maxNetAddressPayload(pver) * 2) + MaxVarIntPayload + MaxUserAgentLen + 1
} }
// NewMsgVersion returns a new bitcoin version message that conforms to the // NewMsgVersion returns a new bitcoin version message that conforms to the
@ -210,6 +227,7 @@ func NewMsgVersion(me *NetAddress, you *NetAddress, nonce uint64,
Nonce: nonce, Nonce: nonce,
UserAgent: userAgent, UserAgent: userAgent,
LastBlock: lastBlock, LastBlock: lastBlock,
RelayTx: true,
} }
} }

View file

@ -64,6 +64,10 @@ func TestVersion(t *testing.T) {
t.Errorf("NewMsgVersion: wrong last block - got %v, want %v", t.Errorf("NewMsgVersion: wrong last block - got %v, want %v",
msg.LastBlock, lastBlock) msg.LastBlock, lastBlock)
} }
if msg.RelayTx != true {
t.Errorf("NewMsgVersion: relaytx is not true by default: - got %v, want %v",
msg.RelayTx, true)
}
// Version message should not have any services set by default. // Version message should not have any services set by default.
if msg.Services != 0 { if msg.Services != 0 {
@ -85,8 +89,8 @@ func TestVersion(t *testing.T) {
// Ensure max payload is expected value. // Ensure max payload is expected value.
// Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + // Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes +
// remote and local net addresses + nonce 8 bytes + length of user agent // remote and local net addresses + nonce 8 bytes + length of user agent
// (varInt) + max allowed user agent length + last block 4 bytes. // (varInt) + max allowed user agent length + last block 4 bytes + relay tx 1 byte.
wantPayload := uint32(2101) wantPayload := uint32(2102)
maxPayload := msg.MaxPayloadLength(pver) maxPayload := msg.MaxPayloadLength(pver)
if maxPayload != wantPayload { if maxPayload != wantPayload {
t.Errorf("MaxPayloadLength: wrong max payload length for "+ t.Errorf("MaxPayloadLength: wrong max payload length for "+
@ -157,9 +161,9 @@ func TestVersionWire(t *testing.T) {
}{ }{
// Latest protocol version. // Latest protocol version.
{ {
baseVersion, baseVersion70001,
baseVersion, baseVersion70001,
baseVersionEncoded, baseVersion70001Encoded,
btcwire.ProtocolVersion, btcwire.ProtocolVersion,
}, },
@ -179,6 +183,14 @@ func TestVersionWire(t *testing.T) {
btcwire.BIP0031Version, btcwire.BIP0031Version,
}, },
// Protocol version BIP0037Version.
{
baseVersion70001,
baseVersion70001,
baseVersion70001Encoded,
btcwire.BIP0037Version,
},
// Protocol version NetAddressTimeVersion. // Protocol version NetAddressTimeVersion.
{ {
baseVersion, baseVersion,
@ -293,8 +305,10 @@ func TestVersionWireErrors(t *testing.T) {
// Force error in user agent. // Force error in user agent.
{baseVersion, baseVersionEncoded, pver, 82, io.ErrShortWrite, io.ErrUnexpectedEOF}, {baseVersion, baseVersionEncoded, pver, 82, io.ErrShortWrite, io.ErrUnexpectedEOF},
// Force error in last block. // Force error in last block.
{baseVersion, baseVersionEncoded, pver, 98, io.ErrShortWrite, io.ErrUnexpectedEOF}, {baseVersion, baseVersionEncoded, pver, 97, io.ErrShortWrite, io.EOF},
// Force error due to user agent too big. // Force error in relay tx.
{baseVersion70001, baseVersion70001Encoded, uint32(70001), 101, io.ErrShortWrite, io.EOF},
// Force error due to user agent too big
{exceedUAVer, exceedUAVerEncoded, pver, newLen, btcwireErr, btcwireErr}, {exceedUAVer, exceedUAVerEncoded, pver, newLen, btcwireErr, btcwireErr},
} }
@ -442,6 +456,77 @@ func TestVersionOptionalFields(t *testing.T) {
} }
} }
// TestVersionRelayTx tests the MsgVersion RelayTx API
func TestVersionRelayTx(t *testing.T) {
// Create version message data.
userAgent := "/btcdtest:0.0.1/"
lastBlock := int32(234234)
tcpAddrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333}
me, err := btcwire.NewNetAddress(tcpAddrMe, btcwire.SFNodeNetwork)
if err != nil {
t.Errorf("NewNetAddress: %v", err)
}
tcpAddrYou := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333}
you, err := btcwire.NewNetAddress(tcpAddrYou, btcwire.SFNodeNetwork)
if err != nil {
t.Errorf("NewNetAddress: %v", err)
}
nonce, err := btcwire.RandomUint64()
if err != nil {
t.Errorf("RandomUint64: error generating nonce: %v", err)
}
// Ensure we get the correct data back out.
msg := btcwire.NewMsgVersion(me, you, nonce, userAgent, lastBlock)
// Explictly set RelayTx to false since true by default.
msg.RelayTx = false
// Encode the message to wire format.
var buf bytes.Buffer
err = msg.BtcEncode(&buf, btcwire.BIP0037Version)
if err != nil {
t.Errorf("BtcEncode error %v", err)
}
b := buf.Bytes()
if len(b) != 102 || b[101] != 0x00 {
t.Errorf("Relay Tx is not false")
}
wantBuf := []byte{
0x71, 0x11, 0x01, 0x00, // Protocol version 70001
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork
0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp
// AddrYou -- No timestamp for NetAddress in version message
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x01, // IP 192.168.0.1
0x20, 0x8d, // Port 8333 in big-endian
// AddrMe -- No timestamp for NetAddress in version message
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1
0x20, 0x8d, // Port 8333 in big-endian
0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Nonce
0x10, // Varint for user agent length
0x2f, 0x62, 0x74, 0x63, 0x64, 0x74, 0x65, 0x73,
0x74, 0x3a, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2f, // User agent
0xfa, 0x92, 0x03, 0x00, // Last block
0x00, // Relay tx (false)
}
// Decode the message from wire format.
msg = &btcwire.MsgVersion{}
rbuf := bytes.NewBuffer(wantBuf)
err = msg.BtcDecode(rbuf, btcwire.BIP0037Version)
if err != nil {
t.Errorf("BtcDecode error %v", err)
}
if msg.RelayTx != false {
t.Errorf("Relay Tx is not false")
}
}
// baseVersion is used in the various tests as a baseline MsgVersion. // baseVersion is used in the various tests as a baseline MsgVersion.
var baseVersion = &btcwire.MsgVersion{ var baseVersion = &btcwire.MsgVersion{
ProtocolVersion: 60002, ProtocolVersion: 60002,
@ -486,3 +571,50 @@ var baseVersionEncoded = []byte{
0x74, 0x3a, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2f, // User agent 0x74, 0x3a, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2f, // User agent
0xfa, 0x92, 0x03, 0x00, // Last block 0xfa, 0x92, 0x03, 0x00, // Last block
} }
// baseVersion70001 is used in the various tests as a baseline MsgVersion.
var baseVersion70001 = &btcwire.MsgVersion{
ProtocolVersion: 70001,
Services: btcwire.SFNodeNetwork,
Timestamp: time.Unix(0x495fab29, 0), // 2009-01-03 12:15:05 -0600 CST)
AddrYou: btcwire.NetAddress{
Timestamp: time.Time{}, // Zero value -- no timestamp in version
Services: btcwire.SFNodeNetwork,
IP: net.ParseIP("192.168.0.1"),
Port: 8333,
},
AddrMe: btcwire.NetAddress{
Timestamp: time.Time{}, // Zero value -- no timestamp in version
Services: btcwire.SFNodeNetwork,
IP: net.ParseIP("127.0.0.1"),
Port: 8333,
},
Nonce: 123123, // 0x1e0f3
UserAgent: "/btcdtest:0.0.1/",
LastBlock: 234234, // 0x392fa
RelayTx: true,
}
// baseVersion70001Encoded is the wire encoded bytes for baseVersion using protocol
// version 70001 and is used in the various tests.
var baseVersion70001Encoded = []byte{
0x71, 0x11, 0x01, 0x00, // Protocol version 70001
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork
0x29, 0xab, 0x5f, 0x49, 0x00, 0x00, 0x00, 0x00, // 64-bit Timestamp
// AddrYou -- No timestamp for NetAddress in version message
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xc0, 0xa8, 0x00, 0x01, // IP 192.168.0.1
0x20, 0x8d, // Port 8333 in big-endian
// AddrMe -- No timestamp for NetAddress in version message
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // SFNodeNetwork
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, // IP 127.0.0.1
0x20, 0x8d, // Port 8333 in big-endian
0xf3, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // Nonce
0x10, // Varint for user agent length
0x2f, 0x62, 0x74, 0x63, 0x64, 0x74, 0x65, 0x73,
0x74, 0x3a, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2f, // User agent
0xfa, 0x92, 0x03, 0x00, // Last block
0x01, // Relay tx
}