Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metachain notarizez based on equivalent proofs #6513

Open
wants to merge 17 commits into
base: feat/equivalent-messages
Choose a base branch
from

Conversation

sstanculeanu
Copy link
Collaborator

Reasoning behind the pull request

  • metachain should notarize based on equivalent proofs

Proposed changes

  • update processors

Testing procedure

  • with feat branch

Pre-requisites

Based on the Contributing Guidelines the PR author and the reviewers must check the following requirements are met:

  • was the PR targeted to the correct branch?
  • if this is a larger feature that probably needs more than one PR, is there a feat branch created?
  • if this is a feat branch merging, do all satellite projects have a proper tag inside go.mod?

@@ -639,7 +642,7 @@ func (bp *baseProcessor) sortHeaderHashesForCurrentBlockByNonce(usedInBlock bool

bp.hdrsForCurrBlock.mutHdrsForBlock.RLock()
for metaBlockHash, headerInfo := range bp.hdrsForCurrBlock.hdrHashAndInfo {
if headerInfo.usedInBlock != usedInBlock {
if headerInfo.usedInBlock != usedInBlock || !headerInfo.hasProof {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that if a header is used in block but has no valid proof, then this is an error case
Could you add the condition separately and log an error for that?
in case we end up in this case we need to find out how it happened and fix.
When picking up a header to notarize it, and adding it to usedInBlock then it should have already been checked that there is a valid proof for it.

Copy link
Collaborator Author

@sstanculeanu sstanculeanu Oct 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usedInBlock field is set to true also when shard headers are requested.. it is basically set in advance to true, even though the header is missing.. so maybe the proof would be received later.. not sure if this is possible though

@@ -1081,8 +1089,18 @@ func (mp *metaProcessor) createAndProcessCrossMiniBlocksDstMe(
continue
}

shouldCheckProof := mp.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, currShardHdr.GetEpoch())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the computeLongestChainFromLastNotarized would return I think the chain of headers without the last one (which is considered the confirmation for the last returned one).

Was computeLongestChainFromLastNotarized updated for equivalent proofs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the blockProcessor as well

isBlockAfterEquivalentMessagesFlag := !check.IfNil(lastMetaBlock) &&
mp.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, lastMetaBlock.GetEpoch())
if isBlockAfterEquivalentMessagesFlag {
// for the first block we need to update both the state of the previous one and for current
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and for all future blocks, updateState should be done only for current, not lastMetaBlock.

I would use a different variable e.g finalMetaBlock and not overwrite the lastMetaBlock (that should still point to the last committed meta block not the one currently being committed).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should work as described, updated the variable name for clarity

@@ -1838,6 +1867,20 @@ func (mp *metaProcessor) checkShardHeadersFinality(
continue
}

if mp.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, lastVerifiedHdr.GetEpoch()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this loop is correct, as it does not get to iterate over all shard headers and verify.
it returns either a nil or an error in the first iteration.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, moved this if into the next for loop and switched the return nil into a break

hasProof := mp.proofsPool.HasProof(shardHeader.GetShardID(), shardHeaderHash)
hdrInfoForHash.hasProof = hasProof
if hasProof {
mp.hdrsForCurrBlock.missingHdrsProofs--
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missingHdrsProofs should be decreased if that proof was missing previously and still missing at this step only

e.g you receive a shard hdr which is not part of the metablock (an older block maybe), so here you would end up decreasing the missing headers proofs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the condition, it was not working as expected

@@ -1994,13 +2059,24 @@ func (mp *metaProcessor) computeExistingAndRequestMissingShardHeaders(metaBlock
if hdr.GetNonce() > mp.hdrsForCurrBlock.highestHdrNonce[shardData.ShardID] {
mp.hdrsForCurrBlock.highestHdrNonce[shardData.ShardID] = hdr.GetNonce()
}

if mp.shouldConsiderProofsForNotarization(hdr) {
notarizedShardHdrsBasedOnProofs++
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of incrementing the missing headers proofs, maybe use a map for the missing header proofs, with key the header hash

then you could correctly check which proofs are still missing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

mp.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, headerInfo.hdr.GetEpoch())
hasMissingProof := isBlockAfterEquivalentMessagesFlag && !headerInfo.hasProof
if hasMissingProof {
continue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an error if a header was used in block but has no proof, should not continue but return an error.
If we get such errors, then we need to fix in the place where the headers are notarized, as there should be the check that the notarized headers have the proper proof.

Please check that the shardInfo (createShardInfo) contains the proof for the shard header itself, along with the proof for the previous block.
This means that the shardInfo would change as well to include 2 proofs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated to return error

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated also to use both proofs

core.MetachainShardId,
sp.metaBlockFinality,
)
if !sp.shouldConsiderProofsForNotarization(metaBlock) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on the else, you should at least check that there is a valid proof for this metablock, otherwise add it to the missing proofs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

if mp.hdrsForCurrBlock.missingHdrs == 0 {
mp.hdrsForCurrBlock.missingFinalityAttestingHdrs = mp.requestMissingFinalityAttestingShardHeaders()
if !mp.shouldConsiderProofsForNotarization(shardHeader) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on the else, you should check that there is a valid proof for this header, otherwise add it to the missing proofs.

hasProofForShardHdr := sp.proofsPool.HasProof(core.MetachainShardId, metaBlockHashes[i])
sp.hdrsForCurrBlock.hdrHashAndInfo[string(metaBlockHashes[i])].hasProof = hasProofForShardHdr
if !hasProofForShardHdr {
sp.hdrsForCurrBlock.missingHdrsProofs++
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add the header hash in a map for missing proofs instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved the logic to be based on hasProof field, which is part of a map too

@@ -9,6 +9,7 @@ import (
type hdrForBlock struct {
missingHdrs uint32
missingFinalityAttestingHdrs uint32
missingHdrsProofs uint32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i might help to rename here to indicate that it's num missing

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed it

if len(currShardHdr.GetMiniBlockHeadersWithDst(mp.shardCoordinator.SelfId())) == 0 {
mp.hdrsForCurrBlock.hdrHashAndInfo[string(orderedHdrsHashes[i])] = &hdrInfo{hdr: currShardHdr, usedInBlock: true}
mp.hdrsForCurrBlock.hdrHashAndInfo[string(orderedHdrsHashes[i])] = &hdrInfo{hdr: currShardHdr, usedInBlock: true, hasProof: true}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

split on multiple lines for better visibility? same below

@@ -1081,8 +1089,18 @@ func (mp *metaProcessor) createAndProcessCrossMiniBlocksDstMe(
continue
}

shouldCheckProof := mp.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, currShardHdr.GetEpoch())
hasProofForHdr := mp.proofsPool.HasProof(currShardHdr.GetShardID(), orderedHdrsHashes[i])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think here we should check if HasProof only if shouldCheckProof is true

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct, optimization.. implemented it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adapt also sortHeadersForCurrentBlockByNonce to have hasProof check?

@@ -639,7 +642,7 @@ func (bp *baseProcessor) sortHeaderHashesForCurrentBlockByNonce(usedInBlock bool

bp.hdrsForCurrBlock.mutHdrsForBlock.RLock()
for metaBlockHash, headerInfo := range bp.hdrsForCurrBlock.hdrHashAndInfo {
if headerInfo.usedInBlock != usedInBlock {
if headerInfo.usedInBlock != usedInBlock || !headerInfo.hasProof {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check for enabled flag here?

@@ -1838,6 +1867,20 @@ func (mp *metaProcessor) checkShardHeadersFinality(
continue
}

if mp.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, lastVerifiedHdr.GetEpoch()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it fits better to check proof in checkShardHeadersValidity which is called just before instead of here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should stay here, as here is the place where we check for finality


headerHash := sp.hasher.Compute(string(marshalledHeader))
if !sp.proofsPool.HasProof(header.GetShardID(), headerHash) {
return process.ErrHeaderNotFinal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return a composed error here to indicate also that the proof is missing?

createAndProcessInfo.currMetaHdrHash = orderedMetaBlocksHashes[i]
if len(createAndProcessInfo.currMetaHdr.GetMiniBlockHeadersWithDst(sp.shardCoordinator.SelfId())) == 0 {
sp.hdrsForCurrBlock.hdrHashAndInfo[string(createAndProcessInfo.currMetaHdrHash)] = &hdrInfo{hdr: createAndProcessInfo.currMetaHdr, usedInBlock: true}
sp.hdrsForCurrBlock.hdrHashAndInfo[string(createAndProcessInfo.currMetaHdrHash)] = &hdrInfo{hdr: createAndProcessInfo.currMetaHdr, usedInBlock: true, hasProof: true}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion to expand on multiple lines

Comment on lines 344 to 345
// check proofs for shard data
for _, shardData := range header.ShardInfo {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think here we should do this only if equivalent messages flag is activated

Comment on lines 1957 to 1959
// if there is an entry for the missing proof, it means that proofsPool did not have it while scanning shardData
// thus header epoch was not available at that time
incompleteProof, hasMissingProof := mp.hdrsForCurrBlock.missingProofs[string(shardHeaderHash)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think here also

}

if mp.hdrsForCurrBlock.missingHdrs == 0 {
shouldRequestMissingFinalityAttestingShardHeaders := notarizedShardHdrsBasedOnProofs != len(metaBlock.ShardInfo)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check this only if equivalent flag enabled?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed, here notarizedShardHdrsBasedOnProofs would be 0, thus the second condition will always be true

Comment on lines 296 to 297
// check proofs for shard data
for _, metaBlockHash := range header.GetMetaBlockHashes() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check if proofs activated?

}

if sp.hdrsForCurrBlock.missingHdrs == 0 {
shouldRequestMissingFinalityAttestingMetaHeaders := notarizedMetaHdrsBasedOnProofs != len(metaBlockHashes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add this only if flag activated

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be ok too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants