gitlab.com/flarenetwork/coreth@v0.1.1/core/tx_cacher.go (about)

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