| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- // Copyright 2020 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 snap
- import (
- "errors"
- "fmt"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/state/snapshot"
- "github.com/ethereum/go-ethereum/rlp"
- )
- // Constants to match up protocol versions and messages
- const (
- SNAP1 = 1
- )
- // ProtocolName is the official short name of the `snap` protocol used during
- // devp2p capability negotiation.
- const ProtocolName = "snap"
- // ProtocolVersions are the supported versions of the `snap` protocol (first
- // is primary).
- var ProtocolVersions = []uint{SNAP1}
- // protocolLengths are the number of implemented message corresponding to
- // different protocol versions.
- var protocolLengths = map[uint]uint64{SNAP1: 8}
- // maxMessageSize is the maximum cap on the size of a protocol message.
- const maxMessageSize = 10 * 1024 * 1024
- const (
- GetAccountRangeMsg = 0x00
- AccountRangeMsg = 0x01
- GetStorageRangesMsg = 0x02
- StorageRangesMsg = 0x03
- GetByteCodesMsg = 0x04
- ByteCodesMsg = 0x05
- GetTrieNodesMsg = 0x06
- TrieNodesMsg = 0x07
- )
- var (
- errMsgTooLarge = errors.New("message too long")
- errDecode = errors.New("invalid message")
- errInvalidMsgCode = errors.New("invalid message code")
- errBadRequest = errors.New("bad request")
- )
- // Packet represents a p2p message in the `snap` protocol.
- type Packet interface {
- Name() string // Name returns a string corresponding to the message type.
- Kind() byte // Kind returns the message type.
- }
- // GetAccountRangePacket represents an account query.
- type GetAccountRangePacket struct {
- ID uint64 // Request ID to match up responses with
- Root common.Hash // Root hash of the account trie to serve
- Origin common.Hash // Hash of the first account to retrieve
- Limit common.Hash // Hash of the last account to retrieve
- Bytes uint64 // Soft limit at which to stop returning data
- }
- // AccountRangePacket represents an account query response.
- type AccountRangePacket struct {
- ID uint64 // ID of the request this is a response for
- Accounts []*AccountData // List of consecutive accounts from the trie
- Proof [][]byte // List of trie nodes proving the account range
- }
- // AccountData represents a single account in a query response.
- type AccountData struct {
- Hash common.Hash // Hash of the account
- Body rlp.RawValue // Account body in slim format
- }
- // Unpack retrieves the accounts from the range packet and converts from slim
- // wire representation to consensus format. The returned data is RLP encoded
- // since it's expected to be serialized to disk without further interpretation.
- //
- // Note, this method does a round of RLP decoding and reencoding, so only use it
- // once and cache the results if need be. Ideally discard the packet afterwards
- // to not double the memory use.
- func (p *AccountRangePacket) Unpack() ([]common.Hash, [][]byte, error) {
- var (
- hashes = make([]common.Hash, len(p.Accounts))
- accounts = make([][]byte, len(p.Accounts))
- )
- for i, acc := range p.Accounts {
- val, err := snapshot.FullAccountRLP(acc.Body)
- if err != nil {
- return nil, nil, fmt.Errorf("invalid account %x: %v", acc.Body, err)
- }
- hashes[i], accounts[i] = acc.Hash, val
- }
- return hashes, accounts, nil
- }
- // GetStorageRangesPacket represents an storage slot query.
- type GetStorageRangesPacket struct {
- ID uint64 // Request ID to match up responses with
- Root common.Hash // Root hash of the account trie to serve
- Accounts []common.Hash // Account hashes of the storage tries to serve
- Origin []byte // Hash of the first storage slot to retrieve (large contract mode)
- Limit []byte // Hash of the last storage slot to retrieve (large contract mode)
- Bytes uint64 // Soft limit at which to stop returning data
- }
- // StorageRangesPacket represents a storage slot query response.
- type StorageRangesPacket struct {
- ID uint64 // ID of the request this is a response for
- Slots [][]*StorageData // Lists of consecutive storage slots for the requested accounts
- Proof [][]byte // Merkle proofs for the *last* slot range, if it's incomplete
- }
- // StorageData represents a single storage slot in a query response.
- type StorageData struct {
- Hash common.Hash // Hash of the storage slot
- Body []byte // Data content of the slot
- }
- // Unpack retrieves the storage slots from the range packet and returns them in
- // a split flat format that's more consistent with the internal data structures.
- func (p *StorageRangesPacket) Unpack() ([][]common.Hash, [][][]byte) {
- var (
- hashset = make([][]common.Hash, len(p.Slots))
- slotset = make([][][]byte, len(p.Slots))
- )
- for i, slots := range p.Slots {
- hashset[i] = make([]common.Hash, len(slots))
- slotset[i] = make([][]byte, len(slots))
- for j, slot := range slots {
- hashset[i][j] = slot.Hash
- slotset[i][j] = slot.Body
- }
- }
- return hashset, slotset
- }
- // GetByteCodesPacket represents a contract bytecode query.
- type GetByteCodesPacket struct {
- ID uint64 // Request ID to match up responses with
- Hashes []common.Hash // Code hashes to retrieve the code for
- Bytes uint64 // Soft limit at which to stop returning data
- }
- // ByteCodesPacket represents a contract bytecode query response.
- type ByteCodesPacket struct {
- ID uint64 // ID of the request this is a response for
- Codes [][]byte // Requested contract bytecodes
- }
- // GetTrieNodesPacket represents a state trie node query.
- type GetTrieNodesPacket struct {
- ID uint64 // Request ID to match up responses with
- Root common.Hash // Root hash of the account trie to serve
- Paths []TrieNodePathSet // Trie node hashes to retrieve the nodes for
- Bytes uint64 // Soft limit at which to stop returning data
- }
- // TrieNodePathSet is a list of trie node paths to retrieve. A naive way to
- // represent trie nodes would be a simple list of `account || storage` path
- // segments concatenated, but that would be very wasteful on the network.
- //
- // Instead, this array special cases the first element as the path in the
- // account trie and the remaining elements as paths in the storage trie. To
- // address an account node, the slice should have a length of 1 consisting
- // of only the account path. There's no need to be able to address both an
- // account node and a storage node in the same request as it cannot happen
- // that a slot is accessed before the account path is fully expanded.
- type TrieNodePathSet [][]byte
- // TrieNodesPacket represents a state trie node query response.
- type TrieNodesPacket struct {
- ID uint64 // ID of the request this is a response for
- Nodes [][]byte // Requested state trie nodes
- }
- func (*GetAccountRangePacket) Name() string { return "GetAccountRange" }
- func (*GetAccountRangePacket) Kind() byte { return GetAccountRangeMsg }
- func (*AccountRangePacket) Name() string { return "AccountRange" }
- func (*AccountRangePacket) Kind() byte { return AccountRangeMsg }
- func (*GetStorageRangesPacket) Name() string { return "GetStorageRanges" }
- func (*GetStorageRangesPacket) Kind() byte { return GetStorageRangesMsg }
- func (*StorageRangesPacket) Name() string { return "StorageRanges" }
- func (*StorageRangesPacket) Kind() byte { return StorageRangesMsg }
- func (*GetByteCodesPacket) Name() string { return "GetByteCodes" }
- func (*GetByteCodesPacket) Kind() byte { return GetByteCodesMsg }
- func (*ByteCodesPacket) Name() string { return "ByteCodes" }
- func (*ByteCodesPacket) Kind() byte { return ByteCodesMsg }
- func (*GetTrieNodesPacket) Name() string { return "GetTrieNodes" }
- func (*GetTrieNodesPacket) Kind() byte { return GetTrieNodesMsg }
- func (*TrieNodesPacket) Name() string { return "TrieNodes" }
- func (*TrieNodesPacket) Kind() byte { return TrieNodesMsg }
|