| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- // Copyright 2014 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- package eth
- import (
- "errors"
- "fmt"
- "io"
- "math/big"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/forkid"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/rlp"
- )
- // Constants to match up protocol versions and messages
- const (
- ETH65 = 65
- ETH66 = 66
- )
- // ProtocolName is the official short name of the `eth` protocol used during
- // devp2p capability negotiation.
- const ProtocolName = "eth"
- // ProtocolVersions are the supported versions of the `eth` protocol (first
- // is primary).
- var ProtocolVersions = []uint{ETH66, ETH65}
- // protocolLengths are the number of implemented message corresponding to
- // different protocol versions.
- var protocolLengths = map[uint]uint64{ETH66: 17, ETH65: 17}
- // maxMessageSize is the maximum cap on the size of a protocol message.
- const maxMessageSize = 10 * 1024 * 1024
- const (
- // Protocol messages in eth/64
- StatusMsg = 0x00
- NewBlockHashesMsg = 0x01
- TransactionsMsg = 0x02
- GetBlockHeadersMsg = 0x03
- BlockHeadersMsg = 0x04
- GetBlockBodiesMsg = 0x05
- BlockBodiesMsg = 0x06
- NewBlockMsg = 0x07
- GetNodeDataMsg = 0x0d
- NodeDataMsg = 0x0e
- GetReceiptsMsg = 0x0f
- ReceiptsMsg = 0x10
- // Protocol messages overloaded in eth/65
- NewPooledTransactionHashesMsg = 0x08
- GetPooledTransactionsMsg = 0x09
- PooledTransactionsMsg = 0x0a
- )
- var (
- errNoStatusMsg = errors.New("no status message")
- errMsgTooLarge = errors.New("message too long")
- errDecode = errors.New("invalid message")
- errInvalidMsgCode = errors.New("invalid message code")
- errProtocolVersionMismatch = errors.New("protocol version mismatch")
- errNetworkIDMismatch = errors.New("network ID mismatch")
- errGenesisMismatch = errors.New("genesis mismatch")
- errForkIDRejected = errors.New("fork ID rejected")
- )
- // Packet represents a p2p message in the `eth` protocol.
- type Packet interface {
- Name() string // Name returns a string corresponding to the message type.
- Kind() byte // Kind returns the message type.
- }
- // StatusPacket is the network packet for the status message for eth/64 and later.
- type StatusPacket struct {
- ProtocolVersion uint32
- NetworkID uint64
- TD *big.Int
- Head common.Hash
- Genesis common.Hash
- ForkID forkid.ID
- }
- // NewBlockHashesPacket is the network packet for the block announcements.
- type NewBlockHashesPacket []struct {
- Hash common.Hash // Hash of one particular block being announced
- Number uint64 // Number of one particular block being announced
- }
- // Unpack retrieves the block hashes and numbers from the announcement packet
- // and returns them in a split flat format that's more consistent with the
- // internal data structures.
- func (p *NewBlockHashesPacket) Unpack() ([]common.Hash, []uint64) {
- var (
- hashes = make([]common.Hash, len(*p))
- numbers = make([]uint64, len(*p))
- )
- for i, body := range *p {
- hashes[i], numbers[i] = body.Hash, body.Number
- }
- return hashes, numbers
- }
- // TransactionsPacket is the network packet for broadcasting new transactions.
- type TransactionsPacket []*types.Transaction
- // GetBlockHeadersPacket represents a block header query.
- type GetBlockHeadersPacket struct {
- Origin HashOrNumber // Block from which to retrieve headers
- Amount uint64 // Maximum number of headers to retrieve
- Skip uint64 // Blocks to skip between consecutive headers
- Reverse bool // Query direction (false = rising towards latest, true = falling towards genesis)
- }
- // GetBlockHeadersPacket represents a block header query over eth/66
- type GetBlockHeadersPacket66 struct {
- RequestId uint64
- *GetBlockHeadersPacket
- }
- // HashOrNumber is a combined field for specifying an origin block.
- type HashOrNumber struct {
- Hash common.Hash // Block hash from which to retrieve headers (excludes Number)
- Number uint64 // Block hash from which to retrieve headers (excludes Hash)
- }
- // EncodeRLP is a specialized encoder for HashOrNumber to encode only one of the
- // two contained union fields.
- func (hn *HashOrNumber) EncodeRLP(w io.Writer) error {
- if hn.Hash == (common.Hash{}) {
- return rlp.Encode(w, hn.Number)
- }
- if hn.Number != 0 {
- return fmt.Errorf("both origin hash (%x) and number (%d) provided", hn.Hash, hn.Number)
- }
- return rlp.Encode(w, hn.Hash)
- }
- // DecodeRLP is a specialized decoder for HashOrNumber to decode the contents
- // into either a block hash or a block number.
- func (hn *HashOrNumber) DecodeRLP(s *rlp.Stream) error {
- _, size, err := s.Kind()
- switch {
- case err != nil:
- return err
- case size == 32:
- hn.Number = 0
- return s.Decode(&hn.Hash)
- case size <= 8:
- hn.Hash = common.Hash{}
- return s.Decode(&hn.Number)
- default:
- return fmt.Errorf("invalid input size %d for origin", size)
- }
- }
- // BlockHeadersPacket represents a block header response.
- type BlockHeadersPacket []*types.Header
- // BlockHeadersPacket represents a block header response over eth/66.
- type BlockHeadersPacket66 struct {
- RequestId uint64
- BlockHeadersPacket
- }
- // NewBlockPacket is the network packet for the block propagation message.
- type NewBlockPacket struct {
- Block *types.Block
- TD *big.Int
- }
- // sanityCheck verifies that the values are reasonable, as a DoS protection
- func (request *NewBlockPacket) sanityCheck() error {
- if err := request.Block.SanityCheck(); err != nil {
- return err
- }
- //TD at mainnet block #7753254 is 76 bits. If it becomes 100 million times
- // larger, it will still fit within 100 bits
- if tdlen := request.TD.BitLen(); tdlen > 100 {
- return fmt.Errorf("too large block TD: bitlen %d", tdlen)
- }
- return nil
- }
- // GetBlockBodiesPacket represents a block body query.
- type GetBlockBodiesPacket []common.Hash
- // GetBlockBodiesPacket represents a block body query over eth/66.
- type GetBlockBodiesPacket66 struct {
- RequestId uint64
- GetBlockBodiesPacket
- }
- // BlockBodiesPacket is the network packet for block content distribution.
- type BlockBodiesPacket []*BlockBody
- // BlockBodiesPacket is the network packet for block content distribution over eth/66.
- type BlockBodiesPacket66 struct {
- RequestId uint64
- BlockBodiesPacket
- }
- // BlockBodiesRLPPacket is used for replying to block body requests, in cases
- // where we already have them RLP-encoded, and thus can avoid the decode-encode
- // roundtrip.
- type BlockBodiesRLPPacket []rlp.RawValue
- // BlockBodiesRLPPacket66 is the BlockBodiesRLPPacket over eth/66
- type BlockBodiesRLPPacket66 struct {
- RequestId uint64
- BlockBodiesRLPPacket
- }
- // BlockBody represents the data content of a single block.
- type BlockBody struct {
- Transactions []*types.Transaction // Transactions contained within a block
- Uncles []*types.Header // Uncles contained within a block
- }
- // Unpack retrieves the transactions and uncles from the range packet and returns
- // them in a split flat format that's more consistent with the internal data structures.
- func (p *BlockBodiesPacket) Unpack() ([][]*types.Transaction, [][]*types.Header) {
- var (
- txset = make([][]*types.Transaction, len(*p))
- uncleset = make([][]*types.Header, len(*p))
- )
- for i, body := range *p {
- txset[i], uncleset[i] = body.Transactions, body.Uncles
- }
- return txset, uncleset
- }
- // GetNodeDataPacket represents a trie node data query.
- type GetNodeDataPacket []common.Hash
- // GetNodeDataPacket represents a trie node data query over eth/66.
- type GetNodeDataPacket66 struct {
- RequestId uint64
- GetNodeDataPacket
- }
- // NodeDataPacket is the network packet for trie node data distribution.
- type NodeDataPacket [][]byte
- // NodeDataPacket is the network packet for trie node data distribution over eth/66.
- type NodeDataPacket66 struct {
- RequestId uint64
- NodeDataPacket
- }
- // GetReceiptsPacket represents a block receipts query.
- type GetReceiptsPacket []common.Hash
- // GetReceiptsPacket represents a block receipts query over eth/66.
- type GetReceiptsPacket66 struct {
- RequestId uint64
- GetReceiptsPacket
- }
- // ReceiptsPacket is the network packet for block receipts distribution.
- type ReceiptsPacket [][]*types.Receipt
- // ReceiptsPacket is the network packet for block receipts distribution over eth/66.
- type ReceiptsPacket66 struct {
- RequestId uint64
- ReceiptsPacket
- }
- // ReceiptsRLPPacket is used for receipts, when we already have it encoded
- type ReceiptsRLPPacket []rlp.RawValue
- // ReceiptsPacket66 is the eth-66 version of ReceiptsRLPPacket
- type ReceiptsRLPPacket66 struct {
- RequestId uint64
- ReceiptsRLPPacket
- }
- // NewPooledTransactionHashesPacket represents a transaction announcement packet.
- type NewPooledTransactionHashesPacket []common.Hash
- // GetPooledTransactionsPacket represents a transaction query.
- type GetPooledTransactionsPacket []common.Hash
- type GetPooledTransactionsPacket66 struct {
- RequestId uint64
- GetPooledTransactionsPacket
- }
- // PooledTransactionsPacket is the network packet for transaction distribution.
- type PooledTransactionsPacket []*types.Transaction
- // PooledTransactionsPacket is the network packet for transaction distribution over eth/66.
- type PooledTransactionsPacket66 struct {
- RequestId uint64
- PooledTransactionsPacket
- }
- // PooledTransactionsPacket is the network packet for transaction distribution, used
- // in the cases we already have them in rlp-encoded form
- type PooledTransactionsRLPPacket []rlp.RawValue
- // PooledTransactionsRLPPacket66 is the eth/66 form of PooledTransactionsRLPPacket
- type PooledTransactionsRLPPacket66 struct {
- RequestId uint64
- PooledTransactionsRLPPacket
- }
- func (*StatusPacket) Name() string { return "Status" }
- func (*StatusPacket) Kind() byte { return StatusMsg }
- func (*NewBlockHashesPacket) Name() string { return "NewBlockHashes" }
- func (*NewBlockHashesPacket) Kind() byte { return NewBlockHashesMsg }
- func (*TransactionsPacket) Name() string { return "Transactions" }
- func (*TransactionsPacket) Kind() byte { return TransactionsMsg }
- func (*GetBlockHeadersPacket) Name() string { return "GetBlockHeaders" }
- func (*GetBlockHeadersPacket) Kind() byte { return GetBlockHeadersMsg }
- func (*BlockHeadersPacket) Name() string { return "BlockHeaders" }
- func (*BlockHeadersPacket) Kind() byte { return BlockHeadersMsg }
- func (*GetBlockBodiesPacket) Name() string { return "GetBlockBodies" }
- func (*GetBlockBodiesPacket) Kind() byte { return GetBlockBodiesMsg }
- func (*BlockBodiesPacket) Name() string { return "BlockBodies" }
- func (*BlockBodiesPacket) Kind() byte { return BlockBodiesMsg }
- func (*NewBlockPacket) Name() string { return "NewBlock" }
- func (*NewBlockPacket) Kind() byte { return NewBlockMsg }
- func (*GetNodeDataPacket) Name() string { return "GetNodeData" }
- func (*GetNodeDataPacket) Kind() byte { return GetNodeDataMsg }
- func (*NodeDataPacket) Name() string { return "NodeData" }
- func (*NodeDataPacket) Kind() byte { return NodeDataMsg }
- func (*GetReceiptsPacket) Name() string { return "GetReceipts" }
- func (*GetReceiptsPacket) Kind() byte { return GetReceiptsMsg }
- func (*ReceiptsPacket) Name() string { return "Receipts" }
- func (*ReceiptsPacket) Kind() byte { return ReceiptsMsg }
- func (*NewPooledTransactionHashesPacket) Name() string { return "NewPooledTransactionHashes" }
- func (*NewPooledTransactionHashesPacket) Kind() byte { return NewPooledTransactionHashesMsg }
- func (*GetPooledTransactionsPacket) Name() string { return "GetPooledTransactions" }
- func (*GetPooledTransactionsPacket) Kind() byte { return GetPooledTransactionsMsg }
- func (*PooledTransactionsPacket) Name() string { return "PooledTransactions" }
- func (*PooledTransactionsPacket) Kind() byte { return PooledTransactionsMsg }
|