github.com/theQRL/go-zond@v0.1.1/consensus/beacon/consensus.go (about) 1 // Copyright 2021 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 beacon 18 19 import ( 20 "errors" 21 "fmt" 22 "math/big" 23 24 "github.com/theQRL/go-zond/common" 25 "github.com/theQRL/go-zond/consensus" 26 "github.com/theQRL/go-zond/consensus/misc/eip1559" 27 "github.com/theQRL/go-zond/consensus/misc/eip4844" 28 "github.com/theQRL/go-zond/core/state" 29 "github.com/theQRL/go-zond/core/types" 30 "github.com/theQRL/go-zond/params" 31 "github.com/theQRL/go-zond/rpc" 32 "github.com/theQRL/go-zond/trie" 33 ) 34 35 // Proof-of-stake protocol constants. 36 var ( 37 beaconDifficulty = common.Big0 // The default block difficulty in the beacon consensus 38 beaconNonce = types.EncodeNonce(0) // The default block nonce in the beacon consensus 39 ) 40 41 // Various error messages to mark blocks invalid. These should be private to 42 // prevent engine specific errors from being referenced in the remainder of the 43 // codebase, inherently breaking if the engine is swapped out. Please put common 44 // error types into the consensus package. 45 var ( 46 errTooManyUncles = errors.New("too many uncles") 47 errInvalidNonce = errors.New("invalid nonce") 48 errInvalidUncleHash = errors.New("invalid uncle hash") 49 errInvalidTimestamp = errors.New("invalid timestamp") 50 ) 51 52 // Beacon is a consensus engine that combines the eth1 consensus and proof-of-stake 53 // algorithm. There is a special flag inside to decide whether to use legacy consensus 54 // rules or new rules. The transition rule is described in the eth1/2 merge spec. 55 // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3675.md 56 // 57 // The beacon here is a half-functional consensus engine with partial functions which 58 // is only used for necessary consensus checks. The legacy consensus engine can be any 59 // engine implements the consensus interface (except the beacon itself). 60 type Beacon struct { 61 ethone consensus.Engine // Original consensus engine used in eth1, e.g. ethash or clique 62 } 63 64 // New creates a consensus engine with the given embedded eth1 engine. 65 func New(ethone consensus.Engine) *Beacon { 66 if _, ok := ethone.(*Beacon); ok { 67 panic("nested consensus engine") 68 } 69 return &Beacon{ethone: ethone} 70 } 71 72 // Author implements consensus.Engine, returning the verified author of the block. 73 func (beacon *Beacon) Author(header *types.Header) (common.Address, error) { 74 if !beacon.IsPoSHeader(header) { 75 return beacon.ethone.Author(header) 76 } 77 return header.Coinbase, nil 78 } 79 80 // VerifyHeader checks whether a header conforms to the consensus rules of the 81 // stock Ethereum consensus engine. 82 func (beacon *Beacon) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header) error { 83 reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1) 84 if err != nil { 85 return err 86 } 87 if !reached { 88 return beacon.ethone.VerifyHeader(chain, header) 89 } 90 // Short circuit if the parent is not known 91 parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) 92 if parent == nil { 93 return consensus.ErrUnknownAncestor 94 } 95 // Sanity checks passed, do a proper verification 96 return beacon.verifyHeader(chain, header, parent) 97 } 98 99 // errOut constructs an error channel with prefilled errors inside. 100 func errOut(n int, err error) chan error { 101 errs := make(chan error, n) 102 for i := 0; i < n; i++ { 103 errs <- err 104 } 105 return errs 106 } 107 108 // splitHeaders splits the provided header batch into two parts according to 109 // the configured ttd. It requires the parent of header batch along with its 110 // td are stored correctly in chain. If ttd is not configured yet, all headers 111 // will be treated legacy PoW headers. 112 // Note, this function will not verify the header validity but just split them. 113 func (beacon *Beacon) splitHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) ([]*types.Header, []*types.Header, error) { 114 // TTD is not defined yet, all headers should be in legacy format. 115 ttd := chain.Config().TerminalTotalDifficulty 116 if ttd == nil { 117 return headers, nil, nil 118 } 119 ptd := chain.GetTd(headers[0].ParentHash, headers[0].Number.Uint64()-1) 120 if ptd == nil { 121 return nil, nil, consensus.ErrUnknownAncestor 122 } 123 // The entire header batch already crosses the transition. 124 if ptd.Cmp(ttd) >= 0 { 125 return nil, headers, nil 126 } 127 var ( 128 preHeaders = headers 129 postHeaders []*types.Header 130 td = new(big.Int).Set(ptd) 131 tdPassed bool 132 ) 133 for i, header := range headers { 134 if tdPassed { 135 preHeaders = headers[:i] 136 postHeaders = headers[i:] 137 break 138 } 139 td = td.Add(td, header.Difficulty) 140 if td.Cmp(ttd) >= 0 { 141 // This is the last PoW header, it still belongs to 142 // the preHeaders, so we cannot split+break yet. 143 tdPassed = true 144 } 145 } 146 return preHeaders, postHeaders, nil 147 } 148 149 // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers 150 // concurrently. The method returns a quit channel to abort the operations and 151 // a results channel to retrieve the async verifications. 152 // VerifyHeaders expect the headers to be ordered and continuous. 153 func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) (chan<- struct{}, <-chan error) { 154 preHeaders, postHeaders, err := beacon.splitHeaders(chain, headers) 155 if err != nil { 156 return make(chan struct{}), errOut(len(headers), err) 157 } 158 if len(postHeaders) == 0 { 159 return beacon.ethone.VerifyHeaders(chain, headers) 160 } 161 if len(preHeaders) == 0 { 162 return beacon.verifyHeaders(chain, headers, nil) 163 } 164 // The transition point exists in the middle, separate the headers 165 // into two batches and apply different verification rules for them. 166 var ( 167 abort = make(chan struct{}) 168 results = make(chan error, len(headers)) 169 ) 170 go func() { 171 var ( 172 old, new, out = 0, len(preHeaders), 0 173 errors = make([]error, len(headers)) 174 done = make([]bool, len(headers)) 175 oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders) 176 newDone, newResult = beacon.verifyHeaders(chain, postHeaders, preHeaders[len(preHeaders)-1]) 177 ) 178 // Collect the results 179 for { 180 for ; done[out]; out++ { 181 results <- errors[out] 182 if out == len(headers)-1 { 183 return 184 } 185 } 186 select { 187 case err := <-oldResult: 188 if !done[old] { // skip TTD-verified failures 189 errors[old], done[old] = err, true 190 } 191 old++ 192 case err := <-newResult: 193 errors[new], done[new] = err, true 194 new++ 195 case <-abort: 196 close(oldDone) 197 close(newDone) 198 return 199 } 200 } 201 }() 202 return abort, results 203 } 204 205 // VerifyUncles verifies that the given block's uncles conform to the consensus 206 // rules of the Ethereum consensus engine. 207 func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 208 if !beacon.IsPoSHeader(block.Header()) { 209 return beacon.ethone.VerifyUncles(chain, block) 210 } 211 // Verify that there is no uncle block. It's explicitly disabled in the beacon 212 if len(block.Uncles()) > 0 { 213 return errTooManyUncles 214 } 215 return nil 216 } 217 218 // verifyHeader checks whether a header conforms to the consensus rules of the 219 // stock Ethereum consensus engine. The difference between the beacon and classic is 220 // (a) The following fields are expected to be constants: 221 // - difficulty is expected to be 0 222 // - nonce is expected to be 0 223 // - unclehash is expected to be Hash(emptyHeader) 224 // to be the desired constants 225 // 226 // (b) we don't verify if a block is in the future anymore 227 // (c) the extradata is limited to 32 bytes 228 func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error { 229 // Ensure that the header's extra-data section is of a reasonable size 230 if len(header.Extra) > 32 { 231 return fmt.Errorf("extra-data longer than 32 bytes (%d)", len(header.Extra)) 232 } 233 // Verify the seal parts. Ensure the nonce and uncle hash are the expected value. 234 if header.Nonce != beaconNonce { 235 return errInvalidNonce 236 } 237 if header.UncleHash != types.EmptyUncleHash { 238 return errInvalidUncleHash 239 } 240 // Verify the timestamp 241 if header.Time <= parent.Time { 242 return errInvalidTimestamp 243 } 244 // Verify the block's difficulty to ensure it's the default constant 245 if beaconDifficulty.Cmp(header.Difficulty) != 0 { 246 return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, beaconDifficulty) 247 } 248 // Verify that the gas limit is <= 2^63-1 249 if header.GasLimit > params.MaxGasLimit { 250 return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit) 251 } 252 // Verify that the gasUsed is <= gasLimit 253 if header.GasUsed > header.GasLimit { 254 return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) 255 } 256 // Verify that the block number is parent's +1 257 if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(common.Big1) != 0 { 258 return consensus.ErrInvalidNumber 259 } 260 // Verify the header's EIP-1559 attributes. 261 if err := eip1559.VerifyEIP1559Header(chain.Config(), parent, header); err != nil { 262 return err 263 } 264 // Verify existence / non-existence of withdrawalsHash. 265 shanghai := chain.Config().IsShanghai(header.Number, header.Time) 266 if shanghai && header.WithdrawalsHash == nil { 267 return errors.New("missing withdrawalsHash") 268 } 269 if !shanghai && header.WithdrawalsHash != nil { 270 return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash) 271 } 272 // Verify the existence / non-existence of cancun-specific header fields 273 cancun := chain.Config().IsCancun(header.Number, header.Time) 274 if !cancun { 275 switch { 276 case header.ExcessBlobGas != nil: 277 return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas) 278 case header.BlobGasUsed != nil: 279 return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed) 280 case header.ParentBeaconRoot != nil: 281 return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot) 282 } 283 } else { 284 if header.ParentBeaconRoot == nil { 285 return errors.New("header is missing beaconRoot") 286 } 287 if err := eip4844.VerifyEIP4844Header(parent, header); err != nil { 288 return err 289 } 290 } 291 return nil 292 } 293 294 // verifyHeaders is similar to verifyHeader, but verifies a batch of headers 295 // concurrently. The method returns a quit channel to abort the operations and 296 // a results channel to retrieve the async verifications. An additional parent 297 // header will be passed if the relevant header is not in the database yet. 298 func (beacon *Beacon) verifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, ancestor *types.Header) (chan<- struct{}, <-chan error) { 299 var ( 300 abort = make(chan struct{}) 301 results = make(chan error, len(headers)) 302 ) 303 go func() { 304 for i, header := range headers { 305 var parent *types.Header 306 if i == 0 { 307 if ancestor != nil { 308 parent = ancestor 309 } else { 310 parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) 311 } 312 } else if headers[i-1].Hash() == headers[i].ParentHash { 313 parent = headers[i-1] 314 } 315 if parent == nil { 316 select { 317 case <-abort: 318 return 319 case results <- consensus.ErrUnknownAncestor: 320 } 321 continue 322 } 323 err := beacon.verifyHeader(chain, header, parent) 324 select { 325 case <-abort: 326 return 327 case results <- err: 328 } 329 } 330 }() 331 return abort, results 332 } 333 334 // Prepare implements consensus.Engine, initializing the difficulty field of a 335 // header to conform to the beacon protocol. The changes are done inline. 336 func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { 337 // Transition isn't triggered yet, use the legacy rules for preparation. 338 reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1) 339 if err != nil { 340 return err 341 } 342 if !reached { 343 return beacon.ethone.Prepare(chain, header) 344 } 345 header.Difficulty = beaconDifficulty 346 return nil 347 } 348 349 // Finalize implements consensus.Engine and processes withdrawals on top. 350 func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) { 351 if !beacon.IsPoSHeader(header) { 352 beacon.ethone.Finalize(chain, header, state, txs, uncles, nil) 353 return 354 } 355 // Withdrawals processing. 356 for _, w := range withdrawals { 357 // Convert amount from gwei to wei. 358 amount := new(big.Int).SetUint64(w.Amount) 359 amount = amount.Mul(amount, big.NewInt(params.GWei)) 360 state.AddBalance(w.Address, amount) 361 } 362 // No block reward which is issued by consensus layer instead. 363 } 364 365 // FinalizeAndAssemble implements consensus.Engine, setting the final state and 366 // assembling the block. 367 func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) { 368 if !beacon.IsPoSHeader(header) { 369 return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts, nil) 370 } 371 shanghai := chain.Config().IsShanghai(header.Number, header.Time) 372 if shanghai { 373 // All blocks after Shanghai must include a withdrawals root. 374 if withdrawals == nil { 375 withdrawals = make([]*types.Withdrawal, 0) 376 } 377 } else { 378 if len(withdrawals) > 0 { 379 return nil, errors.New("withdrawals set before Shanghai activation") 380 } 381 } 382 // Finalize and assemble the block. 383 beacon.Finalize(chain, header, state, txs, uncles, withdrawals) 384 385 // Assign the final state root to header. 386 header.Root = state.IntermediateRoot(true) 387 388 // Assemble and return the final block. 389 return types.NewBlockWithWithdrawals(header, txs, uncles, receipts, withdrawals, trie.NewStackTrie(nil)), nil 390 } 391 392 // Seal generates a new sealing request for the given input block and pushes 393 // the result into the given channel. 394 // 395 // Note, the method returns immediately and will send the result async. More 396 // than one result may also be returned depending on the consensus algorithm. 397 func (beacon *Beacon) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { 398 if !beacon.IsPoSHeader(block.Header()) { 399 return beacon.ethone.Seal(chain, block, results, stop) 400 } 401 // The seal verification is done by the external consensus engine, 402 // return directly without pushing any block back. In another word 403 // beacon won't return any result by `results` channel which may 404 // blocks the receiver logic forever. 405 return nil 406 } 407 408 // SealHash returns the hash of a block prior to it being sealed. 409 func (beacon *Beacon) SealHash(header *types.Header) common.Hash { 410 return beacon.ethone.SealHash(header) 411 } 412 413 // CalcDifficulty is the difficulty adjustment algorithm. It returns 414 // the difficulty that a new block should have when created at time 415 // given the parent block's time and difficulty. 416 func (beacon *Beacon) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { 417 // Transition isn't triggered yet, use the legacy rules for calculation 418 if reached, _ := IsTTDReached(chain, parent.Hash(), parent.Number.Uint64()); !reached { 419 return beacon.ethone.CalcDifficulty(chain, time, parent) 420 } 421 return beaconDifficulty 422 } 423 424 // APIs implements consensus.Engine, returning the user facing RPC APIs. 425 func (beacon *Beacon) APIs(chain consensus.ChainHeaderReader) []rpc.API { 426 return beacon.ethone.APIs(chain) 427 } 428 429 // Close shutdowns the consensus engine 430 func (beacon *Beacon) Close() error { 431 return beacon.ethone.Close() 432 } 433 434 // IsPoSHeader reports the header belongs to the PoS-stage with some special fields. 435 // This function is not suitable for a part of APIs like Prepare or CalcDifficulty 436 // because the header difficulty is not set yet. 437 func (beacon *Beacon) IsPoSHeader(header *types.Header) bool { 438 if header.Difficulty == nil { 439 panic("IsPoSHeader called with invalid difficulty") 440 } 441 return header.Difficulty.Cmp(beaconDifficulty) == 0 442 } 443 444 // InnerEngine returns the embedded eth1 consensus engine. 445 func (beacon *Beacon) InnerEngine() consensus.Engine { 446 return beacon.ethone 447 } 448 449 // SetThreads updates the mining threads. Delegate the call 450 // to the eth1 engine if it's threaded. 451 func (beacon *Beacon) SetThreads(threads int) { 452 type threaded interface { 453 SetThreads(threads int) 454 } 455 if th, ok := beacon.ethone.(threaded); ok { 456 th.SetThreads(threads) 457 } 458 } 459 460 // IsTTDReached checks if the TotalTerminalDifficulty has been surpassed on the `parentHash` block. 461 // It depends on the parentHash already being stored in the database. 462 // If the parentHash is not stored in the database a UnknownAncestor error is returned. 463 func IsTTDReached(chain consensus.ChainHeaderReader, parentHash common.Hash, parentNumber uint64) (bool, error) { 464 if chain.Config().TerminalTotalDifficulty == nil { 465 return false, nil 466 } 467 td := chain.GetTd(parentHash, parentNumber) 468 if td == nil { 469 return false, consensus.ErrUnknownAncestor 470 } 471 return td.Cmp(chain.Config().TerminalTotalDifficulty) >= 0, nil 472 }