github.com/core-coin/go-core/v2@v2.1.9/core/tx_cacher.go (about)

     1  // Copyright 2018 by the Authors
     2  // This file is part of the go-core library.
     3  //
     4  // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"runtime"
    21  
    22  	"github.com/core-coin/go-core/v2/core/types"
    23  )
    24  
    25  // senderCacher is a concurrent transaction sender recoverer and cacher.
    26  var senderCacher = newTxSenderCacher(runtime.NumCPU())
    27  
    28  // txSenderCacherRequest is a request for recovering transaction senders with a
    29  // specific signature scheme and caching it into the transactions themselves.
    30  //
    31  // The inc field defines the number of transactions to skip after each recovery,
    32  // which is used to feed the same underlying input array to different threads but
    33  // ensure they process the early transactions fast.
    34  type txSenderCacherRequest struct {
    35  	signer types.Signer
    36  	txs    []*types.Transaction
    37  	inc    int
    38  }
    39  
    40  // txSenderCacher is a helper structure to concurrently ecrecover transaction
    41  // senders from digital signatures on background threads.
    42  type txSenderCacher struct {
    43  	threads int
    44  	tasks   chan *txSenderCacherRequest
    45  }
    46  
    47  // newTxSenderCacher creates a new transaction sender background cacher and starts
    48  // as many processing goroutines as allowed by the GOMAXPROCS on construction.
    49  func newTxSenderCacher(threads int) *txSenderCacher {
    50  	cacher := &txSenderCacher{
    51  		tasks:   make(chan *txSenderCacherRequest, threads),
    52  		threads: threads,
    53  	}
    54  	for i := 0; i < threads; i++ {
    55  		go cacher.cache()
    56  	}
    57  	return cacher
    58  }
    59  
    60  // cache is an infinite loop, caching transaction senders from various forms of
    61  // data structures.
    62  func (cacher *txSenderCacher) cache() {
    63  	for task := range cacher.tasks {
    64  		for i := 0; i < len(task.txs); i += task.inc {
    65  			types.Sender(task.signer, task.txs[i])
    66  		}
    67  	}
    68  }
    69  
    70  // recover recovers the senders from a batch of transactions and caches them
    71  // back into the same data structures. There is no validation being done, nor
    72  // any reaction to invalid signatures. That is up to calling code later.
    73  func (cacher *txSenderCacher) recover(signer types.Signer, txs []*types.Transaction) {
    74  	// If there's nothing to recover, abort
    75  	if len(txs) == 0 {
    76  		return
    77  	}
    78  	// Ensure we have meaningful task sizes and schedule the recoveries
    79  	tasks := cacher.threads
    80  	if len(txs) < tasks*4 {
    81  		tasks = (len(txs) + 3) / 4
    82  	}
    83  	for i := 0; i < tasks; i++ {
    84  		cacher.tasks <- &txSenderCacherRequest{
    85  			signer: signer,
    86  			txs:    txs[i:],
    87  			inc:    tasks,
    88  		}
    89  	}
    90  }
    91  
    92  // recoverFromBlocks recovers the senders from a batch of blocks and caches them
    93  // back into the same data structures. There is no validation being done, nor
    94  // any reaction to invalid signatures. That is up to calling code later.
    95  func (cacher *txSenderCacher) recoverFromBlocks(signer types.Signer, blocks []*types.Block) {
    96  	count := 0
    97  	for _, block := range blocks {
    98  		count += len(block.Transactions())
    99  	}
   100  	txs := make([]*types.Transaction, 0, count)
   101  	for _, block := range blocks {
   102  		txs = append(txs, block.Transactions()...)
   103  	}
   104  	cacher.recover(signer, txs)
   105  }