github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/model/flow/account.go (about)

     1  package flow
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  
     7  	"github.com/onflow/crypto"
     8  	"github.com/onflow/crypto/hash"
     9  )
    10  
    11  // Account represents an account on the Flow network.
    12  //
    13  // An account can be an externally owned account or a contract account with code.
    14  type Account struct {
    15  	Address   Address
    16  	Balance   uint64
    17  	Keys      []AccountPublicKey
    18  	Contracts map[string][]byte
    19  }
    20  
    21  // AccountPublicKey is a public key associated with an account.
    22  //
    23  // An account public key contains the public key, signing and hashing algorithms, and a key weight.
    24  type AccountPublicKey struct {
    25  	Index     int
    26  	PublicKey crypto.PublicKey
    27  	SignAlgo  crypto.SigningAlgorithm
    28  	HashAlgo  hash.HashingAlgorithm
    29  	SeqNumber uint64
    30  	Weight    int
    31  	Revoked   bool
    32  }
    33  
    34  func (a AccountPublicKey) MarshalJSON() ([]byte, error) {
    35  	return json.Marshal(struct {
    36  		PublicKey []byte
    37  		SignAlgo  crypto.SigningAlgorithm
    38  		HashAlgo  hash.HashingAlgorithm
    39  		SeqNumber uint64
    40  		Weight    int
    41  	}{
    42  		a.PublicKey.Encode(),
    43  		a.SignAlgo,
    44  		a.HashAlgo,
    45  		a.SeqNumber,
    46  		a.Weight,
    47  	})
    48  }
    49  
    50  func (a *AccountPublicKey) UnmarshalJSON(data []byte) error {
    51  	temp := struct {
    52  		PublicKey []byte
    53  		SignAlgo  crypto.SigningAlgorithm
    54  		HashAlgo  hash.HashingAlgorithm
    55  		SeqNumber uint64
    56  		Weight    int
    57  	}{}
    58  	err := json.Unmarshal(data, &temp)
    59  	if err != nil {
    60  		return err
    61  	}
    62  	if a == nil {
    63  		a = new(AccountPublicKey)
    64  	}
    65  	a.PublicKey, err = crypto.DecodePublicKey(temp.SignAlgo, temp.PublicKey)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	a.SignAlgo = temp.SignAlgo
    70  	a.HashAlgo = temp.HashAlgo
    71  	a.SeqNumber = temp.SeqNumber
    72  	a.Weight = temp.Weight
    73  	return nil
    74  }
    75  
    76  // Validate returns an error if this account key is invalid.
    77  //
    78  // An account key can be invalid for the following reasons:
    79  // - It specifies an incompatible signature/hash algorithm pairing
    80  // - (TODO) It specifies a negative key weight
    81  func (a AccountPublicKey) Validate() error {
    82  	if !CompatibleAlgorithms(a.SignAlgo, a.HashAlgo) {
    83  		return fmt.Errorf(
    84  			"signing algorithm (%s) is incompatible with hashing algorithm (%s)",
    85  			a.SignAlgo,
    86  			a.HashAlgo,
    87  		)
    88  	}
    89  	return nil
    90  }
    91  
    92  // AccountPrivateKey is a private key associated with an account.
    93  type AccountPrivateKey struct {
    94  	PrivateKey crypto.PrivateKey
    95  	SignAlgo   crypto.SigningAlgorithm
    96  	HashAlgo   hash.HashingAlgorithm
    97  }
    98  
    99  // PublicKey returns a weighted public key.
   100  func (a AccountPrivateKey) PublicKey(weight int) AccountPublicKey {
   101  	return AccountPublicKey{
   102  		PublicKey: a.PrivateKey.PublicKey(),
   103  		SignAlgo:  a.SignAlgo,
   104  		HashAlgo:  a.HashAlgo,
   105  		Weight:    weight,
   106  	}
   107  }
   108  
   109  func (a AccountPrivateKey) MarshalJSON() ([]byte, error) {
   110  	return json.Marshal(struct {
   111  		PrivateKey []byte
   112  		SignAlgo   crypto.SigningAlgorithm
   113  		HashAlgo   hash.HashingAlgorithm
   114  	}{
   115  		a.PrivateKey.Encode(),
   116  		a.SignAlgo,
   117  		a.HashAlgo,
   118  	})
   119  }
   120  
   121  // CompatibleAlgorithms returns true if the signature and hash algorithms are compatible.
   122  func CompatibleAlgorithms(sigAlgo crypto.SigningAlgorithm, hashAlgo hash.HashingAlgorithm) bool {
   123  	switch sigAlgo {
   124  	case crypto.ECDSAP256, crypto.ECDSASecp256k1:
   125  		switch hashAlgo {
   126  		case hash.SHA2_256, hash.SHA3_256:
   127  			return true
   128  		}
   129  	}
   130  	return false
   131  }