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