github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/accounts/keystore/wallet.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum 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-ethereum 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-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package keystore
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	blscrypto "github.com/ethereum/go-ethereum/crypto/bls"
    22  	"github.com/ethereum/go-ethereum/log"
    23  	"math/big"
    24  
    25  	ethereum "github.com/ethereum/go-ethereum"
    26  	"github.com/ethereum/go-ethereum/accounts"
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/core/types"
    29  )
    30  
    31  // keystoreWallet implements the accounts.Wallet interface for the original
    32  // keystore.
    33  type keystoreWallet struct {
    34  	account  accounts.Account // Single account contained in this wallet
    35  	keystore *KeyStore        // Keystore where the account originates from
    36  }
    37  
    38  // URL implements accounts.Wallet, returning the URL of the account within.
    39  func (w *keystoreWallet) URL() accounts.URL {
    40  	return w.account.URL
    41  }
    42  
    43  // Status implements accounts.Wallet, returning whether the account held by the
    44  // keystore wallet is unlocked or not.
    45  func (w *keystoreWallet) Status() (string, error) {
    46  	w.keystore.mu.RLock()
    47  	defer w.keystore.mu.RUnlock()
    48  
    49  	if _, ok := w.keystore.unlocked[w.account.Address]; ok {
    50  		return "Unlocked", nil
    51  	}
    52  	return "Locked", nil
    53  }
    54  
    55  // Open implements accounts.Wallet, but is a noop for plain wallets since there
    56  // is no connection or decryption step necessary to access the list of accounts.
    57  func (w *keystoreWallet) Open(passphrase string) error { return nil }
    58  
    59  // Close implements accounts.Wallet, but is a noop for plain wallets since there
    60  // is no meaningful open operation.
    61  func (w *keystoreWallet) Close() error { return nil }
    62  
    63  // Accounts implements accounts.Wallet, returning an account list consisting of
    64  // a single account that the plain kestore wallet contains.
    65  func (w *keystoreWallet) Accounts() []accounts.Account {
    66  	return []accounts.Account{w.account}
    67  }
    68  
    69  // Contains implements accounts.Wallet, returning whether a particular account is
    70  // or is not wrapped by this wallet instance.
    71  func (w *keystoreWallet) Contains(account accounts.Account) bool {
    72  	return account.Address == w.account.Address && (account.URL == (accounts.URL{}) || account.URL == w.account.URL)
    73  }
    74  
    75  // Decrypt decrypts an ECIES ciphertext.
    76  func (w *keystoreWallet) Decrypt(account accounts.Account, c, s1, s2 []byte) ([]byte, error) {
    77  	if account.Address != w.account.Address {
    78  		log.Debug(accounts.ErrUnknownAccount.Error(), "account", account)
    79  		return nil, accounts.ErrUnknownAccount
    80  	}
    81  	if account.URL != (accounts.URL{}) && account.URL != w.account.URL {
    82  		log.Debug(accounts.ErrUnknownAccount.Error(), "account", account)
    83  		return nil, accounts.ErrUnknownAccount
    84  	}
    85  	// Account seems valid, request the keystore to sign
    86  	return w.keystore.Decrypt(account, c, s1, s2)
    87  }
    88  
    89  // Derive implements accounts.Wallet, but is a noop for plain wallets since there
    90  // is no notion of hierarchical account derivation for plain keystore accounts.
    91  func (w *keystoreWallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) {
    92  	return accounts.Account{}, accounts.ErrNotSupported
    93  }
    94  
    95  // SelfDerive implements accounts.Wallet, but is a noop for plain wallets since
    96  // there is no notion of hierarchical account derivation for plain keystore accounts.
    97  func (w *keystoreWallet) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainStateReader) {}
    98  
    99  // SignHash implements accounts.Wallet, attempting to sign the given hash with
   100  // the given account. If the wallet does not wrap this particular account, an
   101  // error is returned to avoid account leakage (even though in theory we may be
   102  // able to sign via our shared keystore backend).
   103  func (w *keystoreWallet) SignHash(account accounts.Account, hash []byte) ([]byte, error) {
   104  	// Make sure the requested account is contained within
   105  	if !w.Contains(account) {
   106  		log.Debug(accounts.ErrUnknownAccount.Error(), "account", account)
   107  		return nil, accounts.ErrUnknownAccount
   108  	}
   109  	// Account seems valid, request the keystore to sign
   110  	return w.keystore.SignHash(account, hash)
   111  }
   112  
   113  func (w *keystoreWallet) GetPublicKey(account accounts.Account) (*ecdsa.PublicKey, error) {
   114  	// Make sure the requested account is contained within
   115  	if !w.Contains(account) {
   116  		log.Debug(accounts.ErrUnknownAccount.Error(), "account", account)
   117  		return nil, accounts.ErrUnknownAccount
   118  	}
   119  	// Account seems valid, request the public key
   120  	return w.keystore.GetPublicKey(account)
   121  }
   122  
   123  func (w *keystoreWallet) SignHashBLS(account accounts.Account, hash []byte) (blscrypto.SerializedSignature, error) {
   124  	// Make sure the requested account is contained within
   125  	if !w.Contains(account) {
   126  		log.Debug(accounts.ErrUnknownAccount.Error(), "account", account)
   127  		return blscrypto.SerializedSignature{}, accounts.ErrUnknownAccount
   128  	}
   129  	// Account seems valid, request the keystore to sign
   130  	return w.keystore.SignHashBLS(account, hash)
   131  }
   132  
   133  func (w *keystoreWallet) SignMessageBLS(account accounts.Account, msg []byte, extraData []byte) (blscrypto.SerializedSignature, error) {
   134  	// Make sure the requested account is contained within
   135  	if !w.Contains(account) {
   136  		log.Debug(accounts.ErrUnknownAccount.Error(), "account", account)
   137  		return blscrypto.SerializedSignature{}, accounts.ErrUnknownAccount
   138  	}
   139  	// Account seems valid, request the keystore to sign
   140  	return w.keystore.SignMessageBLS(account, msg, extraData)
   141  }
   142  
   143  func (w *keystoreWallet) GenerateProofOfPossession(account accounts.Account, address common.Address) ([]byte, []byte, error) {
   144  	// Make sure the requested account is contained within
   145  	if !w.Contains(account) {
   146  		log.Debug(accounts.ErrUnknownAccount.Error(), "account", account)
   147  		return nil, nil, accounts.ErrUnknownAccount
   148  	}
   149  	// Account seems valid, request the keystore to sign
   150  	return w.keystore.GenerateProofOfPossession(account, address)
   151  }
   152  
   153  func (w *keystoreWallet) GenerateProofOfPossessionBLS(account accounts.Account, address common.Address) ([]byte, []byte, error) {
   154  	// Make sure the requested account is contained within
   155  	if !w.Contains(account) {
   156  		log.Debug(accounts.ErrUnknownAccount.Error(), "account", account)
   157  		return nil, nil, accounts.ErrUnknownAccount
   158  	}
   159  	// Account seems valid, request the keystore to sign
   160  	return w.keystore.GenerateProofOfPossessionBLS(account, address)
   161  }
   162  
   163  // SignTx implements accounts.Wallet, attempting to sign the given transaction
   164  // with the given account. If the wallet does not wrap this particular account,
   165  // an error is returned to avoid account leakage (even though in theory we may
   166  // be able to sign via our shared keystore backend).
   167  func (w *keystoreWallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   168  	// Make sure the requested account is contained within
   169  	if !w.Contains(account) {
   170  		log.Debug(accounts.ErrUnknownAccount.Error(), "account", account)
   171  		return nil, accounts.ErrUnknownAccount
   172  	}
   173  	// Account seems valid, request the keystore to sign
   174  	return w.keystore.SignTx(account, tx, chainID)
   175  }
   176  
   177  // SignHashWithPassphrase implements accounts.Wallet, attempting to sign the
   178  // given hash with the given account using passphrase as extra authentication.
   179  func (w *keystoreWallet) SignHashWithPassphrase(account accounts.Account, passphrase string, hash []byte) ([]byte, error) {
   180  	// Make sure the requested account is contained within
   181  	if !w.Contains(account) {
   182  		log.Debug(accounts.ErrUnknownAccount.Error(), "account", account)
   183  		return nil, accounts.ErrUnknownAccount
   184  	}
   185  	// Account seems valid, request the keystore to sign
   186  	return w.keystore.SignHashWithPassphrase(account, passphrase, hash)
   187  }
   188  
   189  // SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given
   190  // transaction with the given account using passphrase as extra authentication.
   191  func (w *keystoreWallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   192  	// Make sure the requested account is contained within
   193  	if !w.Contains(account) {
   194  		log.Debug(accounts.ErrUnknownAccount.Error(), "account", account)
   195  		return nil, accounts.ErrUnknownAccount
   196  	}
   197  	// Account seems valid, request the keystore to sign
   198  	return w.keystore.SignTxWithPassphrase(account, passphrase, tx, chainID)
   199  }