github.com/ethereum/go-ethereum@v1.16.1/core/sender_cacher.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"runtime"
    21  	"sync"
    22  
    23  	"github.com/ethereum/go-ethereum/core/types"
    24  )
    25  
    26  // senderCacherOnce is used to ensure that the SenderCacher is initialized only once.
    27  var senderCacherOnce = sync.OnceValue(func() *txSenderCacher {
    28  	return newTxSenderCacher(runtime.NumCPU())
    29  })
    30  
    31  // SenderCacher returns the singleton instance of SenderCacher, initializing it if called for the first time.
    32  // This function is thread-safe and ensures that initialization happens only once.
    33  func SenderCacher() *txSenderCacher {
    34  	return senderCacherOnce()
    35  }
    36  
    37  // txSenderCacherRequest is a request for recovering transaction senders with a
    38  // specific signature scheme and caching it into the transactions themselves.
    39  //
    40  // The inc field defines the number of transactions to skip after each recovery,
    41  // which is used to feed the same underlying input array to different threads but
    42  // ensure they process the early transactions fast.
    43  type txSenderCacherRequest struct {
    44  	signer types.Signer
    45  	txs    []*types.Transaction
    46  	inc    int
    47  }
    48  
    49  // txSenderCacher is a helper structure to concurrently ecrecover transaction
    50  // senders from digital signatures on background threads.
    51  type txSenderCacher struct {
    52  	threads int
    53  	tasks   chan *txSenderCacherRequest
    54  }
    55  
    56  // newTxSenderCacher creates a new transaction sender background cacher and starts
    57  // as many processing goroutines as allowed by the GOMAXPROCS on construction.
    58  func newTxSenderCacher(threads int) *txSenderCacher {
    59  	cacher := &txSenderCacher{
    60  		tasks:   make(chan *txSenderCacherRequest, threads),
    61  		threads: threads,
    62  	}
    63  	for i := 0; i < threads; i++ {
    64  		go cacher.cache()
    65  	}
    66  	return cacher
    67  }
    68  
    69  // cache is an infinite loop, caching transaction senders from various forms of
    70  // data structures.
    71  func (cacher *txSenderCacher) cache() {
    72  	for task := range cacher.tasks {
    73  		for i := 0; i < len(task.txs); i += task.inc {
    74  			types.Sender(task.signer, task.txs[i])
    75  		}
    76  	}
    77  }
    78  
    79  // Recover recovers the senders from a batch of transactions and caches them
    80  // back into the same data structures. There is no validation being done, nor
    81  // any reaction to invalid signatures. That is up to calling code later.
    82  func (cacher *txSenderCacher) Recover(signer types.Signer, txs []*types.Transaction) {
    83  	// If there's nothing to recover, abort
    84  	if len(txs) == 0 {
    85  		return
    86  	}
    87  	// Ensure we have meaningful task sizes and schedule the recoveries
    88  	tasks := cacher.threads
    89  	if len(txs) < tasks*4 {
    90  		tasks = (len(txs) + 3) / 4
    91  	}
    92  	for i := 0; i < tasks; i++ {
    93  		cacher.tasks <- &txSenderCacherRequest{
    94  			signer: signer,
    95  			txs:    txs[i:],
    96  			inc:    tasks,
    97  		}
    98  	}
    99  }
   100  
   101  // RecoverFromBlocks recovers the senders from a batch of blocks and caches them
   102  // back into the same data structures. There is no validation being done, nor
   103  // any reaction to invalid signatures. That is up to calling code later.
   104  func (cacher *txSenderCacher) RecoverFromBlocks(signer types.Signer, blocks []*types.Block) {
   105  	count := 0
   106  	for _, block := range blocks {
   107  		count += len(block.Transactions())
   108  	}
   109  	txs := make([]*types.Transaction, 0, count)
   110  	for _, block := range blocks {
   111  		txs = append(txs, block.Transactions()...)
   112  	}
   113  	cacher.Recover(signer, txs)
   114  }