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 }