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 }