github.com/btcsuite/btcd@v0.24.0/wire/message_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  	"encoding/binary"
    10  	"io"
    11  	"net"
    12  	"reflect"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/btcsuite/btcd/chaincfg/chainhash"
    17  	"github.com/davecgh/go-spew/spew"
    18  )
    19  
    20  // makeHeader is a convenience function to make a message header in the form of
    21  // a byte slice.  It is used to force errors when reading messages.
    22  func makeHeader(btcnet BitcoinNet, command string,
    23  	payloadLen uint32, checksum uint32) []byte {
    24  
    25  	// The length of a bitcoin message header is 24 bytes.
    26  	// 4 byte magic number of the bitcoin network + 12 byte command + 4 byte
    27  	// payload length + 4 byte checksum.
    28  	buf := make([]byte, 24)
    29  	binary.LittleEndian.PutUint32(buf, uint32(btcnet))
    30  	copy(buf[4:], []byte(command))
    31  	binary.LittleEndian.PutUint32(buf[16:], payloadLen)
    32  	binary.LittleEndian.PutUint32(buf[20:], checksum)
    33  	return buf
    34  }
    35  
    36  // TestMessage tests the Read/WriteMessage and Read/WriteMessageN API.
    37  func TestMessage(t *testing.T) {
    38  	pver := ProtocolVersion
    39  
    40  	// Create the various types of messages to test.
    41  
    42  	// MsgVersion.
    43  	addrYou := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 8333}
    44  	you := NewNetAddress(addrYou, SFNodeNetwork)
    45  	you.Timestamp = time.Time{} // Version message has zero value timestamp.
    46  	addrMe := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333}
    47  	me := NewNetAddress(addrMe, SFNodeNetwork)
    48  	me.Timestamp = time.Time{} // Version message has zero value timestamp.
    49  	msgVersion := NewMsgVersion(me, you, 123123, 0)
    50  
    51  	msgVerack := NewMsgVerAck()
    52  	msgGetAddr := NewMsgGetAddr()
    53  	msgAddr := NewMsgAddr()
    54  	msgGetBlocks := NewMsgGetBlocks(&chainhash.Hash{})
    55  	msgBlock := &blockOne
    56  	msgInv := NewMsgInv()
    57  	msgGetData := NewMsgGetData()
    58  	msgNotFound := NewMsgNotFound()
    59  	msgTx := NewMsgTx(1)
    60  	msgPing := NewMsgPing(123123)
    61  	msgPong := NewMsgPong(123123)
    62  	msgGetHeaders := NewMsgGetHeaders()
    63  	msgHeaders := NewMsgHeaders()
    64  	msgAlert := NewMsgAlert([]byte("payload"), []byte("signature"))
    65  	msgMemPool := NewMsgMemPool()
    66  	msgFilterAdd := NewMsgFilterAdd([]byte{0x01})
    67  	msgFilterClear := NewMsgFilterClear()
    68  	msgFilterLoad := NewMsgFilterLoad([]byte{0x01}, 10, 0, BloomUpdateNone)
    69  	bh := NewBlockHeader(1, &chainhash.Hash{}, &chainhash.Hash{}, 0, 0)
    70  	msgMerkleBlock := NewMsgMerkleBlock(bh)
    71  	msgReject := NewMsgReject("block", RejectDuplicate, "duplicate block")
    72  	msgGetCFilters := NewMsgGetCFilters(GCSFilterRegular, 0, &chainhash.Hash{})
    73  	msgGetCFHeaders := NewMsgGetCFHeaders(GCSFilterRegular, 0, &chainhash.Hash{})
    74  	msgGetCFCheckpt := NewMsgGetCFCheckpt(GCSFilterRegular, &chainhash.Hash{})
    75  	msgCFilter := NewMsgCFilter(GCSFilterRegular, &chainhash.Hash{},
    76  		[]byte("payload"))
    77  	msgCFHeaders := NewMsgCFHeaders()
    78  	msgCFCheckpt := NewMsgCFCheckpt(GCSFilterRegular, &chainhash.Hash{}, 0)
    79  
    80  	tests := []struct {
    81  		in     Message    // Value to encode
    82  		out    Message    // Expected decoded value
    83  		pver   uint32     // Protocol version for wire encoding
    84  		btcnet BitcoinNet // Network to use for wire encoding
    85  		bytes  int        // Expected num bytes read/written
    86  	}{
    87  		{msgVersion, msgVersion, pver, MainNet, 125},
    88  		{msgVerack, msgVerack, pver, MainNet, 24},
    89  		{msgGetAddr, msgGetAddr, pver, MainNet, 24},
    90  		{msgAddr, msgAddr, pver, MainNet, 25},
    91  		{msgGetBlocks, msgGetBlocks, pver, MainNet, 61},
    92  		{msgBlock, msgBlock, pver, MainNet, 239},
    93  		{msgInv, msgInv, pver, MainNet, 25},
    94  		{msgGetData, msgGetData, pver, MainNet, 25},
    95  		{msgNotFound, msgNotFound, pver, MainNet, 25},
    96  		{msgTx, msgTx, pver, MainNet, 34},
    97  		{msgPing, msgPing, pver, MainNet, 32},
    98  		{msgPong, msgPong, pver, MainNet, 32},
    99  		{msgGetHeaders, msgGetHeaders, pver, MainNet, 61},
   100  		{msgHeaders, msgHeaders, pver, MainNet, 25},
   101  		{msgAlert, msgAlert, pver, MainNet, 42},
   102  		{msgMemPool, msgMemPool, pver, MainNet, 24},
   103  		{msgFilterAdd, msgFilterAdd, pver, MainNet, 26},
   104  		{msgFilterClear, msgFilterClear, pver, MainNet, 24},
   105  		{msgFilterLoad, msgFilterLoad, pver, MainNet, 35},
   106  		{msgMerkleBlock, msgMerkleBlock, pver, MainNet, 110},
   107  		{msgReject, msgReject, pver, MainNet, 79},
   108  		{msgGetCFilters, msgGetCFilters, pver, MainNet, 61},
   109  		{msgGetCFHeaders, msgGetCFHeaders, pver, MainNet, 61},
   110  		{msgGetCFCheckpt, msgGetCFCheckpt, pver, MainNet, 57},
   111  		{msgCFilter, msgCFilter, pver, MainNet, 65},
   112  		{msgCFHeaders, msgCFHeaders, pver, MainNet, 90},
   113  		{msgCFCheckpt, msgCFCheckpt, pver, MainNet, 58},
   114  	}
   115  
   116  	t.Logf("Running %d tests", len(tests))
   117  	for i, test := range tests {
   118  		// Encode to wire format.
   119  		var buf bytes.Buffer
   120  		nw, err := WriteMessageN(&buf, test.in, test.pver, test.btcnet)
   121  		if err != nil {
   122  			t.Errorf("WriteMessage #%d error %v", i, err)
   123  			continue
   124  		}
   125  
   126  		// Ensure the number of bytes written match the expected value.
   127  		if nw != test.bytes {
   128  			t.Errorf("WriteMessage #%d unexpected num bytes "+
   129  				"written - got %d, want %d", i, nw, test.bytes)
   130  		}
   131  
   132  		// Decode from wire format.
   133  		rbuf := bytes.NewReader(buf.Bytes())
   134  		nr, msg, _, err := ReadMessageN(rbuf, test.pver, test.btcnet)
   135  		if err != nil {
   136  			t.Errorf("ReadMessage #%d error %v, msg %v", i, err,
   137  				spew.Sdump(msg))
   138  			continue
   139  		}
   140  		if !reflect.DeepEqual(msg, test.out) {
   141  			t.Errorf("ReadMessage #%d\n got: %v want: %v", i,
   142  				spew.Sdump(msg), spew.Sdump(test.out))
   143  			continue
   144  		}
   145  
   146  		// Ensure the number of bytes read match the expected value.
   147  		if nr != test.bytes {
   148  			t.Errorf("ReadMessage #%d unexpected num bytes read - "+
   149  				"got %d, want %d", i, nr, test.bytes)
   150  		}
   151  	}
   152  
   153  	// Do the same thing for Read/WriteMessage, but ignore the bytes since
   154  	// they don't return them.
   155  	t.Logf("Running %d tests", len(tests))
   156  	for i, test := range tests {
   157  		// Encode to wire format.
   158  		var buf bytes.Buffer
   159  		err := WriteMessage(&buf, test.in, test.pver, test.btcnet)
   160  		if err != nil {
   161  			t.Errorf("WriteMessage #%d error %v", i, err)
   162  			continue
   163  		}
   164  
   165  		// Decode from wire format.
   166  		rbuf := bytes.NewReader(buf.Bytes())
   167  		msg, _, err := ReadMessage(rbuf, test.pver, test.btcnet)
   168  		if err != nil {
   169  			t.Errorf("ReadMessage #%d error %v, msg %v", i, err,
   170  				spew.Sdump(msg))
   171  			continue
   172  		}
   173  		if !reflect.DeepEqual(msg, test.out) {
   174  			t.Errorf("ReadMessage #%d\n got: %v want: %v", i,
   175  				spew.Sdump(msg), spew.Sdump(test.out))
   176  			continue
   177  		}
   178  	}
   179  }
   180  
   181  // TestReadMessageWireErrors performs negative tests against wire decoding into
   182  // concrete messages to confirm error paths work correctly.
   183  func TestReadMessageWireErrors(t *testing.T) {
   184  	pver := ProtocolVersion
   185  	btcnet := MainNet
   186  
   187  	// Ensure message errors are as expected with no function specified.
   188  	wantErr := "something bad happened"
   189  	testErr := MessageError{Description: wantErr}
   190  	if testErr.Error() != wantErr {
   191  		t.Errorf("MessageError: wrong error - got %v, want %v",
   192  			testErr.Error(), wantErr)
   193  	}
   194  
   195  	// Ensure message errors are as expected with a function specified.
   196  	wantFunc := "foo"
   197  	testErr = MessageError{Func: wantFunc, Description: wantErr}
   198  	if testErr.Error() != wantFunc+": "+wantErr {
   199  		t.Errorf("MessageError: wrong error - got %v, want %v",
   200  			testErr.Error(), wantErr)
   201  	}
   202  
   203  	// Wire encoded bytes for main and testnet3 networks magic identifiers.
   204  	testNet3Bytes := makeHeader(TestNet3, "", 0, 0)
   205  
   206  	// Wire encoded bytes for a message that exceeds max overall message
   207  	// length.
   208  	mpl := uint32(MaxMessagePayload)
   209  	exceedMaxPayloadBytes := makeHeader(btcnet, "getaddr", mpl+1, 0)
   210  
   211  	// Wire encoded bytes for a command which is invalid utf-8.
   212  	badCommandBytes := makeHeader(btcnet, "bogus", 0, 0)
   213  	badCommandBytes[4] = 0x81
   214  
   215  	// Wire encoded bytes for a command which is valid, but not supported.
   216  	unsupportedCommandBytes := makeHeader(btcnet, "bogus", 0, 0)
   217  
   218  	// Wire encoded bytes for a message which exceeds the max payload for
   219  	// a specific message type.
   220  	exceedTypePayloadBytes := makeHeader(btcnet, "getaddr", 1, 0)
   221  
   222  	// Wire encoded bytes for a message which does not deliver the full
   223  	// payload according to the header length.
   224  	shortPayloadBytes := makeHeader(btcnet, "version", 115, 0)
   225  
   226  	// Wire encoded bytes for a message with a bad checksum.
   227  	badChecksumBytes := makeHeader(btcnet, "version", 2, 0xbeef)
   228  	badChecksumBytes = append(badChecksumBytes, []byte{0x0, 0x0}...)
   229  
   230  	// Wire encoded bytes for a message which has a valid header, but is
   231  	// the wrong format.  An addr starts with a varint of the number of
   232  	// contained in the message.  Claim there is two, but don't provide
   233  	// them.  At the same time, forge the header fields so the message is
   234  	// otherwise accurate.
   235  	badMessageBytes := makeHeader(btcnet, "addr", 1, 0xeaadc31c)
   236  	badMessageBytes = append(badMessageBytes, 0x2)
   237  
   238  	// Wire encoded bytes for a message which the header claims has 15k
   239  	// bytes of data to discard.
   240  	discardBytes := makeHeader(btcnet, "bogus", 15*1024, 0)
   241  
   242  	tests := []struct {
   243  		buf     []byte     // Wire encoding
   244  		pver    uint32     // Protocol version for wire encoding
   245  		btcnet  BitcoinNet // Bitcoin network for wire encoding
   246  		max     int        // Max size of fixed buffer to induce errors
   247  		readErr error      // Expected read error
   248  		bytes   int        // Expected num bytes read
   249  	}{
   250  		// Latest protocol version with intentional read errors.
   251  
   252  		// Short header.
   253  		{
   254  			[]byte{},
   255  			pver,
   256  			btcnet,
   257  			0,
   258  			io.EOF,
   259  			0,
   260  		},
   261  
   262  		// Wrong network.  Want MainNet, but giving TestNet3.
   263  		{
   264  			testNet3Bytes,
   265  			pver,
   266  			btcnet,
   267  			len(testNet3Bytes),
   268  			&MessageError{},
   269  			24,
   270  		},
   271  
   272  		// Exceed max overall message payload length.
   273  		{
   274  			exceedMaxPayloadBytes,
   275  			pver,
   276  			btcnet,
   277  			len(exceedMaxPayloadBytes),
   278  			&MessageError{},
   279  			24,
   280  		},
   281  
   282  		// Invalid UTF-8 command.
   283  		{
   284  			badCommandBytes,
   285  			pver,
   286  			btcnet,
   287  			len(badCommandBytes),
   288  			&MessageError{},
   289  			24,
   290  		},
   291  
   292  		// Valid, but unsupported command.
   293  		{
   294  			unsupportedCommandBytes,
   295  			pver,
   296  			btcnet,
   297  			len(unsupportedCommandBytes),
   298  			ErrUnknownMessage,
   299  			24,
   300  		},
   301  
   302  		// Exceed max allowed payload for a message of a specific type.
   303  		{
   304  			exceedTypePayloadBytes,
   305  			pver,
   306  			btcnet,
   307  			len(exceedTypePayloadBytes),
   308  			&MessageError{},
   309  			24,
   310  		},
   311  
   312  		// Message with a payload shorter than the header indicates.
   313  		{
   314  			shortPayloadBytes,
   315  			pver,
   316  			btcnet,
   317  			len(shortPayloadBytes),
   318  			io.EOF,
   319  			24,
   320  		},
   321  
   322  		// Message with a bad checksum.
   323  		{
   324  			badChecksumBytes,
   325  			pver,
   326  			btcnet,
   327  			len(badChecksumBytes),
   328  			&MessageError{},
   329  			26,
   330  		},
   331  
   332  		// Message with a valid header, but wrong format.
   333  		{
   334  			badMessageBytes,
   335  			pver,
   336  			btcnet,
   337  			len(badMessageBytes),
   338  			io.EOF,
   339  			25,
   340  		},
   341  
   342  		// 15k bytes of data to discard.
   343  		{
   344  			discardBytes,
   345  			pver,
   346  			btcnet,
   347  			len(discardBytes),
   348  			ErrUnknownMessage,
   349  			24,
   350  		},
   351  	}
   352  
   353  	t.Logf("Running %d tests", len(tests))
   354  	for i, test := range tests {
   355  		// Decode from wire format.
   356  		r := newFixedReader(test.max, test.buf)
   357  		nr, _, _, err := ReadMessageN(r, test.pver, test.btcnet)
   358  		if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) {
   359  			t.Errorf("ReadMessage #%d wrong error got: %v <%T>, "+
   360  				"want: %T", i, err, err, test.readErr)
   361  			continue
   362  		}
   363  
   364  		// Ensure the number of bytes written match the expected value.
   365  		if nr != test.bytes {
   366  			t.Errorf("ReadMessage #%d unexpected num bytes read - "+
   367  				"got %d, want %d", i, nr, test.bytes)
   368  		}
   369  
   370  		// For errors which are not of type MessageError, check them for
   371  		// equality.
   372  		if _, ok := err.(*MessageError); !ok {
   373  			if err != test.readErr {
   374  				t.Errorf("ReadMessage #%d wrong error got: %v <%T>, "+
   375  					"want: %v <%T>", i, err, err,
   376  					test.readErr, test.readErr)
   377  				continue
   378  			}
   379  		}
   380  	}
   381  }
   382  
   383  // TestWriteMessageWireErrors performs negative tests against wire encoding from
   384  // concrete messages to confirm error paths work correctly.
   385  func TestWriteMessageWireErrors(t *testing.T) {
   386  	pver := ProtocolVersion
   387  	btcnet := MainNet
   388  	wireErr := &MessageError{}
   389  
   390  	// Fake message with a command that is too long.
   391  	badCommandMsg := &fakeMessage{command: "somethingtoolong"}
   392  
   393  	// Fake message with a problem during encoding
   394  	encodeErrMsg := &fakeMessage{forceEncodeErr: true}
   395  
   396  	// Fake message that has payload which exceeds max overall message size.
   397  	exceedOverallPayload := make([]byte, MaxMessagePayload+1)
   398  	exceedOverallPayloadErrMsg := &fakeMessage{payload: exceedOverallPayload}
   399  
   400  	// Fake message that has payload which exceeds max allowed per message.
   401  	exceedPayload := make([]byte, 1)
   402  	exceedPayloadErrMsg := &fakeMessage{payload: exceedPayload, forceLenErr: true}
   403  
   404  	// Fake message that is used to force errors in the header and payload
   405  	// writes.
   406  	bogusPayload := []byte{0x01, 0x02, 0x03, 0x04}
   407  	bogusMsg := &fakeMessage{command: "bogus", payload: bogusPayload}
   408  
   409  	tests := []struct {
   410  		msg    Message    // Message to encode
   411  		pver   uint32     // Protocol version for wire encoding
   412  		btcnet BitcoinNet // Bitcoin network for wire encoding
   413  		max    int        // Max size of fixed buffer to induce errors
   414  		err    error      // Expected error
   415  		bytes  int        // Expected num bytes written
   416  	}{
   417  		// Command too long.
   418  		{badCommandMsg, pver, btcnet, 0, wireErr, 0},
   419  		// Force error in payload encode.
   420  		{encodeErrMsg, pver, btcnet, 0, wireErr, 0},
   421  		// Force error due to exceeding max overall message payload size.
   422  		{exceedOverallPayloadErrMsg, pver, btcnet, 0, wireErr, 0},
   423  		// Force error due to exceeding max payload for message type.
   424  		{exceedPayloadErrMsg, pver, btcnet, 0, wireErr, 0},
   425  		// Force error in header write.
   426  		{bogusMsg, pver, btcnet, 0, io.ErrShortWrite, 0},
   427  		// Force error in payload write.
   428  		{bogusMsg, pver, btcnet, 24, io.ErrShortWrite, 24},
   429  	}
   430  
   431  	t.Logf("Running %d tests", len(tests))
   432  	for i, test := range tests {
   433  		// Encode wire format.
   434  		w := newFixedWriter(test.max)
   435  		nw, err := WriteMessageN(w, test.msg, test.pver, test.btcnet)
   436  		if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
   437  			t.Errorf("WriteMessage #%d wrong error got: %v <%T>, "+
   438  				"want: %T", i, err, err, test.err)
   439  			continue
   440  		}
   441  
   442  		// Ensure the number of bytes written match the expected value.
   443  		if nw != test.bytes {
   444  			t.Errorf("WriteMessage #%d unexpected num bytes "+
   445  				"written - got %d, want %d", i, nw, test.bytes)
   446  		}
   447  
   448  		// For errors which are not of type MessageError, check them for
   449  		// equality.
   450  		if _, ok := err.(*MessageError); !ok {
   451  			if err != test.err {
   452  				t.Errorf("ReadMessage #%d wrong error got: %v <%T>, "+
   453  					"want: %v <%T>", i, err, err,
   454  					test.err, test.err)
   455  				continue
   456  			}
   457  		}
   458  	}
   459  }