github.com/dominant-strategies/go-quai@v0.28.2/consensus/blake3pow/blake3pow.go (about) 1 package blake3pow 2 3 import ( 4 "math/big" 5 "math/rand" 6 "sync" 7 "time" 8 9 "github.com/dominant-strategies/go-quai/common" 10 "github.com/dominant-strategies/go-quai/common/hexutil" 11 "github.com/dominant-strategies/go-quai/consensus" 12 "github.com/dominant-strategies/go-quai/log" 13 "github.com/dominant-strategies/go-quai/metrics" 14 "github.com/dominant-strategies/go-quai/rpc" 15 ) 16 17 var ( 18 // sharedBlake3pow is a full instance that can be shared between multiple users. 19 sharedBlake3pow *Blake3pow 20 ) 21 22 func init() { 23 sharedConfig := Config{ 24 PowMode: ModeNormal, 25 } 26 sharedBlake3pow = New(sharedConfig, nil, false) 27 } 28 29 // Mode defines the type and amount of PoW verification a blake3pow engine makes. 30 type Mode uint 31 32 const ( 33 ModeNormal Mode = iota 34 ModeShared 35 ModeTest 36 ModeFake 37 ModeFullFake 38 ) 39 40 // Config are the configuration parameters of the blake3pow. 41 type Config struct { 42 PowMode Mode 43 44 DurationLimit *big.Int 45 46 GasCeil uint64 47 48 MinDifficulty *big.Int 49 50 // When set, notifications sent by the remote sealer will 51 // be block header JSON objects instead of work package arrays. 52 NotifyFull bool 53 54 Log *log.Logger `toml:"-"` 55 } 56 57 // Blake3pow is a proof-of-work consensus engine using the blake3 hash algorithm 58 type Blake3pow struct { 59 config Config 60 61 // Mining related fields 62 rand *rand.Rand // Properly seeded random source for nonces 63 threads int // Number of threads to mine on if mining 64 update chan struct{} // Notification channel to update mining parameters 65 hashrate metrics.Meter // Meter tracking the average hashrate 66 remote *remoteSealer 67 68 // The fields below are hooks for testing 69 shared *Blake3pow // Shared PoW verifier to avoid cache regeneration 70 fakeFail uint64 // Block number which fails PoW check even in fake mode 71 fakeDelay time.Duration // Time delay to sleep for before returning from verify 72 73 lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields 74 closeOnce sync.Once // Ensures exit channel will not be closed twice. 75 } 76 77 // New creates a full sized blake3pow PoW scheme and starts a background thread for 78 // remote mining, also optionally notifying a batch of remote services of new work 79 // packages. 80 func New(config Config, notify []string, noverify bool) *Blake3pow { 81 if config.Log == nil { 82 config.Log = &log.Log 83 } 84 blake3pow := &Blake3pow{ 85 config: config, 86 update: make(chan struct{}), 87 hashrate: metrics.NewMeterForced(), 88 } 89 if config.PowMode == ModeShared { 90 blake3pow.shared = sharedBlake3pow 91 } 92 blake3pow.remote = startRemoteSealer(blake3pow, notify, noverify) 93 return blake3pow 94 } 95 96 // NewTester creates a small sized blake3pow PoW scheme useful only for testing 97 // purposes. 98 func NewTester(notify []string, noverify bool) *Blake3pow { 99 return New(Config{PowMode: ModeTest}, notify, noverify) 100 } 101 102 // NewFaker creates a blake3pow consensus engine with a fake PoW scheme that accepts 103 // all blocks' seal as valid, though they still have to conform to the Quai 104 // consensus rules. 105 func NewFaker() *Blake3pow { 106 return &Blake3pow{ 107 config: Config{ 108 PowMode: ModeFake, 109 Log: &log.Log, 110 }, 111 } 112 } 113 114 // NewFakeFailer creates a blake3pow consensus engine with a fake PoW scheme that 115 // accepts all blocks as valid apart from the single one specified, though they 116 // still have to conform to the Quai consensus rules. 117 func NewFakeFailer(fail uint64) *Blake3pow { 118 return &Blake3pow{ 119 config: Config{ 120 PowMode: ModeFake, 121 Log: &log.Log, 122 }, 123 fakeFail: fail, 124 } 125 } 126 127 // NewFakeDelayer creates a blake3pow consensus engine with a fake PoW scheme that 128 // accepts all blocks as valid, but delays verifications by some time, though 129 // they still have to conform to the Quai consensus rules. 130 func NewFakeDelayer(delay time.Duration) *Blake3pow { 131 return &Blake3pow{ 132 config: Config{ 133 PowMode: ModeFake, 134 Log: &log.Log, 135 }, 136 fakeDelay: delay, 137 } 138 } 139 140 // NewFullFaker creates an blake3pow consensus engine with a full fake scheme that 141 // accepts all blocks as valid, without checking any consensus rules whatsoever. 142 func NewFullFaker() *Blake3pow { 143 return &Blake3pow{ 144 config: Config{ 145 PowMode: ModeFullFake, 146 Log: &log.Log, 147 }, 148 } 149 } 150 151 // NewShared creates a full sized blake3pow PoW shared between all requesters running 152 // in the same process. 153 func NewShared() *Blake3pow { 154 return &Blake3pow{shared: sharedBlake3pow} 155 } 156 157 // Close closes the exit channel to notify all backend threads exiting. 158 func (blake3pow *Blake3pow) Close() error { 159 blake3pow.closeOnce.Do(func() { 160 // Short circuit if the exit channel is not allocated. 161 if blake3pow.remote == nil { 162 return 163 } 164 close(blake3pow.remote.requestExit) 165 <-blake3pow.remote.exitCh 166 }) 167 return nil 168 } 169 170 // Threads returns the number of mining threads currently enabled. This doesn't 171 // necessarily mean that mining is running! 172 func (blake3pow *Blake3pow) Threads() int { 173 blake3pow.lock.Lock() 174 defer blake3pow.lock.Unlock() 175 176 return blake3pow.threads 177 } 178 179 // SetThreads updates the number of mining threads currently enabled. Calling 180 // this method does not start mining, only sets the thread count. If zero is 181 // specified, the miner will use all cores of the machine. Setting a thread 182 // count below zero is allowed and will cause the miner to idle, without any 183 // work being done. 184 func (blake3pow *Blake3pow) SetThreads(threads int) { 185 blake3pow.lock.Lock() 186 defer blake3pow.lock.Unlock() 187 188 if blake3pow.shared != nil { 189 // If we're running a shared PoW, set the thread count on that instead 190 blake3pow.shared.SetThreads(threads) 191 } else { 192 // Update the threads and ping any running seal to pull in any changes 193 blake3pow.threads = threads 194 select { 195 case blake3pow.update <- struct{}{}: 196 default: 197 } 198 } 199 } 200 201 // Hashrate implements PoW, returning the measured rate of the search invocations 202 // per second over the last minute. 203 // Note the returned hashrate includes local hashrate, but also includes the total 204 // hashrate of all remote miner. 205 func (blake3pow *Blake3pow) Hashrate() float64 { 206 // Short circuit if we are run the blake3pow in normal/test mode. 207 if blake3pow.config.PowMode != ModeNormal && blake3pow.config.PowMode != ModeTest { 208 return blake3pow.hashrate.Rate1() 209 } 210 var res = make(chan uint64, 1) 211 212 select { 213 case blake3pow.remote.fetchRateCh <- res: 214 case <-blake3pow.remote.exitCh: 215 // Return local hashrate only if blake3pow is stopped. 216 return blake3pow.hashrate.Rate1() 217 } 218 219 // Gather total submitted hash rate of remote sealers. 220 return blake3pow.hashrate.Rate1() + float64(<-res) 221 } 222 223 // SubmitHashrate can be used for remote miners to submit their hash rate. 224 // This enables the node to report the combined hash rate of all miners 225 // which submit work through this node. 226 // 227 // It accepts the miner hash rate and an identifier which must be unique 228 // between nodes. 229 func (blake3pow *Blake3pow) SubmitHashrate(rate hexutil.Uint64, id common.Hash) bool { 230 if blake3pow.remote == nil { 231 return false 232 } 233 234 var done = make(chan struct{}, 1) 235 select { 236 case blake3pow.remote.submitRateCh <- &hashrate{done: done, rate: uint64(rate), id: id}: 237 case <-blake3pow.remote.exitCh: 238 return false 239 } 240 241 // Block until hash rate submitted successfully. 242 <-done 243 return true 244 } 245 246 // APIs implements consensus.Engine, returning the user facing RPC APIs. 247 func (blake3pow *Blake3pow) APIs(chain consensus.ChainHeaderReader) []rpc.API { 248 // In order to ensure backward compatibility, we exposes blake3pow RPC APIs 249 // to both eth and blake3pow namespaces. 250 return []rpc.API{ 251 { 252 Namespace: "eth", 253 Version: "1.0", 254 Service: &API{blake3pow}, 255 Public: true, 256 }, 257 { 258 Namespace: "blake3pow", 259 Version: "1.0", 260 Service: &API{blake3pow}, 261 Public: true, 262 }, 263 } 264 }