github.com/koko1123/flow-go-1@v0.29.6/ledger/partial/ledger.go (about) 1 package partial 2 3 import ( 4 "fmt" 5 6 "github.com/koko1123/flow-go-1/ledger" 7 "github.com/koko1123/flow-go-1/ledger/common/pathfinder" 8 "github.com/koko1123/flow-go-1/ledger/partial/ptrie" 9 ) 10 11 const DefaultPathFinderVersion = 1 12 13 // Ledger implements the ledger functionality for a limited subset of keys (partial ledger). 14 // Partial ledgers are designed to be constructed and verified by a collection of proofs from a complete ledger. 15 // The partial ledger uses a partial binary Merkle trie which holds intermediate hash value for the pruned branched and prevents updates to keys that were not part of proofs. 16 type Ledger struct { 17 ptrie *ptrie.PSMT 18 state ledger.State 19 proof ledger.Proof 20 pathFinderVersion uint8 21 } 22 23 // NewLedger creates a new in-memory trie-backed ledger storage with persistence. 24 func NewLedger(proof ledger.Proof, s ledger.State, pathFinderVer uint8) (*Ledger, error) { 25 26 // Decode proof encodings 27 if len(proof) < 1 { 28 return nil, fmt.Errorf("at least a proof is needed to be able to contruct a partial trie") 29 } 30 batchProof, err := ledger.DecodeTrieBatchProof(proof) 31 if err != nil { 32 return nil, fmt.Errorf("decoding proof failed: %w", err) 33 } 34 35 // decode proof 36 psmt, err := ptrie.NewPSMT(ledger.RootHash(s), batchProof) 37 38 if err != nil { 39 // TODO provide more details based on the error type 40 return nil, ledger.NewErrLedgerConstruction(err) 41 } 42 43 return &Ledger{ptrie: psmt, proof: proof, state: s, pathFinderVersion: pathFinderVer}, nil 44 } 45 46 // Ready implements interface module.ReadyDoneAware 47 func (l *Ledger) Ready() <-chan struct{} { 48 ready := make(chan struct{}) 49 close(ready) 50 return ready 51 } 52 53 // Done implements interface module.ReadyDoneAware 54 func (l *Ledger) Done() <-chan struct{} { 55 done := make(chan struct{}) 56 close(done) 57 return done 58 } 59 60 // InitialState returns the initial state of the ledger 61 func (l *Ledger) InitialState() ledger.State { 62 return l.state 63 } 64 65 // HasState returns true if the given state exists inside the ledger 66 func (l *Ledger) HasState(other ledger.State) bool { 67 return l.state.Equals(other) 68 } 69 70 // GetSingleValue reads value of a given key at the given state 71 func (l *Ledger) GetSingleValue(query *ledger.QuerySingleValue) (value ledger.Value, err error) { 72 path, err := pathfinder.KeyToPath(query.Key(), l.pathFinderVersion) 73 if err != nil { 74 return nil, err 75 } 76 payload, err := l.ptrie.GetSinglePayload(path) 77 if err != nil { 78 if _, ok := err.(*ptrie.ErrMissingPath); ok { 79 return nil, &ledger.ErrMissingKeys{Keys: []ledger.Key{query.Key()}} 80 } 81 return nil, err 82 } 83 return payload.Value(), err 84 } 85 86 // Get read the values of the given keys at the given state 87 // it returns the values in the same order as given registerIDs and errors (if any) 88 func (l *Ledger) Get(query *ledger.Query) (values []ledger.Value, err error) { 89 // TODO compare query.State() to the ledger sc 90 paths, err := pathfinder.KeysToPaths(query.Keys(), l.pathFinderVersion) 91 if err != nil { 92 return nil, err 93 } 94 payloads, err := l.ptrie.Get(paths) 95 if err != nil { 96 if pErr, ok := err.(*ptrie.ErrMissingPath); ok { 97 //store mappings and restore keys from missing paths 98 pathToKey := make(map[ledger.Path]ledger.Key) 99 100 for i, key := range query.Keys() { 101 path := paths[i] 102 pathToKey[path] = key 103 } 104 105 keys := make([]ledger.Key, len(pErr.Paths)) 106 for i, path := range pErr.Paths { 107 keys[i] = pathToKey[path] 108 } 109 return nil, &ledger.ErrMissingKeys{Keys: keys} 110 } 111 return nil, err 112 } 113 values, err = pathfinder.PayloadsToValues(payloads) 114 if err != nil { 115 return nil, err 116 } 117 return values, err 118 } 119 120 // Set updates the ledger given an update 121 // it returns the state after update and errors (if any) 122 func (l *Ledger) Set(update *ledger.Update) (newState ledger.State, trieUpdate *ledger.TrieUpdate, err error) { 123 // TODO: add test case 124 if update.Size() == 0 { 125 // return current state root unchanged 126 return update.State(), nil, nil 127 } 128 129 trieUpdate, err = pathfinder.UpdateToTrieUpdate(update, l.pathFinderVersion) 130 if err != nil { 131 return ledger.DummyState, nil, err 132 } 133 134 newRootHash, err := l.ptrie.Update(trieUpdate.Paths, trieUpdate.Payloads) 135 if err != nil { 136 if pErr, ok := err.(*ptrie.ErrMissingPath); ok { 137 //store mappings and restore keys from missing paths 138 pathToKey := make(map[ledger.Path]ledger.Key) 139 140 for i, key := range update.Keys() { 141 path := trieUpdate.Paths[i] 142 pathToKey[path] = key 143 } 144 145 keys := make([]ledger.Key, len(pErr.Paths)) 146 for i, path := range pErr.Paths { 147 keys[i] = pathToKey[path] 148 } 149 return ledger.DummyState, nil, &ledger.ErrMissingKeys{Keys: keys} 150 } 151 return ledger.DummyState, nil, err 152 } 153 154 // TODO log info state 155 return ledger.State(newRootHash), trieUpdate, nil 156 } 157 158 // Prove provides proofs for a ledger query and errors (if any) 159 // TODO implement this by iterating over initial proofs to find the ones for the query 160 func (l *Ledger) Prove(query *ledger.Query) (proof ledger.Proof, err error) { 161 return nil, err 162 }