1.personal.newAccount 创建账户方法

用户在控制台输入personal.newAccount会创建一个新的账户,会进入到ethapi.api中的newAccount方法中,这个方法会返回一个地址。

  1. func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) {
  2. acc, err := fetchKeystore(s.am).NewAccount(password)
  3. if err == nil {
  4. return acc.Address, nil
  5. }
  6. return common.Address{}, err
  7. }

创建账户过程中,首先会通过账户管理系统(account manager)来获取Keystore,然后通过椭圆加密算法产生公私钥对,并获取地址

  1. func newKey(rand io.Reader) (*Key, error) {
  2. privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand)
  3. if err != nil {
  4. return nil, err
  5. }
  6. return newKeyFromECDSA(privateKeyECDSA), nil
  7. }

在获取到公私钥对后,会对用户输入的密码进行加密,并保存入文件。

  1. func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error {
  2. keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)
  3. if err != nil {
  4. return err
  5. }
  6. return writeKeyFile(filename, keyjson)
  7. }

在保存文件的同时,会将新创建的账户加入到缓存中。

  1. func (ks *KeyStore) NewAccount(passphrase string) (accounts.Account, error) {
  2. _, account, err := storeNewKey(ks.storage, crand.Reader, passphrase)
  3. if err != nil {
  4. return accounts.Account{}, err
  5. }
  6. // Add the account to the cache immediately rather
  7. // than waiting for file system notifications to pick it up.
  8. ks.cache.add(account)
  9. ks.refreshWallets()
  10. return account, nil
  11. }

2.personal.listAccounts列出所有账户方法

用户在控制台输入personal.listAccounts,会进入到ethapi.api中的listAccounts方法中,这个方法会从用户管理中读取所有钱包信息,返回所有注册钱包下的所有地址信息。

  1. func (s *PrivateAccountAPI) ListAccounts() []common.Address {
  2. addresses := make([]common.Address, 0) // return [] instead of nil if empty
  3. for _, wallet := range s.am.Wallets() {
  4. for _, account := range wallet.Accounts() {
  5. addresses = append(addresses, account.Address)
  6. }
  7. }
  8. return addresses
  9. }

3.eth.sendTransaction

sendTransaction经过RPC调用之后,最终会调用ethapi.api.go中的sendTransaction方法。

  1. // SendTransaction will create a transaction from the given arguments and
  2. // tries to sign it with the key associated with args.To. If the given passwd isn't
  3. // able to decrypt the key it fails.
  4. func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs, passwd string) (common.Hash, error) {
  5. // Look up the wallet containing the requested signer
  6. account := accounts.Account{Address: args.From}
  7. wallet, err := s.am.Find(account)
  8. if err != nil {
  9. return common.Hash{}, err
  10. }
  11. //对于每一个账户,Nonce会随着转账数的增加而增加,这个参数主要是为了防止双花攻击。
  12. if args.Nonce == nil {
  13. // Hold the addresse's mutex around signing to prevent concurrent assignment of
  14. // the same nonce to multiple accounts.
  15. s.nonceLock.LockAddr(args.From)
  16. defer s.nonceLock.UnlockAddr(args.From)
  17. }
  18. // Set some sanity defaults and terminate on failure
  19. if err := args.setDefaults(ctx, s.b); err != nil {
  20. return common.Hash{}, err
  21. }
  22. // Assemble the transaction and sign with the wallet
  23. tx := args.toTransaction()
  24. ...

这个方法利用传入的参数from构造一个account,表示转出方。接着会通过账户管理系统accountManager获得该账户的钱包(wallet)。
am.Find方法会从账户管理系统中对钱包进行遍历,找到包含这个account的钱包。

  1. // Find attempts to locate the wallet corresponding to a specific account. Since
  2. // accounts can be dynamically added to and removed from wallets, this method has
  3. // a linear runtime in the number of wallets.
  4. func (am *Manager) Find(account Account) (Wallet, error) {
  5. am.lock.RLock()
  6. defer am.lock.RUnlock()
  7. for _, wallet := range am.wallets {
  8. if wallet.Contains(account) {
  9. return wallet, nil
  10. }
  11. }
  12. return nil, ErrUnknownAccount
  13. }

接下来会调用setDefaults方法设置一些交易的默认值。如果没有设置Gas,GasPrice,Nonce等,那么它们将会被设置为默认值。
当交易的这些参数都设置好之后,会利用toTransaction方法创建一笔交易。

  1. func (args *SendTxArgs) toTransaction() *types.Transaction {
  2. var input []byte
  3. if args.Data != nil {
  4. input = *args.Data
  5. } else if args.Input != nil {
  6. input = *args.Input
  7. }
  8. if args.To == nil {
  9. return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
  10. }
  11. return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
  12. }

这里会对传入的交易信息的to参数进行判断。如果没有to值,那么这是一笔合约转账;而如果有to值,那么就是发起的一笔转账。最终,代码会调用NewTransaction创建一笔交易信息。

  1. func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
  2. if len(data) > 0 {
  3. data = common.CopyBytes(data)
  4. }
  5. d := txdata{
  6. AccountNonce: nonce,
  7. Recipient: to,
  8. Payload: data,
  9. Amount: new(big.Int),
  10. GasLimit: gasLimit,
  11. Price: new(big.Int),
  12. V: new(big.Int),
  13. R: new(big.Int),
  14. S: new(big.Int),
  15. }
  16. if amount != nil {
  17. d.Amount.Set(amount)
  18. }
  19. if gasPrice != nil {
  20. d.Price.Set(gasPrice)
  21. }
  22. return &Transaction{data: d}
  23. }

这里就是填充了交易结构体中的一些参数,来创建一个交易。到这里,我们的交易就已经创建成功了。
回到sendTransaction方法中,此时我们已经创建好了一笔交易,接着我们获取区块链的配置信息,检查是否是EIP155的配置,并获取链ID。

  1. ...
  2. var chainID *big.Int
  3. if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
  4. chainID = config.ChainId
  5. }
  6. signed, err := wallet.SignTx(account, tx, chainID)
  7. if err != nil {
  8. return common.Hash{}, err
  9. }
  10. return submitTransaction(ctx, s.b, signed)
  11. }

接下来就要对这笔交易签名来确保这笔交易的真实有效。这里调用SignTx实现签名。

  1. // SignTx signs the given transaction with the requested account.
  2. func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
  3. // Look up the key to sign with and abort if it cannot be found
  4. ks.mu.RLock()
  5. defer ks.mu.RUnlock()
  6. unlockedKey, found := ks.unlocked[a.Address]
  7. if !found {
  8. return nil, ErrLocked
  9. }
  10. // Depending on the presence of the chain ID, sign with EIP155 or homestead
  11. if chainID != nil {
  12. return types.SignTx(tx, types.NewEIP155Signer(chainID), unlockedKey.PrivateKey)
  13. }
  14. return types.SignTx(tx, types.HomesteadSigner{}, unlockedKey.PrivateKey)
  15. }

这里首先我们先验证账户是否已解锁。若没有解锁,则直接则异常退出。接下来我们检查chainID,判断是使用哪一种签名的方式,调用SignTx方法进行签名。

  1. // SignTx signs the transaction using the given signer and private key
  2. func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
  3. h := s.Hash(tx)
  4. sig, err := crypto.Sign(h[:], prv)
  5. if err != nil {
  6. return nil, err
  7. }
  8. return tx.WithSignature(s, sig)
  9. }

在签名时,首先获取交易的RLP哈希值,然后用传入的私钥进行椭圆加密。接着调用WithSignature方法进行初始化。
进行到这里,我们交易的签名已经完成,并且封装成为一个带签名的交易。
然后,我们就需要将这笔交易提交出去。调用SubmitTransaction方法提交交易。

  1. // submitTransaction is a helper function that submits tx to txPool and logs a message.
  2. func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) {
  3. if err := b.SendTx(ctx, tx); err != nil {
  4. return common.Hash{}, err
  5. }
  6. if tx.To() == nil {
  7. signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
  8. from, err := types.Sender(signer, tx)
  9. if err != nil {
  10. return common.Hash{}, err
  11. }
  12. addr := crypto.CreateAddress(from, tx.Nonce())
  13. log.Info("Submitted contract creation", "fullhash", tx.Hash().Hex(), "contract", addr.Hex())
  14. } else {
  15. log.Info("Submitted transaction", "fullhash", tx.Hash().Hex(), "recipient", tx.To())
  16. }
  17. return tx.Hash(), nil
  18. }

submitTransaction方法会将交易发送给backend进行处理,返回经过签名后的交易的hash值。这里主要是SendTx方法对交易进行处理。
sendTx方法会将参数转给txpool的Addlocal方法进行处理,而AddLocal方法会将该笔交易放入到交易池中进行等待。这里我们看将交易放入到交易池中的方法。

  1. // addTx enqueues a single transaction into the pool if it is valid.
  2. func (pool *TxPool) addTx(tx *types.Transaction, local bool) error {
  3. pool.mu.Lock()
  4. defer pool.mu.Unlock()
  5. // Try to inject the transaction and update any state
  6. replace, err := pool.add(tx, local)
  7. if err != nil {
  8. return err
  9. }
  10. // If we added a new transaction, run promotion checks and return
  11. if !replace {
  12. from, _ := types.Sender(pool.signer, tx) // already validated
  13. pool.promoteExecutables([]common.Address{from})
  14. }
  15. return nil
  16. }

这里一共有两部操作,第一步操作是调用add方法将交易放入到交易池中,第二步是判断replace参数。如果该笔交易合法并且交易原来不存在在交易池中,则执行promoteExecutables方法,将可处理的交易变为待处理(pending)。
首先看第一步add方法。

  1. // add validates a transaction and inserts it into the non-executable queue for
  2. // later pending promotion and execution. If the transaction is a replacement for
  3. // an already pending or queued one, it overwrites the previous and returns this
  4. // so outer code doesn't uselessly call promote.
  5. //
  6. // If a newly added transaction is marked as local, its sending account will be
  7. // whitelisted, preventing any associated transaction from being dropped out of
  8. // the pool due to pricing constraints.
  9. func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
  10. // If the transaction is already known, discard it
  11. hash := tx.Hash()
  12. if pool.all[hash] != nil {
  13. log.Trace("Discarding already known transaction", "hash", hash)
  14. return false, fmt.Errorf("known transaction: %x", hash)
  15. }
  16. // If the transaction fails basic validation, discard it
  17. if err := pool.validateTx(tx, local); err != nil {
  18. log.Trace("Discarding invalid transaction", "hash", hash, "err", err)
  19. invalidTxCounter.Inc(1)
  20. return false, err
  21. }
  22. // If the transaction pool is full, discard underpriced transactions
  23. if uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue {
  24. // If the new transaction is underpriced, don't accept it
  25. if pool.priced.Underpriced(tx, pool.locals) {
  26. log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice())
  27. underpricedTxCounter.Inc(1)
  28. return false, ErrUnderpriced
  29. }
  30. // New transaction is better than our worse ones, make room for it
  31. drop := pool.priced.Discard(len(pool.all)-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals)
  32. for _, tx := range drop {
  33. log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice())
  34. underpricedTxCounter.Inc(1)
  35. pool.removeTx(tx.Hash())
  36. }
  37. }
  38. // If the transaction is replacing an already pending one, do directly
  39. from, _ := types.Sender(pool.signer, tx) // already validated
  40. if list := pool.pending[from]; list != nil && list.Overlaps(tx) {
  41. // Nonce already pending, check if required price bump is met
  42. inserted, old := list.Add(tx, pool.config.PriceBump)
  43. if !inserted {
  44. pendingDiscardCounter.Inc(1)
  45. return false, ErrReplaceUnderpriced
  46. }
  47. // New transaction is better, replace old one
  48. if old != nil {
  49. delete(pool.all, old.Hash())
  50. pool.priced.Removed()
  51. pendingReplaceCounter.Inc(1)
  52. }
  53. pool.all[tx.Hash()] = tx
  54. pool.priced.Put(tx)
  55. pool.journalTx(from, tx)
  56. log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To())
  57. // We've directly injected a replacement transaction, notify subsystems
  58. go pool.txFeed.Send(TxPreEvent{tx})
  59. return old != nil, nil
  60. }
  61. // New transaction isn't replacing a pending one, push into queue
  62. replace, err := pool.enqueueTx(hash, tx)
  63. if err != nil {
  64. return false, err
  65. }
  66. // Mark local addresses and journal local transactions
  67. if local {
  68. pool.locals.add(from)
  69. }
  70. pool.journalTx(from, tx)
  71. log.Trace("Pooled new future transaction", "hash", hash, "from", from, "to", tx.To())
  72. return replace, nil
  73. }

这个方法主要执行以下操作:
1.检查交易池是否含有这笔交易,如果有这笔交易,则异常退出。
2.调用validateTx方法对交易的合法性进行验证。如果是非法的交易,则异常退出。
3.接下来判断交易池是否超过容量。
<1>如果超过容量,并且该笔交易的费用低于当前交易池中列表的最小值,则拒绝这一笔交易。
<2>如果超过容量,并且该笔交易的费用比当前交易池中列表最小值高,那么从交易池中移除交易费用最低的交易,为当前这一笔交易留出空间。
4.接着继续调用Overlaps方法检查该笔交易的Nonce值,确认该用户下的交易是否存在该笔交易。
<1>如果已经存在这笔交易,则删除之前的交易,并将该笔交易放入交易池中,然后返回。
<2>如果不存在,则调用enqueueTx将该笔交易放入交易池中。如果交易是本地发出的,则将发送者保存在交易池的local中。
接下来看看validateTx方法会怎样验证交易的合法性。

  1. // validateTx checks whether a transaction is valid according to the consensus
  2. // rules and adheres to some heuristic limits of the local node (price and size).
  3. func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
  4. // Heuristic limit, reject transactions over 32KB to prevent DOS attacks
  5. if tx.Size() > 32*1024 {
  6. return ErrOversizedData
  7. }
  8. // Transactions can't be negative. This may never happen using RLP decoded
  9. // transactions but may occur if you create a transaction using the RPC.
  10. if tx.Value().Sign() < 0 {
  11. return ErrNegativeValue
  12. }
  13. // Ensure the transaction doesn't exceed the current block limit gas.
  14. if pool.currentMaxGas < tx.Gas() {
  15. return ErrGasLimit
  16. }
  17. // Make sure the transaction is signed properly
  18. from, err := types.Sender(pool.signer, tx)
  19. if err != nil {
  20. return ErrInvalidSender
  21. }
  22. // Drop non-local transactions under our own minimal accepted gas price
  23. local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network
  24. if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 {
  25. return ErrUnderpriced
  26. }
  27. // Ensure the transaction adheres to nonce ordering
  28. if pool.currentState.GetNonce(from) > tx.Nonce() {
  29. return ErrNonceTooLow
  30. }
  31. // Transactor should have enough funds to cover the costs
  32. // cost == V + GP * GL
  33. if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 {
  34. return ErrInsufficientFunds
  35. }
  36. intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)
  37. if err != nil {
  38. return err
  39. }
  40. if tx.Gas() < intrGas {
  41. return ErrIntrinsicGas
  42. }
  43. return nil
  44. }

validateTx会验证一笔交易的以下几个特性:
1.首先验证这笔交易的大小,如果大于32kb则拒绝这笔交易,这样主要是为了防止DDOS攻击。
2.接着验证转账金额。如果金额小于0则拒绝这笔交易。
3.这笔交易的gas不能超过交易池的gas上限。
4.验证这笔交易的签名是否合法。
5.如果这笔交易不是来自本地并且这笔交易的gas小于当前交易池中的gas,则拒绝这笔交易。
6.当前用户的nonce如果大于这笔交易的nonce,则拒绝这笔交易。
7.当前用户的余额是否充足,如果不充足则拒绝该笔交易。
8.验证这笔交易的固有花费,如果小于交易池的gas,则拒绝该笔交易。
以上就是在进行交易验证时所需验证的参数。这一系列的验证操作结束后,回到addTx的第二步。
会判断replace。如果replace是false,则会执行promoteExecutables方法。
promoteExecutables会将所有可处理的交易放入pending区,并移除所有非法的交易。

  1. // promoteExecutables moves transactions that have become processable from the
  2. // future queue to the set of pending transactions. During this process, all
  3. // invalidated transactions (low nonce, low balance) are deleted.
  4. func (pool *TxPool) promoteExecutables(accounts []common.Address) {
  5. // Gather all the accounts potentially needing updates
  6. if accounts == nil {
  7. accounts = make([]common.Address, 0, len(pool.queue))
  8. for addr := range pool.queue {
  9. accounts = append(accounts, addr)
  10. }
  11. }
  12. // Iterate over all accounts and promote any executable transactions
  13. for _, addr := range accounts {
  14. list := pool.queue[addr]
  15. if list == nil {
  16. continue // Just in case someone calls with a non existing account
  17. }
  18. // Drop all transactions that are deemed too old (low nonce)
  19. for _, tx := range list.Forward(pool.currentState.GetNonce(addr)) {
  20. hash := tx.Hash()
  21. log.Trace("Removed old queued transaction", "hash", hash)
  22. delete(pool.all, hash)
  23. pool.priced.Removed()
  24. }
  25. // Drop all transactions that are too costly (low balance or out of gas)
  26. drops, _ := list.Filter(pool.currentState.GetBalance(addr), pool.currentMaxGas)
  27. for _, tx := range drops {
  28. hash := tx.Hash()
  29. log.Trace("Removed unpayable queued transaction", "hash", hash)
  30. delete(pool.all, hash)
  31. pool.priced.Removed()
  32. queuedNofundsCounter.Inc(1)
  33. }
  34. // Gather all executable transactions and promote them
  35. for _, tx := range list.Ready(pool.pendingState.GetNonce(addr)) {
  36. hash := tx.Hash()
  37. log.Trace("Promoting queued transaction", "hash", hash)
  38. pool.promoteTx(addr, hash, tx)
  39. }
  40. // Drop all transactions over the allowed limit
  41. if !pool.locals.contains(addr) {
  42. for _, tx := range list.Cap(int(pool.config.AccountQueue)) {
  43. hash := tx.Hash()
  44. delete(pool.all, hash)
  45. pool.priced.Removed()
  46. queuedRateLimitCounter.Inc(1)
  47. log.Trace("Removed cap-exceeding queued transaction", "hash", hash)
  48. }
  49. }
  50. // Delete the entire queue entry if it became empty.
  51. if list.Empty() {
  52. delete(pool.queue, addr)
  53. }
  54. }
  55. // If the pending limit is overflown, start equalizing allowances
  56. pending := uint64(0)
  57. for _, list := range pool.pending {
  58. pending += uint64(list.Len())
  59. }
  60. if pending > pool.config.GlobalSlots {
  61. pendingBeforeCap := pending
  62. // Assemble a spam order to penalize large transactors first
  63. spammers := prque.New()
  64. for addr, list := range pool.pending {
  65. // Only evict transactions from high rollers
  66. if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots {
  67. spammers.Push(addr, float32(list.Len()))
  68. }
  69. }
  70. // Gradually drop transactions from offenders
  71. offenders := []common.Address{}
  72. for pending > pool.config.GlobalSlots && !spammers.Empty() {
  73. // Retrieve the next offender if not local address
  74. offender, _ := spammers.Pop()
  75. offenders = append(offenders, offender.(common.Address))
  76. // Equalize balances until all the same or below threshold
  77. if len(offenders) > 1 {
  78. // Calculate the equalization threshold for all current offenders
  79. threshold := pool.pending[offender.(common.Address)].Len()
  80. // Iteratively reduce all offenders until below limit or threshold reached
  81. for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold {
  82. for i := 0; i < len(offenders)-1; i++ {
  83. list := pool.pending[offenders[i]]
  84. for _, tx := range list.Cap(list.Len() - 1) {
  85. // Drop the transaction from the global pools too
  86. hash := tx.Hash()
  87. delete(pool.all, hash)
  88. pool.priced.Removed()
  89. // Update the account nonce to the dropped transaction
  90. if nonce := tx.Nonce(); pool.pendingState.GetNonce(offenders[i]) > nonce {
  91. pool.pendingState.SetNonce(offenders[i], nonce)
  92. }
  93. log.Trace("Removed fairness-exceeding pending transaction", "hash", hash)
  94. }
  95. pending--
  96. }
  97. }
  98. }
  99. }
  100. // If still above threshold, reduce to limit or min allowance
  101. if pending > pool.config.GlobalSlots && len(offenders) > 0 {
  102. for pending > pool.config.GlobalSlots && uint64(pool.pending[offenders[len(offenders)-1]].Len()) > pool.config.AccountSlots {
  103. for _, addr := range offenders {
  104. list := pool.pending[addr]
  105. for _, tx := range list.Cap(list.Len() - 1) {
  106. // Drop the transaction from the global pools too
  107. hash := tx.Hash()
  108. delete(pool.all, hash)
  109. pool.priced.Removed()
  110. // Update the account nonce to the dropped transaction
  111. if nonce := tx.Nonce(); pool.pendingState.GetNonce(addr) > nonce {
  112. pool.pendingState.SetNonce(addr, nonce)
  113. }
  114. log.Trace("Removed fairness-exceeding pending transaction", "hash", hash)
  115. }
  116. pending--
  117. }
  118. }
  119. }
  120. pendingRateLimitCounter.Inc(int64(pendingBeforeCap - pending))
  121. }
  122. // If we've queued more transactions than the hard limit, drop oldest ones
  123. queued := uint64(0)
  124. for _, list := range pool.queue {
  125. queued += uint64(list.Len())
  126. }
  127. if queued > pool.config.GlobalQueue {
  128. // Sort all accounts with queued transactions by heartbeat
  129. addresses := make(addresssByHeartbeat, 0, len(pool.queue))
  130. for addr := range pool.queue {
  131. if !pool.locals.contains(addr) { // don't drop locals
  132. addresses = append(addresses, addressByHeartbeat{addr, pool.beats[addr]})
  133. }
  134. }
  135. sort.Sort(addresses)
  136. // Drop transactions until the total is below the limit or only locals remain
  137. for drop := queued - pool.config.GlobalQueue; drop > 0 && len(addresses) > 0; {
  138. addr := addresses[len(addresses)-1]
  139. list := pool.queue[addr.address]
  140. addresses = addresses[:len(addresses)-1]
  141. // Drop all transactions if they are less than the overflow
  142. if size := uint64(list.Len()); size <= drop {
  143. for _, tx := range list.Flatten() {
  144. pool.removeTx(tx.Hash())
  145. }
  146. drop -= size
  147. queuedRateLimitCounter.Inc(int64(size))
  148. continue
  149. }
  150. // Otherwise drop only last few transactions
  151. txs := list.Flatten()
  152. for i := len(txs) - 1; i >= 0 && drop > 0; i-- {
  153. pool.removeTx(txs[i].Hash())
  154. drop--
  155. queuedRateLimitCounter.Inc(1)
  156. }
  157. }
  158. }
  159. }

这个方法首先会迭代所有当前账户的交易,检查当前交易的nonce。如果nonce太低,则删除该笔交易。(list.Forward方法)
接下来检查余额不足或者gas不足的交易并删除。(list.Filter方法)
然后将剩余的交易状态更新为pending并放在pending集合中。然后将当前消息池该用户的nonce值+1,接着广播TxPreEvent事件,告诉他们本地有一笔新的合法交易等待处理。(pool.promoteTx方法)
接着检查消息池的pending列表是否超过容量,如果超过将进行扩容操作。如果一个账户进行的状态超过限制,从交易池中删除最先添加的交易。
在promoteExecutable中有一个promoteTx方法,这个方法是将交易防区pending区方法中。在promoteTx方法中,最后一步执行的是一个Send方法。
这个Send方法会同步将pending区的交易广播至它所连接到的节点,并返回通知到的节点的数量。
然后被通知到的节点继续通知到它添加的节点,继而广播至全网。
至此,发送交易就结束了。此时交易池中的交易等待挖矿打包处理。