github.com/klaytn/klaytn@v1.12.1/node/cn/snap/protocol.go (about)

     1  // Modifications Copyright 2022 The klaytn Authors
     2  // Copyright 2020 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from eth/protocols/snap/protocol.go (2022/06/29).
    19  // Modified and improved for the klaytn development.
    20  
    21  package snap
    22  
    23  import (
    24  	"errors"
    25  
    26  	"github.com/klaytn/klaytn/common"
    27  )
    28  
    29  // Constants to match up protocol versions and messages
    30  const (
    31  	SNAP1 = 1
    32  )
    33  
    34  // ProtocolName is the official short name of the `snap` protocol used during
    35  // devp2p capability negotiation.
    36  const ProtocolName = "snap"
    37  
    38  // ProtocolVersions are the supported versions of the `snap` protocol (first
    39  // is primary).
    40  var ProtocolVersions = []uint{SNAP1}
    41  
    42  // ProtocolLengths are the number of implemented message corresponding to
    43  // different protocol versions.
    44  var ProtocolLengths = map[uint]uint64{SNAP1: 8}
    45  
    46  // maxMessageSize is the maximum cap on the size of a protocol message.
    47  const maxMessageSize = 10 * 1024 * 1024
    48  
    49  const (
    50  	GetAccountRangeMsg  = 0x00
    51  	AccountRangeMsg     = 0x01
    52  	GetStorageRangesMsg = 0x02
    53  	StorageRangesMsg    = 0x03
    54  	GetByteCodesMsg     = 0x04
    55  	ByteCodesMsg        = 0x05
    56  	GetTrieNodesMsg     = 0x06
    57  	TrieNodesMsg        = 0x07
    58  )
    59  
    60  var (
    61  	errMsgTooLarge    = errors.New("message too long")
    62  	errDecode         = errors.New("invalid message")
    63  	errInvalidMsgCode = errors.New("invalid message code")
    64  	errBadRequest     = errors.New("bad request")
    65  )
    66  
    67  // Packet represents a p2p message in the `snap` protocol.
    68  type Packet interface {
    69  	Name() string // Name returns a string corresponding to the message type.
    70  	Kind() byte   // Kind returns the message type.
    71  }
    72  
    73  // GetAccountRangePacket represents an account query.
    74  type GetAccountRangePacket struct {
    75  	ID     uint64      // Request ID to match up responses with
    76  	Root   common.Hash // Root hash of the account trie to serve
    77  	Origin common.Hash // Hash of the first account to retrieve
    78  	Limit  common.Hash // Hash of the last account to retrieve
    79  	Bytes  uint64      // Soft limit at which to stop returning data
    80  }
    81  
    82  // AccountRangePacket represents an account query response.
    83  type AccountRangePacket struct {
    84  	ID       uint64         // ID of the request this is a response for
    85  	Accounts []*AccountData // List of consecutive accounts from the trie
    86  	Proof    [][]byte       // List of trie nodes proving the account range
    87  }
    88  
    89  // AccountData represents a single account in a query response.
    90  type AccountData struct {
    91  	Hash common.Hash // Hash of the account
    92  	Body []byte      // Account body
    93  }
    94  
    95  // Unpack retrieves the accounts from the range packet and converts from slim
    96  // wire representation to consensus format. The returned data is RLP encoded
    97  // since it's expected to be serialized to disk without further interpretation.
    98  //
    99  // Note, this method does a round of RLP decoding and reencoding, so only use it
   100  // once and cache the results if need be. Ideally discard the packet afterwards
   101  // to not double the memory use.
   102  func (p *AccountRangePacket) Unpack() ([]common.Hash, [][]byte) {
   103  	var (
   104  		hashes   = make([]common.Hash, len(p.Accounts))
   105  		accounts = make([][]byte, len(p.Accounts))
   106  	)
   107  	for i, acc := range p.Accounts {
   108  		hashes[i], accounts[i] = acc.Hash, acc.Body
   109  	}
   110  	return hashes, accounts
   111  }
   112  
   113  // GetStorageRangesPacket represents an storage slot query.
   114  type GetStorageRangesPacket struct {
   115  	ID       uint64        // Request ID to match up responses with
   116  	Root     common.Hash   // Root hash of the account trie to serve
   117  	Accounts []common.Hash // Account hashes of the storage tries to serve
   118  	Origin   []byte        // Hash of the first storage slot to retrieve (large contract mode)
   119  	Limit    []byte        // Hash of the last storage slot to retrieve (large contract mode)
   120  	Bytes    uint64        // Soft limit at which to stop returning data
   121  }
   122  
   123  // StorageRangesPacket represents a storage slot query response.
   124  type StorageRangesPacket struct {
   125  	ID    uint64           // ID of the request this is a response for
   126  	Slots [][]*StorageData // Lists of consecutive storage slots for the requested accounts
   127  	Proof [][]byte         // Merkle proofs for the *last* slot range, if it's incomplete
   128  }
   129  
   130  // StorageData represents a single storage slot in a query response.
   131  type StorageData struct {
   132  	Hash common.Hash // Hash of the storage slot
   133  	Body []byte      // Data content of the slot
   134  }
   135  
   136  // Unpack retrieves the storage slots from the range packet and returns them in
   137  // a split flat format that's more consistent with the internal data structures.
   138  func (p *StorageRangesPacket) Unpack() ([][]common.Hash, [][][]byte) {
   139  	var (
   140  		hashset = make([][]common.Hash, len(p.Slots))
   141  		slotset = make([][][]byte, len(p.Slots))
   142  	)
   143  	for i, slots := range p.Slots {
   144  		hashset[i] = make([]common.Hash, len(slots))
   145  		slotset[i] = make([][]byte, len(slots))
   146  		for j, slot := range slots {
   147  			hashset[i][j] = slot.Hash
   148  			slotset[i][j] = slot.Body
   149  		}
   150  	}
   151  	return hashset, slotset
   152  }
   153  
   154  // GetByteCodesPacket represents a contract bytecode query.
   155  type GetByteCodesPacket struct {
   156  	ID     uint64        // Request ID to match up responses with
   157  	Hashes []common.Hash // Code hashes to retrieve the code for
   158  	Bytes  uint64        // Soft limit at which to stop returning data
   159  }
   160  
   161  // ByteCodesPacket represents a contract bytecode query response.
   162  type ByteCodesPacket struct {
   163  	ID    uint64   // ID of the request this is a response for
   164  	Codes [][]byte // Requested contract bytecodes
   165  }
   166  
   167  // GetTrieNodesPacket represents a state trie node query.
   168  type GetTrieNodesPacket struct {
   169  	ID    uint64            // Request ID to match up responses with
   170  	Root  common.Hash       // Root hash of the account trie to serve
   171  	Paths []TrieNodePathSet // Trie node hashes to retrieve the nodes for
   172  	Bytes uint64            // Soft limit at which to stop returning data
   173  }
   174  
   175  // TrieNodePathSet is a list of trie node paths to retrieve. A naive way to
   176  // represent trie nodes would be a simple list of `account || storage` path
   177  // segments concatenated, but that would be very wasteful on the network.
   178  //
   179  // Instead, this array special cases the first element as the path in the
   180  // account trie and the remaining elements as paths in the storage trie. To
   181  // address an account node, the slice should have a length of 1 consisting
   182  // of only the account path. There's no need to be able to address both an
   183  // account node and a storage node in the same request as it cannot happen
   184  // that a slot is accessed before the account path is fully expanded.
   185  type TrieNodePathSet [][]byte
   186  
   187  // TrieNodesPacket represents a state trie node query response.
   188  type TrieNodesPacket struct {
   189  	ID    uint64   // ID of the request this is a response for
   190  	Nodes [][]byte // Requested state trie nodes
   191  }
   192  
   193  func (*GetAccountRangePacket) Name() string { return "GetAccountRange" }
   194  func (*GetAccountRangePacket) Kind() byte   { return GetAccountRangeMsg }
   195  
   196  func (*AccountRangePacket) Name() string { return "AccountRange" }
   197  func (*AccountRangePacket) Kind() byte   { return AccountRangeMsg }
   198  
   199  func (*GetStorageRangesPacket) Name() string { return "GetStorageRanges" }
   200  func (*GetStorageRangesPacket) Kind() byte   { return GetStorageRangesMsg }
   201  
   202  func (*StorageRangesPacket) Name() string { return "StorageRanges" }
   203  func (*StorageRangesPacket) Kind() byte   { return StorageRangesMsg }
   204  
   205  func (*GetByteCodesPacket) Name() string { return "GetByteCodes" }
   206  func (*GetByteCodesPacket) Kind() byte   { return GetByteCodesMsg }
   207  
   208  func (*ByteCodesPacket) Name() string { return "ByteCodes" }
   209  func (*ByteCodesPacket) Kind() byte   { return ByteCodesMsg }
   210  
   211  func (*GetTrieNodesPacket) Name() string { return "GetTrieNodes" }
   212  func (*GetTrieNodesPacket) Kind() byte   { return GetTrieNodesMsg }
   213  
   214  func (*TrieNodesPacket) Name() string { return "TrieNodes" }
   215  func (*TrieNodesPacket) Kind() byte   { return TrieNodesMsg }