decred.org/dcrdex@v1.0.5/client/asset/eth/node.go (about)

     1  // This code is available on the terms of the project LICENSE.md file,
     2  // also available online at https://blueoakcouncil.org/license/1.0.0.
     3  
     4  package eth
     5  
     6  import (
     7  	"bytes"
     8  	"crypto/ecdsa"
     9  	"fmt"
    10  
    11  	"github.com/ethereum/go-ethereum/accounts"
    12  	"github.com/ethereum/go-ethereum/accounts/keystore"
    13  	"github.com/ethereum/go-ethereum/common"
    14  	"github.com/ethereum/go-ethereum/crypto"
    15  )
    16  
    17  func importKeyToKeyStore(ks *keystore.KeyStore, priv *ecdsa.PrivateKey, pw []byte) error {
    18  	accounts := ks.Accounts()
    19  	if len(accounts) == 0 {
    20  		_, err := ks.ImportECDSA(priv, string(pw))
    21  		return err
    22  	} else if len(accounts) == 1 {
    23  		address := crypto.PubkeyToAddress(priv.PublicKey)
    24  		if !bytes.Equal(accounts[0].Address.Bytes(), address.Bytes()) {
    25  			errMsg := "importKeyToKeyStore: attemping to import account to eth wallet: %v, " +
    26  				"but node already contains imported account: %v"
    27  			return fmt.Errorf(errMsg, address, accounts[0].Address)
    28  		}
    29  	} else {
    30  		return fmt.Errorf("importKeyToKeyStore: eth wallet keystore contains %v accounts", accounts)
    31  	}
    32  	return nil
    33  }
    34  
    35  // accountCredentials captures the account-specific geth interfaces.
    36  type accountCredentials struct {
    37  	ks     *keystore.KeyStore
    38  	acct   *accounts.Account
    39  	addr   common.Address
    40  	wallet accounts.Wallet
    41  }
    42  
    43  func pathCredentials(dir string) (*accountCredentials, error) {
    44  	// TODO: Use StandardScryptN and StandardScryptP?
    45  	return credentialsFromKeyStore(keystore.NewKeyStore(dir, keystore.LightScryptN, keystore.LightScryptP))
    46  
    47  }
    48  
    49  func credentialsFromKeyStore(ks *keystore.KeyStore) (*accountCredentials, error) {
    50  	accts := ks.Accounts()
    51  	if len(accts) != 1 {
    52  		return nil, fmt.Errorf("unexpected number of accounts, %d", len(accts))
    53  	}
    54  	acct := accts[0]
    55  	wallets := ks.Wallets()
    56  	if len(wallets) != 1 {
    57  		return nil, fmt.Errorf("unexpected number of wallets, %d", len(wallets))
    58  	}
    59  	return &accountCredentials{
    60  		ks:     ks,
    61  		acct:   &acct,
    62  		addr:   acct.Address,
    63  		wallet: wallets[0],
    64  	}, nil
    65  }
    66  
    67  func signData(creds *accountCredentials, data []byte) (sig, pubKey []byte, err error) {
    68  	h := crypto.Keccak256(data)
    69  	sig, err = creds.ks.SignHash(*creds.acct, h)
    70  	if err != nil {
    71  		return nil, nil, err
    72  	}
    73  	if len(sig) != 65 {
    74  		return nil, nil, fmt.Errorf("unexpected signature length %d", len(sig))
    75  	}
    76  
    77  	pubKey, err = recoverPubkey(h, sig)
    78  	if err != nil {
    79  		return nil, nil, fmt.Errorf("SignMessage: error recovering pubkey %w", err)
    80  	}
    81  
    82  	// Lop off the "recovery id", since we already recovered the pub key and
    83  	// it's not used for validation.
    84  	sig = sig[:64]
    85  
    86  	return
    87  }