msginv_test.go raw

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