以太坊源码分析(5)accounts代码分析

## 1.personal.newAccount创建账户方法
用户在控制台输入personal.newAccount会创建一个新的账户,会进入到ethapi.api中的newAccount方法中,这个方法会返回一个地址。
```
func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) {
acc, err := fetchKeystore(s.am).NewAccount(password)
if err == nil {
return acc.Address, nil
}
return common.Address{}, err
}
```
 
创建账户过程中,首先会通过账户管理系统(account manager)来获取Keystore,然后通过椭圆加密算法产生公私钥对,并获取地址
```
func newKey(rand io.Reader) (*Key, error) {
privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand)
if err != nil {
return nil, err
}
return newKeyFromECDSA(privateKeyECDSA), nil
}
```
在获取到公私钥对后,会对用户输入的密码进行加密,并保存入文件。
```

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)
}
```
在保存文件的同时,会将新创建的账户加入到缓存中。
```

func (ks *KeyStore) NewAccount(passphrase string) (accounts.Account, error) {
_, account, err := storeNewKey(ks.storage, crand.Reader, passphrase)
if err != nil {
return accounts.Account{}, err
}
// Add the account to the cache immediately rather
// than waiting for file system notifications to pick it up.
ks.cache.add(account)
ks.refreshWallets()
return account, nil
}
```
 ## 2.personal.listAccounts列出所有账户方法
用户在控制台输入personal.listAccounts,会进入到ethapi.api中的listAccounts方法中,这个方法会从用户管理中读取所有钱包信息,返回所有注册钱包下的所有地址信息。
```
func (s *PrivateAccountAPI) ListAccounts() []common.Address {
addresses := make([]common.Address, 0) // return [] instead of nil if empty
for _, wallet := range s.am.Wallets() {
for _, account := range wallet.Accounts() {
addresses = append(addresses, account.Address)
}
}
return addresses
}
```
## 3.eth.sendTransaction

sendTransaction经过RPC调用之后,最终会调用ethapi.api.go中的sendTransaction方法。
```
// SendTransaction will create a transaction from the given arguments and
// tries to sign it with the key associated with args.To. If the given passwd isn't
// able to decrypt the key it fails.
func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs, passwd string) (common.Hash, error) {
// Look up the wallet containing the requested signer
account := accounts.Account{Address: args.From}

wallet, err := s.am.Find(account)
if err != nil {
return common.Hash{}, err
}

//对于每一个账户,Nonce会随着转账数的增加而增加,这个参数主要是为了防止双花攻击。
if args.Nonce == nil {
// Hold the addresse's mutex around signing to prevent concurrent assignment of
// the same nonce to multiple accounts.
s.nonceLock.LockAddr(args.From)
defer s.nonceLock.UnlockAddr(args.From)
}

// Set some sanity defaults and terminate on failure
if err := args.setDefaults(ctx, s.b); err != nil {
return common.Hash{}, err
}
// Assemble the transaction and sign with the wallet
tx := args.toTransaction()
...
```
这个方法利用传入的参数from构造一个account,表示转出方。接着会通过账户管理系统accountManager获得该账户的钱包(wallet)。
am.Find方法会从账户管理系统中对钱包进行遍历,找到包含这个account的钱包。
```
// Find attempts to locate the wallet corresponding to a specific account. Since
// accounts can be dynamically added to and removed from wallets, this method has
// a linear runtime in the number of wallets.
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
}
```
接下来会调用setDefaults方法设置一些交易的默认值。如果没有设置Gas,GasPrice,Nonce等,那么它们将会被设置为默认值。
当交易的这些参数都设置好之后,会利用toTransaction方法创建一笔交易。
```
func (args *SendTxArgs) toTransaction() *types.Transaction {
var input []byte
if args.Data != nil {
input = *args.Data
} else if args.Input != nil {
input = *args.Input
}
if args.T
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尹成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值