github.com/btcsuite/btcd@v0.24.0/wire/msginv_test.go (about)

     1  // Copyright (c) 2013-2016 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package wire
     6  
     7  import (
     8  	"bytes"
     9  	"io"
    10  	"reflect"
    11  	"testing"
    12  
    13  	"github.com/btcsuite/btcd/chaincfg/chainhash"
    14  	"github.com/davecgh/go-spew/spew"
    15  )
    16  
    17  // TestInv tests the MsgInv API.
    18  func TestInv(t *testing.T) {
    19  	pver := ProtocolVersion
    20  
    21  	// Ensure the command is expected value.
    22  	wantCmd := "inv"
    23  	msg := NewMsgInv()
    24  	if cmd := msg.Command(); cmd != wantCmd {
    25  		t.Errorf("NewMsgInv: wrong command - got %v want %v",
    26  			cmd, wantCmd)
    27  	}
    28  
    29  	// Ensure max payload is expected value for latest protocol version.
    30  	// Num inventory vectors (varInt) + max allowed inventory vectors.
    31  	wantPayload := uint32(1800009)
    32  	maxPayload := msg.MaxPayloadLength(pver)
    33  	if maxPayload != wantPayload {
    34  		t.Errorf("MaxPayloadLength: wrong max payload length for "+
    35  			"protocol version %d - got %v, want %v", pver,
    36  			maxPayload, wantPayload)
    37  	}
    38  
    39  	// Ensure inventory vectors are added properly.
    40  	hash := chainhash.Hash{}
    41  	iv := NewInvVect(InvTypeBlock, &hash)
    42  	err := msg.AddInvVect(iv)
    43  	if err != nil {
    44  		t.Errorf("AddInvVect: %v", err)
    45  	}
    46  	if msg.InvList[0] != iv {
    47  		t.Errorf("AddInvVect: wrong invvect added - got %v, want %v",
    48  			spew.Sprint(msg.InvList[0]), spew.Sprint(iv))
    49  	}
    50  
    51  	// Ensure adding more than the max allowed inventory vectors per
    52  	// message returns an error.
    53  	for i := 0; i < MaxInvPerMsg; i++ {
    54  		err = msg.AddInvVect(iv)
    55  	}
    56  	if err == nil {
    57  		t.Errorf("AddInvVect: expected error on too many inventory " +
    58  			"vectors not received")
    59  	}
    60  
    61  	// Ensure creating the message with a size hint larger than the max
    62  	// works as expected.
    63  	msg = NewMsgInvSizeHint(MaxInvPerMsg + 1)
    64  	wantCap := MaxInvPerMsg
    65  	if cap(msg.InvList) != wantCap {
    66  		t.Errorf("NewMsgInvSizeHint: wrong cap for size hint - "+
    67  			"got %v, want %v", cap(msg.InvList), wantCap)
    68  	}
    69  }
    70  
    71  // TestInvWire tests the MsgInv wire encode and decode for various numbers
    72  // of inventory vectors and protocol versions.
    73  func TestInvWire(t *testing.T) {
    74  	// Block 203707 hash.
    75  	hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc"
    76  	blockHash, err := chainhash.NewHashFromStr(hashStr)
    77  	if err != nil {
    78  		t.Errorf("NewHashFromStr: %v", err)
    79  	}
    80  
    81  	// Transaction 1 of Block 203707 hash.
    82  	hashStr = "d28a3dc7392bf00a9855ee93dd9a81eff82a2c4fe57fbd42cfe71b487accfaf0"
    83  	txHash, err := chainhash.NewHashFromStr(hashStr)
    84  	if err != nil {
    85  		t.Errorf("NewHashFromStr: %v", err)
    86  	}
    87  
    88  	iv := NewInvVect(InvTypeBlock, blockHash)
    89  	iv2 := NewInvVect(InvTypeTx, txHash)
    90  
    91  	// Empty inv message.
    92  	NoInv := NewMsgInv()
    93  	NoInvEncoded := []byte{
    94  		0x00, // Varint for number of inventory vectors
    95  	}
    96  
    97  	// Inv message with multiple inventory vectors.
    98  	MultiInv := NewMsgInv()
    99  	MultiInv.AddInvVect(iv)
   100  	MultiInv.AddInvVect(iv2)
   101  	MultiInvEncoded := []byte{
   102  		0x02,                   // Varint for number of inv vectors
   103  		0x02, 0x00, 0x00, 0x00, // InvTypeBlock
   104  		0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7,
   105  		0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b,
   106  		0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b,
   107  		0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash
   108  		0x01, 0x00, 0x00, 0x00, // InvTypeTx
   109  		0xf0, 0xfa, 0xcc, 0x7a, 0x48, 0x1b, 0xe7, 0xcf,
   110  		0x42, 0xbd, 0x7f, 0xe5, 0x4f, 0x2c, 0x2a, 0xf8,
   111  		0xef, 0x81, 0x9a, 0xdd, 0x93, 0xee, 0x55, 0x98,
   112  		0x0a, 0xf0, 0x2b, 0x39, 0xc7, 0x3d, 0x8a, 0xd2, // Tx 1 of block 203707 hash
   113  	}
   114  
   115  	tests := []struct {
   116  		in   *MsgInv         // Message to encode
   117  		out  *MsgInv         // Expected decoded message
   118  		buf  []byte          // Wire encoding pver uint32
   119  		pver uint32          // Protocol version for wire encoding
   120  		enc  MessageEncoding // Message encodinf format
   121  	}{
   122  		// Latest protocol version with no inv vectors.
   123  		{
   124  			NoInv,
   125  			NoInv,
   126  			NoInvEncoded,
   127  			ProtocolVersion,
   128  			BaseEncoding,
   129  		},
   130  
   131  		// Latest protocol version with multiple inv vectors.
   132  		{
   133  			MultiInv,
   134  			MultiInv,
   135  			MultiInvEncoded,
   136  			ProtocolVersion,
   137  			BaseEncoding,
   138  		},
   139  
   140  		// Protocol version BIP0035Version no inv vectors.
   141  		{
   142  			NoInv,
   143  			NoInv,
   144  			NoInvEncoded,
   145  			BIP0035Version,
   146  			BaseEncoding,
   147  		},
   148  
   149  		// Protocol version BIP0035Version with multiple inv vectors.
   150  		{
   151  			MultiInv,
   152  			MultiInv,
   153  			MultiInvEncoded,
   154  			BIP0035Version,
   155  			BaseEncoding,
   156  		},
   157  
   158  		// Protocol version BIP0031Version no inv vectors.
   159  		{
   160  			NoInv,
   161  			NoInv,
   162  			NoInvEncoded,
   163  			BIP0031Version,
   164  			BaseEncoding,
   165  		},
   166  
   167  		// Protocol version BIP0031Version with multiple inv vectors.
   168  		{
   169  			MultiInv,
   170  			MultiInv,
   171  			MultiInvEncoded,
   172  			BIP0031Version,
   173  			BaseEncoding,
   174  		},
   175  
   176  		// Protocol version NetAddressTimeVersion no inv vectors.
   177  		{
   178  			NoInv,
   179  			NoInv,
   180  			NoInvEncoded,
   181  			NetAddressTimeVersion,
   182  			BaseEncoding,
   183  		},
   184  
   185  		// Protocol version NetAddressTimeVersion with multiple inv vectors.
   186  		{
   187  			MultiInv,
   188  			MultiInv,
   189  			MultiInvEncoded,
   190  			NetAddressTimeVersion,
   191  			BaseEncoding,
   192  		},
   193  
   194  		// Protocol version MultipleAddressVersion no inv vectors.
   195  		{
   196  			NoInv,
   197  			NoInv,
   198  			NoInvEncoded,
   199  			MultipleAddressVersion,
   200  			BaseEncoding,
   201  		},
   202  
   203  		// Protocol version MultipleAddressVersion with multiple inv vectors.
   204  		{
   205  			MultiInv,
   206  			MultiInv,
   207  			MultiInvEncoded,
   208  			MultipleAddressVersion,
   209  			BaseEncoding,
   210  		},
   211  	}
   212  
   213  	t.Logf("Running %d tests", len(tests))
   214  	for i, test := range tests {
   215  		// Encode the message to wire format.
   216  		var buf bytes.Buffer
   217  		err := test.in.BtcEncode(&buf, test.pver, test.enc)
   218  		if err != nil {
   219  			t.Errorf("BtcEncode #%d error %v", i, err)
   220  			continue
   221  		}
   222  		if !bytes.Equal(buf.Bytes(), test.buf) {
   223  			t.Errorf("BtcEncode #%d\n got: %s want: %s", i,
   224  				spew.Sdump(buf.Bytes()), spew.Sdump(test.buf))
   225  			continue
   226  		}
   227  
   228  		// Decode the message from wire format.
   229  		var msg MsgInv
   230  		rbuf := bytes.NewReader(test.buf)
   231  		err = msg.BtcDecode(rbuf, test.pver, test.enc)
   232  		if err != nil {
   233  			t.Errorf("BtcDecode #%d error %v", i, err)
   234  			continue
   235  		}
   236  		if !reflect.DeepEqual(&msg, test.out) {
   237  			t.Errorf("BtcDecode #%d\n got: %s want: %s", i,
   238  				spew.Sdump(msg), spew.Sdump(test.out))
   239  			continue
   240  		}
   241  	}
   242  }
   243  
   244  // TestInvWireErrors performs negative tests against wire encode and decode
   245  // of MsgInv to confirm error paths work correctly.
   246  func TestInvWireErrors(t *testing.T) {
   247  	pver := ProtocolVersion
   248  	wireErr := &MessageError{}
   249  
   250  	// Block 203707 hash.
   251  	hashStr := "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc"
   252  	blockHash, err := chainhash.NewHashFromStr(hashStr)
   253  	if err != nil {
   254  		t.Errorf("NewHashFromStr: %v", err)
   255  	}
   256  
   257  	iv := NewInvVect(InvTypeBlock, blockHash)
   258  
   259  	// Base inv message used to induce errors.
   260  	baseInv := NewMsgInv()
   261  	baseInv.AddInvVect(iv)
   262  	baseInvEncoded := []byte{
   263  		0x02,                   // Varint for number of inv vectors
   264  		0x02, 0x00, 0x00, 0x00, // InvTypeBlock
   265  		0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7,
   266  		0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b,
   267  		0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b,
   268  		0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Block 203707 hash
   269  	}
   270  
   271  	// Inv message that forces an error by having more than the max allowed
   272  	// inv vectors.
   273  	maxInv := NewMsgInv()
   274  	for i := 0; i < MaxInvPerMsg; i++ {
   275  		maxInv.AddInvVect(iv)
   276  	}
   277  	maxInv.InvList = append(maxInv.InvList, iv)
   278  	maxInvEncoded := []byte{
   279  		0xfd, 0x51, 0xc3, // Varint for number of inv vectors (50001)
   280  	}
   281  
   282  	tests := []struct {
   283  		in       *MsgInv         // Value to encode
   284  		buf      []byte          // Wire encoding
   285  		pver     uint32          // Protocol version for wire encoding
   286  		enc      MessageEncoding // Message encoding format
   287  		max      int             // Max size of fixed buffer to induce errors
   288  		writeErr error           // Expected write error
   289  		readErr  error           // Expected read error
   290  	}{
   291  		// Latest protocol version with intentional read/write errors.
   292  		// Force error in inventory vector count
   293  		{baseInv, baseInvEncoded, pver, BaseEncoding, 0, io.ErrShortWrite, io.EOF},
   294  		// Force error in inventory list.
   295  		{baseInv, baseInvEncoded, pver, BaseEncoding, 1, io.ErrShortWrite, io.EOF},
   296  		// Force error with greater than max inventory vectors.
   297  		{maxInv, maxInvEncoded, pver, BaseEncoding, 3, wireErr, wireErr},
   298  	}
   299  
   300  	t.Logf("Running %d tests", len(tests))
   301  	for i, test := range tests {
   302  		// Encode to wire format.
   303  		w := newFixedWriter(test.max)
   304  		err := test.in.BtcEncode(w, test.pver, test.enc)
   305  		if reflect.TypeOf(err) != reflect.TypeOf(test.writeErr) {
   306  			t.Errorf("BtcEncode #%d wrong error got: %v, want: %v",
   307  				i, err, test.writeErr)
   308  			continue
   309  		}
   310  
   311  		// For errors which are not of type MessageError, check them for
   312  		// equality.
   313  		if _, ok := err.(*MessageError); !ok {
   314  			if err != test.writeErr {
   315  				t.Errorf("BtcEncode #%d wrong error got: %v, "+
   316  					"want: %v", i, err, test.writeErr)
   317  				continue
   318  			}
   319  		}
   320  
   321  		// Decode from wire format.
   322  		var msg MsgInv
   323  		r := newFixedReader(test.max, test.buf)
   324  		err = msg.BtcDecode(r, test.pver, test.enc)
   325  		if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) {
   326  			t.Errorf("BtcDecode #%d wrong error got: %v, want: %v",
   327  				i, err, test.readErr)
   328  			continue
   329  		}
   330  
   331  		// For errors which are not of type MessageError, check them for
   332  		// equality.
   333  		if _, ok := err.(*MessageError); !ok {
   334  			if err != test.readErr {
   335  				t.Errorf("BtcDecode #%d wrong error got: %v, "+
   336  					"want: %v", i, err, test.readErr)
   337  				continue
   338  			}
   339  		}
   340  
   341  	}
   342  }