以太坊源碼分析 賬號(hào)

AccountManager創(chuàng)建

p2p節(jié)點(diǎn)創(chuàng)建時(shí)會(huì)創(chuàng)建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數(shù)組,數(shù)組中調(diào)用了newKeyStore

  2. 利用backends 創(chuàng)建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,其中調(diào)用了newKeyStore
    backends := []accounts.Backend{
    keystore.NewKeyStore(keydir, scryptN, scryptP),
    }

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

    }

keystore.NewKeyStore

  1. 初始化了一個(gè)KeyStore,調(diào)用init方法

keystore.init

  1. 調(diào)用ks.cache.accounts方法遍歷硬盤上keystore目錄下的所有賬號(hào)

  2. 根據(jù)賬號(hào)初始化keystoreWallet,并緩存到ks.wallets數(shù)組中

    // 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列表,這個(gè)方法會(huì)遍歷keystore目錄,將所有的賬號(hào)都遍歷出來
    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 {
    //加載賬號(hào)列表
   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
    //遍歷目錄,將新創(chuàng)建的,新刪除的,更新的賬號(hào)目錄遍歷出來
   creates, deletes, updates, err := ac.fileC.scan(ac.keydir)
   
    //將賬號(hào)添加到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. 注冊(cè)事件

  3. 根據(jù)事件更新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 {
        //注冊(cè)事件
       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)
    }
    //開啟事件監(jiān)聽
    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 {
             //當(dāng)新填wallet時(shí),合并
         case WalletArrived:
            am.wallets = merge(am.wallets, event.Wallet)
             //上刪除wallet時(shí),刪除
         case WalletDropped:
            am.wallets = drop(am.wallets, event.Wallet)
         }
   }
}

創(chuàng)建賬號(hào)

accountcmd.accountCreate()入口函數(shù)

  • password := getPassPhrase 拿到用戶輸入的密碼
  • address, err := keystore.StoreKey(keydir, password, scryptN, scryptP) 生成公私鑰及對(duì)應(yīng)的keystore文件
    • key.storeNewKey

      • newKey 生成key,key中包含地址,公鑰,私鑰
        • privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand) 生成公私鑰
        • newKeyFromECDSA(privateKeyECDSA) 根據(jù)公私鑰生成key
      • a := accounts.Account 根據(jù)key生成賬號(hào)
      • ks.StoreKey(a.URL.Path, key, auth) 用輸入的密碼加密keystore并寫入文件系統(tǒng)中

      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 創(chuàng)建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
      }
      //生成賬號(hào)
      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
      }
      //將加密的數(shù)據(jù),寫入到文件中
      return writeKeyFile(filename, keyjson)
      }

解鎖賬號(hào)

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) {
   //根據(jù)keystore和address,獲得對(duì)應(yīng)的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))
   }
    //根據(jù)下標(biāo),返回緩存的賬號(hào)信息
   return accs[index], nil
}

ks.Unlock(account, password)

ks.TimedUnlock

調(diào)用解密函數(shù),解密keystore文件,獲得秘鑰,構(gòu)建賬號(hào)對(duì)象返回

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

更新賬號(hào)

更新賬號(hào)很簡(jiǎn)單,先用老密碼解密keystore文件,然后用新密碼在加密keystore并保存在文件系統(tǒng)中

// 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)
       //關(guān)鍵方法,更新
      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)
}

導(dǎo)入錢包

accountcmd.importWallet

  1. 讀取參數(shù)中的文件信息

  2. 使用KeyStoreType類型的backend解密文件內(nèi)容

  3. 生成賬號(hào)信息

    func importWallet(ctx cli.Context) error {
    keyfile := ctx.Args().First()
    //讀取參數(shù)中的文件信息
    keyJSON, err := ioutil.ReadFile(keyfile)
    // 獲取對(duì)應(yīng)的密碼
    passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx))
    //獲得對(duì)應(yīng)類型的backend
    ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(
    keystore.KeyStore)
    //解密文件獲得賬號(hào)信息
    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) {
    //解密賬號(hào)信息
   a, _, err := importPreSaleKey(ks.storage, keyJSON, passphrase)
   if err != nil {
      return a, err
   }
    //緩存賬號(hào)
   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) {
    //解密數(shù)據(jù)
   key, err := decryptPreSaleKey(keyJSON, password)
   if err != nil {
      return accounts.Account{}, nil, err
   }
   key.Id = uuid.NewRandom()
    // 生成賬號(hào)信息
   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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容