在启动节点时,解锁参数可以同时指定多个帐号,格式为--unlock "addr1,addr2,addr3..." --password "pwd",其中unlock参数为多个帐号的地址,用逗号分隔;password参数为口令文件,文件中的口令每行一个口令。
在创建帐号时,命令./ghpb --datadir node/data account init可以多次执行,每次执行后,会在路径node/data/keystore下生成多个帐号文件,比如UTC–2018-11-29T08-21-25.565157387Z–3e8aadb68222c70b309e87cd5c27e97950879076。当节点启动指定多个帐号时,会加载对应的帐号文件,并解锁。下边看一下解锁的代码。
启动节点入口main.go的init方法,调用过程为init()–>ghpb–>startNode()
1 | func init() { |
1 | // ghpb is the main entry point into the system if no special subcommand is ran. |
在startNode方法中
- 首先获取keyStore的指针
- MakePasswordList方法解析–password参数指定的口令文件,文件中的内容每一行对应一个口令
- 获取帐号列表,进行遍历解锁
- 后边是启动节点,并启动一个协程,开启钱包事件监听。这部分内容后续章节中再进行解读。下边看下遍历时,每个帐号是怎么使用口令解锁的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67// startNode boots up the system node and all registered protocols, after which
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
// miner.
func startNode(ctx *cli.Context, stack *node.Node, conf *config.HpbConfig) {
// Unlock any account specifically requested
ks := stack.AccountManager().KeyStore().(*keystore.KeyStore)
passwords := utils.MakePasswordList(ctx)
unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
for i, account := range unlocks {
if trimmed := strings.TrimSpace(account); trimmed != "" {
unlockAccount(ctx, ks, trimmed, i, passwords)
}
}
if unlocks[0] != "" {
account, err := utils.MakeAddress(ks, strings.TrimSpace(unlocks[0]))
if err != nil {
utils.Fatalf("Could not list accounts: %v", err)
}
conf.Node.DefaultAddress = account.Address
}
//set rpc aii
//utils.SetNodeAPI(&conf.Node, stack)
// Start up the node itself
utils.StartNode(stack)
// Register wallet event handlers to open and auto-derive wallets
events := make(chan accounts.WalletEvent, 16)
stack.AccountManager().Subscribe(events)
go func() {
// Open any wallets already attached
for _, wallet := range stack.AccountManager().Wallets() {
if err := wallet.Open(""); err != nil {
log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
}
}
// Listen for wallet event till termination
for event := range events {
switch event.Kind {
case accounts.WalletArrived:
if err := event.Wallet.Open(""); err != nil {
log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
}
case accounts.WalletOpened:
status, _ := event.Wallet.Status()
log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
case accounts.WalletDropped:
log.Info("Old wallet dropped", "url", event.Wallet.URL())
event.Wallet.Close()
}
}
}()
// Start auxiliary services if enabled
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) && (conf.Network.RoleType == "") {
// Set the gas price to the limits from the CLI and start mining
stack.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name))
if err := stack.StartMining(true); err != nil {
utils.Fatalf("Failed to start mining: %v", err)
}
}
}
在unlockAccount方法中,每个帐号会进行尝试3次解锁。每次会从口令列表中取出一个口令进行解锁帐号,如果解锁成功则返回,失败则继续。方法getPassPhrase每次从众多口令中取一个口令的方式是以下部分代码实现的 ,如果口令个数大于3个的话,则每次都会取最后一个。不是很理解为何要这样做,按理说应该每个帐号对应一个口令的。😂😂😂
1 | if len(passwords) > 0 { |