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