github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/environment/account_key_reader.go (about) 1 package environment 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/cadence/runtime" 7 "github.com/onflow/cadence/runtime/common" 8 9 "github.com/onflow/flow-go/fvm/crypto" 10 "github.com/onflow/flow-go/fvm/errors" 11 "github.com/onflow/flow-go/fvm/storage/state" 12 "github.com/onflow/flow-go/fvm/tracing" 13 "github.com/onflow/flow-go/model/flow" 14 "github.com/onflow/flow-go/module/trace" 15 ) 16 17 // AccountKeyReader provide read access to account keys. 18 type AccountKeyReader interface { 19 // GetAccountKey retrieves a public key by index from an existing account. 20 // 21 // This function returns a nil key with no errors, if a key doesn't exist at 22 // the given index. An error is returned if the specified account does not 23 // exist, the provided index is not valid, or if the key retrieval fails. 24 GetAccountKey( 25 runtimeAddress common.Address, 26 keyIndex int, 27 ) ( 28 *runtime.AccountKey, 29 error, 30 ) 31 AccountKeysCount(runtimeAddress common.Address) (uint64, error) 32 } 33 34 type ParseRestrictedAccountKeyReader struct { 35 txnState state.NestedTransactionPreparer 36 impl AccountKeyReader 37 } 38 39 func NewParseRestrictedAccountKeyReader( 40 txnState state.NestedTransactionPreparer, 41 impl AccountKeyReader, 42 ) AccountKeyReader { 43 return ParseRestrictedAccountKeyReader{ 44 txnState: txnState, 45 impl: impl, 46 } 47 } 48 49 func (reader ParseRestrictedAccountKeyReader) GetAccountKey( 50 runtimeAddress common.Address, 51 keyIndex int, 52 ) ( 53 *runtime.AccountKey, 54 error, 55 ) { 56 return parseRestrict2Arg1Ret( 57 reader.txnState, 58 trace.FVMEnvGetAccountKey, 59 reader.impl.GetAccountKey, 60 runtimeAddress, 61 keyIndex) 62 } 63 64 func (reader ParseRestrictedAccountKeyReader) AccountKeysCount( 65 runtimeAddress common.Address, 66 ) ( 67 uint64, 68 error, 69 ) { 70 return parseRestrict1Arg1Ret( 71 reader.txnState, 72 "AccountKeysCount", 73 reader.impl.AccountKeysCount, 74 runtimeAddress, 75 ) 76 } 77 78 type accountKeyReader struct { 79 tracer tracing.TracerSpan 80 meter Meter 81 82 accounts Accounts 83 } 84 85 func NewAccountKeyReader( 86 tracer tracing.TracerSpan, 87 meter Meter, 88 accounts Accounts, 89 ) AccountKeyReader { 90 return &accountKeyReader{ 91 tracer: tracer, 92 meter: meter, 93 accounts: accounts, 94 } 95 } 96 97 func (reader *accountKeyReader) GetAccountKey( 98 runtimeAddress common.Address, 99 keyIndex int, 100 ) ( 101 *runtime.AccountKey, 102 error, 103 ) { 104 defer reader.tracer.StartChildSpan(trace.FVMEnvGetAccountKey).End() 105 106 formatErr := func(err error) (*runtime.AccountKey, error) { 107 return nil, fmt.Errorf("getting account key failed: %w", err) 108 } 109 110 err := reader.meter.MeterComputation(ComputationKindGetAccountKey, 1) 111 if err != nil { 112 return formatErr(err) 113 } 114 115 // Don't return an error for invalid key indices 116 if keyIndex < 0 { 117 return nil, nil 118 } 119 120 address := flow.ConvertAddress(runtimeAddress) 121 122 // address verification is also done in this step 123 accountPublicKey, err := reader.accounts.GetPublicKey( 124 address, 125 uint64(keyIndex)) 126 if err != nil { 127 // If a key is not found at a given index, then return a nil key with 128 // no errors. This is to be inline with the Cadence runtime. Otherwise, 129 // Cadence runtime cannot distinguish between a 'key not found error' 130 // vs other internal errors. 131 if errors.IsAccountPublicKeyNotFoundError(err) { 132 return nil, nil 133 } 134 135 return formatErr(err) 136 } 137 138 // Prepare the account key to return 139 runtimeAccountKey, err := FlowToRuntimeAccountKey(accountPublicKey) 140 if err != nil { 141 return formatErr(err) 142 } 143 144 return runtimeAccountKey, nil 145 } 146 147 func (reader *accountKeyReader) AccountKeysCount( 148 runtimeAddress common.Address, 149 ) ( 150 uint64, 151 error, 152 ) { 153 defer reader.tracer.StartChildSpan(trace.FVMEnvAccountKeysCount).End() 154 155 formatErr := func(err error) (uint64, error) { 156 return 0, fmt.Errorf("fetching account key count failed: %w", err) 157 } 158 159 err := reader.meter.MeterComputation(ComputationKindAccountKeysCount, 1) 160 if err != nil { 161 return formatErr(err) 162 } 163 164 // address verification is also done in this step 165 return reader.accounts.GetPublicKeyCount( 166 flow.ConvertAddress(runtimeAddress)) 167 } 168 169 func FlowToRuntimeAccountKey( 170 flowKey flow.AccountPublicKey, 171 ) ( 172 *runtime.AccountKey, 173 error, 174 ) { 175 signAlgo := crypto.CryptoToRuntimeSigningAlgorithm(flowKey.SignAlgo) 176 if signAlgo == runtime.SignatureAlgorithmUnknown { 177 return nil, errors.NewValueErrorf( 178 flowKey.SignAlgo.String(), 179 "signature algorithm type not found", 180 ) 181 } 182 183 hashAlgo := crypto.CryptoToRuntimeHashingAlgorithm(flowKey.HashAlgo) 184 if hashAlgo == runtime.HashAlgorithmUnknown { 185 return nil, errors.NewValueErrorf( 186 flowKey.HashAlgo.String(), 187 "hashing algorithm type not found", 188 ) 189 } 190 191 publicKey := &runtime.PublicKey{ 192 PublicKey: flowKey.PublicKey.Encode(), 193 SignAlgo: signAlgo, 194 } 195 196 return &runtime.AccountKey{ 197 KeyIndex: flowKey.Index, 198 PublicKey: publicKey, 199 HashAlgo: hashAlgo, 200 Weight: flowKey.Weight, 201 IsRevoked: flowKey.Revoked, 202 }, nil 203 }