github.com/ava-labs/subnet-evm@v0.6.4/accounts/keystore/wallet.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2017 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package keystore
    28  
    29  import (
    30  	"math/big"
    31  
    32  	"github.com/ava-labs/subnet-evm/accounts"
    33  	"github.com/ava-labs/subnet-evm/core/types"
    34  	"github.com/ava-labs/subnet-evm/interfaces"
    35  	"github.com/ethereum/go-ethereum/crypto"
    36  )
    37  
    38  // keystoreWallet implements the accounts.Wallet interface for the original
    39  // keystore.
    40  type keystoreWallet struct {
    41  	account  accounts.Account // Single account contained in this wallet
    42  	keystore *KeyStore        // Keystore where the account originates from
    43  }
    44  
    45  // URL implements accounts.Wallet, returning the URL of the account within.
    46  func (w *keystoreWallet) URL() accounts.URL {
    47  	return w.account.URL
    48  }
    49  
    50  // Status implements accounts.Wallet, returning whether the account held by the
    51  // keystore wallet is unlocked or not.
    52  func (w *keystoreWallet) Status() (string, error) {
    53  	w.keystore.mu.RLock()
    54  	defer w.keystore.mu.RUnlock()
    55  
    56  	if _, ok := w.keystore.unlocked[w.account.Address]; ok {
    57  		return "Unlocked", nil
    58  	}
    59  	return "Locked", nil
    60  }
    61  
    62  // Open implements accounts.Wallet, but is a noop for plain wallets since there
    63  // is no connection or decryption step necessary to access the list of accounts.
    64  func (w *keystoreWallet) Open(passphrase string) error { return nil }
    65  
    66  // Close implements accounts.Wallet, but is a noop for plain wallets since there
    67  // is no meaningful open operation.
    68  func (w *keystoreWallet) Close() error { return nil }
    69  
    70  // Accounts implements accounts.Wallet, returning an account list consisting of
    71  // a single account that the plain keystore wallet contains.
    72  func (w *keystoreWallet) Accounts() []accounts.Account {
    73  	return []accounts.Account{w.account}
    74  }
    75  
    76  // Contains implements accounts.Wallet, returning whether a particular account is
    77  // or is not wrapped by this wallet instance.
    78  func (w *keystoreWallet) Contains(account accounts.Account) bool {
    79  	return account.Address == w.account.Address && (account.URL == (accounts.URL{}) || account.URL == w.account.URL)
    80  }
    81  
    82  // Derive implements accounts.Wallet, but is a noop for plain wallets since there
    83  // is no notion of hierarchical account derivation for plain keystore accounts.
    84  func (w *keystoreWallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) {
    85  	return accounts.Account{}, accounts.ErrNotSupported
    86  }
    87  
    88  // SelfDerive implements accounts.Wallet, but is a noop for plain wallets since
    89  // there is no notion of hierarchical account derivation for plain keystore accounts.
    90  func (w *keystoreWallet) SelfDerive(bases []accounts.DerivationPath, chain interfaces.ChainStateReader) {
    91  }
    92  
    93  // signHash attempts to sign the given hash with
    94  // the given account. If the wallet does not wrap this particular account, an
    95  // error is returned to avoid account leakage (even though in theory we may be
    96  // able to sign via our shared keystore backend).
    97  func (w *keystoreWallet) signHash(account accounts.Account, hash []byte) ([]byte, error) {
    98  	// Make sure the requested account is contained within
    99  	if !w.Contains(account) {
   100  		return nil, accounts.ErrUnknownAccount
   101  	}
   102  	// Account seems valid, request the keystore to sign
   103  	return w.keystore.SignHash(account, hash)
   104  }
   105  
   106  // SignData signs keccak256(data). The mimetype parameter describes the type of data being signed.
   107  func (w *keystoreWallet) SignData(account accounts.Account, mimeType string, data []byte) ([]byte, error) {
   108  	return w.signHash(account, crypto.Keccak256(data))
   109  }
   110  
   111  // SignDataWithPassphrase signs keccak256(data). The mimetype parameter describes the type of data being signed.
   112  func (w *keystoreWallet) SignDataWithPassphrase(account accounts.Account, passphrase, mimeType string, data []byte) ([]byte, error) {
   113  	// Make sure the requested account is contained within
   114  	if !w.Contains(account) {
   115  		return nil, accounts.ErrUnknownAccount
   116  	}
   117  	// Account seems valid, request the keystore to sign
   118  	return w.keystore.SignHashWithPassphrase(account, passphrase, crypto.Keccak256(data))
   119  }
   120  
   121  // SignText implements accounts.Wallet, attempting to sign the hash of
   122  // the given text with the given account.
   123  func (w *keystoreWallet) SignText(account accounts.Account, text []byte) ([]byte, error) {
   124  	return w.signHash(account, accounts.TextHash(text))
   125  }
   126  
   127  // SignTextWithPassphrase implements accounts.Wallet, attempting to sign the
   128  // hash of the given text with the given account using passphrase as extra authentication.
   129  func (w *keystoreWallet) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {
   130  	// Make sure the requested account is contained within
   131  	if !w.Contains(account) {
   132  		return nil, accounts.ErrUnknownAccount
   133  	}
   134  	// Account seems valid, request the keystore to sign
   135  	return w.keystore.SignHashWithPassphrase(account, passphrase, accounts.TextHash(text))
   136  }
   137  
   138  // SignTx implements accounts.Wallet, attempting to sign the given transaction
   139  // with the given account. If the wallet does not wrap this particular account,
   140  // an error is returned to avoid account leakage (even though in theory we may
   141  // be able to sign via our shared keystore backend).
   142  func (w *keystoreWallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   143  	// Make sure the requested account is contained within
   144  	if !w.Contains(account) {
   145  		return nil, accounts.ErrUnknownAccount
   146  	}
   147  	// Account seems valid, request the keystore to sign
   148  	return w.keystore.SignTx(account, tx, chainID)
   149  }
   150  
   151  // SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given
   152  // transaction with the given account using passphrase as extra authentication.
   153  func (w *keystoreWallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   154  	// Make sure the requested account is contained within
   155  	if !w.Contains(account) {
   156  		return nil, accounts.ErrUnknownAccount
   157  	}
   158  	// Account seems valid, request the keystore to sign
   159  	return w.keystore.SignTxWithPassphrase(account, passphrase, tx, chainID)
   160  }