<!--?xml version="1.0" encoding="UTF-8"?-->
从创建账户的代码开始:personal.newAccount()
创建一个账户我打印了一些调试信息,这些信息是插入在rpc的执行模块中的,为了方便调试我每个方法执行后都打印如下日志
[rpc_execute_result] reply=[<common.Address Value> <error Value>] ; {NewAccount func(*eth.PrivateAccountAPI, string) (common.Address, error) <func(*eth.PrivateAccountAPI, string) (common.Address, error) Value> %!s(int=3)} ; args=[<*eth.PrivateAccountAPI Value> 123456]
从上面这段日志可以看出,创建账户 返回的是一个 Address
reply=[<common.Address Value> <error Value>]
具体实现在 eth.PrivateAccountAPI 这个对象的 NewAccount 方法中
{NewAccount func(*eth.PrivateAccountAPI, string) ...
我传给这个方法的参数,也就是我的密码是 123456
[<*eth.PrivateAccountAPI Value> 123456]
那么我们很容易就能找到 eth.PrivateAccountAPI 的源码 go-ethereum/eth/api.go
// PrivateAccountAPI provides an API to access accounts managed by this node.
// It offers methods to create, (un)lock en list accounts. Some methods accept
// passwords and are therefore considered private by default.
type PrivateAccountAPI struct {
am *accounts.Manager
txPool *core.TxPool
txMu *sync.Mutex
gpo *GasPriceOracle
}
我们看到 am 这个属性,是 accounts.Manager 类型,猜也猜出来他是干什么的了
// NewAccount will create a new account and returns the address for the new account.
func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) {
acc, err := s.am.NewAccount(password)
if err == nil {
return acc.Address, nil
}
return common.Address{}, err
}
再看 NewAccount 的实现,果不其然是用 s.am.NewAccount 实现的这个功能,那么将目标转向 accounts.Manager
源码在 go-ethereum/accounts/account_manager.go 中;
// NewAccount generates a new key and stores it into the key directory,
// encrypting it with the passphrase.
func (am *Manager) NewAccount(passphrase string) (Account, error) {
_, account, err := storeNewKey(am.keyStore, crand.Reader, passphrase)
if err != nil {
return Account{}, err
}
// Add the account to the cache immediately rather
// than waiting for file system notifications to pick it up.
am.cache.add(account)
return account, nil
}
前面都是结构性的东西只要仔细找大家都能找到,想要看懂 storeNewKey 方法的具体实现,可能需要了解一些 椭圆曲线 相关知识,以及椭圆曲线在非对称加密中的具体应用,但不知道有没有这个必要;
毕竟 openssl 用了这么多年,又有多少人真正关注过 RSA 呢?
创建账户一直看到生成一个私钥文件到 keystore 目录就可以了,本着这个目的继续往下看;
go-ethereum/accounts/key.go 中可以找到 storeNewKey 方法
func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, Account, error) {
key, err := newKey(rand)
if err != nil {
return nil, Account{}, err
}
a := Account{Address: key.Address, File: ks.JoinPath(keyFileName(key.Address))}
if err := ks.StoreKey(a.File, key, auth); err != nil {
zeroKey(key.PrivateKey)
return nil, a, err
}
return key, a, err
}
到 newKey 方法瞧一瞧
func newKey(rand io.Reader) (*Key, error) {
privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), rand)
if err != nil {
return nil, err
}
return newKeyFromECDSA(privateKeyECDSA), nil
}
神秘的椭圆曲线签名算法就藏在 ecdsa 中,ecdsa.GenerateKey 根据随机数 rand 生成了一个私钥 privateKeyECDSA
看到这才知道 ecdsa 是 go 标准库中提供的 api;
ks.StoreKey 这个方法在 go-ethereum/accounts/key_store_passphrase.go 中可以找到具体实现
func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error {
keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)
if err != nil {
return err
}
return writeKeyFile(filename, keyjson)
}
看到这里,就看到这里吧,生成账户的代码基本上就看完了,使用 椭圆曲线生成私钥,再用私钥生成公钥然后把它们存储在 keystore 目录中,其实关键就是那个加密算法,但是看不懂,其余的都不重要。