use of org.hyperledger.besu.ethereum.core.Block in project besu by hyperledger.
the class ProposalValidator method validateProposalAndRoundChangeAreConsistent.
private boolean validateProposalAndRoundChangeAreConsistent(final Proposal proposal) {
final ConsensusRoundIdentifier proposalRoundIdentifier = proposal.getRoundIdentifier();
if (proposalRoundIdentifier.getRoundNumber() == 0) {
if (!validateRoundZeroProposalHasNoRoundChangesOrPrepares(proposal)) {
return false;
}
return validateBlockCoinbaseMatchesMsgAuthor(proposal);
} else {
if (!validateRoundChanges(proposal, proposal.getRoundChanges())) {
LOG.info("{}: failed to validate piggy-backed round change payloads", ERROR_PREFIX);
return false;
}
// The RoundChangePayloadValidator ensures the PreparedRound is less than targetRound
// therefore, no need to validate that here.
final Optional<SignedData<RoundChangePayload>> roundChangeWithLatestPreparedRound = getRoundChangeWithLatestPreparedRound(proposal.getRoundChanges());
if (roundChangeWithLatestPreparedRound.isPresent()) {
final PreparedRoundMetadata metadata = roundChangeWithLatestPreparedRound.get().getPayload().getPreparedRoundMetadata().get();
// The Hash in the roundchange/proposals is NOT the same as the value in the
// prepares/roundchanges
// as said payloads reference the block with an OLD round number in it - therefore, need
// to create a block with the old round in it, then re-calc expected hash
// Need to check that if we substitute the LatestPrepareCert round number into the supplied
// block that we get the SAME hash as PreparedCert.
final BftBlockInterface bftBlockInterface = protocolContext.getConsensusContext(BftContext.class).getBlockInterface();
final Block currentBlockWithOldRound = bftBlockInterface.replaceRoundInBlock(proposal.getBlock(), metadata.getPreparedRound(), BftBlockHeaderFunctions.forCommittedSeal(bftExtraDataCodec));
final Hash expectedPriorBlockHash = currentBlockWithOldRound.getHash();
if (!metadata.getPreparedBlockHash().equals(expectedPriorBlockHash)) {
LOG.info("{}: Latest Prepared Metadata blockhash does not align with proposed block", ERROR_PREFIX);
return false;
}
// validate the prepares
if (!validatePrepares(metadata, proposal.getRoundIdentifier().getSequenceNumber(), proposal.getPrepares())) {
LOG.info("{}: Piggy-backed prepares failed validation", ERROR_PREFIX);
return false;
}
} else {
// no one prepared, so prepares should be empty
if (!proposal.getPrepares().isEmpty()) {
LOG.info("{}: No PreparedMetadata exists, so prepare list must be empty", ERROR_PREFIX);
return false;
}
return validateBlockCoinbaseMatchesMsgAuthor(proposal);
}
return true;
}
}
use of org.hyperledger.besu.ethereum.core.Block in project besu by hyperledger.
the class QbftRound method startRoundWith.
public void startRoundWith(final RoundChangeArtifacts roundChangeArtifacts, final long headerTimestamp) {
final Optional<PreparedCertificate> bestPreparedCertificate = roundChangeArtifacts.getBestPreparedPeer();
Block blockToPublish;
if (bestPreparedCertificate.isEmpty()) {
LOG.debug("Sending proposal with new block. round={}", roundState.getRoundIdentifier());
blockToPublish = blockCreator.createBlock(headerTimestamp);
} else {
LOG.debug("Sending proposal from PreparedCertificate. round={}", roundState.getRoundIdentifier());
blockToPublish = bestPreparedCertificate.get().getBlock();
}
updateStateWithProposalAndTransmit(blockToPublish, roundChangeArtifacts.getRoundChanges(), bestPreparedCertificate.map(PreparedCertificate::getPrepares).orElse(emptyList()));
}
use of org.hyperledger.besu.ethereum.core.Block in project besu by hyperledger.
the class QbftRound method handleProposalMessage.
public void handleProposalMessage(final Proposal msg) {
LOG.debug("Received a proposal message. round={}. author={}", roundState.getRoundIdentifier(), msg.getAuthor());
final Block block = msg.getSignedPayload().getPayload().getProposedBlock();
if (updateStateWithProposedBlock(msg)) {
sendPrepare(block);
}
}
use of org.hyperledger.besu.ethereum.core.Block in project besu by hyperledger.
the class QbftRound method peerIsPrepared.
private void peerIsPrepared(final Prepare msg) {
final boolean wasPrepared = roundState.isPrepared();
roundState.addPrepareMessage(msg);
if (wasPrepared != roundState.isPrepared()) {
LOG.debug("Sending commit message. round={}", roundState.getRoundIdentifier());
final Block block = roundState.getProposedBlock().get();
try {
transmitter.multicastCommit(getRoundIdentifier(), block.getHash(), createCommitSeal(block));
// Note: the local-node's commit message was added to RoundState on block acceptance
// and thus does not need to be done again here.
} catch (final SecurityModuleException e) {
LOG.warn("Failed to construct a commit seal: {}", e.getMessage());
}
}
}
use of org.hyperledger.besu.ethereum.core.Block in project besu by hyperledger.
the class QbftRound method updateStateWithProposedBlock.
private boolean updateStateWithProposedBlock(final Proposal msg) {
final boolean wasPrepared = roundState.isPrepared();
final boolean wasCommitted = roundState.isCommitted();
final boolean blockAccepted = roundState.setProposedBlock(msg);
if (blockAccepted) {
final Block block = roundState.getProposedBlock().get();
final SECPSignature commitSeal;
try {
commitSeal = createCommitSeal(block);
} catch (final SecurityModuleException e) {
LOG.warn("Failed to construct commit seal; {}", e.getMessage());
return true;
}
// There are times handling a proposed block is enough to enter prepared.
if (wasPrepared != roundState.isPrepared()) {
LOG.debug("Sending commit message. round={}", roundState.getRoundIdentifier());
transmitter.multicastCommit(getRoundIdentifier(), block.getHash(), commitSeal);
}
// prepare
try {
final Commit localCommitMessage = messageFactory.createCommit(roundState.getRoundIdentifier(), msg.getBlock().getHash(), commitSeal);
roundState.addCommitMessage(localCommitMessage);
} catch (final SecurityModuleException e) {
LOG.warn("Failed to create signed Commit message; {}", e.getMessage());
return true;
}
// It is possible sufficient commit seals are now available and the block should be imported
if (wasCommitted != roundState.isCommitted()) {
importBlockToChain();
}
}
return blockAccepted;
}
Aggregations