// Copyright 2014 The go-ethereum Authors
// (original work)
// Copyright 2024 The Erigon Authors
// (modifications)
// This file is part of Erigon.
//
// Erigon 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.
//
// Erigon 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 Erigon. If not, see <http://www.gnu.org/licenses/>.

package eth

import (
	"fmt"
	"io"
	"math/big"

	"github.com/holiman/uint256"

	"github.com/erigontech/erigon/common"
	"github.com/erigontech/erigon/execution/rlp"
	"github.com/erigontech/erigon/execution/types"
	"github.com/erigontech/erigon/node/direct"
	"github.com/erigontech/erigon/node/gointerfaces/sentryproto"
	"github.com/erigontech/erigon/p2p/forkid"
)

var ProtocolToString = map[uint]string{
	direct.ETH68: "eth68",
	direct.ETH69: "eth69",
	direct.ETH70: "eth70",
	direct.ETH71: "eth71",
}

// ProtocolName is the official short name of the `eth` protocol used during
// devp2p capability negotiation.
const ProtocolName = "eth"

// maxMessageSize is the maximum cap on the size of a protocol message.
const maxMessageSize = 10 * 1024 * 1024
const ProtocolMaxMsgSize = maxMessageSize

var ProtocolLengths = map[uint]uint64{direct.ETH68: 17, direct.ETH69: 18, direct.ETH70: 18, direct.ETH71: 20}

const (
	// Protocol messages in eth/64
	StatusMsg          = 0x00
	NewBlockHashesMsg  = 0x01
	TransactionsMsg    = 0x02
	GetBlockHeadersMsg = 0x03
	BlockHeadersMsg    = 0x04
	GetBlockBodiesMsg  = 0x05
	BlockBodiesMsg     = 0x06
	NewBlockMsg        = 0x07
	GetReceiptsMsg     = 0x0f
	ReceiptsMsg        = 0x10

	// Protocol messages overloaded in eth/65
	NewPooledTransactionHashesMsg = 0x08
	GetPooledTransactionsMsg      = 0x09
	PooledTransactionsMsg         = 0x0a
	BlockRangeUpdateMsg           = 0x11

	// Protocol messages added in eth/71 (EIP-8159 Block Access List Exchange)
	GetBlockAccessListsMsg = 0x12
	BlockAccessListsMsg    = 0x13
)

var ToProto = map[uint]map[uint64]sentryproto.MessageId{
	direct.ETH68: {
		GetBlockHeadersMsg:            sentryproto.MessageId_GET_BLOCK_HEADERS_66,
		BlockHeadersMsg:               sentryproto.MessageId_BLOCK_HEADERS_66,
		GetBlockBodiesMsg:             sentryproto.MessageId_GET_BLOCK_BODIES_66,
		BlockBodiesMsg:                sentryproto.MessageId_BLOCK_BODIES_66,
		GetReceiptsMsg:                sentryproto.MessageId_GET_RECEIPTS_66,
		ReceiptsMsg:                   sentryproto.MessageId_RECEIPTS_66,
		NewBlockHashesMsg:             sentryproto.MessageId_NEW_BLOCK_HASHES_66,
		NewBlockMsg:                   sentryproto.MessageId_NEW_BLOCK_66,
		TransactionsMsg:               sentryproto.MessageId_TRANSACTIONS_66,
		NewPooledTransactionHashesMsg: sentryproto.MessageId_NEW_POOLED_TRANSACTION_HASHES_68, // Modified in eth/68
		GetPooledTransactionsMsg:      sentryproto.MessageId_GET_POOLED_TRANSACTIONS_66,
		PooledTransactionsMsg:         sentryproto.MessageId_POOLED_TRANSACTIONS_66,
	},
	direct.ETH69: {
		StatusMsg:                     sentryproto.MessageId_STATUS_69,
		GetBlockHeadersMsg:            sentryproto.MessageId_GET_BLOCK_HEADERS_66,
		BlockHeadersMsg:               sentryproto.MessageId_BLOCK_HEADERS_66,
		GetBlockBodiesMsg:             sentryproto.MessageId_GET_BLOCK_BODIES_66,
		BlockBodiesMsg:                sentryproto.MessageId_BLOCK_BODIES_66,
		GetReceiptsMsg:                sentryproto.MessageId_GET_RECEIPTS_69, // Modified in eth/69
		ReceiptsMsg:                   sentryproto.MessageId_RECEIPTS_66,
		NewBlockHashesMsg:             sentryproto.MessageId_NEW_BLOCK_HASHES_66,
		NewBlockMsg:                   sentryproto.MessageId_NEW_BLOCK_66,
		TransactionsMsg:               sentryproto.MessageId_TRANSACTIONS_66,
		NewPooledTransactionHashesMsg: sentryproto.MessageId_NEW_POOLED_TRANSACTION_HASHES_68,
		GetPooledTransactionsMsg:      sentryproto.MessageId_GET_POOLED_TRANSACTIONS_66,
		PooledTransactionsMsg:         sentryproto.MessageId_POOLED_TRANSACTIONS_66,
		BlockRangeUpdateMsg:           sentryproto.MessageId_BLOCK_RANGE_UPDATE_69, // Modified in eth/69
	},
	direct.ETH70: {
		StatusMsg:                     sentryproto.MessageId_STATUS_69,
		GetBlockHeadersMsg:            sentryproto.MessageId_GET_BLOCK_HEADERS_66,
		BlockHeadersMsg:               sentryproto.MessageId_BLOCK_HEADERS_66,
		GetBlockBodiesMsg:             sentryproto.MessageId_GET_BLOCK_BODIES_66,
		BlockBodiesMsg:                sentryproto.MessageId_BLOCK_BODIES_66,
		GetReceiptsMsg:                sentryproto.MessageId_GET_RECEIPTS_70, // Modified in eth/70
		ReceiptsMsg:                   sentryproto.MessageId_RECEIPTS_70,     // Modified in eth/70
		NewBlockHashesMsg:             sentryproto.MessageId_NEW_BLOCK_HASHES_66,
		NewBlockMsg:                   sentryproto.MessageId_NEW_BLOCK_66,
		TransactionsMsg:               sentryproto.MessageId_TRANSACTIONS_66,
		NewPooledTransactionHashesMsg: sentryproto.MessageId_NEW_POOLED_TRANSACTION_HASHES_68,
		GetPooledTransactionsMsg:      sentryproto.MessageId_GET_POOLED_TRANSACTIONS_66,
		PooledTransactionsMsg:         sentryproto.MessageId_POOLED_TRANSACTIONS_66,
		BlockRangeUpdateMsg:           sentryproto.MessageId_BLOCK_RANGE_UPDATE_69,
	},
	direct.ETH71: {
		StatusMsg:                     sentryproto.MessageId_STATUS_69,
		GetBlockHeadersMsg:            sentryproto.MessageId_GET_BLOCK_HEADERS_66,
		BlockHeadersMsg:               sentryproto.MessageId_BLOCK_HEADERS_66,
		GetBlockBodiesMsg:             sentryproto.MessageId_GET_BLOCK_BODIES_66,
		BlockBodiesMsg:                sentryproto.MessageId_BLOCK_BODIES_66,
		GetReceiptsMsg:                sentryproto.MessageId_GET_RECEIPTS_70,
		ReceiptsMsg:                   sentryproto.MessageId_RECEIPTS_70,
		NewBlockHashesMsg:             sentryproto.MessageId_NEW_BLOCK_HASHES_66,
		NewBlockMsg:                   sentryproto.MessageId_NEW_BLOCK_66,
		TransactionsMsg:               sentryproto.MessageId_TRANSACTIONS_66,
		NewPooledTransactionHashesMsg: sentryproto.MessageId_NEW_POOLED_TRANSACTION_HASHES_68,
		GetPooledTransactionsMsg:      sentryproto.MessageId_GET_POOLED_TRANSACTIONS_66,
		PooledTransactionsMsg:         sentryproto.MessageId_POOLED_TRANSACTIONS_66,
		BlockRangeUpdateMsg:           sentryproto.MessageId_BLOCK_RANGE_UPDATE_69,
		// Added in eth/71 (EIP-8159 Block Access List Exchange)
		GetBlockAccessListsMsg: sentryproto.MessageId_GET_BLOCK_ACCESS_LISTS_71,
		BlockAccessListsMsg:    sentryproto.MessageId_BLOCK_ACCESS_LISTS_71,
	},
}

var FromProto = map[uint]map[sentryproto.MessageId]uint64{
	direct.ETH68: {
		sentryproto.MessageId_GET_BLOCK_HEADERS_66:             GetBlockHeadersMsg,
		sentryproto.MessageId_BLOCK_HEADERS_66:                 BlockHeadersMsg,
		sentryproto.MessageId_GET_BLOCK_BODIES_66:              GetBlockBodiesMsg,
		sentryproto.MessageId_BLOCK_BODIES_66:                  BlockBodiesMsg,
		sentryproto.MessageId_GET_RECEIPTS_66:                  GetReceiptsMsg,
		sentryproto.MessageId_RECEIPTS_66:                      ReceiptsMsg,
		sentryproto.MessageId_NEW_BLOCK_HASHES_66:              NewBlockHashesMsg,
		sentryproto.MessageId_NEW_BLOCK_66:                     NewBlockMsg,
		sentryproto.MessageId_TRANSACTIONS_66:                  TransactionsMsg,
		sentryproto.MessageId_NEW_POOLED_TRANSACTION_HASHES_68: NewPooledTransactionHashesMsg,
		sentryproto.MessageId_GET_POOLED_TRANSACTIONS_66:       GetPooledTransactionsMsg,
		sentryproto.MessageId_POOLED_TRANSACTIONS_66:           PooledTransactionsMsg,
	},
	direct.ETH69: {
		sentryproto.MessageId_GET_BLOCK_HEADERS_66:             GetBlockHeadersMsg,
		sentryproto.MessageId_BLOCK_HEADERS_66:                 BlockHeadersMsg,
		sentryproto.MessageId_GET_BLOCK_BODIES_66:              GetBlockBodiesMsg,
		sentryproto.MessageId_BLOCK_BODIES_66:                  BlockBodiesMsg,
		sentryproto.MessageId_GET_RECEIPTS_69:                  GetReceiptsMsg,
		sentryproto.MessageId_RECEIPTS_66:                      ReceiptsMsg,
		sentryproto.MessageId_NEW_BLOCK_HASHES_66:              NewBlockHashesMsg,
		sentryproto.MessageId_NEW_BLOCK_66:                     NewBlockMsg,
		sentryproto.MessageId_TRANSACTIONS_66:                  TransactionsMsg,
		sentryproto.MessageId_NEW_POOLED_TRANSACTION_HASHES_68: NewPooledTransactionHashesMsg,
		sentryproto.MessageId_GET_POOLED_TRANSACTIONS_66:       GetPooledTransactionsMsg,
		sentryproto.MessageId_POOLED_TRANSACTIONS_66:           PooledTransactionsMsg,
		sentryproto.MessageId_BLOCK_RANGE_UPDATE_69:            BlockRangeUpdateMsg,
	},
	direct.ETH70: {
		sentryproto.MessageId_GET_BLOCK_HEADERS_66:             GetBlockHeadersMsg,
		sentryproto.MessageId_BLOCK_HEADERS_66:                 BlockHeadersMsg,
		sentryproto.MessageId_GET_BLOCK_BODIES_66:              GetBlockBodiesMsg,
		sentryproto.MessageId_BLOCK_BODIES_66:                  BlockBodiesMsg,
		sentryproto.MessageId_GET_RECEIPTS_70:                  GetReceiptsMsg,
		sentryproto.MessageId_RECEIPTS_70:                      ReceiptsMsg,
		sentryproto.MessageId_NEW_BLOCK_HASHES_66:              NewBlockHashesMsg,
		sentryproto.MessageId_NEW_BLOCK_66:                     NewBlockMsg,
		sentryproto.MessageId_TRANSACTIONS_66:                  TransactionsMsg,
		sentryproto.MessageId_NEW_POOLED_TRANSACTION_HASHES_68: NewPooledTransactionHashesMsg,
		sentryproto.MessageId_GET_POOLED_TRANSACTIONS_66:       GetPooledTransactionsMsg,
		sentryproto.MessageId_POOLED_TRANSACTIONS_66:           PooledTransactionsMsg,
		sentryproto.MessageId_BLOCK_RANGE_UPDATE_69:            BlockRangeUpdateMsg,
	},
	direct.ETH71: {
		sentryproto.MessageId_GET_BLOCK_HEADERS_66:             GetBlockHeadersMsg,
		sentryproto.MessageId_BLOCK_HEADERS_66:                 BlockHeadersMsg,
		sentryproto.MessageId_GET_BLOCK_BODIES_66:              GetBlockBodiesMsg,
		sentryproto.MessageId_BLOCK_BODIES_66:                  BlockBodiesMsg,
		sentryproto.MessageId_GET_RECEIPTS_70:                  GetReceiptsMsg,
		sentryproto.MessageId_RECEIPTS_70:                      ReceiptsMsg,
		sentryproto.MessageId_NEW_BLOCK_HASHES_66:              NewBlockHashesMsg,
		sentryproto.MessageId_NEW_BLOCK_66:                     NewBlockMsg,
		sentryproto.MessageId_TRANSACTIONS_66:                  TransactionsMsg,
		sentryproto.MessageId_NEW_POOLED_TRANSACTION_HASHES_68: NewPooledTransactionHashesMsg,
		sentryproto.MessageId_GET_POOLED_TRANSACTIONS_66:       GetPooledTransactionsMsg,
		sentryproto.MessageId_POOLED_TRANSACTIONS_66:           PooledTransactionsMsg,
		sentryproto.MessageId_BLOCK_RANGE_UPDATE_69:            BlockRangeUpdateMsg,
		// Added in eth/71 (EIP-8159 Block Access List Exchange)
		sentryproto.MessageId_GET_BLOCK_ACCESS_LISTS_71: GetBlockAccessListsMsg,
		sentryproto.MessageId_BLOCK_ACCESS_LISTS_71:     BlockAccessListsMsg,
	},
}

// 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
}

// StatusPacket69 is the network packet for the status message for eth/69 and later.
type StatusPacket69 struct {
	ProtocolVersion           uint32
	NetworkID                 uint64
	Genesis                   common.Hash
	ForkID                    forkid.ID
	MinimumBlock, LatestBlock uint64
	LatestBlockHash           common.Hash
}

// 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
}

// 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)
}

// GetBlockHeadersPacket66 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, _ := s.Kind()
	origin, err := s.Raw()
	if err == nil {
		switch {
		case size == 32:
			err = rlp.DecodeBytes(origin, &hn.Hash)
		case size <= 8:
			err = rlp.DecodeBytes(origin, &hn.Number)
		default:
			err = fmt.Errorf("invalid input size %d for origin", size)
		}
	}
	return err
}

// BlockHeadersPacket represents a block header response.
type BlockHeadersPacket []*types.Header

// BlockHeadersPacket66 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    uint256.Int
}

func (nbp NewBlockPacket) EncodeRLP(w io.Writer) error {
	encodingSize := 0
	// size of Block
	blockLen := nbp.Block.EncodingSize()
	encodingSize += rlp.ListPrefixLen(blockLen) + blockLen
	// size of TD
	encodingSize += rlp.Uint256Len(nbp.TD)
	// prefix
	var b [32]byte
	if err := rlp.EncodeListPrefix(encodingSize, w, b[:]); err != nil {
		return err
	}
	// encode Block
	if err := nbp.Block.EncodeRLP(w); err != nil {
		return err
	}
	// encode TD
	if err := rlp.EncodeUint256(nbp.TD, w, b[:]); err != nil {
		return err
	}
	return nil
}

func (nbp *NewBlockPacket) DecodeRLP(s *rlp.Stream) error {
	_, err := s.List()
	if err != nil {
		return err
	}
	// decode Block
	nbp.Block = &types.Block{}
	if err = nbp.Block.DecodeRLP(s); err != nil {
		return err
	}
	// decode TD
	if err = s.ReadUint256(&nbp.TD); err != nil {
		return fmt.Errorf("read TD: %w", err)
	}
	if err = s.ListEnd(); err != nil {
		return err
	}
	return nil
}

// SanityCheck verifies that the values are reasonable, as a DoS protection
func (nbp *NewBlockPacket) SanityCheck() error {
	return nbp.Block.SanityCheck()
}

// 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 []*types.Body

// BlockRawBodiesPacket is the network packet for block content distribution.
type BlockRawBodiesPacket []*types.RawBody

// BlockBodiesPacket66 is the network packet for block content distribution over eth/66.
type BlockBodiesPacket66 struct {
	RequestId uint64
	BlockBodiesPacket
}

// BlockRawBodiesPacket66 is the network packet for block content distribution over eth/66.
type BlockRawBodiesPacket66 struct {
	RequestId uint64
	BlockRawBodiesPacket
}

// 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
}

// GetBlockAccessListsPacket is the eth/71 request to retrieve Block Access
// Lists (EIP-7928) for a list of block hashes (EIP-8159).
type GetBlockAccessListsPacket []common.Hash

// GetBlockAccessListsPacket66 wraps GetBlockAccessListsPacket in the eth/66
// request-id envelope. Reused unchanged for eth/71.
type GetBlockAccessListsPacket66 struct {
	RequestId uint64
	GetBlockAccessListsPacket
}

// BlockAccessListsPacket is the eth/71 response to a GetBlockAccessLists
// request. Entries are positionally aligned with the request: element i is
// the BAL for request hash i. The BAL payload is the canonical RLP encoding
// of a types.BlockAccessList per EIP-7928, passed through as RawValue since
// rawdb stores it in that exact form.
//
// EIP-8159 (post ethereum/EIPs#11553) defines three wire-distinguishable
// entry shapes:
//   - 0x80 (RLP empty string) — "peer does not have this BAL". The caller
//     should treat the slot as missing and may retry from another peer.
//   - 0xc0 (RLP empty list) — "block has a genuinely empty BAL". Valid only
//     when the corresponding header's BlockAccessListHash equals the
//     empty-BAL hash (see common/empty.BlockAccessListHash); otherwise the
//     peer is misbehaving.
//   - any other payload — actual BAL bytes whose keccak256 MUST match the
//     header's BlockAccessListHash.
type BlockAccessListsPacket []rlp.RawValue

// BlockAccessListsPacket66 wraps BlockAccessListsPacket in the eth/66
// request-id envelope. Reused unchanged for eth/71.
type BlockAccessListsPacket66 struct {
	RequestId uint64
	BlockAccessListsPacket
}

func (p *GetBlockAccessListsPacket66) Name() string { return "GetBlockAccessLists" }
func (p *GetBlockAccessListsPacket66) Kind() byte   { return GetBlockAccessListsMsg }

func (p *BlockAccessListsPacket66) Name() string { return "BlockAccessLists" }
func (p *BlockAccessListsPacket66) Kind() byte   { return BlockAccessListsMsg }

// Unpack retrieves the transactions, uncles, withdrawals from the range packet and returns
// them in a split flat format that's more consistent with the internal data structures.
func (p *BlockRawBodiesPacket) Unpack() ([][][]byte, [][]*types.Header, []types.Withdrawals) {
	var (
		txSet         = make([][][]byte, len(*p))
		uncleSet      = make([][]*types.Header, len(*p))
		withdrawalSet = make([]types.Withdrawals, len(*p))
	)
	for i, body := range *p {
		txSet[i], uncleSet[i], withdrawalSet[i] = body.Transactions, body.Uncles, body.Withdrawals
	}
	return txSet, uncleSet, withdrawalSet
}

// GetReceiptsPacket represents a block receipts query.
type GetReceiptsPacket []common.Hash

// GetReceiptsPacket66 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

// ReceiptsPacket66 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

// ReceiptsRLPPacket66 is the eth-66 version of ReceiptsRLPPacket
type ReceiptsRLPPacket66 struct {
	RequestId uint64
	ReceiptsRLPPacket
}

// GetReceiptsPacket70 represents a block receipts query over eth/70.
// The server omits receipts before FirstBlockReceiptIndex for the first block.
type GetReceiptsPacket70 struct {
	RequestId              uint64
	FirstBlockReceiptIndex uint64
	GetReceiptsPacket
}

// ReceiptsRLPPacket70 is the eth/70 version of ReceiptsRLPPacket.
// When LastBlockIncomplete is true, the final receipt list is incomplete.
type ReceiptsRLPPacket70 struct {
	RequestId           uint64
	LastBlockIncomplete bool
	ReceiptsRLPPacket
}

type BlockRangeUpdatePacket struct {
	Earliest, Latest uint64
	LatestHash       common.Hash
}

func (packet *BlockRangeUpdatePacket) Validate() error {
	if packet.Earliest > packet.Latest {
		return fmt.Errorf("invalid block range: earliest (%d) > latest (%d)", packet.Earliest, packet.Latest)
	}
	if packet.LatestHash == (common.Hash{}) {
		return fmt.Errorf("invalid block range: latest block hash is zero")
	}
	return nil
}

func (*StatusPacket) Name() string { return "Status" }
func (*StatusPacket) Kind() byte   { return StatusMsg }

func (*StatusPacket69) Name() string { return "Status" }
func (*StatusPacket69) Kind() byte   { return StatusMsg }

func (*NewBlockHashesPacket) Name() string { return "NewBlockHashes" }
func (*NewBlockHashesPacket) Kind() byte   { return NewBlockHashesMsg }

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 (*GetReceiptsPacket) Name() string { return "GetReceipts" }
func (*GetReceiptsPacket) Kind() byte   { return GetReceiptsMsg }

func (*ReceiptsPacket) Name() string { return "Receipts" }
func (*ReceiptsPacket) Kind() byte   { return ReceiptsMsg }

func (*BlockRangeUpdatePacket) Name() string { return "BlockRangeUpdate" }
func (*BlockRangeUpdatePacket) Kind() byte   { return BlockRangeUpdateMsg }
