本文分析以太坊的账户管理的源码,主要包括两个部分: 获取钱包列表、订阅钱包事件。
1. 获取钱包列表
账户组件之间的关系:
从图中可以看出wallet、account、address这三者的区别和联系i:wallet中可能包含多个account,而每个account中包含一个address和账户所在路径(URL)。
这里有两个重要接口:Backend和Wallet。
- Backend指的是钱包后端,目前实现了两种:KeyStore钱包和USB硬件钱包。可以看到,Backend接口有两个函数Wallets()和Subscribe(),分别对应于获取钱包列表和订阅钱包事件这两个功能。
- Wallet指的是单个钱包,可以看到包含了一些打开、关闭、签名相关的接口函数。还有一些函数如Derive()是给分层确定性(HD)钱包使用的,目前KeyStore钱包后端没有实现,USB钱包需要driver支持。
这里主要分析KeyStore钱包。KeyStore实现了Backend接口,看一下相关字段:
- storage:实现了keyStore接口,用于访问账户关联的私钥
- wallets:所有钱包的集合,每个钱包是一个keystoreWallet实例
- accountCache:缓存所有账户信息,初始化时会扫描datadir/keystore目录获取所有账号
下面开始分析具体代码。以太坊启动创建Node时调用了makeAccountManager()创建账号管理器:
func New(conf *Config) (*Node, error) { …… am, ephemeralKeystore, err := makeAccountManager(conf) …… }
看一下makeAccountManager()的实现,代码位于node/config.go:
func makeAccountManager(conf *Config) (*accounts.Manager, string, error) { scryptN, scryptP, keydir, err := conf.AccountConfig() …… if err := os.MkdirAll(keydir, 0700); err != nil { return nil, "", err } // Assemble the account manager and supported backends backends := []accounts.Backend{ keystore.NewKeyStore(keydir, scryptN, scryptP), } …… return accounts