github.com/koko1123/flow-go-1@v0.29.6/fvm/environment/account_key_reader.go (about)

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