github.com/elastos/Elastos.ELA.SideChain.ETH@v0.2.2/consensus/pbft/pbft.go (about) 1 // Copyright (c) 2017-2019 The Elastos Foundation 2 // Use of this source code is governed by an MIT 3 // license that can be found in the LICENSE file. 4 // 5 6 package pbft 7 8 import ( 9 "bytes" 10 "errors" 11 "fmt" 12 "github.com/elastos/Elastos.ELA.SideChain.ESC/chainbridge-core/crypto" 13 "io" 14 "math/big" 15 "path/filepath" 16 "strings" 17 "time" 18 19 "github.com/elastos/Elastos.ELA.SideChain.ESC/common" 20 "github.com/elastos/Elastos.ELA.SideChain.ESC/consensus" 21 "github.com/elastos/Elastos.ELA.SideChain.ESC/core" 22 "github.com/elastos/Elastos.ELA.SideChain.ESC/core/state" 23 "github.com/elastos/Elastos.ELA.SideChain.ESC/core/types" 24 "github.com/elastos/Elastos.ELA.SideChain.ESC/dpos" 25 dmsg "github.com/elastos/Elastos.ELA.SideChain.ESC/dpos/msg" 26 "github.com/elastos/Elastos.ELA.SideChain.ESC/log" 27 "github.com/elastos/Elastos.ELA.SideChain.ESC/params" 28 "github.com/elastos/Elastos.ELA.SideChain.ESC/rlp" 29 "github.com/elastos/Elastos.ELA.SideChain.ESC/rpc" 30 "github.com/elastos/Elastos.ELA.SideChain.ESC/smallcrosstx" 31 "github.com/elastos/Elastos.ELA.SideChain.ESC/spv" 32 "github.com/elastos/Elastos.ELA.SideChain.ESC/withdrawfailedtx" 33 "github.com/elastos/Elastos.ELA/core/types/payload" 34 35 ecom "github.com/elastos/Elastos.ELA/common" 36 daccount "github.com/elastos/Elastos.ELA/dpos/account" 37 "github.com/elastos/Elastos.ELA/dpos/dtime" 38 "github.com/elastos/Elastos.ELA/dpos/p2p/peer" 39 "github.com/elastos/Elastos.ELA/events" 40 "github.com/elastos/Elastos.ELA/p2p/msg" 41 42 "golang.org/x/crypto/sha3" 43 ) 44 45 var ( 46 extraVanity = 32 // Fixed number of extra-data prefix bytes 47 extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal 48 diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures 49 diffNoTurn = big.NewInt(1) // Block difficulty for in-turn signatures 50 ) 51 52 const ( 53 // maxRequestedBlocks is the maximum number of requested block 54 // hashes to store in memory. 55 maxRequestedBlocks = msg.MaxInvPerMsg 56 ) 57 58 var ( 59 // errUnknownBlock is returned when the list of signers is requested for a block 60 // that is not part of the local blockchain. 61 errUnknownBlock = errors.New("unknown block") 62 63 // errInvalidMixDigest is returned if a block's mix digest is non-zero. 64 errInvalidMixDigest = errors.New("non-zero mix digest") 65 // errInvalidUncleHash is returned if a block contains an non-empty uncle list. 66 errInvalidUncleHash = errors.New("non empty uncle hash") 67 // to contain a 64 byte secp256k1 signature. 68 errMissingSignature = errors.New("extra-data 64 byte signature suffix missing") 69 // errUnauthorizedSigner is returned if a header is signed by a non-authorized entity. 70 errUnauthorizedSigner = errors.New("unauthorized signer") 71 // ErrInvalidTimestamp is returned if the timestamp of a block is lower than 72 // the previous block's timestamp + the minimum block period. 73 ErrInvalidTimestamp = errors.New("invalid timestamp") 74 75 ErrAlreadyConfirmedBlock = errors.New("already confirmed block") 76 77 ErrWaitSyncBlock = errors.New("has confirmed, wait sync block") 78 79 ErrInvalidConfirm = errors.New("invalid confirm") 80 81 ErrSignerNotOnduty = errors.New("singer is not on duty") 82 83 ErrConsensusIsRunning = errors.New("current consensus is running") 84 85 ErrWaitRecoverStatus = errors.New("wait for recoved states") 86 87 // errInvalidDifficulty is returned if the difficulty of a block neither 2. 88 errInvalidDifficulty = errors.New("invalid difficulty") 89 90 errChainForkBlock = errors.New("chain fork block") 91 92 errDoubleSignBlock = errors.New("double sign block") 93 ) 94 95 // Pbft is a consensus engine based on Byzantine fault-tolerant algorithm 96 type Pbft struct { 97 datadir string 98 cfg params.PbftConfig 99 dispatcher *dpos.Dispatcher 100 confirmCh chan *payload.Confirm 101 unConfirmCh chan *payload.Confirm 102 account daccount.Account 103 bridgeAccount crypto.Keypair 104 network *dpos.Network 105 blockPool *dpos.BlockPool 106 chain *core.BlockChain 107 timeSource dtime.MedianTimeSource 108 109 // IsCurrent returns whether BlockChain synced to best height. 110 IsCurrent func() bool 111 StartMine func() 112 OnDuty func() 113 OnInsertChainError func(id peer.PID, block *types.Block, err error) 114 115 requestedBlocks map[common.Hash]struct{} 116 requestedProposals map[ecom.Uint256]struct{} 117 statusMap map[uint32]map[string]*dmsg.ConsensusStatus 118 notHandledProposal map[string]struct{} 119 120 enableViewLoop bool 121 recoverStarted bool 122 isRecoved bool 123 period uint64 124 isSealOver bool 125 isRecovering bool 126 } 127 128 func New(chainConfig *params.ChainConfig, dataDir string) *Pbft { 129 logpath := filepath.Join(dataDir, "/logs/dpos") 130 dposPath := filepath.Join(dataDir, "/network/dpos") 131 if strings.LastIndex(dataDir, "/") == len(dataDir)-1 { 132 dposPath = filepath.Join(dataDir, "network/dpos") 133 logpath = filepath.Join(dataDir, "logs/dpos") 134 } 135 cfg := chainConfig.Pbft 136 if cfg == nil { 137 dpos.InitLog(0, 0, 0, logpath) 138 return &Pbft{} 139 } 140 pbftKeystore := chainConfig.PbftKeyStore 141 password := []byte(chainConfig.PbftKeyStorePassWord) 142 dpos.InitLog(cfg.PrintLevel, cfg.MaxPerLogSize, cfg.MaxLogsSize, logpath) 143 producers := make([][]byte, len(cfg.Producers)) 144 for i, v := range cfg.Producers { 145 producers[i] = common.Hex2Bytes(v) 146 } 147 account, err := dpos.GetDposAccount(pbftKeystore, password) 148 var bridgeAccount crypto.Keypair 149 if err != nil { 150 if string(password) == "" { 151 fmt.Println("create dpos account error:", err.Error(), "pbftKeystore:", pbftKeystore, "password") 152 } else { 153 fmt.Println("create dpos account error:", err.Error(), "pbftKeystore:", pbftKeystore, "password", string(password)) 154 } 155 //can't return, because common node need verify use this engine 156 } else { 157 bridgeAccount, err = dpos.GetBridgeAccount(pbftKeystore, password) 158 if err != nil { 159 if string(password) == "" { 160 fmt.Println("create GetArbiterAccount error:", err.Error(), "pbftKeystore:", pbftKeystore, "password") 161 } else { 162 fmt.Println("create GetArbiterAccount error:", err.Error(), "pbftKeystore:", pbftKeystore, "password", string(password)) 163 } 164 } 165 } 166 medianTimeSouce := dtime.NewMedianTime() 167 168 pbft := &Pbft{ 169 datadir: dataDir, 170 cfg: *cfg, 171 confirmCh: make(chan *payload.Confirm), 172 unConfirmCh: make(chan *payload.Confirm), 173 account: account, 174 bridgeAccount: bridgeAccount, 175 requestedBlocks: make(map[common.Hash]struct{}), 176 requestedProposals: make(map[ecom.Uint256]struct{}), 177 statusMap: make(map[uint32]map[string]*dmsg.ConsensusStatus), 178 notHandledProposal: make(map[string]struct{}), 179 period: 5, 180 timeSource: medianTimeSouce, 181 } 182 blockPool := dpos.NewBlockPool(pbft.verifyConfirm, pbft.verifyBlock, DBlockSealHash) 183 pbft.blockPool = blockPool 184 var accpubkey []byte 185 186 if account != nil { 187 accpubkey = account.PublicKeyBytes() 188 network, err := dpos.NewNetwork(&dpos.NetworkConfig{ 189 IPAddress: cfg.IPAddress, 190 Magic: cfg.Magic, 191 DefaultPort: cfg.DPoSPort, 192 Account: account, 193 MedianTime: medianTimeSouce, 194 MaxNodePerHost: cfg.MaxNodePerHost, 195 Listener: pbft, 196 DataPath: dposPath, 197 PublicKey: accpubkey, 198 GetCurrentHeight: pbft.GetMainChainHeight, 199 AnnounceAddr: func() { 200 events.Notify(dpos.ETAnnounceAddr, nil) 201 }, 202 }) 203 if err != nil { 204 dpos.Error("New dpos network error:", err.Error()) 205 return nil 206 } 207 pbft.network = network 208 pbft.subscribeEvent() 209 } 210 pbft.dispatcher = dpos.NewDispatcher(producers, pbft.onConfirm, pbft.onUnConfirm, 211 10*time.Second, accpubkey, medianTimeSouce, pbft, chainConfig.GetPbftBlock()) 212 return pbft 213 } 214 215 func (p *Pbft) GetMainChainHeight(pid peer.PID) uint64 { 216 return spv.GetSpvHeight() 217 } 218 219 func (p *Pbft) subscribeEvent() { 220 events.Subscribe(func(e *events.Event) { 221 switch e.Type { 222 case events.ETDirectPeersChanged: 223 peersInfo := e.Data.(*peer.PeersInfo) 224 go p.network.UpdatePeers(peersInfo.CurrentPeers, peersInfo.NextPeers) 225 case dpos.ETNewPeer: 226 count := len(p.network.GetActivePeers()) 227 log.Info("new peer accept", "active peer count", count) 228 height := p.chain.CurrentHeader().Number.Uint64() 229 cfg := p.chain.Config() 230 if cfg.PBFTBlock != nil && height >= cfg.PBFTBlock.Uint64()-cfg.PreConnectOffset && height < cfg.PBFTBlock.Uint64() { 231 log.Info("before change engine AnnounceDAddr") 232 go p.AnnounceDAddr() 233 } 234 235 if p.chain.Engine() == p && !p.dispatcher.GetConsensusView().HasProducerMajorityCount(count) { 236 log.Info("end change engine AnnounceDAddr") 237 go p.AnnounceDAddr() 238 } 239 case dpos.ETNextProducers: 240 producers := e.Data.([]peer.PID) 241 log.Info("update next producers", "totalCount", spv.GetTotalProducersCount()) 242 p.dispatcher.GetConsensusView().UpdateNextProducers(producers, spv.GetTotalProducersCount()) 243 case dpos.ETOnSPVHeight: 244 height := e.Data.(uint32) 245 if spv.GetWorkingHeight() >= height { 246 if uint64(spv.GetWorkingHeight()-height) <= p.chain.Config().PreConnectOffset { 247 curProducers := p.dispatcher.GetConsensusView().GetProducers() 248 isSame := p.dispatcher.GetConsensusView().IsSameProducers(curProducers) 249 if !isSame { 250 go p.AnnounceDAddr() 251 } else { 252 log.Info("For the same batch of aribters, no need to re-connect direct net") 253 } 254 } 255 } 256 case dpos.ETSmallCroTx: 257 if croTx, ok := e.Data.(*smallcrosstx.ETSmallCrossTx); ok { 258 msg := dmsg.NewSmallCroTx(croTx.Signature, croTx.RawTx) 259 p.BroadMessage(msg) 260 } 261 262 case dpos.ETFailedWithdrawTx: 263 if failEvt, ok := e.Data.(*withdrawfailedtx.FailedWithdrawEvent); ok { 264 msg := dmsg.NewFailedWithdrawTx(failEvt.Signature, failEvt.Txid) 265 p.BroadMessage(msg) 266 } 267 } 268 }) 269 } 270 271 func (p *Pbft) IsSameProducers(curProducers [][]byte) bool { 272 return p.dispatcher.GetConsensusView().IsSameProducers(curProducers) 273 } 274 275 func (p *Pbft) IsCurrentProducers(curProducers [][]byte) bool { 276 return p.dispatcher.GetConsensusView().IsCurrentProducers(curProducers) 277 } 278 279 func (p *Pbft) GetDataDir() string { 280 return p.datadir 281 } 282 283 func (p *Pbft) GetPbftConfig() params.PbftConfig { 284 return p.cfg 285 } 286 287 func (p *Pbft) CurrentBlock() *types.Block { 288 if p.chain == nil { 289 return nil 290 } 291 return p.chain.CurrentBlock() 292 } 293 294 func (p *Pbft) GetBlockByHeight(height uint64) *types.Block { 295 if p.chain == nil { 296 return nil 297 } 298 return p.chain.GetBlockByNumber(height) 299 } 300 301 func (p *Pbft) Author(header *types.Header) (common.Address, error) { 302 return header.Coinbase, nil 303 } 304 305 func (p *Pbft) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { 306 dpos.Info("Pbft VerifyHeader") 307 return p.verifyHeader(chain, header, nil, seal) 308 } 309 310 func (p *Pbft) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { 311 dpos.Info("Pbft VerifyHeaders") 312 abort := make(chan struct{}) 313 results := make(chan error, len(headers)) 314 315 go func() { 316 for i, header := range headers { 317 var err error 318 //Check header is verified 319 if seals[i] { 320 // Don't waste time checking blocks from the future 321 if header.Time > uint64(time.Now().Unix()) { 322 err = consensus.ErrFutureBlock 323 } 324 } 325 if err == nil && !p.IsInBlockPool(p.SealHash(header)) { 326 err = p.verifyHeader(chain, header, headers[:i], seals[i]) 327 } else if err == nil { 328 err = p.verifySeal(chain, header, headers[:i]) 329 } 330 331 select { 332 case <-abort: 333 return 334 case results <- err: 335 } 336 } 337 }() 338 return abort, results 339 } 340 341 func (p *Pbft) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header, seal bool) error { 342 343 if header.Number == nil || header.Number.Uint64() == 0 { 344 return errUnknownBlock 345 } 346 // Don't waste time checking blocks from the future 347 if seal && header.Time > uint64(time.Now().Unix()) { 348 return consensus.ErrFutureBlock 349 } 350 351 // Verify that the gas limit is <= 2^63-1 352 cap := uint64(0x7fffffffffffffff) 353 if header.GasLimit > cap { 354 return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) 355 } 356 // Verify that the gasUsed is <= gasLimit 357 if header.GasUsed > header.GasLimit { 358 return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) 359 } 360 // Ensure that the mix digest is zero as we don't have fork protection currently 361 if header.MixDigest != (common.Hash{}) { 362 return errInvalidMixDigest 363 } 364 // Ensure that the block doesn't contain any uncles which are meaningless in Pbft 365 if header.UncleHash != types.CalcUncleHash(nil) { 366 return errInvalidUncleHash 367 } 368 369 number := header.Number.Uint64() 370 var parent *types.Header 371 if len(parents) > 0 { 372 parent = parents[len(parents)-1] 373 } else { 374 parent = chain.GetHeader(header.ParentHash, number-1) 375 } 376 if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { 377 return consensus.ErrUnknownAncestor 378 } 379 log.Info("verify header HasConfirmed", "seal:", seal, "height", header.Number) 380 if !seal && p.dispatcher.GetFinishedHeight() == number { 381 log.Warn("verify header already confirm block") 382 return ErrAlreadyConfirmedBlock 383 } 384 385 if parent.Time+p.period > header.Time { 386 return ErrInvalidTimestamp 387 } 388 389 if number > 0 { 390 if header.Difficulty == nil || (header.Difficulty.Cmp(diffInTurn) != 0) { 391 return errInvalidDifficulty 392 } 393 } 394 395 if seal { 396 return p.verifySeal(chain, header, parents) 397 } 398 399 return nil 400 } 401 402 func (p *Pbft) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { 403 dpos.Info("Pbft VerifyUncles") 404 if len(block.Uncles()) > 0 { 405 return errors.New("uncles not allowed") 406 } 407 return nil 408 } 409 410 func (p *Pbft) VerifySeal(chain consensus.ChainReader, header *types.Header) error { 411 dpos.Info("Pbft VerifySeal") 412 return p.verifySeal(chain, header, nil) 413 } 414 415 func (p *Pbft) verifySeal(chain consensus.ChainReader, header *types.Header, parents []*types.Header) error { 416 // Verifying the genesis block is not supported 417 number := header.Number.Uint64() 418 if number == 0 { 419 return errUnknownBlock 420 } 421 422 // Retrieve the confirm from the header extra-data 423 var confirm payload.Confirm 424 err := confirm.Deserialize(bytes.NewReader(header.Extra)) 425 if err != nil { 426 return err 427 } 428 err = p.verifyConfirm(&confirm, header.Nonce.Uint64()) 429 if err != nil { 430 return err 431 } 432 433 if oldHeader := chain.GetHeaderByNumber(number); oldHeader != nil { 434 var oldConfirm payload.Confirm 435 err := oldConfirm.Deserialize(bytes.NewReader(oldHeader.Extra)) 436 if err != nil { 437 return nil 438 } 439 440 if confirm.Proposal.ViewOffset < oldConfirm.Proposal.ViewOffset && number < chain.CurrentHeader().Number.Uint64() { 441 log.Warn("verify seal chain fork", "oldViewOffset", oldConfirm.Proposal.ViewOffset, "newViewOffset", confirm.Proposal.ViewOffset, "height", number) 442 //return errChainForkBlock 443 } 444 if confirm.Proposal.ViewOffset == oldConfirm.Proposal.ViewOffset && oldHeader.Hash() != header.Hash() { 445 return errDoubleSignBlock 446 } 447 } 448 449 return nil 450 } 451 452 func (p *Pbft) Prepare(chain consensus.ChainReader, header *types.Header) error { 453 log.Info("Pbft Prepare:", "height:", header.Number.Uint64(), "parent", header.ParentHash.String()) 454 p.isSealOver = false 455 nowTime := uint64(time.Now().Unix()) 456 if p.dispatcher != nil { 457 nowTime = uint64(p.dispatcher.GetNowTime().Unix()) 458 } 459 header.Difficulty = p.CalcDifficulty(chain, nowTime, nil) 460 if p.dispatcher != nil { 461 header.Nonce = types.EncodeNonce(p.dispatcher.GetConsensusView().GetSpvHeight()) 462 } 463 parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) 464 if parent == nil { 465 return consensus.ErrUnknownAncestor 466 } 467 if !p.isRecoved { 468 return ErrWaitRecoverStatus 469 } 470 if p.dispatcher.GetConsensusView().IsRunning() && p.enableViewLoop { 471 return ErrConsensusIsRunning 472 } 473 p.Start(parent.Time) 474 header.Time = parent.Time + p.period 475 if header.Time < nowTime { 476 header.Time = nowTime 477 p.dispatcher.ResetView(nowTime) 478 } 479 if !p.IsOnduty() { 480 return ErrSignerNotOnduty 481 } 482 if header.Number.Uint64() <= p.dispatcher.GetFinishedHeight() { 483 return ErrAlreadyConfirmedBlock 484 } 485 return nil 486 } 487 488 func (p *Pbft) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, 489 uncles []*types.Header) { 490 dpos.Info("Pbft Finalize:", "height:", header.Number.Uint64()) 491 sealHash := p.SealHash(header) 492 hash, _ := ecom.Uint256FromBytes(sealHash.Bytes()) 493 p.dispatcher.FinishedProposal(header.Number.Uint64(), *hash, header.Time) 494 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 495 header.UncleHash = types.CalcUncleHash(nil) 496 p.CleanFinalConfirmedBlock(header.Number.Uint64()) 497 } 498 499 func (p *Pbft) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, 500 uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { 501 dpos.Info("Pbft FinalizeAndAssemble") 502 // No block rewards in DPoS, so the state remains as is and uncles are dropped 503 header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) 504 header.UncleHash = types.CalcUncleHash(nil) 505 506 // Assemble and return the final block for sealing 507 return types.NewBlock(header, txs, nil, receipts), nil 508 } 509 510 func (p *Pbft) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { 511 dpos.Info("Pbft Seal:", block.NumberU64()) 512 if p.account == nil { 513 return errors.New("no signer inited") 514 } 515 516 if !p.isRecoved { 517 return ErrWaitRecoverStatus 518 } 519 520 parent := chain.GetHeader(block.ParentHash(), block.NumberU64()-1) 521 if parent == nil { 522 return consensus.ErrUnknownAncestor 523 } 524 525 if block.NumberU64() <= p.dispatcher.GetFinishedHeight() { 526 return ErrAlreadyConfirmedBlock 527 } 528 if !p.IsProducer() { 529 return errUnauthorizedSigner 530 } 531 if !p.IsOnduty() { 532 return ErrSignerNotOnduty 533 } 534 p.BroadBlockMsg(block) 535 536 if err := p.StartProposal(block); err != nil { 537 return err 538 } 539 p.isSealOver = false 540 header := block.Header() 541 //Waiting for statistics of voting results 542 delay := time.Unix(int64(header.Time), 0).Sub(p.dispatcher.GetNowTime()) 543 log.Info("wait seal time", "delay", delay) 544 time.Sleep(delay) 545 changeViewTime := p.dispatcher.GetConsensusView().GetChangeViewTime() 546 toleranceDelay := changeViewTime.Sub(p.dispatcher.GetNowTime()) 547 log.Info("changeViewLeftTime", "toleranceDelay", toleranceDelay) 548 select { 549 case confirm := <-p.confirmCh: 550 log.Info("Received confirmCh", "proposal", confirm.Proposal.Hash().String(), "block:", block.NumberU64()) 551 p.addConfirmToBlock(header, confirm) 552 p.isSealOver = true 553 break 554 case <-p.unConfirmCh: 555 log.Warn("proposal is rejected") 556 p.isSealOver = true 557 return nil 558 case <-time.After(toleranceDelay): 559 log.Warn("seal time out stop mine") 560 p.isSealOver = true 561 return nil 562 case <-stop: 563 log.Warn("pbft seal is stop") 564 p.isSealOver = true 565 return nil 566 } 567 finalBlock := block.WithSeal(header) 568 go func() { 569 select { 570 case results <- finalBlock: 571 p.BroadBlockMsg(finalBlock) 572 p.CleanFinalConfirmedBlock(block.NumberU64()) 573 default: 574 dpos.Warn("Sealing result is not read by miner", "sealhash", SealHash(header)) 575 } 576 }() 577 578 return nil 579 } 580 581 func (p *Pbft) addConfirmToBlock(header *types.Header, confirm *payload.Confirm) error { 582 sealBuf := new(bytes.Buffer) 583 if err := confirm.Serialize(sealBuf); err != nil { 584 log.Error("confirm serialize error", "error", err) 585 return err 586 } 587 header.Extra = make([]byte, sealBuf.Len()) 588 copy(header.Extra[:], sealBuf.Bytes()[:]) 589 sealHash := SealHash(header) 590 hash, _ := ecom.Uint256FromBytes(sealHash.Bytes()) 591 p.dispatcher.FinishedProposal(header.Number.Uint64(), *hash, header.Time) 592 return nil 593 } 594 595 func (p *Pbft) onConfirm(confirm *payload.Confirm) error { 596 log.Info("--------[onConfirm]------", "proposal:", confirm.Proposal.Hash()) 597 if p.isSealOver && p.IsOnduty() { 598 log.Warn("seal block is over, can't confirm") 599 return errors.New("seal block is over, can't confirm") 600 } 601 err := p.blockPool.AppendConfirm(confirm) 602 if err != nil { 603 log.Error("Received confirm", "proposal", confirm.Proposal.Hash().String(), "err:", err) 604 return err 605 } 606 if p.IsOnduty() { 607 log.Info("on duty, set confirm block") 608 p.confirmCh <- confirm 609 } else { 610 log.Info("not on duty, not broad confirm block") 611 } 612 613 return err 614 } 615 616 func (p *Pbft) onUnConfirm(unconfirm *payload.Confirm) error { 617 log.Info("--------[onUnConfirm]------", "proposal:", unconfirm.Proposal.Hash()) 618 if p.isSealOver { 619 return errors.New("seal block is over, can't unconfirm") 620 } 621 if p.IsOnduty() { 622 p.unConfirmCh <- unconfirm 623 } 624 return nil 625 } 626 627 func (p *Pbft) SealHash(header *types.Header) common.Hash { 628 return SealHash(header) 629 } 630 631 func (p *Pbft) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { 632 dpos.Info("Pbft CalcDifficulty") 633 if p.IsOnduty() { 634 return diffInTurn 635 } 636 return diffNoTurn 637 } 638 639 func (p *Pbft) APIs(chain consensus.ChainReader) []rpc.API { 640 return []rpc.API{{ 641 Namespace: "pbft", 642 Version: "1.0", 643 Service: &API{chain: chain, pbft: p}, 644 Public: false, 645 }} 646 } 647 648 func (p *Pbft) Close() error { 649 dpos.Info("Pbft Close") 650 p.enableViewLoop = false 651 return nil 652 } 653 654 func (p *Pbft) SignersCount() int { 655 dpos.Info("Pbft SignersCount") 656 count := p.dispatcher.GetConsensusView().GetTotalProducersCount() 657 return count 658 } 659 660 // SealHash returns the hash of a block prior to it being sealed. 661 func SealHash(header *types.Header) (hash common.Hash) { 662 hasher := sha3.NewLegacyKeccak256() 663 encodeSigHeader(hasher, header) 664 hasher.Sum(hash[:0]) 665 return hash 666 } 667 668 func DBlockSealHash(block dpos.DBlock) (hash ecom.Uint256, err error) { 669 if b, ok := block.(*types.Block); ok { 670 hasher := sha3.NewLegacyKeccak256() 671 encodeSigHeader(hasher, b.Header()) 672 hasher.Sum(hash[:0]) 673 return hash, nil 674 } else { 675 return ecom.EmptyHash, errors.New("verifyBlock errror, block is not ethereum block") 676 } 677 } 678 679 func encodeSigHeader(w io.Writer, header *types.Header) { 680 err := rlp.Encode(w, []interface{}{ 681 header.ParentHash, 682 header.UncleHash, 683 header.Coinbase, 684 header.Root, 685 header.TxHash, 686 header.ReceiptHash, 687 header.Bloom, 688 header.Difficulty, 689 header.Number, 690 header.GasLimit, 691 header.GasUsed, 692 header.Time, 693 //header.Extra[:len(header.Extra)-crypto.SignatureLength], // Yes, this will panic if extra is too short 694 header.MixDigest, 695 header.Nonce, 696 }) 697 if err != nil { 698 panic("can't encode: " + err.Error()) 699 } 700 } 701 702 func (p *Pbft) AddDirectLinkPeer(pid peer.PID, addr string) { 703 if p.network != nil { 704 p.network.AddDirectLinkAddr(pid, addr) 705 } 706 } 707 708 func (p *Pbft) GetActivePeersCount() int { 709 if p.network != nil { 710 return len(p.network.GetActivePeers()) 711 } 712 return 0 713 } 714 715 func (p *Pbft) StartServer() { 716 if p.network != nil { 717 p.network.Start() 718 p.Recover() 719 } 720 } 721 722 func (p *Pbft) StopServer() { 723 if p.network != nil { 724 p.network.Stop() 725 } 726 p.enableViewLoop = false 727 } 728 729 func (p *Pbft) Start(headerTime uint64) { 730 if p.account == nil { 731 return 732 } 733 if !p.enableViewLoop { 734 p.enableViewLoop = true 735 p.dispatcher.GetConsensusView().SetChangViewTime(headerTime) 736 p.dispatcher.GetConsensusView().UpdateDutyIndex(p.chain.CurrentBlock().NumberU64()) 737 go p.changeViewLoop() 738 } else { 739 p.dispatcher.ResetView(headerTime) 740 } 741 p.dispatcher.GetConsensusView().SetRunning() 742 } 743 744 func (p *Pbft) changeViewLoop() { 745 for p.enableViewLoop { 746 p.network.PostChangeViewTask() 747 time.Sleep(1 * time.Second) 748 } 749 } 750 751 func (p *Pbft) Recover() { 752 if p.IsCurrent == nil || p.account == nil || p.isRecovering || 753 !p.dispatcher.IsProducer(p.account.PublicKeyBytes()) { 754 log.Info(" Recover Error") 755 p.dispatcher.GetConsensusView().DumpInfo() 756 return 757 } 758 p.isRecovering = true 759 for { 760 if p.IsCurrent() && len(p.network.GetActivePeers()) > 0 && 761 p.dispatcher.GetConsensusView().HasProducerMajorityCount(len(p.network.GetActivePeers())) { 762 log.Info("----- PostRecoverTask --------", "GetActivePeers", len(p.network.GetActivePeers()), "total", len(p.dispatcher.GetConsensusView().GetProducers())) 763 p.network.PostRecoverTask() 764 p.isRecovering = false 765 return 766 } 767 time.Sleep(time.Second) 768 } 769 } 770 771 func (p *Pbft) IsOnduty() bool { 772 if p.account == nil { 773 return false 774 } 775 return p.dispatcher.ProducerIsOnDuty() 776 } 777 778 func (p *Pbft) IsProducer() bool { 779 if p.account == nil { 780 return false 781 } 782 return p.dispatcher.IsProducer(p.account.PublicKeyBytes()) 783 } 784 785 func (p *Pbft) SetBlockChain(chain *core.BlockChain) { 786 p.chain = chain 787 } 788 789 func (p *Pbft) GetBlockChain() *core.BlockChain { 790 return p.chain 791 } 792 793 func (p *Pbft) broadConfirmMsg(confirm *payload.Confirm, height uint64) { 794 msg := dmsg.NewConfirmMsg(confirm, height) 795 p.BroadMessage(msg) 796 } 797 798 func (p *Pbft) verifyConfirm(confirm *payload.Confirm, elaHeight uint64) error { 799 minSignCount := 0 800 if elaHeight == 0 { 801 minSignCount = p.dispatcher.GetConsensusView().GetCRMajorityCount() 802 } else { 803 _, count, err := spv.GetProducers(elaHeight) 804 if err != nil { 805 return err 806 } 807 minSignCount = p.dispatcher.GetConsensusView().GetMajorityCountByTotalSigners(count) 808 } 809 err := dpos.CheckConfirm(confirm, minSignCount) 810 return err 811 } 812 813 func (p *Pbft) verifyBlock(block dpos.DBlock) error { 814 if p.chain == nil { 815 return errors.New("pbft chain is nil") 816 } 817 if b, ok := block.(*types.Block); ok { 818 err := p.VerifyHeader(p.chain, b.Header(), false) 819 if err != nil { 820 return err 821 } 822 err = p.chain.Validator().ValidateBody(b) 823 if err != nil { 824 log.Error("validateBody error", "height:", b.GetHeight()) 825 return err 826 } 827 } else { 828 return errors.New("verifyBlock errror, block is not ethereum block") 829 } 830 831 return nil 832 } 833 834 func (p *Pbft) IsInBlockPool(hash common.Hash) bool { 835 if u256, err := ecom.Uint256FromBytes(hash.Bytes()); err == nil { 836 _, suc := p.blockPool.GetBlock(*u256) 837 return suc 838 } 839 return false 840 } 841 842 func (p *Pbft) CleanFinalConfirmedBlock(height uint64) { 843 p.blockPool.CleanFinalConfirmedBlock(height) 844 } 845 846 func (p *Pbft) OnViewChanged(isOnDuty bool, force bool) { 847 if isOnDuty && p.OnDuty != nil { 848 p.OnDuty() 849 } 850 proposal := p.dispatcher.UpdatePrecociousProposals() 851 if proposal != nil { 852 log.Info("UpdatePrecociousProposals process proposal") 853 p.OnProposalReceived(peer.PID{}, proposal) 854 } 855 856 if !force { 857 p.dispatcher.CleanProposals(true) 858 if p.IsCurrent() && isOnDuty { 859 log.Info("---------startMine()-------") 860 p.dispatcher.GetConsensusView().SetReady() 861 p.StartMine() 862 } 863 } 864 } 865 866 func (p *Pbft) GetTimeSource() dtime.MedianTimeSource { 867 return p.timeSource 868 } 869 870 func (p *Pbft) IsBadBlock(height uint64) bool { 871 blocks := p.chain.BadBlocks() 872 for _, block := range blocks { 873 if block.GetHeight() == height { 874 return true 875 } 876 } 877 return false 878 } 879 880 func (p *Pbft) GetDposAccount() daccount.Account { 881 return p.account 882 } 883 884 func (p *Pbft) IsOnDuty() bool { 885 return p.dispatcher.ProducerIsOnDuty() 886 }