github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/ledger/common/pathfinder/pathfinder.go (about)

     1  // Package pathfinder computes the trie storage path for any given key/value pair
     2  package pathfinder
     3  
     4  import (
     5  	"crypto/sha256"
     6  	"fmt"
     7  
     8  	"github.com/onflow/crypto/hash"
     9  
    10  	"github.com/onflow/flow-go/ledger"
    11  )
    12  
    13  // PathByteSize captures number of bytes each path takes
    14  const PathByteSize = 32
    15  
    16  // KeyToPath converts key into a path
    17  // version zero applies sha2-256 on value of the key parts (in order ignoring types)
    18  func KeyToPath(key ledger.Key, version uint8) (ledger.Path, error) {
    19  	switch version {
    20  	case 0:
    21  		{
    22  			ret := make([]byte, 0)
    23  			for _, kp := range key.KeyParts {
    24  				ret = append(ret, kp.Value...)
    25  			}
    26  			h := sha256.New()
    27  			_, err := h.Write(ret)
    28  			if err != nil {
    29  				return ledger.DummyPath, err
    30  			}
    31  			path, err := ledger.ToPath(h.Sum(nil))
    32  			if err != nil {
    33  				return ledger.DummyPath, err
    34  			}
    35  			return path, nil
    36  		}
    37  	case 1:
    38  		{
    39  			var path ledger.Path
    40  			hash.ComputeSHA3_256((*[ledger.PathLen]byte)(&path), key.CanonicalForm())
    41  			return path, nil
    42  		}
    43  	}
    44  	return ledger.DummyPath, fmt.Errorf("unsupported key to path version")
    45  }
    46  
    47  // KeysToPaths converts an slice of keys into a paths
    48  func KeysToPaths(keys []ledger.Key, version uint8) ([]ledger.Path, error) {
    49  	paths := make([]ledger.Path, len(keys))
    50  	for i, k := range keys {
    51  		p, err := KeyToPath(k, version)
    52  		if err != nil {
    53  			return nil, err
    54  		}
    55  		paths[i] = p
    56  	}
    57  	return paths, nil
    58  }
    59  
    60  // UpdateToTrieUpdate converts an update into a trie update
    61  func UpdateToTrieUpdate(u *ledger.Update, version uint8) (*ledger.TrieUpdate, error) {
    62  
    63  	paths, err := KeysToPaths(u.Keys(), version)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	payloads, err := UpdateToPayloads(u)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	trieUpdate := &ledger.TrieUpdate{RootHash: ledger.RootHash(u.State()), Paths: paths, Payloads: payloads}
    74  
    75  	return trieUpdate, nil
    76  }
    77  
    78  // QueryToTrieRead converts a ledger query into a trie read
    79  func QueryToTrieRead(q *ledger.Query, version uint8) (*ledger.TrieRead, error) {
    80  
    81  	paths, err := KeysToPaths(q.Keys(), version)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	trieRead := &ledger.TrieRead{RootHash: ledger.RootHash(q.State()), Paths: paths}
    87  
    88  	return trieRead, nil
    89  }
    90  
    91  // PayloadsToValues extracts values from an slice of payload
    92  func PayloadsToValues(payloads []*ledger.Payload) ([]ledger.Value, error) {
    93  	ret := make([]ledger.Value, len(payloads))
    94  	for i, p := range payloads {
    95  		ret[i] = p.Value()
    96  	}
    97  	return ret, nil
    98  }
    99  
   100  // PathsFromPayloads constructs paths from an slice of payload
   101  func PathsFromPayloads(payloads []*ledger.Payload, version uint8) ([]ledger.Path, error) {
   102  	paths := make([]ledger.Path, len(payloads))
   103  	for i, pay := range payloads {
   104  		k, err := pay.Key()
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  		p, err := KeyToPath(k, version)
   109  		if err != nil {
   110  			return nil, err
   111  		}
   112  		paths[i] = p
   113  	}
   114  	return paths, nil
   115  }
   116  
   117  // UpdateToPayloads constructs an slice of payloads given ledger update
   118  func UpdateToPayloads(update *ledger.Update) ([]*ledger.Payload, error) {
   119  	keys := update.Keys()
   120  	values := update.Values()
   121  	payloads := make([]*ledger.Payload, len(keys))
   122  	for i := range keys {
   123  		payload := ledger.NewPayload(keys[i], values[i])
   124  		payloads[i] = payload
   125  	}
   126  	return payloads, nil
   127  }