dcrd/wire/msgminingstate.go
John C. Vernaleo 5076a00512 Initial Decred Commit.
Includes work by cjepson, ay-p, jolan, and jcv.

Initial conceptual framework by tacotime.
2016-02-07 14:00:12 -05:00

198 lines
5.5 KiB
Go

// Copyright (c) 2013-2015 The btcsuite developers
// Copyright (c) 2015 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package wire
import (
"fmt"
"io"
"github.com/decred/dcrd/chaincfg/chainhash"
)
// MaxMSBlocksAtHeadPerMsg is the maximum number of block hashes allowed
// per message.
const MaxMSBlocksAtHeadPerMsg = 8
// MaxMSVotesAtHeadPerMsg is the maximum number of votes at head per message.
const MaxMSVotesAtHeadPerMsg = 40 // 8 * 5
// MsgMiningState implements the Message interface and represents a mining state
// message. It is used to request a list of blocks located at the chain tip
// along with all votes for those blocks. The list is returned is limited by
// the maximum number of blocks per message and the maximum number of votes per
// message.
type MsgMiningState struct {
ProtocolVersion uint32
Height uint32
BlockHashes []*chainhash.Hash
VoteHashes []*chainhash.Hash
}
// AddBlockHash adds a new block hash to the message.
func (msg *MsgMiningState) AddBlockHash(hash *chainhash.Hash) error {
if len(msg.BlockHashes)+1 > MaxMSBlocksAtHeadPerMsg {
str := fmt.Sprintf("too many block hashes for message [max %v]",
MaxMSBlocksAtHeadPerMsg)
return messageError("MsgMiningState.AddBlockHash", str)
}
msg.BlockHashes = append(msg.BlockHashes, hash)
return nil
}
// AddVoteHash adds a new vote hash to the message.
func (msg *MsgMiningState) AddVoteHash(hash *chainhash.Hash) error {
if len(msg.VoteHashes)+1 > MaxMSVotesAtHeadPerMsg {
str := fmt.Sprintf("too many vote hashes for message [max %v]",
MaxMSVotesAtHeadPerMsg)
return messageError("MsgMiningState.AddVoteHash", str)
}
msg.VoteHashes = append(msg.VoteHashes, hash)
return nil
}
// BtcDecode decodes r using the protocol encoding into the receiver.
// This is part of the Message interface implementation.
func (msg *MsgMiningState) BtcDecode(r io.Reader, pver uint32) error {
err := readElement(r, &msg.ProtocolVersion)
if err != nil {
return err
}
err = readElement(r, &msg.Height)
if err != nil {
return err
}
// Read num block hashes and limit to max.
count, err := readVarInt(r, pver)
if err != nil {
return err
}
if count > MaxMSBlocksAtHeadPerMsg {
str := fmt.Sprintf("too many block hashes for message "+
"[count %v, max %v]", count, MaxMSBlocksAtHeadPerMsg)
return messageError("MsgMiningState.BtcDecode", str)
}
msg.BlockHashes = make([]*chainhash.Hash, 0, count)
for i := uint64(0); i < count; i++ {
sha := chainhash.Hash{}
err := readElement(r, &sha)
if err != nil {
return err
}
msg.AddBlockHash(&sha)
}
// Read num vote hashes and limit to max.
count, err = readVarInt(r, pver)
if err != nil {
return err
}
if count > MaxMSVotesAtHeadPerMsg {
str := fmt.Sprintf("too many vote hashes for message "+
"[count %v, max %v]", count, MaxMSVotesAtHeadPerMsg)
return messageError("MsgMiningState.BtcDecode", str)
}
msg.VoteHashes = make([]*chainhash.Hash, 0, count)
for i := uint64(0); i < count; i++ {
sha := chainhash.Hash{}
err := readElement(r, &sha)
if err != nil {
return err
}
msg.AddVoteHash(&sha)
}
return nil
}
// BtcEncode encodes the receiver to w using the protocol encoding.
// This is part of the Message interface implementation.
func (msg *MsgMiningState) BtcEncode(w io.Writer, pver uint32) error {
err := writeElement(w, msg.ProtocolVersion)
if err != nil {
return err
}
err = writeElement(w, msg.Height)
if err != nil {
return err
}
// Write block hashes.
count := len(msg.BlockHashes)
if count > MaxMSBlocksAtHeadPerMsg {
str := fmt.Sprintf("too many block hashes for message "+
"[count %v, max %v]", count, MaxMSBlocksAtHeadPerMsg)
return messageError("MsgMiningState.BtcEncode", str)
}
err = writeVarInt(w, pver, uint64(count))
if err != nil {
return err
}
for _, hash := range msg.BlockHashes {
err = writeElement(w, hash)
if err != nil {
return err
}
}
// Write vote hashes.
count = len(msg.VoteHashes)
if count > MaxMSVotesAtHeadPerMsg {
str := fmt.Sprintf("too many vote hashes for message "+
"[count %v, max %v]", count, MaxMSVotesAtHeadPerMsg)
return messageError("MsgMiningState.BtcEncode", str)
}
err = writeVarInt(w, pver, uint64(count))
if err != nil {
return err
}
for _, hash := range msg.VoteHashes {
err = writeElement(w, hash)
if err != nil {
return err
}
}
return nil
}
// Command returns the protocol command string for the message. This is part
// of the Message interface implementation.
func (msg *MsgMiningState) Command() string {
return CmdMiningState
}
// MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation.
func (msg *MsgMiningState) MaxPayloadLength(pver uint32) uint32 {
// Protocol version 4 bytes + Height 4 bytes + num block hashes (varInt) +
// block hashes + num vote hashes (varInt) + vote hashes
return 4 + 4 + MaxVarIntPayload + (MaxMSBlocksAtHeadPerMsg *
chainhash.HashSize) + MaxVarIntPayload + (MaxMSVotesAtHeadPerMsg *
chainhash.HashSize)
}
// NewMsgMiningState returns a new decred miningstate message that conforms to
// the Message interface using the defaults for the fields.
func NewMsgMiningState() *MsgMiningState {
return &MsgMiningState{
ProtocolVersion: ProtocolVersion,
Height: 0,
BlockHashes: make([]*chainhash.Hash, 0, MaxMSBlocksAtHeadPerMsg),
VoteHashes: make([]*chainhash.Hash, 0, MaxMSVotesAtHeadPerMsg),
}
}