github.com/core-coin/go-core/v2@v2.1.9/accounts/accounts.go (about) 1 // Copyright 2017 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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 go-core 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 go-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package accounts implements high level Core account management. 18 package accounts 19 20 import ( 21 "fmt" 22 "math/big" 23 24 "golang.org/x/crypto/sha3" 25 26 core "github.com/core-coin/go-core/v2" 27 "github.com/core-coin/go-core/v2/common" 28 "github.com/core-coin/go-core/v2/core/types" 29 "github.com/core-coin/go-core/v2/event" 30 ) 31 32 // Account represents an Core account located at a specific location defined 33 // by the optional URL field. 34 type Account struct { 35 Address common.Address `json:"address"` // Core account address derived from the key 36 URL URL `json:"url"` // Optional resource locator within a backend 37 } 38 39 const ( 40 MimetypeDataWithValidator = "data/validator" 41 MimetypeTypedData = "data/typed" 42 MimetypeClique = "application/x-clique-header" 43 MimetypeTextPlain = "text/plain" 44 ) 45 46 // Wallet represents a software or hardware wallet that might contain one or more 47 // accounts (derived from the same seed). 48 type Wallet interface { 49 // URL retrieves the canonical path under which this wallet is reachable. It is 50 // user by upper layers to define a sorting order over all wallets from multiple 51 // backends. 52 URL() URL 53 54 // Status returns a textual status to aid the user in the current state of the 55 // wallet. It also returns an error indicating any failure the wallet might have 56 // encountered. 57 Status() (string, error) 58 59 // Open initializes access to a wallet instance. It is not meant to unlock or 60 // decrypt account keys, rather simply to establish a connection to hardware 61 // wallets and/or to access derivation seeds. 62 // 63 // The passphrase parameter may or may not be used by the implementation of a 64 // particular wallet instance. The reason there is no passwordless open method 65 // is to strive towards a uniform wallet handling, oblivious to the different 66 // backend providers. 67 // 68 // Please note, if you open a wallet, you must close it to release any allocated 69 // resources (especially important when working with hardware wallets). 70 Open(passphrase string) error 71 72 // Close releases any resources held by an open wallet instance. 73 Close() error 74 75 // Accounts retrieves the list of signing accounts the wallet is currently aware 76 // of. For hierarchical deterministic wallets, the list will not be exhaustive, 77 // rather only contain the accounts explicitly pinned during account derivation. 78 Accounts() []Account 79 80 // Contains returns whether an account is part of this particular wallet or not. 81 Contains(account Account) bool 82 83 // Derive attempts to explicitly derive a hierarchical deterministic account at 84 // the specified derivation path. If requested, the derived account will be added 85 // to the wallet's tracked account list. 86 Derive(path DerivationPath, pin bool) (Account, error) 87 88 // SelfDerive sets a base account derivation path from which the wallet attempts 89 // to discover non zero accounts and automatically add them to list of tracked 90 // accounts. 91 // 92 // Note, self derivation will increment the last component of the specified path 93 // opposed to decending into a child path to allow discovering accounts starting 94 // from non zero components. 95 // 96 // Some hardware wallets switched derivation paths through their evolution, so 97 // this method supports providing multiple bases to discover old user accounts 98 // too. Only the last base will be used to derive the next empty account. 99 // 100 // You can disable automatic account discovery by calling SelfDerive with a nil 101 // chain state reader. 102 SelfDerive(bases []DerivationPath, chain core.ChainStateReader) 103 104 // SignData requests the wallet to sign the hash of the given data 105 // It looks up the account specified either solely via its address contained within, 106 // or optionally with the aid of any location metadata from the embedded URL field. 107 // 108 // If the wallet requires additional authentication to sign the request (e.g. 109 // a password to decrypt the account, or a PIN code o verify the transaction), 110 // an AuthNeededError instance will be returned, containing infos for the user 111 // about which fields or actions are needed. The user may retry by providing 112 // the needed details via SignDataWithPassphrase, or by other means (e.g. unlock 113 // the account in a keystore). 114 SignData(account Account, mimeType string, data []byte) ([]byte, error) 115 116 // SignDataWithPassphrase is identical to SignData, but also takes a password 117 // NOTE: there's an chance that an erroneous call might mistake the two strings, and 118 // supply password in the mimetype field, or vice versa. Thus, an implementation 119 // should never echo the mimetype or return the mimetype in the error-response 120 SignDataWithPassphrase(account Account, passphrase, mimeType string, data []byte) ([]byte, error) 121 122 // SignText requests the wallet to sign the hash of a given piece of data, prefixed 123 // by the Core prefix scheme 124 // It looks up the account specified either solely via its address contained within, 125 // or optionally with the aid of any location metadata from the embedded URL field. 126 // 127 // If the wallet requires additional authentication to sign the request (e.g. 128 // a password to decrypt the account, or a PIN code o verify the transaction), 129 // an AuthNeededError instance will be returned, containing infos for the user 130 // about which fields or actions are needed. The user may retry by providing 131 // the needed details via SignHashWithPassphrase, or by other means (e.g. unlock 132 // the account in a keystore). 133 // 134 // This method should return the signature in 'canonical' format, with v 0 or 1 135 SignText(account Account, text []byte) ([]byte, error) 136 137 // SignTextWithPassphrase is identical to Signtext, but also takes a password 138 SignTextWithPassphrase(account Account, passphrase string, hash []byte) ([]byte, error) 139 140 // SignTx requests the wallet to sign the given transaction. 141 // 142 // It looks up the account specified either solely via its address contained within, 143 // or optionally with the aid of any location metadata from the embedded URL field. 144 // 145 // If the wallet requires additional authentication to sign the request (e.g. 146 // a password to decrypt the account, or a PIN code to verify the transaction), 147 // an AuthNeededError instance will be returned, containing infos for the user 148 // about which fields or actions are needed. The user may retry by providing 149 // the needed details via SignTxWithPassphrase, or by other means (e.g. unlock 150 // the account in a keystore). 151 SignTx(account Account, tx *types.Transaction, networkID *big.Int) (*types.Transaction, error) 152 153 // SignTxWithPassphrase is identical to SignTx, but also takes a password 154 SignTxWithPassphrase(account Account, passphrase string, tx *types.Transaction, networkID *big.Int) (*types.Transaction, error) 155 } 156 157 // Backend is a "wallet provider" that may contain a batch of accounts they can 158 // sign transactions with and upon request, do so. 159 type Backend interface { 160 // Wallets retrieves the list of wallets the backend is currently aware of. 161 // 162 // The returned wallets are not opened by default. For software HD wallets this 163 // means that no base seeds are decrypted, and for hardware wallets that no actual 164 // connection is established. 165 // 166 // The resulting wallet list will be sorted alphabetically based on its internal 167 // URL assigned by the backend. Since wallets (especially hardware) may come and 168 // go, the same wallet might appear at a different positions in the list during 169 // subsequent retrievals. 170 Wallets() []Wallet 171 172 // Subscribe creates an async subscription to receive notifications when the 173 // backend detects the arrival or departure of a wallet. 174 Subscribe(sink chan<- WalletEvent) event.Subscription 175 } 176 177 // TextHash is a helper function that calculates a hash for the given message that can be 178 // safely used to calculate a signature from. 179 // 180 // The hash is calulcated as 181 // 182 // SHA3("\x19Core Signed Message:\n"${message length}${message}). 183 // 184 // This gives context to the signed message and prevents signing of transactions. 185 func TextHash(data []byte) []byte { 186 hash, _ := TextAndHash(data) 187 return hash 188 } 189 190 // TextAndHash is a helper function that calculates a hash for the given message that can be 191 // safely used to calculate a signature from. 192 // 193 // The hash is calulcated as 194 // 195 // SHA3("\x19Core Signed Message:\n"${message length}${message}). 196 // 197 // This gives context to the signed message and prevents signing of transactions. 198 func TextAndHash(data []byte) ([]byte, string) { 199 msg := fmt.Sprintf("\x19Core Signed Message:\n%d%s", len(data), string(data)) 200 hasher := sha3.New256() 201 hasher.Write([]byte(msg)) 202 return hasher.Sum(nil), msg 203 } 204 205 // WalletEventType represents the different event types that can be fired by 206 // the wallet subscription subsystem. 207 type WalletEventType int 208 209 const ( 210 // WalletArrived is fired when a new wallet is detected either via 211 // a filesystem event in the keystore. 212 WalletArrived WalletEventType = iota 213 214 // WalletOpened is fired when a wallet is successfully opened with the purpose 215 // of starting any background processes such as automatic key derivation. 216 WalletOpened 217 218 // WalletDropped 219 WalletDropped 220 ) 221 222 // WalletEvent is an event fired by an account backend when a wallet arrival or 223 // departure is detected. 224 type WalletEvent struct { 225 Wallet Wallet // Wallet instance arrived or departed 226 Kind WalletEventType // Event type that happened in the system 227 }