github.com/aidoskuneen/adk-node@v0.0.0-20220315131952-2e32567cb7f4/eth/protocols/snap/protocol.go (about)

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