HandlePeerBlock() validates and handles an inbound certificate (with a block) from a remote peer
(msg *lib.BlockMessage, syncing bool)
| 502 | |
| 503 | // HandlePeerBlock() validates and handles an inbound certificate (with a block) from a remote peer |
| 504 | func (c *Controller) HandlePeerBlock(msg *lib.BlockMessage, syncing bool) (*lib.QuorumCertificate, lib.ErrorI) { |
| 505 | // log the start of 'peer block handling' |
| 506 | c.log.Info("Handling peer block") |
| 507 | // define a convenience variable for the certificate |
| 508 | qc := msg.BlockAndCertificate |
| 509 | // do a basic validation on the QC before loading the committee |
| 510 | if err := qc.CheckBasic(); err != nil { |
| 511 | // exit with error |
| 512 | return nil, err |
| 513 | } |
| 514 | // if syncing the blockchain |
| 515 | if syncing { |
| 516 | // use checkpoints to protect against long-range attacks |
| 517 | if qc.Header.Height%CheckpointFrequency == 0 { |
| 518 | // attempt to load the checkpoint from the file |
| 519 | checkpoint := c.checkpointFromFile(qc.Header.Height, qc.Header.ChainId) |
| 520 | // if checkpoint loading from file failed |
| 521 | if checkpoint == nil { |
| 522 | var err lib.ErrorI |
| 523 | // get the checkpoint from the base chain (or file if independent) |
| 524 | checkpoint, err = c.RCManager.GetCheckpoint(c.LoadRootChainId(qc.Header.Height), qc.Header.Height, c.Config.ChainId) |
| 525 | // if getting the checkpoint failed |
| 526 | if err != nil { |
| 527 | // warn of the inability to get the checkpoint |
| 528 | c.log.Warnf(err.Error()) |
| 529 | } |
| 530 | } |
| 531 | // if checkpoint fails |
| 532 | if len(checkpoint) != 0 && !bytes.Equal(qc.BlockHash, checkpoint) { |
| 533 | // log and kill program |
| 534 | c.log.Fatalf("Invalid checkpoint %s vs %s at height %d", lib.BytesToString(qc.BlockHash), checkpoint, qc.Header.Height) |
| 535 | } |
| 536 | } |
| 537 | } else { |
| 538 | // load the committee from the root chain using the root height embedded in the certificate message |
| 539 | v, err := c.Consensus.LoadCommittee(c.LoadRootChainId(qc.Header.Height), qc.Header.RootHeight) |
| 540 | if err != nil { |
| 541 | // exit with error |
| 542 | return nil, err |
| 543 | } |
| 544 | // validate the quorum certificate |
| 545 | isPartialQC, err := qc.Check(v, c.LoadMaxBlockSize(), &lib.View{NetworkId: c.Config.NetworkID, ChainId: c.Config.ChainId}, false) |
| 546 | if err != nil { |
| 547 | // exit with error |
| 548 | return nil, err |
| 549 | } |
| 550 | // if the quorum certificate doesn't have a +2/3rds majority |
| 551 | if isPartialQC { |
| 552 | // exit with error |
| 553 | return nil, lib.ErrNoMaj23() |
| 554 | } |
| 555 | // update the non signer percent for the validators |
| 556 | c.Metrics.UpdateNonSignerPercent(qc.Signature, v) |
| 557 | } |
| 558 | // ensure the proposal inside the quorum certificate is valid at a stateless level |
| 559 | block, err := qc.CheckProposalBasic(c.FSM.Height(), c.Config.NetworkID, c.Config.ChainId) |
| 560 | // if this certificate isn't finalized |
| 561 | if err == nil && qc.Header.Phase != lib.Phase_PRECOMMIT_VOTE { |
no test coverage detected