github.com/c2s/go-ethereum@v1.9.7/eth/api_test.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package eth
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"math/big"
    23  	"reflect"
    24  	"sort"
    25  	"testing"
    26  
    27  	"github.com/davecgh/go-spew/spew"
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/core/rawdb"
    30  	"github.com/ethereum/go-ethereum/core/state"
    31  	"github.com/ethereum/go-ethereum/crypto"
    32  )
    33  
    34  var dumper = spew.ConfigState{Indent: "    "}
    35  
    36  func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, start *common.Hash, requestedNum int, expectedNum int) AccountRangeResult {
    37  	result, err := accountRange(*trie, start, requestedNum)
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  
    42  	if len(result.Accounts) != expectedNum {
    43  		t.Fatalf("expected %d results.  Got %d", expectedNum, len(result.Accounts))
    44  	}
    45  
    46  	for _, address := range result.Accounts {
    47  		if address == nil {
    48  			t.Fatalf("null address returned")
    49  		}
    50  		if !statedb.Exist(*address) {
    51  			t.Fatalf("account not found in state %s", address.Hex())
    52  		}
    53  	}
    54  
    55  	return result
    56  }
    57  
    58  type resultHash []*common.Hash
    59  
    60  func (h resultHash) Len() int           { return len(h) }
    61  func (h resultHash) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
    62  func (h resultHash) Less(i, j int) bool { return bytes.Compare(h[i].Bytes(), h[j].Bytes()) < 0 }
    63  
    64  func TestAccountRange(t *testing.T) {
    65  	var (
    66  		statedb  = state.NewDatabase(rawdb.NewMemoryDatabase())
    67  		state, _ = state.New(common.Hash{}, statedb)
    68  		addrs    = [AccountRangeMaxResults * 2]common.Address{}
    69  		m        = map[common.Address]bool{}
    70  	)
    71  
    72  	for i := range addrs {
    73  		hash := common.HexToHash(fmt.Sprintf("%x", i))
    74  		addr := common.BytesToAddress(crypto.Keccak256Hash(hash.Bytes()).Bytes())
    75  		addrs[i] = addr
    76  		state.SetBalance(addrs[i], big.NewInt(1))
    77  		if _, ok := m[addr]; ok {
    78  			t.Fatalf("bad")
    79  		} else {
    80  			m[addr] = true
    81  		}
    82  	}
    83  
    84  	state.Commit(true)
    85  	root := state.IntermediateRoot(true)
    86  
    87  	trie, err := statedb.OpenTrie(root)
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  
    92  	t.Logf("test getting number of results less than max")
    93  	accountRangeTest(t, &trie, state, &common.Hash{0x0}, AccountRangeMaxResults/2, AccountRangeMaxResults/2)
    94  
    95  	t.Logf("test getting number of results greater than max %d", AccountRangeMaxResults)
    96  	accountRangeTest(t, &trie, state, &common.Hash{0x0}, AccountRangeMaxResults*2, AccountRangeMaxResults)
    97  
    98  	t.Logf("test with empty 'start' hash")
    99  	accountRangeTest(t, &trie, state, nil, AccountRangeMaxResults, AccountRangeMaxResults)
   100  
   101  	t.Logf("test pagination")
   102  
   103  	// test pagination
   104  	firstResult := accountRangeTest(t, &trie, state, &common.Hash{0x0}, AccountRangeMaxResults, AccountRangeMaxResults)
   105  
   106  	t.Logf("test pagination 2")
   107  	secondResult := accountRangeTest(t, &trie, state, &firstResult.Next, AccountRangeMaxResults, AccountRangeMaxResults)
   108  
   109  	hList := make(resultHash, 0)
   110  	for h1, addr1 := range firstResult.Accounts {
   111  		h := &common.Hash{}
   112  		h.SetBytes(h1.Bytes())
   113  		hList = append(hList, h)
   114  		for h2, addr2 := range secondResult.Accounts {
   115  			// Make sure that the hashes aren't the same
   116  			if bytes.Equal(h1.Bytes(), h2.Bytes()) {
   117  				t.Fatalf("pagination test failed:  results should not overlap")
   118  			}
   119  
   120  			// If either address is nil, then it makes no sense to compare
   121  			// them as they might be two different accounts.
   122  			if addr1 == nil || addr2 == nil {
   123  				continue
   124  			}
   125  
   126  			// Since the two hashes are different, they should not have
   127  			// the same preimage, but let's check anyway in case there
   128  			// is a bug in the (hash, addr) map generation code.
   129  			if bytes.Equal(addr1.Bytes(), addr2.Bytes()) {
   130  				t.Fatalf("pagination test failed: addresses should not repeat")
   131  			}
   132  		}
   133  	}
   134  
   135  	// Test to see if it's possible to recover from the middle of the previous
   136  	// set and get an even split between the first and second sets.
   137  	t.Logf("test random access pagination")
   138  	sort.Sort(hList)
   139  	middleH := hList[AccountRangeMaxResults/2]
   140  	middleResult := accountRangeTest(t, &trie, state, middleH, AccountRangeMaxResults, AccountRangeMaxResults)
   141  	innone, infirst, insecond := 0, 0, 0
   142  	for h := range middleResult.Accounts {
   143  		if _, ok := firstResult.Accounts[h]; ok {
   144  			infirst++
   145  		} else if _, ok := secondResult.Accounts[h]; ok {
   146  			insecond++
   147  		} else {
   148  			innone++
   149  		}
   150  	}
   151  	if innone != 0 {
   152  		t.Fatalf("%d hashes in the 'middle' set were neither in the first not the second set", innone)
   153  	}
   154  	if infirst != AccountRangeMaxResults/2 {
   155  		t.Fatalf("Imbalance in the number of first-test results: %d != %d", infirst, AccountRangeMaxResults/2)
   156  	}
   157  	if insecond != AccountRangeMaxResults/2 {
   158  		t.Fatalf("Imbalance in the number of second-test results: %d != %d", insecond, AccountRangeMaxResults/2)
   159  	}
   160  }
   161  
   162  func TestEmptyAccountRange(t *testing.T) {
   163  	var (
   164  		statedb  = state.NewDatabase(rawdb.NewMemoryDatabase())
   165  		state, _ = state.New(common.Hash{}, statedb)
   166  	)
   167  
   168  	state.Commit(true)
   169  	root := state.IntermediateRoot(true)
   170  
   171  	trie, err := statedb.OpenTrie(root)
   172  	if err != nil {
   173  		t.Fatal(err)
   174  	}
   175  
   176  	results, err := accountRange(trie, &common.Hash{0x0}, AccountRangeMaxResults)
   177  	if err != nil {
   178  		t.Fatalf("Empty results should not trigger an error: %v", err)
   179  	}
   180  	if results.Next != common.HexToHash("0") {
   181  		t.Fatalf("Empty results should not return a second page")
   182  	}
   183  	if len(results.Accounts) != 0 {
   184  		t.Fatalf("Empty state should not return addresses: %v", results.Accounts)
   185  	}
   186  }
   187  
   188  func TestStorageRangeAt(t *testing.T) {
   189  	// Create a state where account 0x010000... has a few storage entries.
   190  	var (
   191  		state, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
   192  		addr     = common.Address{0x01}
   193  		keys     = []common.Hash{ // hashes of Keys of storage
   194  			common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"),
   195  			common.HexToHash("426fcb404ab2d5d8e61a3d918108006bbb0a9be65e92235bb10eefbdb6dcd053"),
   196  			common.HexToHash("48078cfed56339ea54962e72c37c7f588fc4f8e5bc173827ba75cb10a63a96a5"),
   197  			common.HexToHash("5723d2c3a83af9b735e3b7f21531e5623d183a9095a56604ead41f3582fdfb75"),
   198  		}
   199  		storage = storageMap{
   200  			keys[0]: {Key: &common.Hash{0x02}, Value: common.Hash{0x01}},
   201  			keys[1]: {Key: &common.Hash{0x04}, Value: common.Hash{0x02}},
   202  			keys[2]: {Key: &common.Hash{0x01}, Value: common.Hash{0x03}},
   203  			keys[3]: {Key: &common.Hash{0x03}, Value: common.Hash{0x04}},
   204  		}
   205  	)
   206  	for _, entry := range storage {
   207  		state.SetState(addr, *entry.Key, entry.Value)
   208  	}
   209  
   210  	// Check a few combinations of limit and start/end.
   211  	tests := []struct {
   212  		start []byte
   213  		limit int
   214  		want  StorageRangeResult
   215  	}{
   216  		{
   217  			start: []byte{}, limit: 0,
   218  			want: StorageRangeResult{storageMap{}, &keys[0]},
   219  		},
   220  		{
   221  			start: []byte{}, limit: 100,
   222  			want: StorageRangeResult{storage, nil},
   223  		},
   224  		{
   225  			start: []byte{}, limit: 2,
   226  			want: StorageRangeResult{storageMap{keys[0]: storage[keys[0]], keys[1]: storage[keys[1]]}, &keys[2]},
   227  		},
   228  		{
   229  			start: []byte{0x00}, limit: 4,
   230  			want: StorageRangeResult{storage, nil},
   231  		},
   232  		{
   233  			start: []byte{0x40}, limit: 2,
   234  			want: StorageRangeResult{storageMap{keys[1]: storage[keys[1]], keys[2]: storage[keys[2]]}, &keys[3]},
   235  		},
   236  	}
   237  	for _, test := range tests {
   238  		result, err := storageRangeAt(state.StorageTrie(addr), test.start, test.limit)
   239  		if err != nil {
   240  			t.Error(err)
   241  		}
   242  		if !reflect.DeepEqual(result, test.want) {
   243  			t.Fatalf("wrong result for range 0x%x.., limit %d:\ngot %s\nwant %s",
   244  				test.start, test.limit, dumper.Sdump(result), dumper.Sdump(&test.want))
   245  		}
   246  	}
   247  }