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  }