-
Notifications
You must be signed in to change notification settings - Fork 175
/
account_key_reader.go
203 lines (175 loc) · 4.68 KB
/
account_key_reader.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package environment
import (
"fmt"
"github.com/onflow/cadence/runtime"
"github.com/onflow/cadence/runtime/common"
"github.com/onflow/flow-go/fvm/crypto"
"github.com/onflow/flow-go/fvm/errors"
"github.com/onflow/flow-go/fvm/storage/state"
"github.com/onflow/flow-go/fvm/tracing"
"github.com/onflow/flow-go/model/flow"
"github.com/onflow/flow-go/module/trace"
)
// AccountKeyReader provide read access to account keys.
type AccountKeyReader interface {
// GetAccountKey retrieves a public key by index from an existing account.
//
// This function returns a nil key with no errors, if a key doesn't exist at
// the given index. An error is returned if the specified account does not
// exist, the provided index is not valid, or if the key retrieval fails.
GetAccountKey(
runtimeAddress common.Address,
keyIndex int,
) (
*runtime.AccountKey,
error,
)
AccountKeysCount(runtimeAddress common.Address) (uint64, error)
}
type ParseRestrictedAccountKeyReader struct {
txnState state.NestedTransactionPreparer
impl AccountKeyReader
}
func NewParseRestrictedAccountKeyReader(
txnState state.NestedTransactionPreparer,
impl AccountKeyReader,
) AccountKeyReader {
return ParseRestrictedAccountKeyReader{
txnState: txnState,
impl: impl,
}
}
func (reader ParseRestrictedAccountKeyReader) GetAccountKey(
runtimeAddress common.Address,
keyIndex int,
) (
*runtime.AccountKey,
error,
) {
return parseRestrict2Arg1Ret(
reader.txnState,
trace.FVMEnvGetAccountKey,
reader.impl.GetAccountKey,
runtimeAddress,
keyIndex)
}
func (reader ParseRestrictedAccountKeyReader) AccountKeysCount(
runtimeAddress common.Address,
) (
uint64,
error,
) {
return parseRestrict1Arg1Ret(
reader.txnState,
"AccountKeysCount",
reader.impl.AccountKeysCount,
runtimeAddress,
)
}
type accountKeyReader struct {
tracer tracing.TracerSpan
meter Meter
accounts Accounts
}
func NewAccountKeyReader(
tracer tracing.TracerSpan,
meter Meter,
accounts Accounts,
) AccountKeyReader {
return &accountKeyReader{
tracer: tracer,
meter: meter,
accounts: accounts,
}
}
func (reader *accountKeyReader) GetAccountKey(
runtimeAddress common.Address,
keyIndex int,
) (
*runtime.AccountKey,
error,
) {
defer reader.tracer.StartChildSpan(trace.FVMEnvGetAccountKey).End()
formatErr := func(err error) (*runtime.AccountKey, error) {
return nil, fmt.Errorf("getting account key failed: %w", err)
}
err := reader.meter.MeterComputation(ComputationKindGetAccountKey, 1)
if err != nil {
return formatErr(err)
}
// Don't return an error for invalid key indices
if keyIndex < 0 {
return nil, nil
}
address := flow.ConvertAddress(runtimeAddress)
// address verification is also done in this step
accountPublicKey, err := reader.accounts.GetPublicKey(
address,
uint64(keyIndex))
if err != nil {
// If a key is not found at a given index, then return a nil key with
// no errors. This is to be inline with the Cadence runtime. Otherwise,
// Cadence runtime cannot distinguish between a 'key not found error'
// vs other internal errors.
if errors.IsAccountPublicKeyNotFoundError(err) {
return nil, nil
}
return formatErr(err)
}
// Prepare the account key to return
runtimeAccountKey, err := FlowToRuntimeAccountKey(accountPublicKey)
if err != nil {
return formatErr(err)
}
return runtimeAccountKey, nil
}
func (reader *accountKeyReader) AccountKeysCount(
runtimeAddress common.Address,
) (
uint64,
error,
) {
defer reader.tracer.StartChildSpan(trace.FVMEnvAccountKeysCount).End()
formatErr := func(err error) (uint64, error) {
return 0, fmt.Errorf("fetching account key count failed: %w", err)
}
err := reader.meter.MeterComputation(ComputationKindAccountKeysCount, 1)
if err != nil {
return formatErr(err)
}
// address verification is also done in this step
return reader.accounts.GetPublicKeyCount(
flow.ConvertAddress(runtimeAddress))
}
func FlowToRuntimeAccountKey(
flowKey flow.AccountPublicKey,
) (
*runtime.AccountKey,
error,
) {
signAlgo := crypto.CryptoToRuntimeSigningAlgorithm(flowKey.SignAlgo)
if signAlgo == runtime.SignatureAlgorithmUnknown {
return nil, errors.NewValueErrorf(
flowKey.SignAlgo.String(),
"signature algorithm type not found",
)
}
hashAlgo := crypto.CryptoToRuntimeHashingAlgorithm(flowKey.HashAlgo)
if hashAlgo == runtime.HashAlgorithmUnknown {
return nil, errors.NewValueErrorf(
flowKey.HashAlgo.String(),
"hashing algorithm type not found",
)
}
publicKey := &runtime.PublicKey{
PublicKey: flowKey.PublicKey.Encode(),
SignAlgo: signAlgo,
}
return &runtime.AccountKey{
KeyIndex: flowKey.Index,
PublicKey: publicKey,
HashAlgo: hashAlgo,
Weight: flowKey.Weight,
IsRevoked: flowKey.Revoked,
}, nil
}