github.com/amazechain/amc@v0.1.3/modules/state/history.go (about) 1 // Copyright 2023 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package state 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "errors" 23 "fmt" 24 "github.com/RoaringBitmap/roaring/roaring64" 25 "github.com/amazechain/amc/common/account" 26 "github.com/amazechain/amc/common/types" 27 "github.com/amazechain/amc/modules" 28 "github.com/amazechain/amc/modules/changeset" 29 "github.com/amazechain/amc/modules/ethdb" 30 "github.com/amazechain/amc/modules/ethdb/bitmapdb" 31 "github.com/ledgerwatch/erigon-lib/kv" 32 ) 33 34 func GetAsOf(tx kv.Tx, indexC kv.Cursor, changesC kv.CursorDupSort, storage bool, key []byte, timestamp uint64) ([]byte, error) { 35 v, err := FindByHistory(tx, indexC, changesC, storage, key, timestamp) 36 if err == nil { 37 return v, nil 38 } 39 if !errors.Is(err, ethdb.ErrKeyNotFound) { 40 return nil, err 41 } 42 if storage { 43 return tx.GetOne(modules.Storage, key) 44 } 45 return tx.GetOne(modules.Account, key) 46 } 47 48 func FindByHistory(tx kv.Tx, indexC kv.Cursor, changesC kv.CursorDupSort, storage bool, key []byte, timestamp uint64) ([]byte, error) { 49 var csBucket string 50 if storage { 51 csBucket = modules.StorageChangeSet 52 } else { 53 csBucket = modules.AccountChangeSet 54 } 55 56 k, v, seekErr := indexC.Seek(changeset.Mapper[csBucket].IndexChunkKey(key, timestamp)) 57 if seekErr != nil { 58 return nil, seekErr 59 } 60 61 if k == nil { 62 return nil, ethdb.ErrKeyNotFound 63 } 64 if storage { 65 if !bytes.Equal(k[:types.AddressLength], key[:types.AddressLength]) || 66 !bytes.Equal(k[types.AddressLength:types.AddressLength+types.HashLength], key[types.AddressLength+types.IncarnationLength:]) { 67 return nil, ethdb.ErrKeyNotFound 68 } 69 } else { 70 if !bytes.HasPrefix(k, key) { 71 return nil, ethdb.ErrKeyNotFound 72 } 73 } 74 index := roaring64.New() 75 if _, err := index.ReadFrom(bytes.NewReader(v)); err != nil { 76 return nil, err 77 } 78 found, ok := bitmapdb.SeekInBitmap64(index, timestamp) 79 changeSetBlock := found 80 81 var data []byte 82 var err error 83 if ok { 84 data, err = changeset.Mapper[csBucket].Find(changesC, changeSetBlock, key) 85 if err != nil { 86 if !errors.Is(err, changeset.ErrNotFound) { 87 return nil, fmt.Errorf("finding %x in the changeset %d: %w", key, changeSetBlock, err) 88 } 89 return nil, ethdb.ErrKeyNotFound 90 } 91 } else { 92 return nil, ethdb.ErrKeyNotFound 93 } 94 95 //restore codehash 96 if !storage { 97 var acc account.StateAccount 98 if err := acc.DecodeForStorage(data); err != nil { 99 return nil, err 100 } 101 if acc.Incarnation > 0 && acc.IsEmptyCodeHash() { 102 var codeHash []byte 103 var err error 104 codeHash, err = tx.GetOne(modules.PlainContractCode, modules.PlainGenerateStoragePrefix(key, acc.Incarnation)) 105 if err != nil { 106 return nil, err 107 } 108 if len(codeHash) > 0 { 109 acc.CodeHash.SetBytes(codeHash) 110 } 111 data = make([]byte, acc.EncodingLengthForStorage()) 112 acc.EncodeForStorage(data) 113 } 114 return data, nil 115 } 116 117 return data, nil 118 } 119 120 // startKey is the concatenation of address and incarnation (BigEndian 8 byte) 121 func WalkAsOfStorage(tx kv.Tx, address types.Address, incarnation uint16, startLocation types.Hash, timestamp uint64, walker func(k1, k2, v []byte) (bool, error)) error { 122 var startkey = make([]byte, types.AddressLength+types.IncarnationLength+types.HashLength) 123 copy(startkey, address.Bytes()) 124 binary.BigEndian.PutUint16(startkey[types.AddressLength:], incarnation) 125 copy(startkey[types.AddressLength+types.IncarnationLength:], startLocation.Bytes()) 126 127 var startkeyNoInc = make([]byte, types.AddressLength+types.HashLength) 128 copy(startkeyNoInc, address.Bytes()) 129 copy(startkeyNoInc[types.AddressLength:], startLocation.Bytes()) 130 131 //for storage 132 mCursor, err := tx.Cursor(modules.Storage) 133 if err != nil { 134 return err 135 } 136 defer mCursor.Close() 137 mainCursor := ethdb.NewSplitCursor( 138 mCursor, 139 startkey, 140 8*(types.AddressLength+types.IncarnationLength), 141 types.AddressLength, /* part1end */ 142 types.AddressLength+types.IncarnationLength, /* part2start */ 143 types.AddressLength+types.IncarnationLength+types.HashLength, /* part3start */ 144 ) 145 146 //for historic data 147 shCursor, err := tx.Cursor(modules.StorageHistory) 148 if err != nil { 149 return err 150 } 151 defer shCursor.Close() 152 var hCursor = ethdb.NewSplitCursor( 153 shCursor, 154 startkeyNoInc, 155 8*types.AddressLength, 156 types.AddressLength, /* part1end */ 157 types.AddressLength, /* part2start */ 158 types.AddressLength+types.HashLength, /* part3start */ 159 ) 160 csCursor, err := tx.CursorDupSort(modules.StorageChangeSet) 161 if err != nil { 162 return err 163 } 164 defer csCursor.Close() 165 166 addr, loc, _, v, err1 := mainCursor.Seek() 167 if err1 != nil { 168 return err1 169 } 170 171 hAddr, hLoc, tsEnc, hV, err2 := hCursor.Seek() 172 if err2 != nil { 173 return err2 174 } 175 for hLoc != nil && binary.BigEndian.Uint64(tsEnc) < timestamp { 176 if hAddr, hLoc, tsEnc, hV, err2 = hCursor.Next(); err2 != nil { 177 return err2 178 } 179 } 180 goOn := true 181 for goOn { 182 cmp, br := types.KeyCmp(addr, hAddr) 183 if br { 184 break 185 } 186 if cmp == 0 { 187 cmp, br = types.KeyCmp(loc, hLoc) 188 } 189 if br { 190 break 191 } 192 193 //next key in state 194 if cmp < 0 { 195 goOn, err = walker(addr, loc, v) 196 } else { 197 index := roaring64.New() 198 if _, err = index.ReadFrom(bytes.NewReader(hV)); err != nil { 199 return err 200 } 201 found, ok := bitmapdb.SeekInBitmap64(index, timestamp) 202 changeSetBlock := found 203 204 if ok { 205 // Extract value from the changeSet 206 csKey := make([]byte, 8+types.AddressLength+types.IncarnationLength) 207 copy(csKey, modules.EncodeBlockNumber(changeSetBlock)) 208 copy(csKey[8:], address[:]) // address + incarnation 209 binary.BigEndian.PutUint16(csKey[8+types.AddressLength:], incarnation) 210 kData := csKey 211 data, err3 := csCursor.SeekBothRange(csKey, hLoc) 212 if err3 != nil { 213 return err3 214 } 215 if !bytes.Equal(kData, csKey) || !bytes.HasPrefix(data, hLoc) { 216 return fmt.Errorf("inconsistent storage changeset and history kData %x, csKey %x, data %x, hLoc %x", kData, csKey, data, hLoc) 217 } 218 data = data[types.HashLength:] 219 if len(data) > 0 { // Skip deleted entries 220 goOn, err = walker(hAddr, hLoc, data) 221 } 222 } else if cmp == 0 { 223 goOn, err = walker(addr, loc, v) 224 } 225 } 226 if err != nil { 227 return err 228 } 229 if goOn { 230 if cmp <= 0 { 231 if addr, loc, _, v, err1 = mainCursor.Next(); err1 != nil { 232 return err1 233 } 234 } 235 if cmp >= 0 { 236 hLoc0 := hLoc 237 for hLoc != nil && (bytes.Equal(hLoc0, hLoc) || binary.BigEndian.Uint64(tsEnc) < timestamp) { 238 if hAddr, hLoc, tsEnc, hV, err2 = hCursor.Next(); err2 != nil { 239 return err2 240 } 241 } 242 } 243 } 244 } 245 return nil 246 } 247 248 func WalkAsOfAccounts(tx kv.Tx, startAddress types.Address, timestamp uint64, walker func(k []byte, v []byte) (bool, error)) error { 249 mainCursor, err := tx.Cursor(modules.Account) 250 if err != nil { 251 return err 252 } 253 defer mainCursor.Close() 254 ahCursor, err := tx.Cursor(modules.AccountsHistory) 255 if err != nil { 256 return err 257 } 258 defer ahCursor.Close() 259 var hCursor = ethdb.NewSplitCursor( 260 ahCursor, 261 startAddress.Bytes(), 262 0, /* fixedBits */ 263 types.AddressLength, /* part1end */ 264 types.AddressLength, /* part2start */ 265 types.AddressLength+8, /* part3start */ 266 ) 267 csCursor, err := tx.CursorDupSort(modules.AccountChangeSet) 268 if err != nil { 269 return err 270 } 271 defer csCursor.Close() 272 273 k, v, err1 := mainCursor.Seek(startAddress.Bytes()) 274 if err1 != nil { 275 return err1 276 } 277 for k != nil && len(k) > types.AddressLength { 278 k, v, err1 = mainCursor.Next() 279 if err1 != nil { 280 return err1 281 } 282 } 283 hK, tsEnc, _, hV, err2 := hCursor.Seek() 284 if err2 != nil { 285 return err2 286 } 287 for hK != nil && binary.BigEndian.Uint64(tsEnc) < timestamp { 288 hK, tsEnc, _, hV, err2 = hCursor.Next() 289 if err2 != nil { 290 return err2 291 } 292 } 293 294 goOn := true 295 for goOn { 296 //exit or next conditions 297 cmp, br := types.KeyCmp(k, hK) 298 if br { 299 break 300 } 301 if cmp < 0 { 302 goOn, err = walker(k, v) 303 } else { 304 index := roaring64.New() 305 _, err = index.ReadFrom(bytes.NewReader(hV)) 306 if err != nil { 307 return err 308 } 309 found, ok := bitmapdb.SeekInBitmap64(index, timestamp) 310 changeSetBlock := found 311 if ok { 312 // Extract value from the changeSet 313 csKey := modules.EncodeBlockNumber(changeSetBlock) 314 kData := csKey 315 data, err3 := csCursor.SeekBothRange(csKey, hK) 316 if err3 != nil { 317 return err3 318 } 319 if !bytes.Equal(kData, csKey) || !bytes.HasPrefix(data, hK) { 320 return fmt.Errorf("inconsistent account history and changesets, kData %x, csKey %x, data %x, hK %x", kData, csKey, data, hK) 321 } 322 data = data[types.AddressLength:] 323 if len(data) > 0 { // Skip accounts did not exist 324 goOn, err = walker(hK, data) 325 } 326 } else if cmp == 0 { 327 goOn, err = walker(k, v) 328 } 329 } 330 if err != nil { 331 return err 332 } 333 if goOn { 334 if cmp <= 0 { 335 k, v, err1 = mainCursor.Next() 336 if err1 != nil { 337 return err1 338 } 339 for k != nil && len(k) > types.AddressLength { 340 k, v, err1 = mainCursor.Next() 341 if err1 != nil { 342 return err1 343 } 344 } 345 } 346 if cmp >= 0 { 347 hK0 := hK 348 for hK != nil && (bytes.Equal(hK0, hK) || binary.BigEndian.Uint64(tsEnc) < timestamp) { 349 hK, tsEnc, _, hV, err1 = hCursor.Next() 350 if err1 != nil { 351 return err1 352 } 353 } 354 } 355 } 356 } 357 return err 358 359 }