github.com/klaytn/klaytn@v1.10.2/blockchain/types/accountkey/account_key.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The klaytn library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package accountkey
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"errors"
    22  
    23  	"github.com/klaytn/klaytn/common"
    24  	"github.com/klaytn/klaytn/log"
    25  )
    26  
    27  type AccountKeyType uint8
    28  
    29  const (
    30  	AccountKeyTypeNil AccountKeyType = iota
    31  	AccountKeyTypeLegacy
    32  	AccountKeyTypePublic
    33  	AccountKeyTypeFail
    34  	AccountKeyTypeWeightedMultiSig
    35  	AccountKeyTypeRoleBased
    36  	AccountKeyTypeLast
    37  )
    38  
    39  var (
    40  	errUndefinedAccountKeyType = errors.New("undefined account key type")
    41  	errWrongPubkeyLength       = errors.New("wrong pubkey length")
    42  	errInvalidSignature        = errors.New("invalid signature")
    43  )
    44  
    45  var logger = log.NewModuleLogger(log.BlockchainTypesAccountKey)
    46  
    47  func (a AccountKeyType) IsLegacyAccountKey() bool {
    48  	return a == AccountKeyTypeLegacy
    49  }
    50  
    51  // AccountKey is a common interface to exploit polymorphism of AccountKey.
    52  // Currently, we have the following implementations of AccountKey:
    53  // - AccountKeyLegacy
    54  // - AccountKeyPublic
    55  type AccountKey interface {
    56  	// Type returns the type of account key.
    57  	Type() AccountKeyType
    58  
    59  	// String returns a string containing all the attributes of the object.
    60  	String() string
    61  
    62  	// Equal returns true if all the attributes are the same. Otherwise, it returns false.
    63  	Equal(AccountKey) bool
    64  
    65  	// Validate returns true if the given public keys are verifiable with the AccountKey.
    66  	Validate(currentBlockNumber uint64, r RoleType, recoveredKeys []*ecdsa.PublicKey, from common.Address) bool
    67  
    68  	// DeepCopy creates a new object and copies all the attributes to the new object.
    69  	DeepCopy() AccountKey
    70  
    71  	// AccountCreationGas returns gas required to create an account with the corresponding key.
    72  	AccountCreationGas(currentBlockNumber uint64) (uint64, error)
    73  
    74  	// SigValidationGas returns gas required to validate a tx with the account.
    75  	SigValidationGas(currentBlockNumber uint64, r RoleType, numSigs int) (uint64, error)
    76  
    77  	// CheckInstallable returns an error if any data in the key is invalid.
    78  	// This checks that the key is ready to be assigned to an account.
    79  	CheckInstallable(currentBlockNumber uint64) error
    80  
    81  	// CheckUpdatable returns nil if the given account key can be used as a new key. The newKey should be the same type with the oldKey's type.
    82  	CheckUpdatable(newKey AccountKey, currentBlockNumber uint64) error
    83  
    84  	// Update returns an error if `key` cannot be assigned to itself. The newKey should be the same type with the oldKey's type.
    85  	Update(newKey AccountKey, currentBlockNumber uint64) error
    86  
    87  	// IsCompositeType returns true if the account type is a composite type.
    88  	// Composite types are AccountKeyRoleBased and AccountKeyRoleBasedRLPBytes.
    89  	IsCompositeType() bool
    90  }
    91  
    92  func NewAccountKey(t AccountKeyType) (AccountKey, error) {
    93  	switch t {
    94  	case AccountKeyTypeNil:
    95  		return NewAccountKeyNil(), nil
    96  	case AccountKeyTypeLegacy:
    97  		return NewAccountKeyLegacy(), nil
    98  	case AccountKeyTypePublic:
    99  		return NewAccountKeyPublic(), nil
   100  	case AccountKeyTypeFail:
   101  		return NewAccountKeyFail(), nil
   102  	case AccountKeyTypeWeightedMultiSig:
   103  		return NewAccountKeyWeightedMultiSig(), nil
   104  	case AccountKeyTypeRoleBased:
   105  		return NewAccountKeyRoleBased(), nil
   106  	}
   107  
   108  	return nil, errUndefinedAccountKeyType
   109  }
   110  
   111  func ValidateAccountKey(currentBlockNumber uint64, from common.Address, accKey AccountKey, recoveredKeys []*ecdsa.PublicKey, roleType RoleType) error {
   112  	if !accKey.Validate(currentBlockNumber, roleType, recoveredKeys, from) {
   113  		return errInvalidSignature
   114  	}
   115  	return nil
   116  }
   117  
   118  // CheckReplacable returns nil if newKey can replace oldKey. The function checks updatability of newKey regardless of the newKey type.
   119  func CheckReplacable(oldKey AccountKey, newKey AccountKey, currentBlockNumber uint64) error {
   120  	if oldKey.Type() == newKey.Type() {
   121  		return oldKey.CheckUpdatable(newKey, currentBlockNumber)
   122  	}
   123  	return newKey.CheckInstallable(currentBlockNumber)
   124  }