github.com/ethereum/go-ethereum@v1.16.1/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  		if i > 0 {
   290  			t.Log("\n")
   291  		}
   292  		t.Logf("-- Test %d", i)
   293  		t.Log(tc.desc)
   294  		t.Log("  request:")
   295  		t.Logf("      root: %x", tc.root)
   296  		t.Logf("      range: %#x - %#x", tc.startingHash, tc.limitHash)
   297  		t.Logf("      responseBytes: %d", tc.nBytes)
   298  		if err := s.snapGetAccountRange(t, &tc); err != nil {
   299  			t.Errorf("test %d failed: %v", i, err)
   300  		}
   301  	}
   302  }
   303  
   304  func hashAdd(h common.Hash, n int64) common.Hash {
   305  	hb := h.Big()
   306  	return common.BigToHash(hb.Add(hb, big.NewInt(n)))
   307  }
   308  
   309  func findNonEmptyStorageRoot(accounts []state.DumpAccount) common.Hash {
   310  	for i := range accounts {
   311  		if len(accounts[i].Storage) != 0 {
   312  			return common.BytesToHash(accounts[i].Root)
   313  		}
   314  	}
   315  	panic("can't find account with non-empty storage")
   316  }
   317  
   318  type stRangesTest struct {
   319  	root     common.Hash
   320  	accounts []common.Hash
   321  	origin   []byte
   322  	limit    []byte
   323  	nBytes   uint64
   324  
   325  	expSlots [][]*snap.StorageData
   326  
   327  	desc string
   328  }
   329  
   330  // TestSnapGetStorageRanges various forms of GetStorageRanges requests.
   331  func (s *Suite) TestSnapGetStorageRanges(t *utesting.T) {
   332  	var (
   333  		acct      = common.HexToAddress("0x8bebc8ba651aee624937e7d897853ac30c95a067")
   334  		acctHash  = common.BytesToHash(s.chain.state[acct].AddressHash)
   335  		ffHash    = common.MaxHash
   336  		zero      = common.Hash{}
   337  		blockroot = s.chain.Head().Root()
   338  	)
   339  
   340  	// These are the storage slots of the test account, encoded as snap response data.
   341  	acctSlots := []*snap.StorageData{
   342  		{
   343  			Hash: common.HexToHash("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"),
   344  			Body: []byte{0x02},
   345  		},
   346  		{
   347  			Hash: common.HexToHash("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"),
   348  			Body: []byte{0x01},
   349  		},
   350  		{
   351  			Hash: common.HexToHash("0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b"),
   352  			Body: []byte{0x03},
   353  		},
   354  	}
   355  
   356  	tests := []stRangesTest{
   357  		/*
   358  			Some tests against this account:
   359  
   360  			"0x8bebc8ba651aee624937e7d897853ac30c95a067": {
   361  				"balance": "1",
   362  				"nonce": 1,
   363  				"root": "0xe318dff15b33aa7f2f12d5567d58628e3e3f2e8859e46b56981a4083b391da17",
   364  				"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
   365  				"storage": {
   366  					// Note: keys below are hashed!!!
   367  					"0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace": "02",
   368  					"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6": "01",
   369  					"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b": "03"
   370  				},
   371  				"key": "0x445cb5c1278fdce2f9cbdb681bdd76c52f8e50e41dbd9e220242a69ba99ac099"
   372  			}
   373  		*/
   374  
   375  		{ // [:] -> [slot1, slot2, slot3]
   376  			desc: `This request has a range of 00..ff.
   377  The server should return all storage slots of the test account.`,
   378  			root:     blockroot,
   379  			accounts: []common.Hash{acctHash},
   380  			origin:   zero[:],
   381  			limit:    ffHash[:],
   382  			nBytes:   500,
   383  			expSlots: [][]*snap.StorageData{acctSlots},
   384  		},
   385  
   386  		{ // [slot1:] -> [slot1, slot2, slot3]
   387  			desc: `This test requests slots starting at the first available key.
   388  The server should return all storage slots of the test account.`,
   389  			root:     blockroot,
   390  			accounts: []common.Hash{acctHash},
   391  			origin:   common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"),
   392  			limit:    ffHash[:],
   393  			nBytes:   1000,
   394  			expSlots: [][]*snap.StorageData{acctSlots},
   395  		},
   396  
   397  		{ // [slot1+:] -> [slot2, slot3]
   398  			desc: `This test requests slots starting at a key one past the first available key.
   399  The server should return the remaining two slots of the test account.`,
   400  			root:     blockroot,
   401  			accounts: []common.Hash{acctHash},
   402  			origin:   common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf"),
   403  			limit:    ffHash[:],
   404  			nBytes:   500,
   405  			expSlots: [][]*snap.StorageData{acctSlots[1:]},
   406  		},
   407  
   408  		{ // [slot1:slot2] -> [slot1, slot2]
   409  			desc:     `This test requests a range which is exactly the first and second available key.`,
   410  			root:     blockroot,
   411  			accounts: []common.Hash{acctHash},
   412  			origin:   common.FromHex("0x405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace"),
   413  			limit:    common.FromHex("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"),
   414  			nBytes:   500,
   415  			expSlots: [][]*snap.StorageData{acctSlots[:2]},
   416  		},
   417  
   418  		{ // [slot1+:slot2+] -> [slot2, slot3]
   419  			desc: `This test requests a range where limitHash is after the second, but before the third slot
   420  of the test account. The server should return slots [2,3] (i.e. the 'next available' needs to be returned).`,
   421  			root:     blockroot,
   422  			accounts: []common.Hash{acctHash},
   423  			origin:   common.FromHex("0x4fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
   424  			limit:    common.FromHex("0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7"),
   425  			nBytes:   500,
   426  			expSlots: [][]*snap.StorageData{acctSlots[1:]},
   427  		},
   428  	}
   429  
   430  	for i, tc := range tests {
   431  		if i > 0 {
   432  			t.Log("\n")
   433  		}
   434  		t.Logf("-- Test %d", i)
   435  		t.Log(tc.desc)
   436  		t.Log("  request:")
   437  		t.Logf("      root: %x", tc.root)
   438  		t.Logf("      accounts: %x", tc.accounts)
   439  		t.Logf("      range: %#x - %#x", tc.origin, tc.limit)
   440  		t.Logf("      responseBytes: %d", tc.nBytes)
   441  		if err := s.snapGetStorageRanges(t, &tc); err != nil {
   442  			t.Errorf("  failed: %v", err)
   443  		}
   444  	}
   445  }
   446  
   447  type byteCodesTest struct {
   448  	nBytes uint64
   449  	hashes []common.Hash
   450  
   451  	expHashes int
   452  
   453  	desc string
   454  }
   455  
   456  // TestSnapGetByteCodes various forms of GetByteCodes requests.
   457  func (s *Suite) TestSnapGetByteCodes(t *utesting.T) {
   458  	var (
   459  		allHashes   = s.chain.CodeHashes()
   460  		headRoot    = s.chain.Head().Root()
   461  		genesisRoot = s.chain.RootAt(0)
   462  	)
   463  
   464  	tests := []byteCodesTest{
   465  		// A few stateroots
   466  		{
   467  			desc:      `Here we request state roots as code hashes. The server should deliver an empty response with no items.`,
   468  			nBytes:    10000,
   469  			hashes:    []common.Hash{genesisRoot, headRoot},
   470  			expHashes: 0,
   471  		},
   472  		{
   473  			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.`,
   474  			nBytes:    10000,
   475  			hashes:    []common.Hash{genesisRoot, genesisRoot},
   476  			expHashes: 0,
   477  		},
   478  		// Empties
   479  		{
   480  			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.`,
   481  			nBytes:    10000,
   482  			hashes:    []common.Hash{types.EmptyRootHash},
   483  			expHashes: 0,
   484  		},
   485  		{
   486  			desc:      `Here we request the empty code hash. The server should deliver an empty response item.`,
   487  			nBytes:    10000,
   488  			hashes:    []common.Hash{types.EmptyCodeHash},
   489  			expHashes: 1,
   490  		},
   491  		{
   492  			desc:      `In this test, we request the empty code hash three times. The server should deliver the empty item three times.`,
   493  			nBytes:    10000,
   494  			hashes:    []common.Hash{types.EmptyCodeHash, types.EmptyCodeHash, types.EmptyCodeHash},
   495  			expHashes: 3,
   496  		},
   497  		// The existing bytecodes
   498  		{
   499  			desc:      `Here we request all available contract codes. The server should deliver them all in one response.`,
   500  			nBytes:    100000,
   501  			hashes:    allHashes,
   502  			expHashes: len(allHashes),
   503  		},
   504  		// The existing, with limited byte arg
   505  		{
   506  			desc:      `In this test, the request has a bytes limit of one. The server should deliver one item.`,
   507  			nBytes:    1,
   508  			hashes:    allHashes,
   509  			expHashes: 1,
   510  		},
   511  		{
   512  			desc:      `In this test, the request has a bytes limit of zero. The server should deliver one item.`,
   513  			nBytes:    0,
   514  			hashes:    allHashes,
   515  			expHashes: 1,
   516  		},
   517  		// Request the same hash multiple times.
   518  		{
   519  			desc:      `This test requests the same code hash multiple times. The server should deliver it multiple times.`,
   520  			nBytes:    1000,
   521  			hashes:    []common.Hash{allHashes[0], allHashes[0], allHashes[0], allHashes[0]},
   522  			expHashes: 4,
   523  		},
   524  	}
   525  
   526  	for i, tc := range tests {
   527  		if i > 0 {
   528  			t.Log("\n")
   529  		}
   530  		t.Logf("-- Test %d", i)
   531  		t.Log(tc.desc)
   532  		t.Log("  request:")
   533  		t.Logf("      hashes: %x", tc.hashes)
   534  		t.Logf("      responseBytes: %d", tc.nBytes)
   535  		if err := s.snapGetByteCodes(t, &tc); err != nil {
   536  			t.Errorf("failed: %v", err)
   537  		}
   538  	}
   539  }
   540  
   541  type trieNodesTest struct {
   542  	root   common.Hash
   543  	paths  []snap.TrieNodePathSet
   544  	nBytes uint64
   545  
   546  	expHashes []common.Hash // expected response
   547  	expReject bool          // if true, request should be rejected
   548  
   549  	desc string
   550  }
   551  
   552  func decodeNibbles(nibbles []byte, bytes []byte) {
   553  	for bi, ni := 0, 0; ni < len(nibbles); bi, ni = bi+1, ni+2 {
   554  		bytes[bi] = nibbles[ni]<<4 | nibbles[ni+1]
   555  	}
   556  }
   557  
   558  // hasTerm returns whether a hex key has the terminator flag.
   559  func hasTerm(s []byte) bool {
   560  	return len(s) > 0 && s[len(s)-1] == 16
   561  }
   562  
   563  func keybytesToHex(str []byte) []byte {
   564  	l := len(str)*2 + 1
   565  	var nibbles = make([]byte, l)
   566  	for i, b := range str {
   567  		nibbles[i*2] = b / 16
   568  		nibbles[i*2+1] = b % 16
   569  	}
   570  	nibbles[l-1] = 16
   571  	return nibbles
   572  }
   573  
   574  func hexToCompact(hex []byte) []byte {
   575  	terminator := byte(0)
   576  	if hasTerm(hex) {
   577  		terminator = 1
   578  		hex = hex[:len(hex)-1]
   579  	}
   580  	buf := make([]byte, len(hex)/2+1)
   581  	buf[0] = terminator << 5 // the flag byte
   582  	if len(hex)&1 == 1 {
   583  		buf[0] |= 1 << 4 // odd flag
   584  		buf[0] |= hex[0] // first nibble is contained in the first byte
   585  		hex = hex[1:]
   586  	}
   587  	decodeNibbles(hex, buf[1:])
   588  	return buf
   589  }
   590  
   591  // TestSnapTrieNodes various forms of GetTrieNodes requests.
   592  func (s *Suite) TestSnapTrieNodes(t *utesting.T) {
   593  	var (
   594  		// This is the known address of the snap storage testing contract.
   595  		storageAcct     = common.HexToAddress("0x8bebc8ba651aee624937e7d897853ac30c95a067")
   596  		storageAcctHash = common.BytesToHash(s.chain.state[storageAcct].AddressHash)
   597  		// This is the known address of an existing account.
   598  		key      = common.FromHex("0xa87387b50b481431c6ccdb9ae99a54d4dcdd4a3eff75d7b17b4818f7bbfc21e9")
   599  		empty    = types.EmptyCodeHash
   600  		accPaths []snap.TrieNodePathSet
   601  	)
   602  	for i := 1; i <= 65; i++ {
   603  		accPaths = append(accPaths, makeSnapPath(key, i))
   604  	}
   605  
   606  	tests := []trieNodesTest{
   607  		{
   608  			desc:      `In this test, we send an empty request to the node.`,
   609  			root:      s.chain.Head().Root(),
   610  			paths:     nil,
   611  			nBytes:    500,
   612  			expHashes: nil,
   613  		},
   614  
   615  		{
   616  			desc: `In this test, we send a request containing an empty path-set.
   617  The server should reject the request.`,
   618  			root: s.chain.Head().Root(),
   619  			paths: []snap.TrieNodePathSet{
   620  				{}, // zero-length pathset should 'abort' and kick us off
   621  				{[]byte{0}},
   622  			},
   623  			nBytes:    5000,
   624  			expHashes: []common.Hash{},
   625  			expReject: true,
   626  		},
   627  
   628  		{
   629  			desc: `Here we request the root node of the trie. The server should respond with the root node.`,
   630  			root: s.chain.RootAt(int(s.chain.Head().NumberU64() - 1)),
   631  			paths: []snap.TrieNodePathSet{
   632  				{[]byte{0}},
   633  				{[]byte{1}, []byte{0}},
   634  			},
   635  			nBytes:    5000,
   636  			expHashes: []common.Hash{s.chain.RootAt(int(s.chain.Head().NumberU64() - 1))},
   637  		},
   638  
   639  		{ // nonsensically long path
   640  			desc: `In this test, we request a very long trie node path. The server should respond with an empty node (keccak256("")).`,
   641  			root: s.chain.Head().Root(),
   642  			paths: []snap.TrieNodePathSet{
   643  				{[]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,
   644  					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}},
   645  			},
   646  			nBytes:    5000,
   647  			expHashes: []common.Hash{types.EmptyCodeHash},
   648  		},
   649  
   650  		{
   651  			// The leaf is only a couple of levels down, so the continued trie traversal causes lookup failures.
   652  			desc:   `Here we request some known accounts from the state.`,
   653  			root:   s.chain.Head().Root(),
   654  			paths:  accPaths,
   655  			nBytes: 5000,
   656  			expHashes: []common.Hash{
   657  				// It's a bit unfortunate these are hard-coded, but the result depends on
   658  				// a lot of aspects of the state trie and can't be guessed in a simple
   659  				// way. So you'll have to update this when the test chain is changed.
   660  				common.HexToHash("0x3e963a69401a70224cbfb8c0cc2249b019041a538675d71ccf80c9328d114e2e"),
   661  				common.HexToHash("0xd0670d09cdfbf3c6320eb3e92c47c57baa6c226551a2d488c05581091e6b1689"),
   662  				empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty,
   663  				empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty,
   664  				empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty, empty,
   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},
   668  		},
   669  
   670  		{
   671  			desc: `In this test, we request some known accounts in state. The requested paths are NOT in key order.`,
   672  			root: s.chain.Head().Root(),
   673  			paths: []snap.TrieNodePathSet{
   674  				accPaths[10], accPaths[1], accPaths[0],
   675  			},
   676  			nBytes: 5000,
   677  			// As with the previous test, this result depends on the whole tree and will have to
   678  			// be updated when the test chain is changed.
   679  			expHashes: []common.Hash{
   680  				empty,
   681  				common.HexToHash("0xd0670d09cdfbf3c6320eb3e92c47c57baa6c226551a2d488c05581091e6b1689"),
   682  				common.HexToHash("0x3e963a69401a70224cbfb8c0cc2249b019041a538675d71ccf80c9328d114e2e"),
   683  			},
   684  		},
   685  
   686  		// Storage tests.
   687  		// These use the known storage test account.
   688  
   689  		{
   690  			desc: `This test requests the storage root node of a known account.`,
   691  			root: s.chain.Head().Root(),
   692  			paths: []snap.TrieNodePathSet{
   693  				{
   694  					storageAcctHash[:],
   695  					[]byte{0},
   696  				},
   697  			},
   698  			nBytes: 5000,
   699  			expHashes: []common.Hash{
   700  				common.HexToHash("0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790"),
   701  			},
   702  		},
   703  
   704  		{
   705  			desc: `This test requests multiple storage nodes of a known account.`,
   706  			root: s.chain.Head().Root(),
   707  			paths: []snap.TrieNodePathSet{
   708  				{
   709  					storageAcctHash[:],
   710  					[]byte{0},
   711  					[]byte{0x1b},
   712  				},
   713  			},
   714  			nBytes: 5000,
   715  			expHashes: []common.Hash{
   716  				common.HexToHash("0xbe3d75a1729be157e79c3b77f00206db4d54e3ea14375a015451c88ec067c790"),
   717  				common.HexToHash("0xf4984a11f61a2921456141df88de6e1a710d28681b91af794c5a721e47839cd7"),
   718  			},
   719  		},
   720  	}
   721  
   722  	for i, tc := range tests {
   723  		if i > 0 {
   724  			t.Log("\n")
   725  		}
   726  		t.Logf("-- Test %d", i)
   727  		t.Log(tc.desc)
   728  		t.Log("  request:")
   729  		t.Logf("    root: %x", tc.root)
   730  		t.Logf("    paths: %x", tc.paths)
   731  		t.Logf("    responseBytes: %d", tc.nBytes)
   732  
   733  		if err := s.snapGetTrieNodes(t, &tc); err != nil {
   734  			t.Errorf("  failed: %v", err)
   735  		}
   736  	}
   737  }
   738  
   739  func makeSnapPath(key []byte, length int) snap.TrieNodePathSet {
   740  	hex := keybytesToHex(key)[:length]
   741  	hex[len(hex)-1] = 0 // remove term flag
   742  	hKey := hexToCompact(hex)
   743  	return snap.TrieNodePathSet{hKey}
   744  }
   745  
   746  func (s *Suite) snapGetAccountRange(t *utesting.T, tc *accRangeTest) error {
   747  	conn, err := s.dialSnap()
   748  	if err != nil {
   749  		t.Fatalf("dial failed: %v", err)
   750  	}
   751  	defer conn.Close()
   752  	if err = conn.peer(s.chain, nil); err != nil {
   753  		t.Fatalf("peering failed: %v", err)
   754  	}
   755  	// write request
   756  	req := &snap.GetAccountRangePacket{
   757  		ID:     uint64(rand.Int63()),
   758  		Root:   tc.root,
   759  		Origin: tc.startingHash,
   760  		Limit:  tc.limitHash,
   761  		Bytes:  tc.nBytes,
   762  	}
   763  	msg, err := conn.snapRequest(snap.GetAccountRangeMsg, req)
   764  	if err != nil {
   765  		return fmt.Errorf("account range request failed: %v", err)
   766  	}
   767  	res, ok := msg.(*snap.AccountRangePacket)
   768  	if !ok {
   769  		return fmt.Errorf("account range response wrong: %T %v", msg, msg)
   770  	}
   771  	if exp, got := tc.expAccounts, len(res.Accounts); exp != got {
   772  		return fmt.Errorf("expected %d accounts, got %d", exp, got)
   773  	}
   774  	// Check that the encoding order is correct
   775  	for i := 1; i < len(res.Accounts); i++ {
   776  		if bytes.Compare(res.Accounts[i-1].Hash[:], res.Accounts[i].Hash[:]) >= 0 {
   777  			return fmt.Errorf("accounts not monotonically increasing: #%d [%x] vs #%d [%x]", i-1, res.Accounts[i-1].Hash[:], i, res.Accounts[i].Hash[:])
   778  		}
   779  	}
   780  	var (
   781  		hashes   []common.Hash
   782  		accounts [][]byte
   783  		proof    = res.Proof
   784  	)
   785  	hashes, accounts, err = res.Unpack()
   786  	if err != nil {
   787  		return err
   788  	}
   789  	if len(hashes) == 0 && len(accounts) == 0 && len(proof) == 0 {
   790  		return nil
   791  	}
   792  	if len(hashes) > 0 {
   793  		if exp, got := tc.expFirst, res.Accounts[0].Hash; exp != got {
   794  			return fmt.Errorf("expected first account %#x, got %#x", exp, got)
   795  		}
   796  		if exp, got := tc.expLast, res.Accounts[len(res.Accounts)-1].Hash; exp != got {
   797  			return fmt.Errorf("expected last account %#x, got %#x", exp, got)
   798  		}
   799  	}
   800  	// Reconstruct a partial trie from the response and verify it
   801  	keys := make([][]byte, len(hashes))
   802  	for i, key := range hashes {
   803  		keys[i] = common.CopyBytes(key[:])
   804  	}
   805  	nodes := make(trienode.ProofList, len(proof))
   806  	for i, node := range proof {
   807  		nodes[i] = node
   808  	}
   809  	proofdb := nodes.Set()
   810  
   811  	_, err = trie.VerifyRangeProof(tc.root, tc.startingHash[:], keys, accounts, proofdb)
   812  	return err
   813  }
   814  
   815  func (s *Suite) snapGetStorageRanges(t *utesting.T, tc *stRangesTest) error {
   816  	conn, err := s.dialSnap()
   817  	if err != nil {
   818  		t.Fatalf("dial failed: %v", err)
   819  	}
   820  	defer conn.Close()
   821  	if err = conn.peer(s.chain, nil); err != nil {
   822  		t.Fatalf("peering failed: %v", err)
   823  	}
   824  
   825  	// write request
   826  	req := &snap.GetStorageRangesPacket{
   827  		ID:       uint64(rand.Int63()),
   828  		Root:     tc.root,
   829  		Accounts: tc.accounts,
   830  		Origin:   tc.origin,
   831  		Limit:    tc.limit,
   832  		Bytes:    tc.nBytes,
   833  	}
   834  	msg, err := conn.snapRequest(snap.GetStorageRangesMsg, req)
   835  	if err != nil {
   836  		return fmt.Errorf("account range request failed: %v", err)
   837  	}
   838  	res, ok := msg.(*snap.StorageRangesPacket)
   839  	if !ok {
   840  		return fmt.Errorf("account range response wrong: %T %v", msg, msg)
   841  	}
   842  
   843  	// Ensure the ranges are monotonically increasing
   844  	for i, slots := range res.Slots {
   845  		for j := 1; j < len(slots); j++ {
   846  			if bytes.Compare(slots[j-1].Hash[:], slots[j].Hash[:]) >= 0 {
   847  				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[:])
   848  			}
   849  		}
   850  	}
   851  
   852  	// Compute expected slot hashes.
   853  	var expHashes [][]common.Hash
   854  	for _, acct := range tc.expSlots {
   855  		var list []common.Hash
   856  		for _, s := range acct {
   857  			list = append(list, s.Hash)
   858  		}
   859  		expHashes = append(expHashes, list)
   860  	}
   861  
   862  	// Check response.
   863  	if !reflect.DeepEqual(res.Slots, tc.expSlots) {
   864  		t.Log("  expected slot hashes:", expHashes)
   865  		return fmt.Errorf("wrong storage slots in response: %#v", res.Slots)
   866  	}
   867  	return nil
   868  }
   869  
   870  func (s *Suite) snapGetByteCodes(t *utesting.T, tc *byteCodesTest) error {
   871  	conn, err := s.dialSnap()
   872  	if err != nil {
   873  		t.Fatalf("dial failed: %v", err)
   874  	}
   875  	defer conn.Close()
   876  	if err = conn.peer(s.chain, nil); err != nil {
   877  		t.Fatalf("peering failed: %v", err)
   878  	}
   879  	// write request
   880  	req := &snap.GetByteCodesPacket{
   881  		ID:     uint64(rand.Int63()),
   882  		Hashes: tc.hashes,
   883  		Bytes:  tc.nBytes,
   884  	}
   885  	msg, err := conn.snapRequest(snap.GetByteCodesMsg, req)
   886  	if err != nil {
   887  		return fmt.Errorf("getBytecodes request failed: %v", err)
   888  	}
   889  	res, ok := msg.(*snap.ByteCodesPacket)
   890  	if !ok {
   891  		return fmt.Errorf("bytecodes response wrong: %T %v", msg, msg)
   892  	}
   893  	if exp, got := tc.expHashes, len(res.Codes); exp != got {
   894  		for i, c := range res.Codes {
   895  			t.Logf("%d. %#x\n", i, c)
   896  		}
   897  		return fmt.Errorf("expected %d bytecodes, got %d", exp, got)
   898  	}
   899  	// Cross reference the requested bytecodes with the response to find gaps
   900  	// that the serving node is missing
   901  	var (
   902  		bytecodes = res.Codes
   903  		hasher    = crypto.NewKeccakState()
   904  		hash      = make([]byte, 32)
   905  		codes     = make([][]byte, len(req.Hashes))
   906  	)
   907  
   908  	for i, j := 0, 0; i < len(bytecodes); i++ {
   909  		// Find the next hash that we've been served, leaving misses with nils
   910  		hasher.Reset()
   911  		hasher.Write(bytecodes[i])
   912  		hasher.Read(hash)
   913  
   914  		for j < len(req.Hashes) && !bytes.Equal(hash, req.Hashes[j][:]) {
   915  			j++
   916  		}
   917  		if j < len(req.Hashes) {
   918  			codes[j] = bytecodes[i]
   919  			j++
   920  			continue
   921  		}
   922  		// We've either ran out of hashes, or got unrequested data
   923  		return errors.New("unexpected bytecode")
   924  	}
   925  
   926  	return nil
   927  }
   928  
   929  func (s *Suite) snapGetTrieNodes(t *utesting.T, tc *trieNodesTest) error {
   930  	conn, err := s.dialSnap()
   931  	if err != nil {
   932  		t.Fatalf("dial failed: %v", err)
   933  	}
   934  	defer conn.Close()
   935  	if err = conn.peer(s.chain, nil); err != nil {
   936  		t.Fatalf("peering failed: %v", err)
   937  	}
   938  
   939  	// write0 request
   940  	req := &snap.GetTrieNodesPacket{
   941  		ID:    uint64(rand.Int63()),
   942  		Root:  tc.root,
   943  		Paths: tc.paths,
   944  		Bytes: tc.nBytes,
   945  	}
   946  	msg, err := conn.snapRequest(snap.GetTrieNodesMsg, req)
   947  	if err != nil {
   948  		if tc.expReject {
   949  			return nil
   950  		}
   951  		return fmt.Errorf("trienodes  request failed: %v", err)
   952  	}
   953  	res, ok := msg.(*snap.TrieNodesPacket)
   954  	if !ok {
   955  		return fmt.Errorf("trienodes response wrong: %T %v", msg, msg)
   956  	}
   957  
   958  	// Check the correctness
   959  
   960  	// Cross reference the requested trienodes with the response to find gaps
   961  	// that the serving node is missing
   962  	hasher := crypto.NewKeccakState()
   963  	hash := make([]byte, 32)
   964  	trienodes := res.Nodes
   965  	if got, want := len(trienodes), len(tc.expHashes); got != want {
   966  		return fmt.Errorf("wrong trienode count, got %d, want %d", got, want)
   967  	}
   968  	for i, trienode := range trienodes {
   969  		hasher.Reset()
   970  		hasher.Write(trienode)
   971  		hasher.Read(hash)
   972  		if got, want := hash, tc.expHashes[i]; !bytes.Equal(got, want[:]) {
   973  			t.Logf("  hash %d wrong, got %#x, want %#x\n", i, got, want)
   974  			err = fmt.Errorf("hash %d wrong, got %#x, want %#x", i, got, want)
   975  		}
   976  	}
   977  	return err
   978  }