package messages import ( "encoding/hex" "encoding/json" "fmt" "github.com/tendermint/go-wire" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" ) //protocol msg byte const ( BlockchainChannel = byte(0x40) BlockRequestByte = byte(0x10) BlockResponseByte = byte(0x11) HeadersRequestByte = byte(0x12) HeadersResponseByte = byte(0x13) BlocksRequestByte = byte(0x14) BlocksResponseByte = byte(0x15) StatusByte = byte(0x21) NewTransactionByte = byte(0x30) NewTransactionsByte = byte(0x31) NewMineBlockByte = byte(0x40) FilterLoadByte = byte(0x50) FilterAddByte = byte(0x51) FilterClearByte = byte(0x52) MerkleRequestByte = byte(0x60) MerkleResponseByte = byte(0x61) MaxBlockchainResponseSize = 22020096 + 2 TxsMsgMaxTxNum = 1024 ) //BlockchainMessage is a generic message for this reactor. type BlockchainMessage interface { String() string } var _ = wire.RegisterInterface( struct{ BlockchainMessage }{}, wire.ConcreteType{&GetBlockMessage{}, BlockRequestByte}, wire.ConcreteType{&BlockMessage{}, BlockResponseByte}, wire.ConcreteType{&GetHeadersMessage{}, HeadersRequestByte}, wire.ConcreteType{&HeadersMessage{}, HeadersResponseByte}, wire.ConcreteType{&GetBlocksMessage{}, BlocksRequestByte}, wire.ConcreteType{&BlocksMessage{}, BlocksResponseByte}, wire.ConcreteType{&StatusMessage{}, StatusByte}, wire.ConcreteType{&TransactionMessage{}, NewTransactionByte}, wire.ConcreteType{&TransactionsMessage{}, NewTransactionsByte}, wire.ConcreteType{&MineBlockMessage{}, NewMineBlockByte}, wire.ConcreteType{&FilterLoadMessage{}, FilterLoadByte}, wire.ConcreteType{&FilterAddMessage{}, FilterAddByte}, wire.ConcreteType{&FilterClearMessage{}, FilterClearByte}, wire.ConcreteType{&GetMerkleBlockMessage{}, MerkleRequestByte}, wire.ConcreteType{&MerkleBlockMessage{}, MerkleResponseByte}, ) //GetBlockMessage request blocks from remote peers by height/hash type GetBlockMessage struct { Height uint64 RawHash [32]byte } //GetHash reutrn the hash of the request func (m *GetBlockMessage) GetHash() *bc.Hash { hash := bc.NewHash(m.RawHash) return &hash } func (m *GetBlockMessage) String() string { if m.Height > 0 { return fmt.Sprintf("{height: %d}", m.Height) } return fmt.Sprintf("{hash: %s}", hex.EncodeToString(m.RawHash[:])) } //BlockMessage response get block msg type BlockMessage struct { RawBlock []byte } //NewBlockMessage construct bock response msg func NewBlockMessage(block *types.Block) (*BlockMessage, error) { rawBlock, err := block.MarshalText() if err != nil { return nil, err } return &BlockMessage{RawBlock: rawBlock}, nil } //GetBlock get block from msg func (m *BlockMessage) GetBlock() (*types.Block, error) { block := &types.Block{ BlockHeader: types.BlockHeader{}, Transactions: []*types.Tx{}, } if err := block.UnmarshalText(m.RawBlock); err != nil { return nil, err } return block, nil } func (m *BlockMessage) String() string { block, err := m.GetBlock() if err != nil { return "{err: wrong message}" } blockHash := block.Hash() return fmt.Sprintf("{block_height: %d, block_hash: %s}", block.Height, blockHash.String()) } //GetHeadersMessage is one of the bytom msg type type GetHeadersMessage struct { RawBlockLocator [][32]byte RawStopHash [32]byte Skip uint64 } //NewGetHeadersMessage return a new GetHeadersMessage func NewGetHeadersMessage(blockLocator []*bc.Hash, stopHash *bc.Hash, skip uint64) *GetHeadersMessage { msg := &GetHeadersMessage{ RawStopHash: stopHash.Byte32(), Skip: skip, } for _, hash := range blockLocator { msg.RawBlockLocator = append(msg.RawBlockLocator, hash.Byte32()) } return msg } //GetBlockLocator return the locator of the msg func (m *GetHeadersMessage) GetBlockLocator() []*bc.Hash { blockLocator := []*bc.Hash{} for _, rawHash := range m.RawBlockLocator { hash := bc.NewHash(rawHash) blockLocator = append(blockLocator, &hash) } return blockLocator } func (m *GetHeadersMessage) String() string { stopHash := bc.NewHash(m.RawStopHash) return fmt.Sprintf("{skip:%d,stopHash:%s}", m.Skip, stopHash.String()) } //GetStopHash return the stop hash of the msg func (m *GetHeadersMessage) GetStopHash() *bc.Hash { hash := bc.NewHash(m.RawStopHash) return &hash } func (m *GetHeadersMessage) GetSkip() uint64 { return m.Skip } //HeadersMessage is one of the bytom msg type type HeadersMessage struct { RawHeaders [][]byte } //NewHeadersMessage create a new HeadersMessage func NewHeadersMessage(headers []*types.BlockHeader) (*HeadersMessage, error) { RawHeaders := [][]byte{} for _, header := range headers { data, err := json.Marshal(header) if err != nil { return nil, err } RawHeaders = append(RawHeaders, data) } return &HeadersMessage{RawHeaders: RawHeaders}, nil } //GetHeaders return the headers in the msg func (m *HeadersMessage) GetHeaders() ([]*types.BlockHeader, error) { headers := []*types.BlockHeader{} for _, data := range m.RawHeaders { header := &types.BlockHeader{} if err := json.Unmarshal(data, header); err != nil { return nil, err } headers = append(headers, header) } return headers, nil } func (m *HeadersMessage) String() string { return fmt.Sprintf("{header_length: %d}", len(m.RawHeaders)) } //GetBlocksMessage is one of the bytom msg type type GetBlocksMessage struct { RawBlockLocator [][32]byte RawStopHash [32]byte } //NewGetBlocksMessage create a new GetBlocksMessage func NewGetBlocksMessage(blockLocator []*bc.Hash, stopHash *bc.Hash) *GetBlocksMessage { msg := &GetBlocksMessage{ RawStopHash: stopHash.Byte32(), } for _, hash := range blockLocator { msg.RawBlockLocator = append(msg.RawBlockLocator, hash.Byte32()) } return msg } //GetBlockLocator return the locator of the msg func (m *GetBlocksMessage) GetBlockLocator() []*bc.Hash { blockLocator := []*bc.Hash{} for _, rawHash := range m.RawBlockLocator { hash := bc.NewHash(rawHash) blockLocator = append(blockLocator, &hash) } return blockLocator } //GetStopHash return the stop hash of the msg func (m *GetBlocksMessage) GetStopHash() *bc.Hash { hash := bc.NewHash(m.RawStopHash) return &hash } func (m *GetBlocksMessage) String() string { return fmt.Sprintf("{stop_hash: %s}", hex.EncodeToString(m.RawStopHash[:])) } //BlocksMessage is one of the bytom msg type type BlocksMessage struct { RawBlocks [][]byte } //NewBlocksMessage create a new BlocksMessage func NewBlocksMessage(blocks []*types.Block) (*BlocksMessage, error) { rawBlocks := [][]byte{} for _, block := range blocks { data, err := json.Marshal(block) if err != nil { return nil, err } rawBlocks = append(rawBlocks, data) } return &BlocksMessage{RawBlocks: rawBlocks}, nil } //GetBlocks returns the blocks in the msg func (m *BlocksMessage) GetBlocks() ([]*types.Block, error) { blocks := []*types.Block{} for _, data := range m.RawBlocks { block := &types.Block{} if err := json.Unmarshal(data, block); err != nil { return nil, err } blocks = append(blocks, block) } return blocks, nil } func (m *BlocksMessage) String() string { return fmt.Sprintf("{blocks_length: %d}", len(m.RawBlocks)) } //StatusResponseMessage get status response msg type StatusMessage struct { BestHeight uint64 BestHash [32]byte IrreversibleHeight uint64 IrreversibleHash [32]byte } //NewStatusResponseMessage construct get status response msg func NewStatusMessage(bestHeader, irreversibleHeader *types.BlockHeader) *StatusMessage { return &StatusMessage{ BestHeight: bestHeader.Height, BestHash: bestHeader.Hash().Byte32(), IrreversibleHeight: irreversibleHeader.Height, IrreversibleHash: irreversibleHeader.Hash().Byte32(), } } //GetHash get hash from msg func (m *StatusMessage) GetBestHash() *bc.Hash { hash := bc.NewHash(m.BestHash) return &hash } func (m *StatusMessage) GetIrreversibleHash() *bc.Hash { hash := bc.NewHash(m.IrreversibleHash) return &hash } func (m *StatusMessage) String() string { return fmt.Sprintf("{best hash: %s, irreversible hash: %s}", hex.EncodeToString(m.BestHash[:]), hex.EncodeToString(m.IrreversibleHash[:])) } //TransactionMessage notify new tx msg type TransactionMessage struct { RawTx []byte } //NewTransactionMessage construct notify new tx msg func NewTransactionMessage(tx *types.Tx) (*TransactionMessage, error) { rawTx, err := tx.TxData.MarshalText() if err != nil { return nil, err } return &TransactionMessage{RawTx: rawTx}, nil } //GetTransaction get tx from msg func (m *TransactionMessage) GetTransaction() (*types.Tx, error) { tx := &types.Tx{} if err := tx.UnmarshalText(m.RawTx); err != nil { return nil, err } return tx, nil } func (m *TransactionMessage) String() string { tx, err := m.GetTransaction() if err != nil { return "{err: wrong message}" } return fmt.Sprintf("{tx_size: %d, tx_hash: %s}", len(m.RawTx), tx.ID.String()) } //TransactionsMessage notify new txs msg type TransactionsMessage struct { RawTxs [][]byte } //NewTransactionsMessage construct notify new txs msg func NewTransactionsMessage(txs []*types.Tx) (*TransactionsMessage, error) { rawTxs := make([][]byte, 0, len(txs)) for _, tx := range txs { rawTx, err := tx.TxData.MarshalText() if err != nil { return nil, err } rawTxs = append(rawTxs, rawTx) } return &TransactionsMessage{RawTxs: rawTxs}, nil } //GetTransactions get txs from msg func (m *TransactionsMessage) GetTransactions() ([]*types.Tx, error) { txs := make([]*types.Tx, 0, len(m.RawTxs)) for _, rawTx := range m.RawTxs { tx := &types.Tx{} if err := tx.UnmarshalText(rawTx); err != nil { return nil, err } txs = append(txs, tx) } return txs, nil } func (m *TransactionsMessage) String() string { return fmt.Sprintf("{tx_num: %d}", len(m.RawTxs)) } //MineBlockMessage new mined block msg type MineBlockMessage struct { RawBlock []byte } //NewMinedBlockMessage construct new mined block msg func NewMinedBlockMessage(block *types.Block) (*MineBlockMessage, error) { rawBlock, err := block.MarshalText() if err != nil { return nil, err } return &MineBlockMessage{RawBlock: rawBlock}, nil } //GetMineBlock get mine block from msg func (m *MineBlockMessage) GetMineBlock() (*types.Block, error) { block := &types.Block{} if err := block.UnmarshalText(m.RawBlock); err != nil { return nil, err } return block, nil } func (m *MineBlockMessage) String() string { block, err := m.GetMineBlock() if err != nil { return "{err: wrong message}" } blockHash := block.Hash() return fmt.Sprintf("{block_height: %d, block_hash: %s}", block.Height, blockHash.String()) } //FilterLoadMessage tells the receiving peer to filter the transactions according to address. type FilterLoadMessage struct { Addresses [][]byte } func (m *FilterLoadMessage) String() string { return fmt.Sprintf("{addresses_length: %d}", len(m.Addresses)) } // FilterAddMessage tells the receiving peer to add address to the filter. type FilterAddMessage struct { Address []byte } func (m *FilterAddMessage) String() string { return fmt.Sprintf("{address: %s}", hex.EncodeToString(m.Address)) } //FilterClearMessage tells the receiving peer to remove a previously-set filter. type FilterClearMessage struct{} func (m *FilterClearMessage) String() string { return "{}" } //GetMerkleBlockMessage request merkle blocks from remote peers by height/hash type GetMerkleBlockMessage struct { Height uint64 RawHash [32]byte } //GetHash reutrn the hash of the request func (m *GetMerkleBlockMessage) GetHash() *bc.Hash { hash := bc.NewHash(m.RawHash) return &hash } func (m *GetMerkleBlockMessage) String() string { if m.Height > 0 { return fmt.Sprintf("{height: %d}", m.Height) } return fmt.Sprintf("{hash: %s}", hex.EncodeToString(m.RawHash[:])) } //MerkleBlockMessage return the merkle block to client type MerkleBlockMessage struct { RawBlockHeader []byte TxHashes [][32]byte RawTxDatas [][]byte StatusHashes [][32]byte RawTxStatuses [][]byte Flags []byte } func (m *MerkleBlockMessage) SetRawBlockHeader(bh types.BlockHeader) error { rawHeader, err := bh.MarshalText() if err != nil { return err } m.RawBlockHeader = rawHeader return nil } func (m *MerkleBlockMessage) SetTxInfo(txHashes []*bc.Hash, txFlags []uint8, relatedTxs []*types.Tx) error { for _, txHash := range txHashes { m.TxHashes = append(m.TxHashes, txHash.Byte32()) } for _, tx := range relatedTxs { rawTxData, err := tx.MarshalText() if err != nil { return err } m.RawTxDatas = append(m.RawTxDatas, rawTxData) } m.Flags = txFlags return nil } func (m *MerkleBlockMessage) SetStatusInfo(statusHashes []*bc.Hash, relatedStatuses []*bc.TxVerifyResult) error { for _, statusHash := range statusHashes { m.StatusHashes = append(m.StatusHashes, statusHash.Byte32()) } for _, status := range relatedStatuses { rawStatusData, err := json.Marshal(status) if err != nil { return err } m.RawTxStatuses = append(m.RawTxStatuses, rawStatusData) } return nil } func (m *MerkleBlockMessage) String() string { return "{}" } //NewMerkleBlockMessage construct merkle block message func NewMerkleBlockMessage() *MerkleBlockMessage { return &MerkleBlockMessage{} }