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