github.com/klaytn/klaytn@v1.12.1/blockchain/types/tx_signatures.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 types 18 19 import ( 20 "crypto/ecdsa" 21 "encoding/json" 22 "errors" 23 "math/big" 24 25 "github.com/klaytn/klaytn/blockchain/types/accountkey" 26 "github.com/klaytn/klaytn/common" 27 "github.com/klaytn/klaytn/common/hexutil" 28 "github.com/klaytn/klaytn/kerrors" 29 ) 30 31 var ErrShouldBeSingleSignature = errors.New("the number of signatures should be one") 32 33 // TxSignatures is a slice of TxSignature. It is created to support multi-sig accounts. 34 // Note that this structure also processes txs having a single signature. 35 // TODO-Klaytn-Accounts: replace TxSignature with TxSignatures to all newly implemented tx types. 36 type TxSignatures []*TxSignature 37 38 func NewTxSignatures() TxSignatures { 39 return TxSignatures{NewTxSignature()} 40 } 41 42 func NewTxSignaturesWithValues(signer Signer, tx *Transaction, txhash common.Hash, prv []*ecdsa.PrivateKey) (TxSignatures, error) { 43 if len(prv) == 0 { 44 return nil, kerrors.ErrEmptySlice 45 } 46 if uint64(len(prv)) > accountkey.MaxNumKeysForMultiSig { 47 return nil, kerrors.ErrMaxKeysExceed 48 } 49 txsigs := make(TxSignatures, len(prv)) 50 51 for i, p := range prv { 52 t, err := NewTxSignatureWithValues(signer, tx, txhash, p) 53 if err != nil { 54 return nil, err 55 } 56 txsigs[i] = t 57 } 58 59 return txsigs, nil 60 } 61 62 func (t TxSignatures) getDefaultSig() (*TxSignature, error) { 63 if t.empty() { 64 return nil, ErrInvalidSig 65 } 66 return t[0], nil 67 } 68 69 func (t TxSignatures) empty() bool { 70 return len(t) == 0 71 } 72 73 func (t TxSignatures) ChainId() *big.Int { 74 txSig, err := t.getDefaultSig() 75 if err != nil { 76 // This path should not be executed. This is written only for debugging. 77 logger.CritWithStack("should not be called if no entries exist", err) 78 } 79 80 // TODO-Klaytn-Multisig: Find a way to handle multiple V values here. 81 return txSig.ChainId() 82 } 83 84 func (t TxSignatures) RawSignatureValues() TxSignatures { 85 return t 86 } 87 88 func (t TxSignatures) ValidateSignature() bool { 89 txSig, err := t.getDefaultSig() 90 if err != nil { 91 return false 92 } 93 94 cid := txSig.ChainId() 95 for _, s := range t { 96 if s.ValidateSignature() == false { 97 return false 98 } 99 if cid.Cmp(s.ChainId()) != 0 { 100 return false 101 } 102 } 103 104 return true 105 } 106 107 func (t TxSignatures) equal(tb TxSignatures) bool { 108 if len(t) != len(tb) { 109 return false 110 } 111 112 for i, s := range t { 113 if s.equal(tb[i]) == false { 114 return false 115 } 116 } 117 118 return true 119 } 120 121 func (t TxSignatures) RecoverAddress(txhash common.Hash, homestead bool, vfunc func(*big.Int) *big.Int) (common.Address, error) { 122 if len(t) != 1 { 123 return common.Address{}, ErrShouldBeSingleSignature 124 } 125 126 txSig, _ := t.getDefaultSig() 127 128 return txSig.RecoverAddress(txhash, homestead, vfunc) 129 } 130 131 func (t TxSignatures) RecoverPubkey(txhash common.Hash, homestead bool, vfunc func(*big.Int) *big.Int) ([]*ecdsa.PublicKey, error) { 132 var err error 133 134 pubkeys := make([]*ecdsa.PublicKey, len(t)) 135 for i, s := range t { 136 pubkeys[i], err = s.RecoverPubkey(txhash, homestead, vfunc) 137 if err != nil { 138 return nil, err 139 } 140 } 141 142 return pubkeys, nil 143 } 144 145 func (t TxSignatures) string() string { 146 b, _ := json.Marshal(t.ToJSON()) 147 148 return string(b) 149 } 150 151 func (t TxSignatures) ToJSON() TxSignaturesJSON { 152 js := make(TxSignaturesJSON, len(t)) 153 154 for i, s := range t { 155 js[i] = &TxSignatureJSON{(*hexutil.Big)(s.V), (*hexutil.Big)(s.R), (*hexutil.Big)(s.S)} 156 } 157 158 return js 159 } 160 161 // TxSignaturesJSON is an array of *TxSignatureJSON. This structure is for JSON marshalling. 162 type TxSignaturesJSON []*TxSignatureJSON 163 164 func (t TxSignaturesJSON) ToTxSignatures() TxSignatures { 165 sigs := make(TxSignatures, len(t)) 166 167 for i, s := range t { 168 sigs[i] = &TxSignature{(*big.Int)(s.V), (*big.Int)(s.R), (*big.Int)(s.S)} 169 } 170 171 return sigs 172 }