robustness_test.go raw

   1  package btcwire
   2  
   3  import (
   4  	"bytes"
   5  	"encoding/binary"
   6  	"testing"
   7  )
   8  
   9  // TestDecodersNeverPanic feeds deterministic pseudo-random bytes to every
  10  // decoder. Errors are expected; panics and hangs are not.
  11  func TestDecodersNeverPanic(t *testing.T) {
  12  	decoders := []struct {
  13  		name   string
  14  		decode func([]byte) error
  15  	}{
  16  		{"version", func(b []byte) error { var v Version; return v.DecodePayload(b) }},
  17  		{"verack", func(b []byte) error { var v VerAck; return v.DecodePayload(b) }},
  18  		{"sendheaders", func(b []byte) error { var v SendHeaders; return v.DecodePayload(b) }},
  19  		{"wtxidrelay", func(b []byte) error { var v WtxidRelay; return v.DecodePayload(b) }},
  20  		{"sendaddrv2", func(b []byte) error { var v SendAddrV2; return v.DecodePayload(b) }},
  21  		{"ping", func(b []byte) error { var v Ping; return v.DecodePayload(b) }},
  22  		{"pong", func(b []byte) error { var v Pong; return v.DecodePayload(b) }},
  23  		{"feefilter", func(b []byte) error { var v FeeFilter; return v.DecodePayload(b) }},
  24  		{"getheaders", func(b []byte) error { var v GetHeaders; return v.DecodePayload(b) }},
  25  		{"headers", func(b []byte) error { var v Headers; return v.DecodePayload(b) }},
  26  		{"getcfheaders", func(b []byte) error { var v GetCFHeaders; return v.DecodePayload(b) }},
  27  		{"cfheaders", func(b []byte) error { var v CFHeaders; return v.DecodePayload(b) }},
  28  		{"getcfilters", func(b []byte) error { var v GetCFilters; return v.DecodePayload(b) }},
  29  		{"cfilter", func(b []byte) error { var v CFilter; return v.DecodePayload(b) }},
  30  		{"getcfcheckpt", func(b []byte) error { var v GetCFCheckpt; return v.DecodePayload(b) }},
  31  		{"cfcheckpt", func(b []byte) error { var v CFCheckpt; return v.DecodePayload(b) }},
  32  		{"inv", func(b []byte) error { var v Inv; return v.DecodePayload(b) }},
  33  		{"getdata", func(b []byte) error { var v GetData; return v.DecodePayload(b) }},
  34  		{"notfound", func(b []byte) error { var v NotFound; return v.DecodePayload(b) }},
  35  		{"tx", func(b []byte) error { var v Tx; return v.DecodePayload(b) }},
  36  	}
  37  
  38  	// xorshift64 keeps the test deterministic and dependency free.
  39  	var state uint64 = 0x9e3779b97f4a7c15
  40  	next := func() byte {
  41  		state ^= state << 13
  42  		state ^= state >> 7
  43  		state ^= state << 17
  44  		return byte(state)
  45  	}
  46  	for length := 0; length < 160; length++ {
  47  		buf := make([]byte, length)
  48  		for i := range buf {
  49  			buf[i] = next()
  50  		}
  51  		for _, decoder := range decoders {
  52  			// The only contract is that decoding random bytes does not
  53  			// panic.
  54  			_ = decoder.decode(buf)
  55  		}
  56  
  57  		// A frame whose magic is correct but whose command, length, and
  58  		// checksum are random exercises the framing validation paths.
  59  		frame := make([]byte, MessageHeaderSize+length)
  60  		for i := range frame {
  61  			frame[i] = next()
  62  		}
  63  		binary.BigEndian.PutUint32(frame[0:4], MainNet)
  64  		// Use the actual payload length so the decoder only allocates the
  65  		// bytes the frame really carries.
  66  		binary.LittleEndian.PutUint32(frame[16:20], uint32(length))
  67  		_, _ = DecodeMessage(MainNet, bytes.NewReader(frame))
  68  
  69  		// The same frame under the wrong network must fail on the magic.
  70  		if _, err := DecodeMessage(TestNet3, bytes.NewReader(frame)); err == nil {
  71  			t.Fatalf("frame with mainnet magic decoded as testnet (length %d)", length)
  72  		}
  73  	}
  74  }
  75  
  76  // TestBlockHeaderDeserializeNeverPanics checks every short and random input
  77  // length for the fixed-size header decoder.
  78  func TestBlockHeaderDeserializeNeverPanics(t *testing.T) {
  79  	var state uint64 = 0x123456789abcdef
  80  	next := func() byte {
  81  		state ^= state << 13
  82  		state ^= state >> 7
  83  		state ^= state << 17
  84  		return byte(state)
  85  	}
  86  	for length := 0; length < 200; length++ {
  87  		buf := make([]byte, length)
  88  		for i := range buf {
  89  			buf[i] = next()
  90  		}
  91  		var h BlockHeader
  92  		err := h.Deserialize(buf)
  93  		if length < BlockHeaderSize && err == nil {
  94  			t.Fatalf("Deserialize(%d bytes) succeeded", length)
  95  		}
  96  		if length >= BlockHeaderSize && err != nil {
  97  			t.Fatalf("Deserialize(%d bytes): %v", length, err)
  98  		}
  99  		// Target must reject rather than panic on random bits.
 100  		_ = h.CheckProofOfWork()
 101  		_, _ = h.Target()
 102  	}
 103  }
 104