inv_test.go raw

   1  package btcwire
   2  
   3  import (
   4  	"bytes"
   5  	"errors"
   6  	"io"
   7  	"reflect"
   8  	"testing"
   9  
  10  	"git.smesh.lol/nostrino/pkg/crypto/chainhash"
  11  )
  12  
  13  func TestInvVectTypes(t *testing.T) {
  14  	if InvVectTypeError != 0 || InvVectTypeTx != 1 || InvVectTypeBlock != 2 ||
  15  		InvVectTypeFilteredBlock != 3 || InvVectTypeWitnessTx != 0x40000001 {
  16  		t.Fatalf("inventory type constants changed: %d %d %d %d %#x",
  17  			InvVectTypeError, InvVectTypeTx, InvVectTypeBlock,
  18  			InvVectTypeFilteredBlock, InvVectTypeWitnessTx)
  19  	}
  20  }
  21  
  22  func TestInvListRoundTrip(t *testing.T) {
  23  	types := []uint32{
  24  		InvVectTypeError,
  25  		InvVectTypeTx,
  26  		InvVectTypeBlock,
  27  		InvVectTypeFilteredBlock,
  28  		InvVectTypeWitnessTx,
  29  	}
  30  	var list []InvVect
  31  	for i, typ := range types {
  32  		list = append(list, InvVect{Type: typ, Hash: testHash(byte(0x60 + i))})
  33  	}
  34  	tests := []struct {
  35  		name  string
  36  		value Payload
  37  		zero  func() Payload
  38  	}{
  39  		{"inv", &Inv{InvList: list}, func() Payload { return &Inv{} }},
  40  		{"getdata", &GetData{InvList: list}, func() Payload { return &GetData{} }},
  41  		{"notfound", &NotFound{InvList: list}, func() Payload { return &NotFound{} }},
  42  	}
  43  	for _, tc := range tests {
  44  		t.Run(tc.name, func(t *testing.T) {
  45  			payload, err := tc.value.EncodePayload()
  46  			if err != nil {
  47  				t.Fatalf("EncodePayload: %v", err)
  48  			}
  49  			if got, wantLen := len(payload), 1+len(list)*invVectSize; got != wantLen {
  50  				t.Fatalf("payload length = %d, want %d", got, wantLen)
  51  			}
  52  			// First vector: type little endian, then the hash in wire order.
  53  			if got, want := payload[1:5], []byte{0x00, 0x00, 0x00, 0x00}; !bytes.Equal(got, want) {
  54  				t.Fatalf("first vector type bytes = %x, want %x", got, want)
  55  			}
  56  			if got := payload[5 : 5+chainhash.HashSize]; !bytes.Equal(got, list[0].Hash[:]) {
  57  				t.Fatalf("first vector hash = %x, want %x", got, list[0].Hash)
  58  			}
  59  			decoded := tc.zero()
  60  			if err := decoded.DecodePayload(payload); err != nil {
  61  				t.Fatalf("DecodePayload: %v", err)
  62  			}
  63  			if !reflect.DeepEqual(decoded, tc.value) {
  64  				t.Fatalf("decoded = %+v, want %+v", decoded, tc.value)
  65  			}
  66  		})
  67  	}
  68  }
  69  
  70  func TestInvListEmpty(t *testing.T) {
  71  	payload, err := (&Inv{InvList: []InvVect{}}).EncodePayload()
  72  	if err != nil {
  73  		t.Fatalf("EncodePayload: %v", err)
  74  	}
  75  	if !bytes.Equal(payload, []byte{0x00}) {
  76  		t.Fatalf("payload = %x, want 00", payload)
  77  	}
  78  	var got Inv
  79  	if err := got.DecodePayload(payload); err != nil {
  80  		t.Fatalf("DecodePayload: %v", err)
  81  	}
  82  	if len(got.InvList) != 0 {
  83  		t.Fatalf("decoded %d vectors, want 0", len(got.InvList))
  84  	}
  85  }
  86  
  87  func TestInvListLimits(t *testing.T) {
  88  	tooMany := make([]InvVect, MaxInvPerMsg+1)
  89  	if _, err := (&GetData{InvList: tooMany}).EncodePayload(); !errors.Is(err, ErrTooManyItems) {
  90  		t.Fatalf("EncodePayload error = %v, want ErrTooManyItems", err)
  91  	}
  92  	// 50001 encoded as 0xfd 0x51 0xc3.
  93  	payload := []byte{0xfd, byte((MaxInvPerMsg + 1) & 0xff), byte((MaxInvPerMsg + 1) >> 8)}
  94  	var got NotFound
  95  	if err := got.DecodePayload(payload); !errors.Is(err, ErrTooManyItems) {
  96  		t.Fatalf("DecodePayload error = %v, want ErrTooManyItems", err)
  97  	}
  98  }
  99  
 100  func TestInvListTruncated(t *testing.T) {
 101  	want := &Inv{InvList: []InvVect{
 102  		{Type: InvVectTypeTx, Hash: testHash(0x70)},
 103  		{Type: InvVectTypeBlock, Hash: testHash(0x71)},
 104  	}}
 105  	payload, err := want.EncodePayload()
 106  	if err != nil {
 107  		t.Fatalf("EncodePayload: %v", err)
 108  	}
 109  	for n := 0; n < len(payload); n++ {
 110  		var got Inv
 111  		if err := got.DecodePayload(payload[:n]); err == nil {
 112  			t.Fatalf("decoding %d of %d bytes succeeded", n, len(payload))
 113  		}
 114  	}
 115  	// A count that claims more data than the payload holds is truncated
 116  	// before any allocation is attempted.
 117  	var got Inv
 118  	if err := got.DecodePayload([]byte{0x02, 0x01}); !errors.Is(err, io.ErrUnexpectedEOF) {
 119  		t.Fatalf("error = %v, want io.ErrUnexpectedEOF", err)
 120  	}
 121  }
 122