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