github.com/klaytn/klaytn@v1.12.1/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 // ValidateMember returns true if the account type contains the given public key in any part of its AccountKey. 69 ValidateMember(recoveredKey *ecdsa.PublicKey, from common.Address) bool 70 71 // DeepCopy creates a new object and copies all the attributes to the new object. 72 DeepCopy() AccountKey 73 74 // AccountCreationGas returns gas required to create an account with the corresponding key. 75 AccountCreationGas(currentBlockNumber uint64) (uint64, error) 76 77 // SigValidationGas returns gas required to validate a tx with the account. 78 SigValidationGas(currentBlockNumber uint64, r RoleType, numSigs int) (uint64, error) 79 80 // CheckInstallable returns an error if any data in the key is invalid. 81 // This checks that the key is ready to be assigned to an account. 82 CheckInstallable(currentBlockNumber uint64) error 83 84 // 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. 85 CheckUpdatable(newKey AccountKey, currentBlockNumber uint64) error 86 87 // Update returns an error if `key` cannot be assigned to itself. The newKey should be the same type with the oldKey's type. 88 Update(newKey AccountKey, currentBlockNumber uint64) error 89 90 // IsCompositeType returns true if the account type is a composite type. 91 // Composite types are AccountKeyRoleBased and AccountKeyRoleBasedRLPBytes. 92 IsCompositeType() bool 93 } 94 95 func NewAccountKey(t AccountKeyType) (AccountKey, error) { 96 switch t { 97 case AccountKeyTypeNil: 98 return NewAccountKeyNil(), nil 99 case AccountKeyTypeLegacy: 100 return NewAccountKeyLegacy(), nil 101 case AccountKeyTypePublic: 102 return NewAccountKeyPublic(), nil 103 case AccountKeyTypeFail: 104 return NewAccountKeyFail(), nil 105 case AccountKeyTypeWeightedMultiSig: 106 return NewAccountKeyWeightedMultiSig(), nil 107 case AccountKeyTypeRoleBased: 108 return NewAccountKeyRoleBased(), nil 109 } 110 111 return nil, errUndefinedAccountKeyType 112 } 113 114 func ValidateAccountKey(currentBlockNumber uint64, from common.Address, accKey AccountKey, recoveredKeys []*ecdsa.PublicKey, roleType RoleType) error { 115 if !accKey.Validate(currentBlockNumber, roleType, recoveredKeys, from) { 116 return errInvalidSignature 117 } 118 return nil 119 } 120 121 // CheckReplacable returns nil if newKey can replace oldKey. The function checks updatability of newKey regardless of the newKey type. 122 func CheckReplacable(oldKey AccountKey, newKey AccountKey, currentBlockNumber uint64) error { 123 if oldKey.Type() == newKey.Type() { 124 return oldKey.CheckUpdatable(newKey, currentBlockNumber) 125 } 126 return newKey.CheckInstallable(currentBlockNumber) 127 }