github.com/amazechain/amc@v0.1.3/modules/changeset/storage_changeset.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 changeset 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "errors" 23 "fmt" 24 "github.com/amazechain/amc/modules" 25 "sort" 26 27 libcommon "github.com/ledgerwatch/erigon-lib/common" 28 "github.com/ledgerwatch/erigon-lib/common/length" 29 "github.com/ledgerwatch/erigon-lib/etl" 30 "github.com/ledgerwatch/erigon-lib/kv" 31 ) 32 33 const ( 34 DefaultIncarnation = uint64(1) 35 ) 36 37 var ( 38 ErrNotFound = errors.New("not found") 39 ) 40 41 func NewStorageChangeSet() *ChangeSet { 42 return &ChangeSet{ 43 Changes: make([]Change, 0), 44 keyLen: length.Addr + length.Hash + modules.Incarnation, 45 } 46 } 47 48 func EncodeStorage(blockN uint64, s *ChangeSet, f func(k, v []byte) error) error { 49 sort.Sort(s) 50 keyPart := length.Addr + modules.Incarnation 51 for _, cs := range s.Changes { 52 newK := make([]byte, length.BlockNum+keyPart) 53 binary.BigEndian.PutUint64(newK, blockN) 54 copy(newK[8:], cs.Key[:keyPart]) 55 newV := make([]byte, 0, length.Hash+len(cs.Value)) 56 newV = append(append(newV, cs.Key[keyPart:]...), cs.Value...) 57 if err := f(newK, newV); err != nil { 58 return err 59 } 60 } 61 return nil 62 } 63 64 func DecodeStorage(dbKey, dbValue []byte) (uint64, []byte, []byte, error) { 65 blockN := binary.BigEndian.Uint64(dbKey) 66 if len(dbValue) < length.Hash { 67 return 0, nil, nil, fmt.Errorf("storage changes purged for block %d", blockN) 68 } 69 k := make([]byte, length.Addr+modules.Incarnation+length.Hash) 70 dbKey = dbKey[length.BlockNum:] // remove BlockN bytes 71 copy(k, dbKey) 72 copy(k[len(dbKey):], dbValue[:length.Hash]) 73 v := dbValue[length.Hash:] 74 if len(v) == 0 { 75 v = nil 76 } 77 78 return blockN, k, v, nil 79 } 80 81 func FindStorage(c kv.CursorDupSort, blockNumber uint64, k []byte) ([]byte, error) { 82 addWithInc, loc := k[:length.Addr+modules.Incarnation], k[length.Addr+modules.Incarnation:] 83 seek := make([]byte, length.BlockNum+length.Addr+modules.Incarnation) 84 binary.BigEndian.PutUint64(seek, blockNumber) 85 copy(seek[8:], addWithInc) 86 v, err := c.SeekBothRange(seek, loc) 87 if err != nil { 88 return nil, err 89 } 90 if !bytes.HasPrefix(v, loc) { 91 return nil, ErrNotFound 92 } 93 return v[length.Hash:], nil 94 } 95 96 // RewindDataPlain generates rewind data for all plain buckets between the timestamp 97 // timestapSrc is the current timestamp, and timestamp Dst is where we rewind 98 func RewindData(db kv.Tx, timestampSrc, timestampDst uint64, changes *etl.Collector, quit <-chan struct{}) error { 99 if err := walkAndCollect( 100 changes.Collect, 101 db, modules.AccountChangeSet, 102 timestampDst+1, timestampSrc, 103 quit, 104 ); err != nil { 105 return err 106 } 107 108 if err := walkAndCollect( 109 changes.Collect, 110 db, modules.StorageChangeSet, 111 timestampDst+1, timestampSrc, 112 quit, 113 ); err != nil { 114 return err 115 } 116 117 return nil 118 } 119 120 func walkAndCollect(collectorFunc func([]byte, []byte) error, db kv.Tx, bucket string, timestampDst, timestampSrc uint64, quit <-chan struct{}) error { 121 return ForRange(db, bucket, timestampDst, timestampSrc+1, func(bl uint64, k, v []byte) error { 122 if err := libcommon.Stopped(quit); err != nil { 123 return err 124 } 125 if innerErr := collectorFunc(libcommon.Copy(k), libcommon.Copy(v)); innerErr != nil { 126 return innerErr 127 } 128 return nil 129 }) 130 }