github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/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 "context" 21 "errors" 22 "fmt" 23 "math/big" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/consensus" 27 "github.com/ethereum/go-ethereum/consensus/misc" 28 "github.com/ethereum/go-ethereum/core/state" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/params" 31 "github.com/ethereum/go-ethereum/rpc" 32 "github.com/ethereum/go-ethereum/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 ) 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, _ := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1) 83 if !reached { 84 return beacon.ethone.VerifyHeader(chain, header, seal) 85 } 86 // Short circuit if the parent is not known 87 parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) 88 if parent == nil { 89 return consensus.ErrUnknownAncestor 90 } 91 // Sanity checks passed, do a proper verification 92 return beacon.verifyHeader(chain, header, parent) 93 } 94 95 // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers 96 // concurrently. The method returns a quit channel to abort the operations and 97 // a results channel to retrieve the async verifications. 98 // VerifyHeaders expect the headers to be ordered and continuous. 99 func (beacon *Beacon) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { 100 if !beacon.IsPoSHeader(headers[len(headers)-1]) { 101 return beacon.ethone.VerifyHeaders(chain, headers, seals) 102 } 103 var ( 104 preHeaders []*types.Header 105 postHeaders []*types.Header 106 preSeals []bool 107 ) 108 for index, header := range headers { 109 if beacon.IsPoSHeader(header) { 110 preHeaders = headers[:index] 111 postHeaders = headers[index:] 112 preSeals = seals[:index] 113 break 114 } 115 } 116 // All the headers have passed the transition point, use new rules. 117 if len(preHeaders) == 0 { 118 return beacon.verifyHeaders(chain, headers, nil) 119 } 120 // The transition point exists in the middle, separate the headers 121 // into two batches and apply different verification rules for them. 122 var ( 123 abort = make(chan struct{}) 124 results = make(chan error, len(headers)) 125 ) 126 go func() { 127 var ( 128 old, new, out = 0, len(preHeaders), 0 129 errors = make([]error, len(headers)) 130 done = make([]bool, len(headers)) 131 oldDone, oldResult = beacon.ethone.VerifyHeaders(chain, preHeaders, preSeals) 132 newDone, newResult = beacon.verifyHeaders(chain, postHeaders, preHeaders[len(preHeaders)-1]) 133 ) 134 for { 135 for ; done[out]; out++ { 136 results <- errors[out] 137 if out == len(headers)-1 { 138 return 139 } 140 } 141 select { 142 case err := <-oldResult: 143 errors[old], done[old] = err, true 144 old++ 145 case err := <-newResult: 146 errors[new], done[new] = err, true 147 new++ 148 case <-abort: 149 close(oldDone) 150 close(newDone) 151 return 152 } 153 } 154 }() 155 return abort, results 156 } 157 158 // VerifyUncles verifies that the given block's uncles conform to the consensus 159 // rules of the Ethereum consensus engine. 160 func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 161 if !beacon.IsPoSHeader(block.Header()) { 162 return beacon.ethone.VerifyUncles(chain, block) 163 } 164 // Verify that there is no uncle block. It's explicitly disabled in the beacon 165 if len(block.Uncles()) > 0 { 166 return errTooManyUncles 167 } 168 return nil 169 } 170 171 // verifyHeader checks whether a header conforms to the consensus rules of the 172 // stock Ethereum consensus engine. The difference between the beacon and classic is 173 // (a) The following fields are expected to be constants: 174 // - difficulty is expected to be 0 175 // - nonce is expected to be 0 176 // - unclehash is expected to be Hash(emptyHeader) 177 // to be the desired constants 178 // 179 // (b) the timestamp is not verified anymore 180 // (c) the extradata is limited to 32 bytes 181 func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error { 182 // Ensure that the header's extra-data section is of a reasonable size 183 if len(header.Extra) > 32 { 184 return fmt.Errorf("extra-data longer than 32 bytes (%d)", len(header.Extra)) 185 } 186 // Verify the seal parts. Ensure the nonce and uncle hash are the expected value. 187 if header.Nonce != beaconNonce { 188 return errInvalidNonce 189 } 190 if header.UncleHash != types.EmptyUncleHash { 191 return errInvalidUncleHash 192 } 193 // Verify the block's difficulty to ensure it's the default constant 194 if beaconDifficulty.Cmp(header.Difficulty) != 0 { 195 return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, beaconDifficulty) 196 } 197 // Verify that the gas limit is <= 2^63-1 198 if header.GasLimit > params.MaxGasLimit { 199 return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit) 200 } 201 // Verify that the gasUsed is <= gasLimit 202 if header.GasUsed > header.GasLimit { 203 return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) 204 } 205 // Verify that the block number is parent's +1 206 if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(common.Big1) != 0 { 207 return consensus.ErrInvalidNumber 208 } 209 // Verify the header's EIP-1559 attributes. 210 return misc.VerifyEip1559Header(chain.Config(), parent, header) 211 } 212 213 // verifyHeaders is similar to verifyHeader, but verifies a batch of headers 214 // concurrently. The method returns a quit channel to abort the operations and 215 // a results channel to retrieve the async verifications. An additional parent 216 // header will be passed if the relevant header is not in the database yet. 217 func (beacon *Beacon) verifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, ancestor *types.Header) (chan<- struct{}, <-chan error) { 218 var ( 219 abort = make(chan struct{}) 220 results = make(chan error, len(headers)) 221 ) 222 go func() { 223 for i, header := range headers { 224 var parent *types.Header 225 if i == 0 { 226 if ancestor != nil { 227 parent = ancestor 228 } else { 229 parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) 230 } 231 } else if headers[i-1].Hash() == headers[i].ParentHash { 232 parent = headers[i-1] 233 } 234 if parent == nil { 235 select { 236 case <-abort: 237 return 238 case results <- consensus.ErrUnknownAncestor: 239 } 240 continue 241 } 242 err := beacon.verifyHeader(chain, header, parent) 243 select { 244 case <-abort: 245 return 246 case results <- err: 247 } 248 } 249 }() 250 return abort, results 251 } 252 253 // Prepare implements consensus.Engine, initializing the difficulty field of a 254 // header to conform to the beacon protocol. The changes are done inline. 255 func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { 256 // Transition isn't triggered yet, use the legacy rules for preparation. 257 reached, err := IsTTDReached(chain, header.ParentHash, header.Number.Uint64()-1) 258 if err != nil { 259 return err 260 } 261 if !reached { 262 return beacon.ethone.Prepare(chain, header) 263 } 264 header.Difficulty = beaconDifficulty 265 return nil 266 } 267 268 // Finalize implements consensus.Engine, setting the final state on the header 269 func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { 270 // Finalize is different with Prepare, it can be used in both block generation 271 // and verification. So determine the consensus rules by header type. 272 if !beacon.IsPoSHeader(header) { 273 beacon.ethone.Finalize(chain, header, state, txs, uncles) 274 return 275 } 276 // The block reward is no longer handled here. It's done by the 277 // external consensus engine. 278 header.Root = state.IntermediateRoot(true) 279 } 280 281 // FinalizeAndAssemble implements consensus.Engine, setting the final state and 282 // assembling the block. 283 func (beacon *Beacon) FinalizeAndAssemble(ctx context.Context, chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { 284 // FinalizeAndAssemble is different with Prepare, it can be used in both block 285 // generation and verification. So determine the consensus rules by header type. 286 if !beacon.IsPoSHeader(header) { 287 return beacon.ethone.FinalizeAndAssemble(ctx, chain, header, state, txs, uncles, receipts) 288 } 289 // Finalize and assemble the block 290 beacon.Finalize(chain, header, state, txs, uncles) 291 return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil 292 } 293 294 // Seal generates a new sealing request for the given input block and pushes 295 // the result into the given channel. 296 // 297 // Note, the method returns immediately and will send the result async. More 298 // than one result may also be returned depending on the consensus algorithm. 299 func (beacon *Beacon) Seal(ctx context.Context, chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { 300 if !beacon.IsPoSHeader(block.Header()) { 301 return beacon.ethone.Seal(ctx, chain, block, results, stop) 302 } 303 // The seal verification is done by the external consensus engine, 304 // return directly without pushing any block back. In another word 305 // beacon won't return any result by `results` channel which may 306 // blocks the receiver logic forever. 307 return nil 308 } 309 310 // SealHash returns the hash of a block prior to it being sealed. 311 func (beacon *Beacon) SealHash(header *types.Header) common.Hash { 312 return beacon.ethone.SealHash(header) 313 } 314 315 // CalcDifficulty is the difficulty adjustment algorithm. It returns 316 // the difficulty that a new block should have when created at time 317 // given the parent block's time and difficulty. 318 func (beacon *Beacon) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { 319 // Transition isn't triggered yet, use the legacy rules for calculation 320 if reached, _ := IsTTDReached(chain, parent.Hash(), parent.Number.Uint64()); !reached { 321 return beacon.ethone.CalcDifficulty(chain, time, parent) 322 } 323 return beaconDifficulty 324 } 325 326 // APIs implements consensus.Engine, returning the user facing RPC APIs. 327 func (beacon *Beacon) APIs(chain consensus.ChainHeaderReader) []rpc.API { 328 return beacon.ethone.APIs(chain) 329 } 330 331 // Close shutdowns the consensus engine 332 func (beacon *Beacon) Close() error { 333 return beacon.ethone.Close() 334 } 335 336 // IsPoSHeader reports the header belongs to the PoS-stage with some special fields. 337 // This function is not suitable for a part of APIs like Prepare or CalcDifficulty 338 // because the header difficulty is not set yet. 339 func (beacon *Beacon) IsPoSHeader(header *types.Header) bool { 340 if header.Difficulty == nil { 341 panic("IsPoSHeader called with invalid difficulty") 342 } 343 return header.Difficulty.Cmp(beaconDifficulty) == 0 344 } 345 346 // InnerEngine returns the embedded eth1 consensus engine. 347 func (beacon *Beacon) InnerEngine() consensus.Engine { 348 return beacon.ethone 349 } 350 351 // SetThreads updates the mining threads. Delegate the call 352 // to the eth1 engine if it's threaded. 353 func (beacon *Beacon) SetThreads(threads int) { 354 type threaded interface { 355 SetThreads(threads int) 356 } 357 if th, ok := beacon.ethone.(threaded); ok { 358 th.SetThreads(threads) 359 } 360 } 361 362 // IsTTDReached checks if the TotalTerminalDifficulty has been surpassed on the `parentHash` block. 363 // It depends on the parentHash already being stored in the database. 364 // If the parentHash is not stored in the database a UnknownAncestor error is returned. 365 func IsTTDReached(chain consensus.ChainHeaderReader, parentHash common.Hash, number uint64) (bool, error) { 366 if chain.Config().TerminalTotalDifficulty == nil { 367 return false, nil 368 } 369 td := chain.GetTd(parentHash, number) 370 if td == nil { 371 return false, consensus.ErrUnknownAncestor 372 } 373 return td.Cmp(chain.Config().TerminalTotalDifficulty) >= 0, nil 374 }