github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/cmd/devp2p/internal/ethtest/snap.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU 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  // go-ethereum 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 General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package ethtest
    18  
    19  import (
    20  	"bytes"
    21  	"errors"
    22  	"fmt"
    23  	"math/big"
    24  	"math/rand"
    25  	"reflect"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/core/state"
    29  	"github.com/ethereum/go-ethereum/core/types"
    30  	"github.com/ethereum/go-ethereum/crypto"
    31  	"github.com/ethereum/go-ethereum/eth/protocols/snap"
    32  	"github.com/ethereum/go-ethereum/internal/utesting"
    33  	"github.com/ethereum/go-ethereum/trie"
    34  	"github.com/ethereum/go-ethereum/trie/trienode"
    35  )
    36  
    37  func (c *Conn) snapRequest(code uint64, msg any) (any, error) {
    38  	if err := c.Write(snapProto, code, msg); err != nil {
    39  		return nil, fmt.Errorf("could not write to connection: %v", err)
    40  	}
    41  	return c.ReadSnap()
    42  }
    43  
    44  func (s *Suite) TestSnapStatus(t *utesting.T) {
    45  	conn, err := s.dialSnap()
    46  	if err != nil {
    47  		t.Fatalf("dial failed: %v", err)
    48  	}
    49  	defer conn.Close()
    50  	if err := conn.peer(s.chain, nil); err != nil {
    51  		t.Fatalf("peering failed: %v", err)
    52  	}
    53  }
    54  
    55  type accRangeTest struct {
    56  	nBytes       uint64
    57  	root         common.Hash
    58  	startingHash common.Hash
    59  	limitHash    common.Hash
    60  
    61  	expAccounts int
    62  	expFirst    common.Hash
    63  	expLast     common.Hash
    64  
    65  	desc string
    66  }
    67  
    68  // TestSnapGetAccountRange various forms of GetAccountRange requests.
    69  func (s *Suite) TestSnapGetAccountRange(t *utesting.T) {
    70  	var (
    71  		ffHash = common.MaxHash
    72  		zero   = common.Hash{}
    73  
    74  		// test values derived from chain/ account dump
    75  		root        = s.chain.Head().Root()
    76  		headstate   = s.chain.AccountsInHashOrder()
    77  		firstKey    = common.BytesToHash(headstate[0].AddressHash)
    78  		secondKey   = common.BytesToHash(headstate[1].AddressHash)
    79  		storageRoot = findNonEmptyStorageRoot(headstate)
    80  	)
    81  
    82  	tests := []accRangeTest{
    83  		// Tests decreasing the number of bytes
    84  		{
    85  			nBytes:       4000,
    86  			root:         root,
    87  			startingHash: zero,
    88  			limitHash:    ffHash,
    89  			expAccounts:  86,
    90  			expFirst:     firstKey,
    91  			expLast:      common.HexToHash("0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099"),
    92  			desc:         "In this test, we request the entire state range, but limit the response to 4000 bytes.",
    93  		},
    94  		{
    95  			nBytes:       3000,
    96  			root:         root,
    97  			startingHash: zero,
    98  			limitHash:    ffHash,
    99  			expAccounts:  65,
   100  			expFirst:     firstKey,
   101  			expLast:      common.HexToHash("0x2e6fe1362b3e388184fd7bf08e99e74170b26361624ffd1c5f646da7067b58b6"),
   102  			desc:         "In this test, we request the entire state range, but limit the response to 3000 bytes.",
   103  		},
   104  		{
   105  			nBytes:       2000,
   106  			root:         root,
   107  			startingHash: zero,
   108  			limitHash:    ffHash,
   109  			expAccounts:  44,
   110  			expFirst:     firstKey,
   111  			expLast:      common.HexToHash("0x1c3f74249a4892081ba0634a819aec9ed25f34c7653f5719b9098487e65ab595"),
   112  			desc:         "In this test, we request the entire state range, but limit the response to 2000 bytes.",
   113  		},
   114  		{
   115  			nBytes:       1,
   116  			root:         root,
   117  			startingHash: zero,
   118  			limitHash:    ffHash,
   119  			expAccounts:  1,
   120  			expFirst:     firstKey,
   121  			expLast:      firstKey,
   122  			desc: `In this test, we request the entire state range, but limit the response to 1 byte.
   123  The server should return the first account of the state.`,
   124  		},
   125  		{
   126  			nBytes:       0,
   127  			root:         root,
   128  			startingHash: zero,
   129  			limitHash:    ffHash,
   130  			expAccounts:  1,
   131  			expFirst:     firstKey,
   132  			expLast:      firstKey,
   133  			desc: `Here we request with a responseBytes limit of zero.
   134  The server should return one account.`,
   135  		},
   136  
   137  		// Tests variations of the range
   138  		{
   139  			nBytes:       4000,
   140  			root:         root,
   141  			startingHash: hashAdd(firstKey, -500),
   142  			limitHash:    hashAdd(firstKey, 1),
   143  			expAccounts:  2,
   144  			expFirst:     firstKey,
   145  			expLast:      secondKey,
   146  			desc: `In this test, we request a range where startingHash is before the first available
   147  account key, and limitHash is after. The server should return the first and second
   148  account of the state (because the second account is the 'next available').`,
   149  		},
   150  
   151  		{
   152  			nBytes:       4000,
   153  			root:         root,
   154  			startingHash: hashAdd(firstKey, -500),
   155  			limitHash:    hashAdd(firstKey, -450),
   156  			expAccounts:  1,
   157  			expFirst:     firstKey,
   158  			expLast:      firstKey,
   159  			desc: `Here we request range where both bounds are before the first available account key.
   160  This should return the first account (even though it's out of bounds).`,
   161  		},
   162  
   163  		// More range tests:
   164  		{
   165  			nBytes:       4000,
   166  			root:         root,
   167  			startingHash: zero,
   168  			limitHash:    zero,
   169  			expAccounts:  1,
   170  			expFirst:     firstKey,
   171  			expLast:      firstKey,
   172  			desc: `In this test, both startingHash and limitHash are zero.
   173  The server should return the first available account.`,
   174  		},
   175  		{
   176  			nBytes:       4000,
   177  			root:         root,
   178  			startingHash: firstKey,
   179  			limitHash:    ffHash,
   180  			expAccounts:  86,
   181  			expFirst:     firstKey,
   182  			expLast:      common.HexToHash("0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099"),
   183  			desc: `In this test, startingHash is exactly the first available account key.
   184  The server should return the first available account of the state as the first item.`,
   185  		},
   186  		{
   187  			nBytes:       4000,
   188  			root:         root,
   189  			startingHash: hashAdd(firstKey, 1),
   190  			limitHash:    ffHash,
   191  			expAccounts:  86,
   192  			expFirst:     secondKey,
   193  			expLast:      common.HexToHash("0x4615e5f5df5b25349a00ad313c6cd0436b6c08ee5826e33a018661997f85ebaa"),
   194  			desc: `In this test, startingHash is after the first available key.
   195  The server should return the second account of the state as the first item.`,
   196  		},
   197  
   198  		// Test different root hashes
   199  
   200  		{
   201  			nBytes:       4000,
   202  			root:         common.Hash{0x13, 0x37},
   203  			startingHash: zero,
   204  			limitHash:    ffHash,
   205  			expAccounts:  0,
   206  			expFirst:     zero,
   207  			expLast:      zero,
   208  			desc:         `This test requests a non-existent state root.`,
   209  		},
   210  
   211  		// The genesis stateroot (we expect it to not be served)
   212  		{
   213  			nBytes:       4000,
   214  			root:         s.chain.RootAt(0),
   215  			startingHash: zero,
   216  			limitHash:    ffHash,
   217  			expAccounts:  0,
   218  			expFirst:     zero,
   219  			expLast:      zero,
   220  			desc: `This test requests data at the state root of the genesis block. We expect the
   221  server to return no data because genesis is older than 127 blocks.`,
   222  		},
   223  
   224  		{
   225  			nBytes:       4000,
   226  			root:         s.chain.RootAt(int(s.chain.Head().Number().Uint64()) - 127),
   227  			startingHash: zero,
   228  			limitHash:    ffHash,
   229  			expAccounts:  84,
   230  			expFirst:     firstKey,
   231  			expLast:      common.HexToHash("0x580aa878e2f92d113a12c0a3ce3c21972b03dbe80786858d49a72097e2c491a3"),
   232  			desc: `This test requests data at a state root that is 127 blocks old.
   233  We expect the server to have this state available.`,
   234  		},
   235  
   236  		{
   237  			nBytes:       4000,
   238  			root:         storageRoot,
   239  			startingHash: zero,
   240  			limitHash:    ffHash,
   241  			expAccounts:  0,
   242  			expFirst:     zero,
   243  			expLast:      zero,
   244  			desc: `This test requests data at a state root that is actually the storage root of
   245  an existing account. The server is supposed to ignore this request.`,
   246  		},
   247  
   248  		// And some non-sensical requests
   249  
   250  		{
   251  			nBytes:       4000,
   252  			root:         root,
   253  			startingHash: ffHash,
   254  			limitHash:    zero,
   255  			expAccounts:  0,
   256  			expFirst:     zero,
   257  			expLast:      zero,
   258  			desc: `In this test, the startingHash is after limitHash (wrong order). The server
   259  should ignore this invalid request.`,
   260  		},
   261  
   262  		{
   263  			nBytes:       4000,
   264  			root:         root,
   265  			startingHash: firstKey,
   266  			limitHash:    hashAdd(firstKey, -1),
   267  			expAccounts:  1,
   268  			expFirst:     firstKey,
   269  			expLast:      firstKey,
   270  			desc: `In this test, the startingHash is the first available key, and limitHash is
   271  a key before startingHash (wrong order). The server should return the first available key.`,
   272  		},
   273  
   274  		// range from [firstkey, 0], wrong order. Expect to get first key.
   275  		{
   276  			nBytes:       4000,
   277  			root:         root,
   278  			startingHash: firstKey,
   279  			limitHash:    zero,
   280  			expAccounts:  1,
   281  			expFirst:     firstKey,
   282  			expLast:      firstKey,
   283  			desc: `In this test, the startingHash is the first available key and limitHash is zero.
   284  (wrong order). The server should return the first available key.`,
   285  		},
   286  	}
   287  
   288  	for i, tc := range tests {
   289  		tc := tc
   290  		if i > 0 {
   291  			t.Log("\n")
   292  		}
   293  		t.Logf("-- Test %d", i)
   294  		t.Log(tc.desc)
   295  		t.Log("  request:")
   296  		t.Logf("      root: %x", tc.root)
   297  		t.Logf("      range: %#x - %#x", tc.startingHash, tc.limitHash)
   298  		t.Logf("      responseBytes: %d", tc.nBytes)
   299  		if err := s.snapGetAccountRange(t, &tc); err != nil {
   300  			t.Errorf("test %d failed: %v", i, err)
   301  		}
   302  	}
   303  }
   304  
   305  func hashAdd(h common.Hash, n int64) common.Hash {
   306  	hb := h.Big()
   307  	return common.BigToHash(hb.Add(hb, big.NewInt(n)))
   308  }
   309  
   310  func findNonEmptyStorageRoot(accounts []state.DumpAccount) common.Hash {
   311  	for i := range accounts {
   312  		if len(accounts[i].Storage) != 0 {
   313  			return common.BytesToHash(accounts[i].Root)
   314  		}
   315  	}
   316  	panic("can't find account with non-empty storage")
   317  }
   318  
   319  type stRangesTest struct {
   320  	root     common.Hash
   321  	accounts []common.Hash
   322  	origin   []byte
   323  	limit    []byte
   324  	nBytes   uint64
   325  
   326  	expSlots [][]*snap.StorageData
   327  
   328  	desc string
   329  }
   330  
   331  // TestSnapGetStorageRanges various forms of GetStorageRanges requests.
   332  func (s *Suite) TestSnapGetStorageRanges(t *utesting.T) {
   333  	var (
   334  		acct      = common.HexToAddress("0x8bebc8ba651aee624937e7d897853ac30c95a067")
   335  		acctHash  = common.BytesToHash(s.chain.state[acct].AddressHash)
   336  		ffHash    = common.MaxHash
   337  		zero      = common.Hash{}
   338  		blockroot = s.chain.Head().Root()
   339  	)
   340  
   341  	// These are the storage slots of the test account, encoded as snap response data.
   342  	acctSlots := []*snap.StorageData{
   343  		{
   344  			Hash: common.HexToHash("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"),
   345  			Body: []byte{0x02},
   346  		},
   347  		{
   348  			Hash: common.HexToHash("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"),
   349  			Body: []byte{0x01},
   350  		},
   351  		{
   352  			Hash: common.HexToHash("0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b"),
   353  			Body: []byte{0x03},
   354  		},
   355  	}
   356  
   357  	tests := []stRangesTest{
   358  		/*
   359  			Some tests against this account:
   360  
   361  			"0x8bebc8ba651aee624937e7d897853ac30c95a067": {
   362  				"balance": "1",
   363  				"nonce": 1,
   364  				"root": "0xe318dff15b33aa7f2f12d5567d58628e3e3f2e8859e46b56981a4083b391da17",
   365  				"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
   366  				"storage": {
   367  					// Note: keys below are hashed!!!
   368  					"0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": "02",
   369  					"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": "01",
   370  					"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b": "03"
   371  				},
   372  				"key": "0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099"
   373  			}
   374  		*/
   375  
   376  		{ // [:] -> [slot1, slot2, slot3]
   377  			desc: `This request has a range of 00..ff.
   378  The server should return all storage slots of the test account.`,
   379  			root:     blockroot,
   380  			accounts: []common.Hash{acctHash},
   381  			origin:   zero[:],
   382  			limit:    ffHash[:],
   383  			nBytes:   500,
   384  			expSlots: [][]*snap.StorageData{acctSlots},
   385  		},
   386  
   387  		{ // [slot1:] -> [slot1, slot2, slot3]
   388  			desc: `This test requests slots starting at the first available key.
   389  The server should return all storage slots of the test account.`,
   390  			root:     blockroot,
   391  			accounts: []common.Hash{acctHash},
   392  			origin:   common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"),
   393  			limit:    ffHash[:],
   394  			nBytes:   1000,
   395  			expSlots: [][]*snap.StorageData{acctSlots},
   396  		},
   397  
   398  		{ // [slot1+:] -> [slot2, slot3]
   399  			desc: `This test requests slots starting at a key one past the first available key.
   400  The server should return the remaining two slots of the test account.`,
   401  			root:     blockroot,
   402  			accounts: []common.Hash{acctHash},
   403  			origin:   common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf"),
   404  			limit:    ffHash[:],
   405  			nBytes:   500,
   406  			expSlots: [][]*snap.StorageData{acctSlots[1:]},
   407  		},
   408  
   409  		{ // [slot1:slot2] -> [slot1, slot2]
   410  			desc:     `This test requests a range which is exactly the first and second available key.`,
   411  			root:     blockroot,
   412  			accounts: []common.Hash{acctHash},
   413  			origin:   common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"),
   414  			limit:    common.FromHex("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"),
   415  			nBytes:   500,
   416  			expSlots: [][]*snap.StorageData{acctSlots[:2]},
   417  		},
   418  
   419  		{ // [slot1+:slot2+] -> [slot2, slot3]
   420  			desc: `This test requests a range where limitHash is after the second, but before the third slot
   421  of the test account. The server should return slots [2,3] (i.e. the 'next available' needs to be returned).`,
   422  			root:     blockroot,
   423  			accounts: []common.Hash{acctHash},
   424  			origin:   common.FromHex("0x4fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
   425  			limit:    common.FromHex("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7"),
   426  			nBytes:   500,
   427  			expSlots: [][]*snap.StorageData{acctSlots[1:]},
   428  		},
   429  	}
   430  
   431  	for i, tc := range tests {
   432  		tc := tc
   433  		if i > 0 {
   434  			t.Log("\n")
   435  		}
   436  		t.Logf("-- Test %d", i)
   437  		t.Log(tc.desc)
   438  		t.Log("  request:")
   439  		t.Logf("      root: %x", tc.root)
   440  		t.Logf("      accounts: %x", tc.accounts)
   441  		t.Logf("      range: %#x - %#x", tc.origin, tc.limit)
   442  		t.Logf("      responseBytes: %d", tc.nBytes)
   443  		if err := s.snapGetStorageRanges(t, &tc); err != nil {
   444  			t.Errorf("  failed: %v", err)
   445  		}
   446  	}
   447  }
   448  
   449  type byteCodesTest struct {
   450  	nBytes uint64
   451  	hashes []common.Hash
   452  
   453  	expHashes int
   454  
   455  	desc string
   456  }
   457  
   458  // TestSnapGetByteCodes various forms of GetByteCodes requests.
   459  func (s *Suite) TestSnapGetByteCodes(t *utesting.T) {
   460  	var (
   461  		allHashes   = s.chain.CodeHashes()
   462  		headRoot    = s.chain.Head().Root()
   463  		genesisRoot = s.chain.RootAt(0)
   464  	)
   465  
   466  	tests := []byteCodesTest{
   467  		// A few stateroots
   468  		{
   469  			desc:      `Here we request state roots as code hashes. The server should deliver an empty response with no items.`,
   470  			nBytes:    10000,
   471  			hashes:    []common.Hash{genesisRoot, headRoot},
   472  			expHashes: 0,
   473  		},
   474  		{
   475  			desc:      `Here we request the genesis state root (which is not an existing code hash) two times. The server should deliver an empty response with no items.`,
   476  			nBytes:    10000,
   477  			hashes:    []common.Hash{genesisRoot, genesisRoot},
   478  			expHashes: 0,
   479  		},
   480  		// Empties
   481  		{
   482  			desc:      `Here we request the empty state root (which is not an existing code hash). The server should deliver an empty response with no items.`,
   483  			nBytes:    10000,
   484  			hashes:    []common.Hash{types.EmptyRootHash},
   485  			expHashes: 0,
   486  		},
   487  		{
   488  			desc:      `Here we request the empty code hash. The server should deliver an empty response item.`,
   489  			nBytes:    10000,
   490  			hashes:    []common.Hash{types.EmptyCodeHash},
   491  			expHashes: 1,
   492  		},
   493  		{
   494  			desc:      `In this test, we request the empty code hash three times. The server should deliver the empty item three times.`,
   495  			nBytes:    10000,
   496  			hashes:    []common.Hash{types.EmptyCodeHash, types.EmptyCodeHash, types.EmptyCodeHash},
   497  			expHashes: 3,
   498  		},
   499  		// The existing bytecodes
   500  		{
   501  			desc:      `Here we request all available contract codes. The server should deliver them all in one response.`,
   502  			nBytes:    100000,
   503  			hashes:    allHashes,
   504  			expHashes: len(allHashes),
   505  		},
   506  		// The existing, with limited byte arg
   507  		{
   508  			desc:      `In this test, the request has a bytes limit of one. The server should deliver one item.`,
   509  			nBytes:    1,
   510  			hashes:    allHashes,
   511  			expHashes: 1,
   512  		},
   513  		{
   514  			desc:      `In this test, the request has a bytes limit of zero. The server should deliver one item.`,
   515  			nBytes:    0,
   516  			hashes:    allHashes,
   517  			expHashes: 1,
   518  		},
   519  		// Request the same hash multiple times.
   520  		{
   521  			desc:      `This test requests the same code hash multiple times. The server should deliver it multiple times.`,
   522  			nBytes:    1000,
   523  			hashes:    []common.Hash{allHashes[0], allHashes[0], allHashes[0], allHashes[0]},
   524  			expHashes: 4,
   525  		},
   526  	}
   527  
   528  	for i, tc := range tests {
   529  		tc := tc
   530  		if i > 0 {
   531  			t.Log("\n")
   532  		}
   533  		t.Logf("-- Test %d", i)
   534  		t.Log(tc.desc)
   535  		t.Log("  request:")
   536  		t.Logf("      hashes: %x", tc.hashes)
   537  		t.Logf("      responseBytes: %d", tc.nBytes)
   538  		if err := s.snapGetByteCodes(t, &tc); err != nil {
   539  			t.Errorf("failed: %v", err)
   540  		}
   541  	}
   542  }
   543  
   544  type trieNodesTest struct {
   545  	root   common.Hash
   546  	paths  []snap.TrieNodePathSet
   547  	nBytes uint64
   548  
   549  	expHashes []common.Hash // expected response
   550  	expReject bool          // if true, request should be rejected
   551  
   552  	desc string
   553  }
   554  
   555  func decodeNibbles(nibbles []byte, bytes []byte) {
   556  	for bi, ni := 0, 0; ni < len(nibbles); bi, ni = bi+1, ni+2 {
   557  		bytes[bi] = nibbles[ni]<<4 | nibbles[ni+1]
   558  	}
   559  }
   560  
   561  // hasTerm returns whether a hex key has the terminator flag.
   562  func hasTerm(s []byte) bool {
   563  	return len(s) > 0 && s[len(s)-1] == 16
   564  }
   565  
   566  func keybytesToHex(str []byte) []byte {
   567  	l := len(str)*2 + 1
   568  	var nibbles = make([]byte, l)
   569  	for i, b := range str {
   570  		nibbles[i*2] = b / 16
   571  		nibbles[i*2+1] = b % 16
   572  	}
   573  	nibbles[l-1] = 16
   574  	return nibbles
   575  }
   576  
   577  func hexToCompact(hex []byte) []byte {
   578  	terminator := byte(0)
   579  	if hasTerm(hex) {
   580  		terminator = 1
   581  		hex = hex[:len(hex)-1]
   582  	}
   583  	buf := make([]byte, len(hex)/2+1)
   584  	buf[0] = terminator << 5 // the flag byte
   585  	if len(hex)&1 == 1 {
   586  		buf[0] |= 1 << 4 // odd flag
   587  		buf[0] |= hex[0] // first nibble is contained in the first byte
   588  		hex = hex[1:]
   589  	}
   590  	decodeNibbles(hex, buf[1:])
   591  	return buf
   592  }
   593  
   594  // TestSnapTrieNodes various forms of GetTrieNodes requests.
   595  func (s *Suite) TestSnapTrieNodes(t *utesting.T) {
   596  	var (
   597  		// This is the known address of the snap storage testing contract.
   598  		storageAcct     = common.HexToAddress("0x8bebc8ba651aee624937e7d897853ac30c95a067")
   599  		storageAcctHash = common.BytesToHash(s.chain.state[storageAcct].AddressHash)
   600  		// This is the known address of an existing account.
   601  		key      = common.FromHex("0xa87387b50b481431c6ccdb9ae99a54d4dcdd4a3eff75d7b17b4818f7bbfc21e9")
   602  		empty    = types.EmptyCodeHash
   603  		accPaths []snap.TrieNodePathSet
   604  	)
   605  	for i := 1; i <= 65; i++ {
   606  		accPaths = append(accPaths, makeSnapPath(key, i))
   607  	}
   608  
   609  	tests := []trieNodesTest{
   610  		{
   611  			desc:      `In this test, we send an empty request to the node.`,
   612  			root:      s.chain.Head().Root(),
   613  			paths:     nil,
   614  			nBytes:    500,
   615  			expHashes: nil,
   616  		},
   617  
   618  		{
   619  			desc: `In this test, we send a request containing an empty path-set.
   620  The server should reject the request.`,
   621  			root: s.chain.Head().Root(),
   622  			paths: []snap.TrieNodePathSet{
   623  				{}, // zero-length pathset should 'abort' and kick us off
   624  				{[]byte{0}},
   625  			},
   626  			nBytes:    5000,
   627  			expHashes: []common.Hash{},
   628  			expReject: true,
   629  		},
   630  
   631  		{
   632  			desc: `Here we request the root node of the trie. The server should respond with the root node.`,
   633  			root: s.chain.RootAt(int(s.chain.Head().NumberU64() - 1)),
   634  			paths: []snap.TrieNodePathSet{
   635  				{[]byte{0}},
   636  				{[]byte{1}, []byte{0}},
   637  			},
   638  			nBytes:    5000,
   639  			expHashes: []common.Hash{s.chain.RootAt(int(s.chain.Head().NumberU64() - 1))},
   640  		},
   641  
   642  		{ // nonsensically long path
   643  			desc: `In this test, we request a very long trie node path. The server should respond with an empty node (keccak256("")).`,
   644  			root: s.chain.Head().Root(),
   645  			paths: []snap.TrieNodePathSet{
   646  				{[]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8,
   647  					0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8}},
   648  			},
   649  			nBytes:    5000,
   650  			expHashes: []common.Hash{types.EmptyCodeHash},
   651  		},
   652  
   653  		{
   654  			// The leaf is only a couple of levels down, so the continued trie traversal causes lookup failures.
   655  			desc:   `Here we request some known accounts from the state.`,
   656  			root:   s.chain.Head().Root(),
   657  			paths:  accPaths,
   658  			nBytes: 5000,
   659  			expHashes: []common.Hash{
   660  				// It's a bit unfortunate these are hard-coded, but the result depends on
   661  				// a lot of aspects of the state trie and can't be guessed in a simple
   662  				// way. So you'll have to update this when the test chain is changed.
   663  				common.HexToHash("0x3e963a69401a70224cbfb8c0cc2249b019041a538675d71ccf80c9328d114e2e"),
   664  				common.HexToHash("0xd0670d09cdfbf3c6320eb3e92c47c57baa6c226551a2d488c05581091e6b1689"),
   665  				empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty,
   666  				empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty,
   667  				empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty,
   668  				empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty,
   669  				empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty,
   670  				empty, empty, empty},
   671  		},
   672  
   673  		{
   674  			desc: `In this test, we request some known accounts in state. The requested paths are NOT in key order.`,
   675  			root: s.chain.Head().Root(),
   676  			paths: []snap.TrieNodePathSet{
   677  				accPaths[10], accPaths[1], accPaths[0],
   678  			},
   679  			nBytes: 5000,
   680  			// As with the previous test, this result depends on the whole tree and will have to
   681  			// be updated when the test chain is changed.
   682  			expHashes: []common.Hash{
   683  				empty,
   684  				common.HexToHash("0xd0670d09cdfbf3c6320eb3e92c47c57baa6c226551a2d488c05581091e6b1689"),
   685  				common.HexToHash("0x3e963a69401a70224cbfb8c0cc2249b019041a538675d71ccf80c9328d114e2e"),
   686  			},
   687  		},
   688  
   689  		// Storage tests.
   690  		// These use the known storage test account.
   691  
   692  		{
   693  			desc: `This test requests the storage root node of a known account.`,
   694  			root: s.chain.Head().Root(),
   695  			paths: []snap.TrieNodePathSet{
   696  				{
   697  					storageAcctHash[:],
   698  					[]byte{0},
   699  				},
   700  			},
   701  			nBytes: 5000,
   702  			expHashes: []common.Hash{
   703  				common.HexToHash("0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790"),
   704  			},
   705  		},
   706  
   707  		{
   708  			desc: `This test requests multiple storage nodes of a known account.`,
   709  			root: s.chain.Head().Root(),
   710  			paths: []snap.TrieNodePathSet{
   711  				{
   712  					storageAcctHash[:],
   713  					[]byte{0},
   714  					[]byte{0x1b},
   715  				},
   716  			},
   717  			nBytes: 5000,
   718  			expHashes: []common.Hash{
   719  				common.HexToHash("0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790"),
   720  				common.HexToHash("0xf4984a11f61a2921456141df88de6e1a710d28681b91af794c5a721e47839cd7"),
   721  			},
   722  		},
   723  	}
   724  
   725  	for i, tc := range tests {
   726  		tc := tc
   727  		if i > 0 {
   728  			t.Log("\n")
   729  		}
   730  		t.Logf("-- Test %d", i)
   731  		t.Log(tc.desc)
   732  		t.Log("  request:")
   733  		t.Logf("    root: %x", tc.root)
   734  		t.Logf("    paths: %x", tc.paths)
   735  		t.Logf("    responseBytes: %d", tc.nBytes)
   736  
   737  		if err := s.snapGetTrieNodes(t, &tc); err != nil {
   738  			t.Errorf("  failed: %v", err)
   739  		}
   740  	}
   741  }
   742  
   743  func makeSnapPath(key []byte, length int) snap.TrieNodePathSet {
   744  	hex := keybytesToHex(key)[:length]
   745  	hex[len(hex)-1] = 0 // remove term flag
   746  	hKey := hexToCompact(hex)
   747  	return snap.TrieNodePathSet{hKey}
   748  }
   749  
   750  func (s *Suite) snapGetAccountRange(t *utesting.T, tc *accRangeTest) error {
   751  	conn, err := s.dialSnap()
   752  	if err != nil {
   753  		t.Fatalf("dial failed: %v", err)
   754  	}
   755  	defer conn.Close()
   756  	if err = conn.peer(s.chain, nil); err != nil {
   757  		t.Fatalf("peering failed: %v", err)
   758  	}
   759  	// write request
   760  	req := &snap.GetAccountRangePacket{
   761  		ID:     uint64(rand.Int63()),
   762  		Root:   tc.root,
   763  		Origin: tc.startingHash,
   764  		Limit:  tc.limitHash,
   765  		Bytes:  tc.nBytes,
   766  	}
   767  	msg, err := conn.snapRequest(snap.GetAccountRangeMsg, req)
   768  	if err != nil {
   769  		return fmt.Errorf("account range request failed: %v", err)
   770  	}
   771  	res, ok := msg.(*snap.AccountRangePacket)
   772  	if !ok {
   773  		return fmt.Errorf("account range response wrong: %T %v", msg, msg)
   774  	}
   775  	if exp, got := tc.expAccounts, len(res.Accounts); exp != got {
   776  		return fmt.Errorf("expected %d accounts, got %d", exp, got)
   777  	}
   778  	// Check that the encoding order is correct
   779  	for i := 1; i < len(res.Accounts); i++ {
   780  		if bytes.Compare(res.Accounts[i-1].Hash[:], res.Accounts[i].Hash[:]) >= 0 {
   781  			return fmt.Errorf("accounts not monotonically increasing: #%d [%x] vs #%d [%x]", i-1, res.Accounts[i-1].Hash[:], i, res.Accounts[i].Hash[:])
   782  		}
   783  	}
   784  	var (
   785  		hashes   []common.Hash
   786  		accounts [][]byte
   787  		proof    = res.Proof
   788  	)
   789  	hashes, accounts, err = res.Unpack()
   790  	if err != nil {
   791  		return err
   792  	}
   793  	if len(hashes) == 0 && len(accounts) == 0 && len(proof) == 0 {
   794  		return nil
   795  	}
   796  	if len(hashes) > 0 {
   797  		if exp, got := tc.expFirst, res.Accounts[0].Hash; exp != got {
   798  			return fmt.Errorf("expected first account %#x, got %#x", exp, got)
   799  		}
   800  		if exp, got := tc.expLast, res.Accounts[len(res.Accounts)-1].Hash; exp != got {
   801  			return fmt.Errorf("expected last account %#x, got %#x", exp, got)
   802  		}
   803  	}
   804  	// Reconstruct a partial trie from the response and verify it
   805  	keys := make([][]byte, len(hashes))
   806  	for i, key := range hashes {
   807  		keys[i] = common.CopyBytes(key[:])
   808  	}
   809  	nodes := make(trienode.ProofList, len(proof))
   810  	for i, node := range proof {
   811  		nodes[i] = node
   812  	}
   813  	proofdb := nodes.Set()
   814  
   815  	_, err = trie.VerifyRangeProof(tc.root, tc.startingHash[:], keys, accounts, proofdb)
   816  	return err
   817  }
   818  
   819  func (s *Suite) snapGetStorageRanges(t *utesting.T, tc *stRangesTest) error {
   820  	conn, err := s.dialSnap()
   821  	if err != nil {
   822  		t.Fatalf("dial failed: %v", err)
   823  	}
   824  	defer conn.Close()
   825  	if err = conn.peer(s.chain, nil); err != nil {
   826  		t.Fatalf("peering failed: %v", err)
   827  	}
   828  
   829  	// write request
   830  	req := &snap.GetStorageRangesPacket{
   831  		ID:       uint64(rand.Int63()),
   832  		Root:     tc.root,
   833  		Accounts: tc.accounts,
   834  		Origin:   tc.origin,
   835  		Limit:    tc.limit,
   836  		Bytes:    tc.nBytes,
   837  	}
   838  	msg, err := conn.snapRequest(snap.GetStorageRangesMsg, req)
   839  	if err != nil {
   840  		return fmt.Errorf("account range request failed: %v", err)
   841  	}
   842  	res, ok := msg.(*snap.StorageRangesPacket)
   843  	if !ok {
   844  		return fmt.Errorf("account range response wrong: %T %v", msg, msg)
   845  	}
   846  
   847  	// Ensure the ranges are monotonically increasing
   848  	for i, slots := range res.Slots {
   849  		for j := 1; j < len(slots); j++ {
   850  			if bytes.Compare(slots[j-1].Hash[:], slots[j].Hash[:]) >= 0 {
   851  				return fmt.Errorf("storage slots not monotonically increasing for account #%d: #%d [%x] vs #%d [%x]", i, j-1, slots[j-1].Hash[:], j, slots[j].Hash[:])
   852  			}
   853  		}
   854  	}
   855  
   856  	// Compute expected slot hashes.
   857  	var expHashes [][]common.Hash
   858  	for _, acct := range tc.expSlots {
   859  		var list []common.Hash
   860  		for _, s := range acct {
   861  			list = append(list, s.Hash)
   862  		}
   863  		expHashes = append(expHashes, list)
   864  	}
   865  
   866  	// Check response.
   867  	if !reflect.DeepEqual(res.Slots, tc.expSlots) {
   868  		t.Log("  expected slot hashes:", expHashes)
   869  		return fmt.Errorf("wrong storage slots in response: %#v", res.Slots)
   870  	}
   871  	return nil
   872  }
   873  
   874  func (s *Suite) snapGetByteCodes(t *utesting.T, tc *byteCodesTest) error {
   875  	conn, err := s.dialSnap()
   876  	if err != nil {
   877  		t.Fatalf("dial failed: %v", err)
   878  	}
   879  	defer conn.Close()
   880  	if err = conn.peer(s.chain, nil); err != nil {
   881  		t.Fatalf("peering failed: %v", err)
   882  	}
   883  	// write request
   884  	req := &snap.GetByteCodesPacket{
   885  		ID:     uint64(rand.Int63()),
   886  		Hashes: tc.hashes,
   887  		Bytes:  tc.nBytes,
   888  	}
   889  	msg, err := conn.snapRequest(snap.GetByteCodesMsg, req)
   890  	if err != nil {
   891  		return fmt.Errorf("getBytecodes request failed: %v", err)
   892  	}
   893  	res, ok := msg.(*snap.ByteCodesPacket)
   894  	if !ok {
   895  		return fmt.Errorf("bytecodes response wrong: %T %v", msg, msg)
   896  	}
   897  	if exp, got := tc.expHashes, len(res.Codes); exp != got {
   898  		for i, c := range res.Codes {
   899  			t.Logf("%d. %#x\n", i, c)
   900  		}
   901  		return fmt.Errorf("expected %d bytecodes, got %d", exp, got)
   902  	}
   903  	// Cross reference the requested bytecodes with the response to find gaps
   904  	// that the serving node is missing
   905  	var (
   906  		bytecodes = res.Codes
   907  		hasher    = crypto.NewKeccakState()
   908  		hash      = make([]byte, 32)
   909  		codes     = make([][]byte, len(req.Hashes))
   910  	)
   911  
   912  	for i, j := 0, 0; i < len(bytecodes); i++ {
   913  		// Find the next hash that we've been served, leaving misses with nils
   914  		hasher.Reset()
   915  		hasher.Write(bytecodes[i])
   916  		hasher.Read(hash)
   917  
   918  		for j < len(req.Hashes) && !bytes.Equal(hash, req.Hashes[j][:]) {
   919  			j++
   920  		}
   921  		if j < len(req.Hashes) {
   922  			codes[j] = bytecodes[i]
   923  			j++
   924  			continue
   925  		}
   926  		// We've either ran out of hashes, or got unrequested data
   927  		return errors.New("unexpected bytecode")
   928  	}
   929  
   930  	return nil
   931  }
   932  
   933  func (s *Suite) snapGetTrieNodes(t *utesting.T, tc *trieNodesTest) error {
   934  	conn, err := s.dialSnap()
   935  	if err != nil {
   936  		t.Fatalf("dial failed: %v", err)
   937  	}
   938  	defer conn.Close()
   939  	if err = conn.peer(s.chain, nil); err != nil {
   940  		t.Fatalf("peering failed: %v", err)
   941  	}
   942  
   943  	// write0 request
   944  	req := &snap.GetTrieNodesPacket{
   945  		ID:    uint64(rand.Int63()),
   946  		Root:  tc.root,
   947  		Paths: tc.paths,
   948  		Bytes: tc.nBytes,
   949  	}
   950  	msg, err := conn.snapRequest(snap.GetTrieNodesMsg, req)
   951  	if err != nil {
   952  		if tc.expReject {
   953  			return nil
   954  		}
   955  		return fmt.Errorf("trienodes  request failed: %v", err)
   956  	}
   957  	res, ok := msg.(*snap.TrieNodesPacket)
   958  	if !ok {
   959  		return fmt.Errorf("trienodes response wrong: %T %v", msg, msg)
   960  	}
   961  
   962  	// Check the correctness
   963  
   964  	// Cross reference the requested trienodes with the response to find gaps
   965  	// that the serving node is missing
   966  	hasher := crypto.NewKeccakState()
   967  	hash := make([]byte, 32)
   968  	trienodes := res.Nodes
   969  	if got, want := len(trienodes), len(tc.expHashes); got != want {
   970  		return fmt.Errorf("wrong trienode count, got %d, want %d", got, want)
   971  	}
   972  	for i, trienode := range trienodes {
   973  		hasher.Reset()
   974  		hasher.Write(trienode)
   975  		hasher.Read(hash)
   976  		if got, want := hash, tc.expHashes[i]; !bytes.Equal(got, want[:]) {
   977  			t.Logf("  hash %d wrong, got %#x, want %#x\n", i, got, want)
   978  			err = fmt.Errorf("hash %d wrong, got %#x, want %#x", i, got, want)
   979  		}
   980  	}
   981  	return err
   982  }