github.com/core-coin/go-core/v2@v2.1.9/xcb/api_test.go (about) 1 // Copyright 2017 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package xcb 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 29 "github.com/core-coin/go-core/v2/common" 30 "github.com/core-coin/go-core/v2/core/rawdb" 31 "github.com/core-coin/go-core/v2/core/state" 32 "github.com/core-coin/go-core/v2/crypto" 33 ) 34 35 var dumper = spew.ConfigState{Indent: " "} 36 37 func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, start common.Hash, requestedNum int, expectedNum int) state.IteratorDump { 38 result := statedb.IteratorDump(true, true, false, start.Bytes(), requestedNum) 39 40 if len(result.Accounts) != expectedNum { 41 t.Fatalf("expected %d results, got %d", expectedNum, len(result.Accounts)) 42 } 43 for address := range result.Accounts { 44 if address == (common.Address{}) { 45 t.Fatalf("empty address returned") 46 } 47 if !statedb.Exist(address) { 48 t.Fatalf("account not found in state %s", address.Hex()) 49 } 50 } 51 return result 52 } 53 54 type resultHash []common.Hash 55 56 func (h resultHash) Len() int { return len(h) } 57 func (h resultHash) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 58 func (h resultHash) Less(i, j int) bool { return bytes.Compare(h[i].Bytes(), h[j].Bytes()) < 0 } 59 60 func TestAccountRange(t *testing.T) { 61 var ( 62 statedb = state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), nil) 63 state, _ = state.New(common.Hash{}, statedb, nil) 64 addrs = [AccountRangeMaxResults * 2]common.Address{} 65 m = map[common.Address]bool{} 66 ) 67 68 for i := range addrs { 69 hash := common.HexToHash(fmt.Sprintf("%x", i)) 70 addr := common.BytesToAddress(crypto.SHA3Hash(hash.Bytes()).Bytes()) 71 addrs[i] = addr 72 state.SetBalance(addrs[i], big.NewInt(1)) 73 if _, ok := m[addr]; ok { 74 t.Fatalf("bad") 75 } else { 76 m[addr] = true 77 } 78 } 79 state.Commit(true) 80 root := state.IntermediateRoot(true) 81 82 trie, err := statedb.OpenTrie(root) 83 if err != nil { 84 t.Fatal(err) 85 } 86 accountRangeTest(t, &trie, state, common.Hash{}, AccountRangeMaxResults/2, AccountRangeMaxResults/2) 87 // test pagination 88 firstResult := accountRangeTest(t, &trie, state, common.Hash{}, AccountRangeMaxResults, AccountRangeMaxResults) 89 secondResult := accountRangeTest(t, &trie, state, common.BytesToHash(firstResult.Next), AccountRangeMaxResults, AccountRangeMaxResults) 90 91 hList := make(resultHash, 0) 92 for addr1 := range firstResult.Accounts { 93 // If address is empty, then it makes no sense to compare 94 // them as they might be two different accounts. 95 if addr1 == (common.Address{}) { 96 continue 97 } 98 if _, duplicate := secondResult.Accounts[addr1]; duplicate { 99 t.Fatalf("pagination test failed: results should not overlap") 100 } 101 hList = append(hList, crypto.SHA3Hash(addr1.Bytes())) 102 } 103 // Test to see if it's possible to recover from the middle of the previous 104 // set and get an even split between the first and second sets. 105 sort.Sort(hList) 106 middleH := hList[AccountRangeMaxResults/2] 107 middleResult := accountRangeTest(t, &trie, state, middleH, AccountRangeMaxResults, AccountRangeMaxResults) 108 missing, infirst, insecond := 0, 0, 0 109 for h := range middleResult.Accounts { 110 if _, ok := firstResult.Accounts[h]; ok { 111 infirst++ 112 } else if _, ok := secondResult.Accounts[h]; ok { 113 insecond++ 114 } else { 115 missing++ 116 } 117 } 118 if missing != 0 { 119 t.Fatalf("%d hashes in the 'middle' set were neither in the first not the second set", missing) 120 } 121 if infirst != AccountRangeMaxResults/2 { 122 t.Fatalf("Imbalance in the number of first-test results: %d != %d", infirst, AccountRangeMaxResults/2) 123 } 124 if insecond != AccountRangeMaxResults/2 { 125 t.Fatalf("Imbalance in the number of second-test results: %d != %d", insecond, AccountRangeMaxResults/2) 126 } 127 } 128 129 func TestEmptyAccountRange(t *testing.T) { 130 var ( 131 statedb = state.NewDatabase(rawdb.NewMemoryDatabase()) 132 state, _ = state.New(common.Hash{}, statedb, nil) 133 ) 134 state.Commit(true) 135 state.IntermediateRoot(true) 136 results := state.IteratorDump(true, true, true, (common.Hash{}).Bytes(), AccountRangeMaxResults) 137 if bytes.Equal(results.Next, (common.Hash{}).Bytes()) { 138 t.Fatalf("Empty results should not return a second page") 139 } 140 if len(results.Accounts) != 0 { 141 t.Fatalf("Empty state should not return addresses: %v", results.Accounts) 142 } 143 } 144 145 func TestStorageRangeAt(t *testing.T) { 146 // Create a state where account 0x010000... has a few storage entries. 147 var ( 148 state, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) 149 addr = common.Address{0x01} 150 keys = []common.Hash{ // hashes of Keys of storage 151 common.HexToHash("04527935532e92b92643e934da84bf65e789e245f4ca0b085b900bbdb81578da"), 152 common.HexToHash("17cd8acc6c4e438664ef675e23dd274fed89954bc8e1e5ad0003f99332212603"), 153 common.HexToHash("d7027bc25d82ac8d2c6419fed9692fa1a3001c98b97baec850241f6119b746c2"), 154 common.HexToHash("e1fb0112e1ea3e72c8828d3024821a29a8637b94469e2f767f49cec25f24f1e3"), 155 } 156 storage = storageMap{ 157 keys[0]: {Key: &common.Hash{0x03}, Value: common.Hash{0x04}}, 158 keys[1]: {Key: &common.Hash{0x01}, Value: common.Hash{0x03}}, 159 keys[2]: {Key: &common.Hash{0x04}, Value: common.Hash{0x02}}, 160 keys[3]: {Key: &common.Hash{0x02}, Value: common.Hash{0x01}}, 161 } 162 ) 163 for _, entry := range storage { 164 state.SetState(addr, *entry.Key, entry.Value) 165 } 166 167 // Check a few combinations of limit and start/end. 168 tests := []struct { 169 start []byte 170 limit int 171 want StorageRangeResult 172 }{ 173 { 174 start: []byte{}, limit: 0, 175 want: StorageRangeResult{storageMap{}, &keys[0]}, 176 }, 177 { 178 start: []byte{}, limit: 100, 179 want: StorageRangeResult{storage, nil}, 180 }, 181 { 182 start: []byte{}, limit: 2, 183 want: StorageRangeResult{storageMap{keys[0]: storage[keys[0]], keys[1]: storage[keys[1]]}, &keys[2]}, 184 }, 185 { 186 start: []byte{0x00}, limit: 4, 187 want: StorageRangeResult{storage, nil}, 188 }, 189 { 190 start: []byte{0x10}, limit: 2, 191 want: StorageRangeResult{storageMap{keys[1]: storage[keys[1]], keys[2]: storage[keys[2]]}, &keys[3]}, 192 }, 193 } 194 for _, test := range tests { 195 result, err := storageRangeAt(state.StorageTrie(addr), test.start, test.limit) 196 if err != nil { 197 t.Error(err) 198 } 199 if !reflect.DeepEqual(result, test.want) { 200 t.Fatalf("wrong result for range 0x%x.., limit %d:\ngot %s\nwant %s", 201 test.start, test.limit, dumper.Sdump(result), dumper.Sdump(&test.want)) 202 } 203 } 204 }