github.com/theQRL/go-zond@v0.1.1/zond/catalyst/queue.go (about)

     1  // Copyright 2022 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 catalyst
    18  
    19  import (
    20  	"sync"
    21  
    22  	"github.com/theQRL/go-zond/beacon/engine"
    23  	"github.com/theQRL/go-zond/common"
    24  	"github.com/theQRL/go-zond/core/types"
    25  	"github.com/theQRL/go-zond/miner"
    26  )
    27  
    28  // maxTrackedPayloads is the maximum number of prepared payloads the execution
    29  // engine tracks before evicting old ones. Ideally we should only ever track the
    30  // latest one; but have a slight wiggle room for non-ideal conditions.
    31  const maxTrackedPayloads = 10
    32  
    33  // maxTrackedHeaders is the maximum number of executed payloads the execution
    34  // engine tracks before evicting old ones. These are tracked outside the chain
    35  // during initial sync to allow ForkchoiceUpdate to reference past blocks via
    36  // hashes only. For the sync target it would be enough to track only the latest
    37  // header, but snap sync also needs the latest finalized height for the ancient
    38  // limit.
    39  const maxTrackedHeaders = 96
    40  
    41  // payloadQueueItem represents an id->payload tuple to store until it's retrieved
    42  // or evicted.
    43  type payloadQueueItem struct {
    44  	id      engine.PayloadID
    45  	payload *miner.Payload
    46  }
    47  
    48  // payloadQueue tracks the latest handful of constructed payloads to be retrieved
    49  // by the beacon chain if block production is requested.
    50  type payloadQueue struct {
    51  	payloads []*payloadQueueItem
    52  	lock     sync.RWMutex
    53  }
    54  
    55  // newPayloadQueue creates a pre-initialized queue with a fixed number of slots
    56  // all containing empty items.
    57  func newPayloadQueue() *payloadQueue {
    58  	return &payloadQueue{
    59  		payloads: make([]*payloadQueueItem, maxTrackedPayloads),
    60  	}
    61  }
    62  
    63  // put inserts a new payload into the queue at the given id.
    64  func (q *payloadQueue) put(id engine.PayloadID, payload *miner.Payload) {
    65  	q.lock.Lock()
    66  	defer q.lock.Unlock()
    67  
    68  	copy(q.payloads[1:], q.payloads)
    69  	q.payloads[0] = &payloadQueueItem{
    70  		id:      id,
    71  		payload: payload,
    72  	}
    73  }
    74  
    75  // get retrieves a previously stored payload item or nil if it does not exist.
    76  func (q *payloadQueue) get(id engine.PayloadID, full bool) *engine.ExecutionPayloadEnvelope {
    77  	q.lock.RLock()
    78  	defer q.lock.RUnlock()
    79  
    80  	for _, item := range q.payloads {
    81  		if item == nil {
    82  			return nil // no more items
    83  		}
    84  		if item.id == id {
    85  			if !full {
    86  				return item.payload.Resolve()
    87  			}
    88  			return item.payload.ResolveFull()
    89  		}
    90  	}
    91  	return nil
    92  }
    93  
    94  // has checks if a particular payload is already tracked.
    95  func (q *payloadQueue) has(id engine.PayloadID) bool {
    96  	q.lock.RLock()
    97  	defer q.lock.RUnlock()
    98  
    99  	for _, item := range q.payloads {
   100  		if item == nil {
   101  			return false
   102  		}
   103  		if item.id == id {
   104  			return true
   105  		}
   106  	}
   107  	return false
   108  }
   109  
   110  // headerQueueItem represents an hash->header tuple to store until it's retrieved
   111  // or evicted.
   112  type headerQueueItem struct {
   113  	hash   common.Hash
   114  	header *types.Header
   115  }
   116  
   117  // headerQueue tracks the latest handful of constructed headers to be retrieved
   118  // by the beacon chain if block production is requested.
   119  type headerQueue struct {
   120  	headers []*headerQueueItem
   121  	lock    sync.RWMutex
   122  }
   123  
   124  // newHeaderQueue creates a pre-initialized queue with a fixed number of slots
   125  // all containing empty items.
   126  func newHeaderQueue() *headerQueue {
   127  	return &headerQueue{
   128  		headers: make([]*headerQueueItem, maxTrackedHeaders),
   129  	}
   130  }
   131  
   132  // put inserts a new header into the queue at the given hash.
   133  func (q *headerQueue) put(hash common.Hash, data *types.Header) {
   134  	q.lock.Lock()
   135  	defer q.lock.Unlock()
   136  
   137  	copy(q.headers[1:], q.headers)
   138  	q.headers[0] = &headerQueueItem{
   139  		hash:   hash,
   140  		header: data,
   141  	}
   142  }
   143  
   144  // get retrieves a previously stored header item or nil if it does not exist.
   145  func (q *headerQueue) get(hash common.Hash) *types.Header {
   146  	q.lock.RLock()
   147  	defer q.lock.RUnlock()
   148  
   149  	for _, item := range q.headers {
   150  		if item == nil {
   151  			return nil // no more items
   152  		}
   153  		if item.hash == hash {
   154  			return item.header
   155  		}
   156  	}
   157  	return nil
   158  }