// TestMerkleBlockOverflowErrors performs tests to ensure encoding and decoding // merkle blocks that are intentionally crafted to use large values for the // number of hashes and flags are handled properly. This could otherwise // potentially be used as an attack vector. func TestMerkleBlockOverflowErrors(t *testing.T) { // Use protocol version 70001 specifically here instead of the latest // protocol version because the test data is using bytes encoded with // that version. pver := uint32(1) // Create bytes for a merkle block that claims to have more than the max // allowed tx hashes. var buf bytes.Buffer wire.TstWriteVarInt(&buf, pver, wire.MaxTxPerTxTree+1) numHashesOffset := 140 exceedMaxHashes := make([]byte, numHashesOffset) copy(exceedMaxHashes, testMerkleBlockBytes[:numHashesOffset]) exceedMaxHashes = append(exceedMaxHashes, buf.Bytes()...) // Create bytes for a merkle block that claims to have more than the max // allowed flag bytes. buf.Reset() wire.TstWriteVarInt(&buf, pver, wire.MaxFlagsPerMerkleBlock+1) numFlagBytesOffset := 210 exceedMaxFlagBytes := make([]byte, numFlagBytesOffset) copy(exceedMaxFlagBytes, testMerkleBlockBytes[:numFlagBytesOffset]) exceedMaxFlagBytes = append(exceedMaxFlagBytes, buf.Bytes()...) tests := []struct { buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding err error // Expected error }{ // Block that claims to have more than max allowed hashes. {exceedMaxHashes, pver, io.ErrUnexpectedEOF}, // Block that claims to have more than max allowed flag bytes. {exceedMaxFlagBytes, pver, io.ErrUnexpectedEOF}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Decode from wire format. var msg wire.MsgMerkleBlock r := bytes.NewReader(test.buf) err := msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.err) { t.Errorf("BtcDecode #%d wrong error got: %v, want: %v", i, err, reflect.TypeOf(test.err)) continue } } }
// NewMerkleBlock returns a new *wire.MsgMerkleBlock and an array of the matched // transaction hashes based on the passed block and filter. func NewMerkleBlock(block *dcrutil.Block, filter *Filter) (*wire.MsgMerkleBlock, []*chainhash.Hash) { numTx := uint32(len(block.Transactions())) mBlock := merkleBlock{ numTx: numTx, allHashes: make([]*chainhash.Hash, 0, numTx), matchedBits: make([]byte, 0, numTx), } // Find and keep track of any transactions that match the filter. var matchedHashes []*chainhash.Hash for _, tx := range block.Transactions() { if filter.MatchTxAndUpdate(tx) { mBlock.matchedBits = append(mBlock.matchedBits, 0x01) matchedHashes = append(matchedHashes, tx.Sha()) } else { mBlock.matchedBits = append(mBlock.matchedBits, 0x00) } mBlock.allHashes = append(mBlock.allHashes, tx.Sha()) } // Calculate the number of merkle branches (height) in the tree. height := uint32(0) for mBlock.calcTreeWidth(height) > 1 { height++ } // Build the depth-first partial merkle tree. mBlock.traverseAndBuild(height, 0) // Create and return the merkle block. msgMerkleBlock := wire.MsgMerkleBlock{ Header: block.MsgBlock().Header, Transactions: uint32(mBlock.numTx), Hashes: make([]*chainhash.Hash, 0, len(mBlock.finalHashes)), Flags: make([]byte, (len(mBlock.bits)+7)/8), } for _, sha := range mBlock.finalHashes { msgMerkleBlock.AddTxHash(sha) } for i := uint32(0); i < uint32(len(mBlock.bits)); i++ { msgMerkleBlock.Flags[i/8] |= mBlock.bits[i] << (i % 8) } return &msgMerkleBlock, matchedHashes }
// TestMerkleBlockWire tests the MsgMerkleBlock wire encode and decode for // various numbers of transaction hashes and protocol versions. func TestMerkleBlockWire(t *testing.T) { tests := []struct { in *wire.MsgMerkleBlock // Message to encode out *wire.MsgMerkleBlock // Expected decoded message buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding }{ // Latest protocol version. { &testMerkleBlock, &testMerkleBlock, testMerkleBlockBytes, wire.ProtocolVersion, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Encode the message to wire format. var buf bytes.Buffer err := test.in.BtcEncode(&buf, test.pver) if err != nil { t.Errorf("BtcEncode #%d error %v", i, err) continue } if !bytes.Equal(buf.Bytes(), test.buf) { t.Errorf("BtcEncode #%d\n got: %s want: %s", i, spew.Sdump(buf.Bytes()), spew.Sdump(test.buf)) continue } // Decode the message from wire format. var msg wire.MsgMerkleBlock rbuf := bytes.NewReader(test.buf) err = msg.BtcDecode(rbuf, test.pver) if err != nil { t.Errorf("BtcDecode #%d error %v", i, err) continue } if !reflect.DeepEqual(&msg, test.out) { t.Errorf("BtcDecode #%d\n got: %s want: %s", i, spew.Sdump(&msg), spew.Sdump(test.out)) continue } } }
// TestMerkleBlock tests the MsgMerkleBlock API. func TestMerkleBlock(t *testing.T) { pver := wire.ProtocolVersion // Test block header. bh := wire.NewBlockHeader( int32(pver), &testBlock.Header.PrevBlock, // PrevHash &testBlock.Header.MerkleRoot, // MerkleRootHash &testBlock.Header.StakeRoot, // StakeRoot uint16(0x0000), // VoteBits [6]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // FinalState uint16(0x0000), // Voters uint8(0x00), // FreshStake uint8(0x00), // Revocations uint32(0), // Poolsize testBlock.Header.Bits, // Bits int64(0x0000000000000000), // Sbits uint32(1), // Height uint32(0), // Size testBlock.Header.Nonce, // Nonce [36]byte{}, // ExtraData ) // Ensure the command is expected value. wantCmd := "merkleblock" msg := wire.NewMsgMerkleBlock(bh) if cmd := msg.Command(); cmd != wantCmd { t.Errorf("NewMsgBlock: wrong command - got %v want %v", cmd, wantCmd) } // Ensure max payload is expected value for latest protocol version. // Num addresses (varInt) + max allowed addresses. wantPayload := uint32(1000000) maxPayload := msg.MaxPayloadLength(pver) if maxPayload != wantPayload { t.Errorf("MaxPayloadLength: wrong max payload length for "+ "protocol version %d - got %v, want %v", pver, maxPayload, wantPayload) } // Load maxTxPerBlock hashes data := make([]byte, 32) for i := 0; i < wire.MaxTxPerTxTree; i++ { rand.Read(data) hash, err := chainhash.NewHash(data) if err != nil { t.Errorf("NewShaHash failed: %v\n", err) return } if err = msg.AddTxHash(hash); err != nil { t.Errorf("AddTxHash failed: %v\n", err) return } if err = msg.AddSTxHash(hash); err != nil { t.Errorf("AddSTxHash failed: %v\n", err) return } } // Add one more Tx to test failure. rand.Read(data) hash, err := chainhash.NewHash(data) if err != nil { t.Errorf("NewShaHash failed: %v\n", err) return } if err = msg.AddTxHash(hash); err == nil { t.Errorf("AddTxHash succeeded when it should have failed") return } // Add one more STx to test failure. rand.Read(data) hash, err = chainhash.NewHash(data) if err != nil { t.Errorf("NewShaHash failed: %v\n", err) return } if err = msg.AddSTxHash(hash); err == nil { t.Errorf("AddTxHash succeeded when it should have failed") return } // Test encode with latest protocol version. var buf bytes.Buffer err = msg.BtcEncode(&buf, pver) if err != nil { t.Errorf("encode of MsgMerkleBlock failed %v err <%v>", msg, err) } // Test decode with latest protocol version. readmsg := wire.MsgMerkleBlock{} err = readmsg.BtcDecode(&buf, pver) if err != nil { t.Errorf("decode of MsgMerkleBlock failed [%v] err <%v>", buf, err) } // Force extra hash to test maxTxPerBlock. msg.Hashes = append(msg.Hashes, hash) err = msg.BtcEncode(&buf, pver) if err == nil { t.Errorf("encode of MsgMerkleBlock succeeded with too many " + "tx hashes when it should have failed") return } // Force too many flag bytes to test maxFlagsPerMerkleBlock. // Reset the number of hashes back to a valid value. msg.Hashes = msg.Hashes[len(msg.Hashes)-1:] msg.Flags = make([]byte, wire.MaxFlagsPerMerkleBlock+1) err = msg.BtcEncode(&buf, pver) if err == nil { t.Errorf("encode of MsgMerkleBlock succeeded with too many " + "flag bytes when it should have failed") return } }
// TestMerkleBlockWireErrors performs negative tests against wire encode and // decode of MsgBlock to confirm error paths work correctly. func TestMerkleBlockWireErrors(t *testing.T) { // Use protocol version 70001 specifically here instead of the latest // because the test data is using bytes encoded with that protocol // version. pver := uint32(1) tests := []struct { in *wire.MsgMerkleBlock // Value to encode buf []byte // Wire encoding pver uint32 // Protocol version for wire encoding max int // Max size of fixed buffer to induce errors writeErr error // Expected write error readErr error // Expected read error }{ // Force error in version. [0] { &testMerkleBlock, testMerkleBlockBytes, pver, 0, io.ErrShortWrite, io.EOF, }, // Force error in prev block hash. [1] { &testMerkleBlock, testMerkleBlockBytes, pver, 4, io.ErrShortWrite, io.EOF, }, // Force error in merkle root. [2] { &testMerkleBlock, testMerkleBlockBytes, pver, 36, io.ErrShortWrite, io.EOF, }, // Force error in stake merkle root. [3] { &testMerkleBlock, testMerkleBlockBytes, pver, 68, io.ErrShortWrite, io.EOF, }, // Force error in VoteBits. [4] { &testMerkleBlock, testMerkleBlockBytes, pver, 100, io.ErrShortWrite, io.EOF, }, // Force error in FinalState. [5] { &testMerkleBlock, testMerkleBlockBytes, pver, 102, io.ErrShortWrite, io.EOF, }, // Force error in Voters. [6] { &testMerkleBlock, testMerkleBlockBytes, pver, 108, io.ErrShortWrite, io.EOF, }, // Force error in FreshStake. [7] { &testMerkleBlock, testMerkleBlockBytes, pver, 110, io.ErrShortWrite, io.EOF, }, // Force error in Revocations. [8] { &testMerkleBlock, testMerkleBlockBytes, pver, 111, io.ErrShortWrite, io.EOF, }, // Force error in poolsize. [9] { &testMerkleBlock, testMerkleBlockBytes, pver, 112, io.ErrShortWrite, io.EOF, }, // Force error in difficulty bits. [10] { &testMerkleBlock, testMerkleBlockBytes, pver, 116, io.ErrShortWrite, io.EOF, }, // Force error in stake difficulty bits. [11] { &testMerkleBlock, testMerkleBlockBytes, pver, 120, io.ErrShortWrite, io.EOF, }, // Force error in height. [12] { &testMerkleBlock, testMerkleBlockBytes, pver, 128, io.ErrShortWrite, io.EOF, }, // Force error in size. [13] { &testMerkleBlock, testMerkleBlockBytes, pver, 132, io.ErrShortWrite, io.EOF, }, // Force error in timestamp. [14] { &testMerkleBlock, testMerkleBlockBytes, pver, 136, io.ErrShortWrite, io.EOF, }, // Force error in header nonce. [15] { &testMerkleBlock, testMerkleBlockBytes, pver, 140, io.ErrShortWrite, io.EOF, }, // Force error in transaction count. [16] { &testMerkleBlock, testMerkleBlockBytes, pver, 180, io.ErrShortWrite, io.EOF, }, // Force error in num hashes. [17] { &testMerkleBlock, testMerkleBlockBytes, pver, 184, io.ErrShortWrite, io.EOF, }, // Force error in hashes. [18] { &testMerkleBlock, testMerkleBlockBytes, pver, 185, io.ErrShortWrite, io.EOF, }, // Force error in num flag bytes. [19] { &testMerkleBlock, testMerkleBlockBytes, pver, 254, io.ErrShortWrite, io.EOF, }, // Force error in flag bytes. [20] { &testMerkleBlock, testMerkleBlockBytes, pver, 255, io.ErrShortWrite, io.EOF, }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { // Encode to wire format. w := newFixedWriter(test.max) err := test.in.BtcEncode(w, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.writeErr) { t.Errorf("BtcEncode #%d wrong error got: %v, want: %v", i, err, test.writeErr) continue } // For errors which are not of type wire.MessageError, check // them for equality. if _, ok := err.(*wire.MessageError); !ok { if err != test.writeErr { t.Errorf("BtcEncode #%d wrong error got: %v, "+ "want: %v", i, err, test.writeErr) continue } } // Decode from wire format. var msg wire.MsgMerkleBlock r := newFixedReader(test.max, test.buf) err = msg.BtcDecode(r, test.pver) if reflect.TypeOf(err) != reflect.TypeOf(test.readErr) { t.Errorf("BtcDecode #%d wrong error got: %v, want: %v", i, err, test.readErr) continue } // For errors which are not of type wire.MessageError, check // them for equality. if _, ok := err.(*wire.MessageError); !ok { if err != test.readErr { t.Errorf("BtcDecode #%d wrong error got: %v, "+ "want: %v", i, err, test.readErr) continue } } } }