コード例 #1
0
ファイル: msgmerkleblock_test.go プロジェクト: ironbits/dcrd
// 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
		}
	}
}
コード例 #2
0
ファイル: merkleblock.go プロジェクト: alexlyp/dcrutil
// 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
}
コード例 #3
0
ファイル: msgmerkleblock_test.go プロジェクト: ironbits/dcrd
// 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
		}
	}
}
コード例 #4
0
ファイル: msgmerkleblock_test.go プロジェクト: ironbits/dcrd
// 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
	}
}
コード例 #5
0
ファイル: msgmerkleblock_test.go プロジェクト: ironbits/dcrd
// 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
			}
		}
	}
}