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 }