personal.newAccount(password)
// 创建一个新的账号
func accountCreate(ctx *cli.Context) error {
// 获取geth配置
cfg := gethConfig{Node: defaultNodeConfig()}
// 加载配置文件
if file := ctx.GlobalString(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil {
utils.Fatalf("%v", err)
}
}
// 设置节点相关协议配置
utils.SetNodeConfig(ctx, &cfg.Node)
// 获取账号配置
scryptN, scryptP, keydir, err := cfg.Node.AccountConfig()
if err != nil {
utils.Fatalf("Failed to read configuration: %v", err)
}
// 解析用户密码
password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
// 通过密码获取一个新的地址,存储到keystore目录
address, err := keystore.StoreKey(keydir, password, scryptN, scryptP)
if err != nil {
utils.Fatalf("Failed to create account: %v", err)
}
fmt.Printf("Address: {%x}\n", address)
return nil
}
在accounts包中,主要实现了以太坊客户端的钱包管理和账户管理,提供了两种钱包,分别是keystore,usb。同时以太坊合约代码的ABI也在accounts中实现。
key.go中
// 生成新的key结构
func newKey(rand io.Reader) (*Key, error) {
// 通过ecdsa生成一对公私钥对
privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand)
if err != nil {
return nil, err
}
// 通过ecdsa公钥生成key结构
return newKeyFromECDSA(privateKeyECDSA), nil
}
// 生成地址,存储
func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Account, error) {
// 通过给定的随机数生成新的key结构
key, err := newKey(rand)
if err != nil {
return nil, accounts.Account{}, err
}
// 封装生成address
a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.JoinPath(keyFileName(key.Address))}}
// 存储私钥
if err := ks.StoreKey(a.URL.Path, key, auth); err != nil {
zeroKey(key.PrivateKey)
return nil, a, err
}
return key, a, err
}
keystore_passphrase.go
accounts.go
package accounts
import (
"math/big"
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
)
// 以太坊地址类型结构
type Account struct {
// 20字节的数据
Address common.Address `json:"address"` // Ethereum account address derived from the key
URL URL `json:"url"` // Optional resource locator within a backend
}
// 钱包接口
type Wallet interface {
// 获取该钱包可以访问的规范路径
URL() URL
// 钱包状态
Status() (string, error)
// 初始化对钱包实例的访问
Open(passphrase string) error
// 释放open方法占用的资源
Close() error
// 账号列表
Accounts() []Account
// 查询指定账户是否属于该钱包
Contains(account Account) bool
// 专门给确定性钱包使用的
Derive(path DerivationPath, pin bool) (Account, error)
// 设置一个账户导出路径
SelfDerive(base DerivationPath, chain ethereum.ChainStateReader)
// 请求钱包为传入的哈希进行签名
SignHash(account Account, hash []byte) ([]byte, error)
// 请求钱包为传入的交易进行签名
SignTx(account Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)
// 请求钱包使用指定 的passphrase为传入的哈希进行签名
SignHashWithPassphrase(account Account, passphrase string, hash []byte) ([]byte, error)
// 请求钱包使用指定 的passphrase为传入的交易进行签名
SignTxWithPassphrase(account Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)
}
// 钱包的后端实现(服务),主要实现keystore钱包以及USB硬件钱包
type Backend interface {
// 获取钱包列表
Wallets() []Wallet
// 订阅钱包相关事件
Subscribe(sink chan<- WalletEvent) event.Subscription
}
// 钱包事件的类型
type WalletEventType int
const (
// 在通过USB或者密码文件检测到新钱包的时候 ,会触发该事件
WalletArrived WalletEventType = iota
// 开户钱包所触发的事件
WalletOpened
WalletDropped
)
// 在检测到钱包账户发生改变时所触发的事件
type WalletEvent struct {
Wallet Wallet
Kind WalletEventType
}
manager.go:
package accounts
import (
"reflect"
"sort"
"sync"
"github.com/ethereum/go-ethereum/event"
)
// 账户管理工具,可以和所有的backends进行通信来签名交易
type Manager struct {
// 已注册的后台服务
backends map[reflect.Type][]Backend
// 钱包管理相关事件
updaters []event.Subscription
updates chan WalletEvent
// 已经注册过的钱包缓存
wallets []Wallet
feed event.Feed
quit chan chan error
lock sync.RWMutex
}
// 新建管理器对象
func NewManager(backends ...Backend) *Manager {
var wallets []Wallet
for _, backend := range backends {
// 调用所有backend的wallet方法,合并成完整的钱包列表
wallets = merge(wallets, backend.Wallets()...)
}
updates := make(chan WalletEvent, 4*len(backends))
subs := make([]event.Subscription, len(backends))
for i, backend := range backends {
// 注册update channel到后端服务中
subs[i] = backend.Subscribe(updates)
}
// 封装
am := &Manager{
backends: make(map[reflect.Type][]Backend),
updaters: subs,
updates: updates,
wallets: wallets,
quit: make(chan chan error),
}
for _, backend := range backends {
kind := reflect.TypeOf(backend)
am.backends[kind] = append(am.backends[kind], backend)
}
// 另起协程,监听钱包事件
go am.update()
return am
}
// 关闭账号管理器
func (am *Manager) Close() error {
errc := make(chan error)
am.quit <- errc
return <-errc
}
// 钱包事件
func (am *Manager) update() {
defer func() {
am.lock.Lock()
for _, sub := range am.updaters {
sub.Unsubscribe()
}
am.updaters = nil
am.lock.Unlock()
}()
// 循环监听钱包相关事件
for {
select {
case event := <-am.updates:
am.lock.Lock()
switch event.Kind {
// 判断事件类型
case WalletArrived:
am.wallets = merge(am.wallets, event.Wallet)
case WalletDropped:
am.wallets = drop(am.wallets, event.Wallet)
}
am.lock.Unlock()
am.feed.Send(event)
// 接收退出
case errc := <-am.quit:
errc <- nil
return
}
}
}
// 返回指定的服务列表
func (am *Manager) Backends(kind reflect.Type) []Backend {
return am.backends[kind]
}
// 返回该账号管理器下的所有签名账户
func (am *Manager) Wallets() []Wallet {
am.lock.RLock()
defer am.lock.RUnlock()
cpy := make([]Wallet, len(am.wallets))
copy(cpy, am.wallets)
return cpy
}
// 通过URL查找指定的钱包
func (am *Manager) Wallet(url string) (Wallet, error) {
am.lock.RLock()
defer am.lock.RUnlock()
parsed, err := parseURL(url)
if err != nil {
return nil, err
}
for _, wallet := range am.Wallets() {
if wallet.URL() == parsed {
return wallet, nil
}
}
return nil, ErrUnknownWallet
}
// 通过指定的ACCOUNT查找钱包
func (am *Manager) Find(account Account) (Wallet, error) {
am.lock.RLock()
defer am.lock.RUnlock()
for _, wallet := range am.wallets {
if wallet.Contains(account) {
return wallet, nil
}
}
return nil, ErrUnknownAccount
}
// 订阅事件
func (am *Manager) Subscribe(sink chan<- WalletEvent) event.Subscription {
return am.feed.Subscribe(sink)
}
// 在指定的位置插入钱包,保证原来列表的顺序
func merge(slice []Wallet, wallets ...Wallet) []Wallet {
for _, wallet := range wallets {
n := sort.Search(len(slice), func(i int) bool { return slice[i].URL().Cmp(wallet.URL()) >= 0 })
if n == len(slice) {
slice = append(slice, wallet)
continue
}
slice = append(slice[:n], append([]Wallet{wallet}, slice[n:]...)...)
}
return slice
}
// 删除钱包列表中指定的钱包
func drop(slice []Wallet, wallets ...Wallet) []Wallet {
for _, wallet := range wallets {
n := sort.Search(len(slice), func(i int) bool { return slice[i].URL().Cmp(wallet.URL()) >= 0 })
if n == len(slice) {
continue
}
slice = append(slice[:n], slice[n+1:]...)
}
return slice
}
通过架构图,可以看到一个wallet中可以包含多个account,每个account中包含一个address结构(address, URL)
type KeyStore struct {
// keyStore接口,用于访问账户关联的私钥
storage keyStore // Storage backend, might be cleartext or encrypted
cache *accountCache // In-memory account cache over the filesystem storage
changes chan struct{} // Channel receiving change notifications from the cache
unlocked map[common.Address]*unlocked // Currently unlocked account (decrypted private keys)
// 所有钱包的集合,
wallets []accounts.Wallet // Wallet wrappers around the individual key files
updateFeed event.Feed // Event feed to notify wallet additions/removals
updateScope event.SubscriptionScope // Subscription scope tracking current live listeners
updating bool // Whether the event notification loop is running
mu sync.RWMutex
}
type unlocked struct {
*Key
abort chan struct{}
}
// 概念指定的目录创建一个keystore
func NewKeyStore(keydir string, scryptN, scryptP int) *KeyStore {
keydir, _ = filepath.Abs(keydir)
ks := &KeyStore{storage: &keyStorePassphrase{keydir, scryptN, scryptP}}
ks.init(keydir)
return ks
}
func NewPlaintextKeyStore(keydir string) *KeyStore {
keydir, _ = filepath.Abs(keydir)
ks := &KeyStore{storage: &keyStorePlain{keydir}}
ks.init(keydir)
return ks
}
func (ks *KeyStore) init(keydir string) {
ks.mu.Lock()
defer ks.mu.Unlock()
ks.unlocked = make(map[common.Address]*unlocked)
// 创建一个accountCache实例
ks.cache, ks.changes = newAccountCache(keydir)
runtime.SetFinalizer(ks, func(m *KeyStore) {
m.cache.close()
})
// 获取当前的账号列表
accs := ks.cache.accounts()
ks.wallets = make([]accounts.Wallet, len(accs))
for i := 0; i < len(accs); i++ {
// 将keyStore填充到钱包中去
ks.wallets[i] = &keystoreWallet{account: accs[i], keystore: ks}
}
}
// 通过keystore获取wallet列表
func (ks *KeyStore) Wallets() []accounts.Wallet {
ks.refreshWallets()
ks.mu.RLock()
defer ks.mu.RUnlock()
cpy := make([]accounts.Wallet, len(ks.wallets))
copy(cpy, ks.wallets)
return cpy
}
config.go
// 创建一个账号管理器
func makeAccountManager(conf *Config) (*accounts.Manager, string, error) {
// 获取配送配置以及私钥存储的目录
scryptN, scryptP, keydir, err := conf.AccountConfig()
var ephemeral string
if keydir == "" {
keydir, err = ioutil.TempDir("", "go-ethereum-keystore")
ephemeral = keydir
}
if err != nil {
return nil, "", err
}
// 以700权限创建keystore目录,默认为datadir/keystore
if err := os.MkdirAll(keydir, 0700); err != nil {
return nil, "", err
}
// 初始化backend列表,创建keyStore实例
backends := []accounts.Backend{
keystore.NewKeyStore(keydir, scryptN, scryptP),
}
if !conf.NoUSB {
if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil {
log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err))
} else {
backends = append(backends, ledgerhub)
}
if trezorhub, err := usbwallet.NewTrezorHub(); err != nil {
log.Warn(fmt.Sprintf("Failed to start Trezor hub, disabling: %v", err))
} else {
backends = append(backends, trezorhub)
}
}
// 在账户的列表初始化完成之后,通过NewManager函数创建一个账号管理器
return accounts.NewManager(backends...), ephemeral, nil
}