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