以太坊源码分析 账号

AccountManager创建

p2p节点创建时会创建accountmanager

node.New

/ New creates a new P2P node, ready for protocol registration.
func New(conf *Config) (*Node, error) {
   // Ensure that the AccountManager method works before the node has started.
   // We rely on this in cmd/geth.
   am, ephemeralKeystore, err := makeAccountManager(conf)
...
}

config.makeAccountManager

  1. 初始化backends数组,数组中调用了newKeyStore

  2. 利用backends 创建accounts.NewManager

    func makeAccountManager(conf Config) (accounts.Manager, string, error) {
    scryptN, scryptP, keydir, err := conf.AccountConfig()
    var ephemeral string
    // Assemble the account manager and supported backends
    //初始化backends,其中调用了newKeyStore
    backends := []accounts.Backend{
    keystore.NewKeyStore(keydir, scryptN, scryptP),
    }

    return accounts.NewManager(backends...), ephemeral, nil
    

    }

keystore.NewKeyStore

  1. 初始化了一个KeyStore,调用init方法

keystore.init

  1. 调用ks.cache.accounts方法遍历硬盘上keystore目录下的所有账号

  2. 根据账号初始化keystoreWallet,并缓存到ks.wallets数组中

    // NewKeyStore creates a keystore for the given directory.
    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 (ks *KeyStore) init(keydir string) {

    // Initialize the set of unlocked keys and the account cache
    ks.unlocked = make(map[common.Address]*unlocked)
    ks.cache, ks.changes = newAccountCache(keydir)

    // Create the initial list of wallets from the cache
    //取缓存中的account列表,这个方法会遍历keystore目录,将所有的账号都遍历出来
    accs := ks.cache.accounts()
    ks.wallets = make([]accounts.Wallet, len(accs))
    for i := 0; i < len(accs); i++ {
        ks.wallets[i] = &keystoreWallet{account: accs[i], keystore: ks}
    }
}

account_cache.accounts

func (ac *accountCache) accounts() []accounts.Account {
    //加载账号列表
   ac.maybeReload()
   ac.mu.Lock()
   defer ac.mu.Unlock()
   cpy := make([]accounts.Account, len(ac.all))
   copy(cpy, ac.all)
   return cpy
}

func (ac *accountCache) maybeReload() {
    ...
    
    ac.scanAccounts()
}

account_cache.scanAccounts

遍历目录,生成account并赋值

// scanAccounts checks if any changes have occurred on the filesystem, and
// updates the account cache accordingly
func (ac *accountCache) scanAccounts() error {
   // Scan the entire folder metadata for file changes
    //遍历目录,将新创建的,新删除的,更新的账号目录遍历出来
   creates, deletes, updates, err := ac.fileC.scan(ac.keydir)
   
    //将账号添加到ac中
   for _, p := range creates.ToSlice() {
      if a := readAccount(p.(string)); a != nil {
         ac.add(*a)
      }
   }
   for _, p := range deletes.ToSlice() {
      ac.deleteByFile(p.(string))
   }
   for _, p := range updates.ToSlice() {
      path := p.(string)
      ac.deleteByFile(path)
      if a := readAccount(path); a != nil {
         ac.add(*a)
      }
   }
}

回到makeAccountManager的最后NewManager方法

  1. 将所有backend中的wallet合并

  2. 注册事件

  3. 根据事件更新wallet列表

    // NewManager creates a generic account manager to sign transaction via various
    // supported backends.
    func NewManager(backends ...Backend) Manager {
    // Retrieve the initial list of wallets from the backends and sort by URL
    var wallets []Wallet
    //将所有backend中的wallet合并
    for _, backend := range backends {
    wallets = merge(wallets, backend.Wallets()...)
    }
    // Subscribe to wallet notifications from all backends
    updates := make(chan WalletEvent, 4
    len(backends))

    subs := make([]event.Subscription, len(backends))
    for i, backend := range backends {
        //注册事件
       subs[i] = backend.Subscribe(updates)
    }
    // Assemble the account manager and return
    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
    

    }

manger.update

// update is the wallet event loop listening for notifications from the backends
// and updating the cache of wallets.
func (am *Manager) update() {

   // Loop until termination
   for {
      select {
      case event := <-am.updates:
         // Wallet event arrived, update local cache
         am.lock.Lock()
         switch event.Kind {
             //当新填wallet时,合并
         case WalletArrived:
            am.wallets = merge(am.wallets, event.Wallet)
             //上删除wallet时,删除
         case WalletDropped:
            am.wallets = drop(am.wallets, event.Wallet)
         }
   }
}

创建账号

accountcmd.accountCreate()入口函数

  • password := getPassPhrase 拿到用户输入的密码
  • address, err := keystore.StoreKey(keydir, password, scryptN, scryptP) 生成公私钥及对应的keystore文件
    • key.storeNewKey

      • newKey 生成key,key中包含地址,公钥,私钥
        • privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand) 生成公私钥
        • newKeyFromECDSA(privateKeyECDSA) 根据公私钥生成key
      • a := accounts.Account 根据key生成账号
      • ks.StoreKey(a.URL.Path, key, auth) 用输入的密码加密keystore并写入文件系统中

      func accountCreate(ctx *cli.Context) error {
      //获取输入的密码
      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 创建keystore文件及公私钥
      address, err := keystore.StoreKey(keydir, password, scryptN, scryptP)

      return nil
      }

      // StoreKey generates a key, encrypts with 'auth' and stores in the given directory
      func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) {
      _, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, rand.Reader, auth)
      return a.Address, err
      }

      func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Account, error) {
      //生成key,key中包含地址,公钥,私钥
      key, err := newKey(rand)
      if err != nil {
      return nil, accounts.Account{}, err
      }
      //生成账号
      a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.JoinPath(keyFileName(key.Address))}}
      //保存key
      if err := ks.StoreKey(a.URL.Path, key, auth); err != nil {
      zeroKey(key.PrivateKey)
      return nil, a, err
      }
      return key, a, err
      }

      func newKey(rand io.Reader) (*Key, error) {
      //生成公钥,私钥
      privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand)
      if err != nil {
      return nil, err
      }
      //生成key,主要是生成地址
      return newKeyFromECDSA(privateKeyECDSA), nil
      }

      func newKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key {
      id := uuid.NewRandom()
      key := &Key{
      Id: id,
      Address: crypto.PubkeyToAddress(privateKeyECDSA.PublicKey),
      PrivateKey: privateKeyECDSA,
      }
      return key
      }

      func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error {
      //加密key
      keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)
      if err != nil {
      return err
      }
      //将加密的数据,写入到文件中
      return writeKeyFile(filename, keyjson)
      }

解锁账号

accountcmd.unlockAccount

// tries unlocking the specified account a few times.
func unlockAccount(ctx *cli.Context, ks *keystore.KeyStore, address string, i int, passwords []string) (accounts.Account, string) {
   //根据keystore和address,获得对应的account
   account, err := utils.MakeAddress(ks, address)
      //获取密码
      password := getPassPhrase(prompt, false, i, passwords)
      //解锁
      err = ks.Unlock(account, password)
      if err == nil {
         log.Info("Unlocked account", "address", account.Address.Hex())
         return account, password
      }
}

utils.MakeAddress

// MakeAddress converts an account specified directly as a hex encoded string or
// a key index in the key store to an internal account representation.
func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) {
   // Otherwise try to interpret the account as a keystore index
   index, err := strconv.Atoi(account)
 
   accs := ks.Accounts()
   if len(accs) <= index {
      return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs))
   }
    //根据下标,返回缓存的账号信息
   return accs[index], nil
}

ks.Unlock(account, password)

ks.TimedUnlock

调用解密函数,解密keystore文件,获得秘钥,构建账号对象返回

func (ks *KeyStore) TimedUnlock(a accounts.Account, passphrase string, timeout time.Duration) error {
   //解锁key
   a, key, err := ks.getDecryptedKey(a, passphrase)
    //生成unlocked对象
   u = &unlocked{Key: key}
   //将unlocked对象保存在队列中
   ks.unlocked[a.Address] = u
   return nil
}

更新账号

更新账号很简单,先用老密码解密keystore文件,然后用新密码在加密keystore并保存在文件系统中

// accountUpdate transitions an account from a previous format to the current
// one, also providing the possibility to change the pass-phrase.
func accountUpdate(ctx *cli.Context) error {
   if len(ctx.Args()) == 0 {
      utils.Fatalf("No accounts specified to update")
   }
   stack, _ := makeConfigNode(ctx)
   ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)

   for _, addr := range ctx.Args() {
      account, oldPassword := unlockAccount(ctx, ks, addr, 0, nil)
      newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil)
       //关键方法,更新
      if err := ks.Update(account, oldPassword, newPassword); err != nil {
         utils.Fatalf("Could not update the account: %v", err)
      }
   }
   return nil
}

// Update changes the passphrase of an existing account.
func (ks *KeyStore) Update(a accounts.Account, passphrase, newPassphrase string) error {
    //解密
   a, key, err := ks.getDecryptedKey(a, passphrase)
   if err != nil {
      return err
   }
    //加密
   return ks.storage.StoreKey(a.URL.Path, key, newPassphrase)
}

导入钱包

accountcmd.importWallet

  1. 读取参数中的文件信息

  2. 使用KeyStoreType类型的backend解密文件内容

  3. 生成账号信息

    func importWallet(ctx cli.Context) error {
    keyfile := ctx.Args().First()
    //读取参数中的文件信息
    keyJSON, err := ioutil.ReadFile(keyfile)
    // 获取对应的密码
    passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx))
    //获得对应类型的backend
    ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(
    keystore.KeyStore)
    //解密文件获得账号信息
    acct, err := ks.ImportPreSaleKey(keyJSON, passphrase)
    return nil
    }

ks.ImportPreSaleKey

// ImportPreSaleKey decrypts the given Ethereum presale wallet and stores
// a key file in the key directory. The key file is encrypted with the same passphrase.
func (ks *KeyStore) ImportPreSaleKey(keyJSON []byte, passphrase string) (accounts.Account, error) {
    //解密账号信息
   a, _, err := importPreSaleKey(ks.storage, keyJSON, passphrase)
   if err != nil {
      return a, err
   }
    //缓存账号
   ks.cache.add(a)
    //刷新钱包
   ks.refreshWallets()
   return a, nil
}

prosale.importPreSaleKey

// creates a Key and stores that in the given KeyStore by decrypting a presale key JSON
func importPreSaleKey(keyStore keyStore, keyJSON []byte, password string) (accounts.Account, *Key, error) {
    //解密数据
   key, err := decryptPreSaleKey(keyJSON, password)
   if err != nil {
      return accounts.Account{}, nil, err
   }
   key.Id = uuid.NewRandom()
    // 生成账号信息
   a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: keyStore.JoinPath(keyFileName(key.Address))}}
   //保存keystore
   err = keyStore.StoreKey(a.URL.Path, key, password)
   return a, key, err
}

https://t.zsxq.com/iiMvfea

我的星球.jpg

你可能感兴趣的:(以太坊源码分析 账号)