github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/consensus/istanbul/backend/engine.go (about) 1 // Copyright 2017 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 backend 18 19 import ( 20 "math/big" 21 "math/rand" 22 "time" 23 24 "github.com/kisexp/xdchain/common" 25 "github.com/kisexp/xdchain/consensus" 26 "github.com/kisexp/xdchain/consensus/istanbul" 27 istanbulcommon "github.com/kisexp/xdchain/consensus/istanbul/common" 28 "github.com/kisexp/xdchain/consensus/istanbul/validator" 29 "github.com/kisexp/xdchain/core/state" 30 "github.com/kisexp/xdchain/core/types" 31 "github.com/kisexp/xdchain/log" 32 "github.com/kisexp/xdchain/rpc" 33 ) 34 35 const ( 36 checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database 37 inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory 38 inmemoryPeers = 40 39 inmemoryMessages = 1024 40 ) 41 42 // Author retrieves the Ethereum address of the account that minted the given 43 // block, which may be different from the header's coinbase if a consensus 44 // engine is based on signatures. 45 func (sb *Backend) Author(header *types.Header) (common.Address, error) { 46 return sb.EngineForBlockNumber(header.Number).Author(header) 47 } 48 49 // Signers extracts all the addresses who have signed the given header 50 // It will extract for each seal who signed it, regardless of if the seal is 51 // repeated 52 func (sb *Backend) Signers(header *types.Header) ([]common.Address, error) { 53 return sb.EngineForBlockNumber(header.Number).Signers(header) 54 } 55 56 // VerifyHeader checks whether a header conforms to the consensus rules of a 57 // given engine. Verifying the seal may be done optionally here, or explicitly 58 // via the VerifySeal method. 59 func (sb *Backend) VerifyHeader(chain consensus.ChainHeaderReader, header *types.Header, seal bool) error { 60 return sb.verifyHeader(chain, header, nil) 61 } 62 63 func (sb *Backend) verifyHeader(chain consensus.ChainHeaderReader, header *types.Header, parents []*types.Header) error { 64 // Assemble the voting snapshot 65 snap, err := sb.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, parents) 66 if err != nil { 67 return err 68 } 69 70 return sb.EngineForBlockNumber(header.Number).VerifyHeader(chain, header, parents, snap.ValSet) 71 } 72 73 // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers 74 // concurrently. The method returns a quit channel to abort the operations and 75 // a results channel to retrieve the async verifications (the order is that of 76 // the input slice). 77 func (sb *Backend) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { 78 abort := make(chan struct{}) 79 results := make(chan error, len(headers)) 80 go func() { 81 errored := false 82 for i, header := range headers { 83 var err error 84 if errored { 85 err = consensus.ErrUnknownAncestor 86 } else { 87 err = sb.verifyHeader(chain, header, headers[:i]) 88 } 89 90 if err != nil { 91 errored = true 92 } 93 94 select { 95 case <-abort: 96 return 97 case results <- err: 98 } 99 } 100 }() 101 return abort, results 102 } 103 104 // VerifyUncles verifies that the given block's uncles conform to the consensus 105 // rules of a given engine. 106 func (sb *Backend) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 107 return sb.EngineForBlockNumber(block.Header().Number).VerifyUncles(chain, block) 108 } 109 110 // VerifySeal checks whether the crypto seal on a header is valid according to 111 // the consensus rules of the given engine. 112 func (sb *Backend) VerifySeal(chain consensus.ChainHeaderReader, header *types.Header) error { 113 // get parent header and ensure the signer is in parent's validator set 114 number := header.Number.Uint64() 115 if number == 0 { 116 return istanbulcommon.ErrUnknownBlock 117 } 118 119 // Assemble the voting snapshot 120 snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil) 121 if err != nil { 122 return err 123 } 124 125 return sb.EngineForBlockNumber(header.Number).VerifySeal(chain, header, snap.ValSet) 126 } 127 128 // Prepare initializes the consensus fields of a block header according to the 129 // rules of a particular engine. The changes are executed inline. 130 func (sb *Backend) Prepare(chain consensus.ChainHeaderReader, header *types.Header) error { 131 // Assemble the voting snapshot 132 snap, err := sb.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil) 133 if err != nil { 134 return err 135 } 136 137 err = sb.EngineForBlockNumber(header.Number).Prepare(chain, header, snap.ValSet) 138 if err != nil { 139 return err 140 } 141 142 // get valid candidate list 143 sb.candidatesLock.RLock() 144 var addresses []common.Address 145 var authorizes []bool 146 for address, authorize := range sb.candidates { 147 if snap.checkVote(address, authorize) { 148 addresses = append(addresses, address) 149 authorizes = append(authorizes, authorize) 150 } 151 } 152 sb.candidatesLock.RUnlock() 153 154 if len(addresses) > 0 { 155 index := rand.Intn(len(addresses)) 156 157 err = sb.EngineForBlockNumber(header.Number).WriteVote(header, addresses[index], authorizes[index]) 158 if err != nil { 159 log.Error("BFT: error writing validator vote", "err", err) 160 return err 161 } 162 } 163 164 return nil 165 } 166 167 // Finalize runs any post-transaction state modifications (e.g. block rewards) 168 // and assembles the final block. 169 // 170 // Note, the block header and state database might be updated to reflect any 171 // consensus rules that happen at finalization (e.g. block rewards). 172 func (sb *Backend) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { 173 sb.EngineForBlockNumber(header.Number).Finalize(chain, header, state, txs, uncles) 174 } 175 176 // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, 177 // nor block rewards given, and returns the final block. 178 func (sb *Backend) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { 179 return sb.EngineForBlockNumber(header.Number).FinalizeAndAssemble(chain, header, state, txs, uncles, receipts) 180 } 181 182 // Seal generates a new block for the given input block with the local miner's 183 // seal place on top. 184 func (sb *Backend) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { 185 // update the block header timestamp and signature and propose the block to core engine 186 header := block.Header() 187 number := header.Number.Uint64() 188 189 // Bail out if we're unauthorized to sign a block 190 snap, err := sb.snapshot(chain, number-1, header.ParentHash, nil) 191 if err != nil { 192 return err 193 } 194 195 block, err = sb.EngineForBlockNumber(header.Number).Seal(chain, block, snap.ValSet) 196 if err != nil { 197 return err 198 } 199 200 delay := time.Until(time.Unix(int64(block.Header().Time), 0)) 201 202 go func() { 203 // wait for the timestamp of header, use this to adjust the block period 204 select { 205 case <-time.After(delay): 206 case <-stop: 207 results <- nil 208 return 209 } 210 211 // get the proposed block hash and clear it if the seal() is completed. 212 sb.sealMu.Lock() 213 sb.proposedBlockHash = block.Hash() 214 215 defer func() { 216 sb.proposedBlockHash = common.Hash{} 217 sb.sealMu.Unlock() 218 }() 219 // post block into Istanbul engine 220 go sb.EventMux().Post(istanbul.RequestEvent{ 221 Proposal: block, 222 }) 223 for { 224 select { 225 case result := <-sb.commitCh: 226 // if the block hash and the hash from channel are the same, 227 // return the result. Otherwise, keep waiting the next hash. 228 if result != nil && block.Hash() == result.Hash() { 229 results <- result 230 return 231 } 232 case <-stop: 233 results <- nil 234 return 235 } 236 } 237 }() 238 return nil 239 } 240 241 // APIs returns the RPC APIs this consensus engine provides. 242 func (sb *Backend) APIs(chain consensus.ChainHeaderReader) []rpc.API { 243 return []rpc.API{{ 244 Namespace: "istanbul", 245 Version: "1.0", 246 Service: &API{chain: chain, backend: sb}, 247 Public: true, 248 }} 249 } 250 251 // Start implements consensus.Istanbul.Start 252 func (sb *Backend) Start(chain consensus.ChainHeaderReader, currentBlock func() *types.Block, hasBadBlock func(hash common.Hash) bool) error { 253 sb.coreMu.Lock() 254 defer sb.coreMu.Unlock() 255 if sb.coreStarted { 256 return istanbul.ErrStartedEngine 257 } 258 259 // clear previous data 260 sb.proposedBlockHash = common.Hash{} 261 if sb.commitCh != nil { 262 close(sb.commitCh) 263 } 264 sb.commitCh = make(chan *types.Block, 1) 265 266 sb.chain = chain 267 sb.currentBlock = currentBlock 268 sb.hasBadBlock = hasBadBlock 269 270 // Check if qbft Consensus needs to be used after chain is set 271 var err error 272 if sb.IsQBFTConsensus() { 273 err = sb.startQBFT() 274 } else { 275 err = sb.startIBFT() 276 } 277 278 if err != nil { 279 return err 280 } 281 282 sb.coreStarted = true 283 284 return nil 285 } 286 287 // Stop implements consensus.Istanbul.Stop 288 func (sb *Backend) Stop() error { 289 sb.coreMu.Lock() 290 defer sb.coreMu.Unlock() 291 if !sb.coreStarted { 292 return istanbul.ErrStoppedEngine 293 } 294 if err := sb.stop(); err != nil { 295 return err 296 } 297 sb.coreStarted = false 298 299 return nil 300 } 301 302 func addrsToString(addrs []common.Address) []string { 303 strs := make([]string, len(addrs)) 304 for i, addr := range addrs { 305 strs[i] = addr.String() 306 } 307 return strs 308 } 309 310 func (sb *Backend) snapLogger(snap *Snapshot) log.Logger { 311 return sb.logger.New( 312 "snap.number", snap.Number, 313 "snap.hash", snap.Hash.String(), 314 "snap.epoch", snap.Epoch, 315 "snap.validators", addrsToString(snap.validators()), 316 "snap.votes", snap.Votes, 317 ) 318 } 319 320 func (sb *Backend) storeSnap(snap *Snapshot) error { 321 logger := sb.snapLogger(snap) 322 logger.Debug("BFT: store snapshot to database") 323 if err := snap.store(sb.db); err != nil { 324 logger.Error("BFT: failed to store snapshot to database", "err", err) 325 return err 326 } 327 328 return nil 329 } 330 331 // snapshot retrieves the authorization snapshot at a given point in time. 332 func (sb *Backend) snapshot(chain consensus.ChainHeaderReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) { 333 // Search for a snapshot in memory or on disk for checkpoints 334 var ( 335 headers []*types.Header 336 snap *Snapshot 337 ) 338 for snap == nil { 339 // If an in-memory snapshot was found, use that 340 if s, ok := sb.recents.Get(hash); ok { 341 snap = s.(*Snapshot) 342 sb.snapLogger(snap).Trace("BFT: loaded voting snapshot from cache") 343 break 344 } 345 // If an on-disk checkpoint snapshot can be found, use that 346 if number%checkpointInterval == 0 { 347 if s, err := loadSnapshot(sb.config.Epoch, sb.db, hash); err == nil { 348 snap = s 349 sb.snapLogger(snap).Trace("BFT: loaded voting snapshot from database") 350 break 351 } 352 } 353 354 // If we're at block zero, make a snapshot 355 if number == 0 { 356 genesis := chain.GetHeaderByNumber(0) 357 if err := sb.EngineForBlockNumber(big.NewInt(0)).VerifyHeader(chain, genesis, nil, nil); err != nil { 358 sb.logger.Error("BFT: invalid genesis block", "err", err) 359 return nil, err 360 } 361 362 // Get the validators from genesis to create a snapshot 363 validators, err := sb.EngineForBlockNumber(big.NewInt(0)).Validators(genesis) 364 if err != nil { 365 sb.logger.Error("BFT: invalid genesis block", "err", err) 366 return nil, err 367 } 368 369 snap = newSnapshot(sb.config.Epoch, 0, genesis.Hash(), validator.NewSet(validators, sb.config.ProposerPolicy)) 370 if err := sb.storeSnap(snap); err != nil { 371 return nil, err 372 } 373 break 374 } 375 376 // No snapshot for this header, gather the header and move backward 377 var header *types.Header 378 if len(parents) > 0 { 379 // If we have explicit parents, pick from there (enforced) 380 header = parents[len(parents)-1] 381 if header.Hash() != hash || header.Number.Uint64() != number { 382 return nil, consensus.ErrUnknownAncestor 383 } 384 parents = parents[:len(parents)-1] 385 } else { 386 // No explicit parents (or no more left), reach out to the database 387 header = chain.GetHeader(hash, number) 388 if header == nil { 389 return nil, consensus.ErrUnknownAncestor 390 } 391 } 392 393 headers = append(headers, header) 394 number, hash = number-1, header.ParentHash 395 } 396 397 // Previous snapshot found, apply any pending headers on top of it 398 for i := 0; i < len(headers)/2; i++ { 399 headers[i], headers[len(headers)-1-i] = headers[len(headers)-1-i], headers[i] 400 } 401 402 snap, err := sb.snapApply(snap, headers) 403 if err != nil { 404 return nil, err 405 } 406 sb.recents.Add(snap.Hash, snap) 407 408 // If we've generated a new checkpoint snapshot, save to disk 409 if snap.Number%checkpointInterval == 0 && len(headers) > 0 { 410 if err = sb.storeSnap(snap); err != nil { 411 return nil, err 412 } 413 } 414 415 return snap, err 416 } 417 418 // SealHash returns the hash of a block prior to it being sealed. 419 func (sb *Backend) SealHash(header *types.Header) common.Hash { 420 return sb.EngineForBlockNumber(header.Number).SealHash(header) 421 } 422 423 func (sb *Backend) snapApply(snap *Snapshot, headers []*types.Header) (*Snapshot, error) { 424 // Allow passing in no headers for cleaner code 425 if len(headers) == 0 { 426 return snap, nil 427 } 428 // Sanity check that the headers can be applied 429 for i := 0; i < len(headers)-1; i++ { 430 if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 { 431 return nil, istanbulcommon.ErrInvalidVotingChain 432 } 433 } 434 if headers[0].Number.Uint64() != snap.Number+1 { 435 return nil, istanbulcommon.ErrInvalidVotingChain 436 } 437 // Iterate through the headers and create a new snapshot 438 snapCpy := snap.copy() 439 440 for _, header := range headers { 441 err := sb.snapApplyHeader(snapCpy, header) 442 if err != nil { 443 return nil, err 444 } 445 } 446 snapCpy.Number += uint64(len(headers)) 447 snapCpy.Hash = headers[len(headers)-1].Hash() 448 449 return snapCpy, nil 450 } 451 452 func (sb *Backend) snapApplyHeader(snap *Snapshot, header *types.Header) error { 453 logger := sb.snapLogger(snap).New("header.number", header.Number.Uint64(), "header.hash", header.Hash().String()) 454 455 logger.Trace("BFT: apply header to voting snapshot") 456 457 // Remove any votes on checkpoint blocks 458 number := header.Number.Uint64() 459 if number%snap.Epoch == 0 { 460 snap.Votes = nil 461 snap.Tally = make(map[common.Address]Tally) 462 } 463 464 // Resolve the authorization key and check against validators 465 validator, err := sb.EngineForBlockNumber(header.Number).Author(header) 466 if err != nil { 467 logger.Error("BFT: invalid header author", "err", err) 468 return err 469 } 470 471 logger = logger.New("header.author", validator) 472 473 if _, v := snap.ValSet.GetByAddress(validator); v == nil { 474 logger.Error("BFT: header author is not a validator") 475 return istanbulcommon.ErrUnauthorized 476 } 477 478 // Read vote from header 479 candidate, authorize, err := sb.EngineForBlockNumber(header.Number).ReadVote(header) 480 if err != nil { 481 logger.Error("BFT: invalid header vote", "err", err) 482 return err 483 } 484 485 logger = logger.New("candidate", candidate.String(), "authorize", authorize) 486 // Header authorized, discard any previous votes from the validator 487 for i, vote := range snap.Votes { 488 if vote.Validator == validator && vote.Address == candidate { 489 logger.Trace("BFT: discard previous vote from tally", "old.authorize", vote.Authorize) 490 // Uncast the vote from the cached tally 491 snap.uncast(vote.Address, vote.Authorize) 492 493 // Uncast the vote from the chronological list 494 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 495 break // only one vote allowed 496 } 497 } 498 499 logger.Debug("BFT: add vote to tally") 500 if snap.cast(candidate, authorize) { 501 snap.Votes = append(snap.Votes, &Vote{ 502 Validator: validator, 503 Block: number, 504 Address: candidate, 505 Authorize: authorize, 506 }) 507 } 508 509 // If the vote passed, update the list of validators 510 if tally := snap.Tally[candidate]; tally.Votes > snap.ValSet.Size()/2 { 511 512 if tally.Authorize { 513 logger.Info("BFT: reached majority to add validator") 514 snap.ValSet.AddValidator(candidate) 515 } else { 516 logger.Info("BFT: reached majority to remove validator") 517 snap.ValSet.RemoveValidator(candidate) 518 519 // Discard any previous votes the deauthorized validator cast 520 for i := 0; i < len(snap.Votes); i++ { 521 if snap.Votes[i].Validator == candidate { 522 // Uncast the vote from the cached tally 523 snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize) 524 525 // Uncast the vote from the chronological list 526 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 527 528 i-- 529 } 530 } 531 } 532 // Discard any previous votes around the just changed account 533 for i := 0; i < len(snap.Votes); i++ { 534 if snap.Votes[i].Address == candidate { 535 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 536 i-- 537 } 538 } 539 delete(snap.Tally, candidate) 540 } 541 return nil 542 }