以太坊源码学习(四)账户

accounts/accounts.go

// Account represents an Ethereum account located at a specific location defined
// by the optional URL field.
type Account struct {
   Address common.Address `json:"address"` // Ethereum account address derived from the key
   URL     URL            `json:"url"`     // Optional resource locator within a backend
}

钱包接口

// Wallet represents a software or hardware wallet that might contain one or more
// accounts (derived from the same seed).
type Wallet interface {
   // URL retrieves the canonical path under which this wallet is reachable. It is
   // user by upper layers to define a sorting order over all wallets from multiple
   // backends.
   // 转账路径
   URL() URL

   // Status returns a textual status to aid the user in the current state of the
   // wallet. It also returns an error indicating any failure the wallet might have
   // encountered.
   // 
   Status() (string, error)

   // Open initializes access to a wallet instance. It is not meant to unlock or
   // decrypt account keys, rather simply to establish a connection to hardware
   // wallets and/or to access derivation seeds.
   //
   // The passphrase parameter may or may not be used by the implementation of a
   // particular wallet instance. The reason there is no passwordless open method
   // is to strive towards a uniform wallet handling, oblivious to the different
   // backend providers.
   //
   // Please note, if you open a wallet, you must close it to release any allocated
   // resources (especially important when working with hardware wallets).
   // 打开钱包
   Open(passphrase string) error

   // Close releases any resources held by an open wallet instance.
   Close() error

   // Accounts retrieves the list of signing accounts the wallet is currently aware
   // of. For hierarchical deterministic wallets, the list will not be exhaustive,
   // rather only contain the accounts explicitly pinned during account derivation.
   // 
   Accounts() []Account

   // Contains returns whether an account is part of this particular wallet or not.
   // 包含
   Contains(account Account) bool

   // Derive attempts to explicitly derive a hierarchical deterministic account at
   // the specified derivation path. If requested, the derived account will be added
   // to the wallet's tracked account list.
   // 派生出分层确定性钱包
   Derive(path DerivationPath, pin bool) (Account, error)

   // SelfDerive sets a base account derivation path from which the wallet attempts
   // to discover non zero accounts and automatically add them to list of tracked
   // accounts.
   //
   // Note, self derivaton will increment the last component of the specified path
   // opposed to decending into a child path to allow discovering accounts starting
   // from non zero components.
   //
   // You can disable automatic account discovery by calling SelfDerive with a nil
   // chain state reader.
   SelfDerive(base DerivationPath, chain ethereum.ChainStateReader)

   // SignHash requests the wallet to sign the given hash.
   //
   // It looks up the account specified either solely via its address contained within,
   // or optionally with the aid of any location metadata from the embedded URL field.
   //
   // If the wallet requires additional authentication to sign the request (e.g.
   // a password to decrypt the account, or a PIN code o verify the transaction),
   // an AuthNeededError instance will be returned, containing infos for the user
   // about which fields or actions are needed. The user may retry by providing
   // the needed details via SignHashWithPassphrase, or by other means (e.g. unlock
   // the account in a keystore).
   SignHash(account Account, hash []byte) ([]byte, error)

   // SignTx requests the wallet to sign the given transaction.
   //
   // It looks up the account specified either solely via its address contained within,
   // or optionally with the aid of any location metadata from the embedded URL field.
   //
   // If the wallet requires additional authentication to sign the request (e.g.
   // a password to decrypt the account, or a PIN code to verify the transaction),
   // an AuthNeededError instance will be returned, containing infos for the user
   // about which fields or actions are needed. The user may retry by providing
   // the needed details via SignTxWithPassphrase, or by other means (e.g. unlock
   // the account in a keystore).
   // 
   SignTx(account Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)

   // SignHashWithPassphrase requests the wallet to sign the given hash with the
   // given passphrase as extra authentication information.
   //
   // It looks up the account specified either solely via its address contained within,
   // or optionally with the aid of any location metadata from the embedded URL field.
   SignHashWithPassphrase(account Account, passphrase string, hash []byte) ([]byte, error)

   // SignTxWithPassphrase requests the wallet to sign the given transaction, with the
   // given passphrase as extra authentication information.
   //
   // It looks up the account specified either solely via its address contained within,
   // or optionally with the aid of any location metadata from the embedded URL field.
   SignTxWithPassphrase(account Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)
}

钱包提供者

// Backend is a "wallet provider" that may contain a batch of accounts they can
// sign transactions with and upon request, do so.
type Backend interface {
   // Wallets retrieves the list of wallets the backend is currently aware of.
   //
   // The returned wallets are not opened by default. For software HD wallets this
   // means that no base seeds are decrypted, and for hardware wallets that no actual
   // connection is established.
   //
   // The resulting wallet list will be sorted alphabetically based on its internal
   // URL assigned by the backend. Since wallets (especially hardware) may come and
   // go, the same wallet might appear at a different positions in the list during
   // subsequent retrievals.
   Wallets() []Wallet

   // Subscribe creates an async subscription to receive notifications when the
   // backend detects the arrival or departure of a wallet.
   Subscribe(sink chan<- WalletEvent) event.Subscription
}

 

/accounts/manager.go

type Manager struct {
   // 所有已注册的Backend 
   backends map[reflect.Type][]Backend // Index of backends currently registered
   // 所有Backend的更新订阅器
   updaters []event.Subscription       // Wallet update subscriptions for all backends
   // Backend的更新订阅槽
   updates  chan WalletEvent           // Subscription sink for backend wallet changes
   // 所有已经注册的Backend钱包缓存
   wallets  []Wallet                   // Cache of all wallets from all registered backends

   feed event.Feed // Wallet feed notifying of arrivals/departures

   quit chan chan error
   lock sync.RWMutex
}
// 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
   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()//监听backends 发来的更新

   return am
}
// and updating the cache of wallets.
func (am *Manager) update() {
   // Close all subscriptions when the manager terminates
   defer func() {
      am.lock.Lock()
      for _, sub := range am.updaters {
         sub.Unsubscribe()
      }
      am.updaters = nil
      am.lock.Unlock()
   }()

   // Loop until termination
   for {
      select {
      case event := <-am.updates:
         // Wallet event arrived, update local cache
         am.lock.Lock()
         switch event.Kind {
         case WalletArrived:
            am.wallets = merge(am.wallets, event.Wallet)
         case WalletDropped:
            am.wallets = drop(am.wallets, event.Wallet)
         }
         am.lock.Unlock()

         // Notify any listeners of the event
         am.feed.Send(event)

      case errc := <-am.quit:
         // Manager terminating, return
         errc <- nil
         return
      }
   }
}

你可能感兴趣的:(区块链)