github.com/calmw/ethereum@v0.1.1/eth/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/calmw/ethereum/beacon/engine" 23 "github.com/calmw/ethereum/common" 24 "github.com/calmw/ethereum/core/types" 25 "github.com/calmw/ethereum/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) *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 return item.payload.Resolve() 86 } 87 } 88 return nil 89 } 90 91 // has checks if a particular payload is already tracked. 92 func (q *payloadQueue) has(id engine.PayloadID) bool { 93 q.lock.RLock() 94 defer q.lock.RUnlock() 95 96 for _, item := range q.payloads { 97 if item == nil { 98 return false 99 } 100 if item.id == id { 101 return true 102 } 103 } 104 return false 105 } 106 107 // headerQueueItem represents an hash->header tuple to store until it's retrieved 108 // or evicted. 109 type headerQueueItem struct { 110 hash common.Hash 111 header *types.Header 112 } 113 114 // headerQueue tracks the latest handful of constructed headers to be retrieved 115 // by the beacon chain if block production is requested. 116 type headerQueue struct { 117 headers []*headerQueueItem 118 lock sync.RWMutex 119 } 120 121 // newHeaderQueue creates a pre-initialized queue with a fixed number of slots 122 // all containing empty items. 123 func newHeaderQueue() *headerQueue { 124 return &headerQueue{ 125 headers: make([]*headerQueueItem, maxTrackedHeaders), 126 } 127 } 128 129 // put inserts a new header into the queue at the given hash. 130 func (q *headerQueue) put(hash common.Hash, data *types.Header) { 131 q.lock.Lock() 132 defer q.lock.Unlock() 133 134 copy(q.headers[1:], q.headers) 135 q.headers[0] = &headerQueueItem{ 136 hash: hash, 137 header: data, 138 } 139 } 140 141 // get retrieves a previously stored header item or nil if it does not exist. 142 func (q *headerQueue) get(hash common.Hash) *types.Header { 143 q.lock.RLock() 144 defer q.lock.RUnlock() 145 146 for _, item := range q.headers { 147 if item == nil { 148 return nil // no more items 149 } 150 if item.hash == hash { 151 return item.header 152 } 153 } 154 return nil 155 }