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