Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/equivalent-proofs-feat-stabiliza…
Browse files Browse the repository at this point in the history
…tion' into equivalent-proofs-feat-stabilization
  • Loading branch information
AdoAdoAdo committed Jan 14, 2025
2 parents be77f2d + 5495467 commit c3333bb
Show file tree
Hide file tree
Showing 14 changed files with 371 additions and 32 deletions.
52 changes: 52 additions & 0 deletions common/common.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package common

import (
"fmt"

"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/core/check"
"github.com/multiversx/mx-chain-core-go/data"
"github.com/multiversx/mx-chain-go/storage"
"github.com/multiversx/mx-chain-vm-v1_2-go/ipc/marshaling"
)

// IsEpochChangeBlockForFlagActivation returns true if the provided header is the first one after the specified flag's activation
Expand All @@ -24,3 +29,50 @@ func IsFlagEnabledAfterEpochsStartBlock(header data.HeaderHandler, enableEpochsH
func ShouldBlockHavePrevProof(header data.HeaderHandler, enableEpochsHandler EnableEpochsHandler, flag core.EnableEpochFlag) bool {
return IsFlagEnabledAfterEpochsStartBlock(header, enableEpochsHandler, flag) && header.GetNonce() > 1
}

// VerifyProofAgainstHeader verifies the fields on the proof match the ones on the header
func VerifyProofAgainstHeader(proof data.HeaderProofHandler, header data.HeaderHandler) error {
if check.IfNilReflect(proof) {
return ErrInvalidHeaderProof
}

if proof.GetHeaderNonce() != header.GetNonce() {
return fmt.Errorf("%w, nonce mismatch", ErrInvalidHeaderProof)
}
if proof.GetHeaderShardId() != header.GetShardID() {
return fmt.Errorf("%w, shard id mismatch", ErrInvalidHeaderProof)
}
if proof.GetHeaderEpoch() != header.GetEpoch() {
return fmt.Errorf("%w, epoch mismatch", ErrInvalidHeaderProof)
}
if proof.GetHeaderRound() != header.GetRound() {
return fmt.Errorf("%w, round mismatch", ErrInvalidHeaderProof)
}

return nil
}

// GetHeader tries to get the header from pool first and if not found, searches for it through storer
func GetHeader(
headerHash []byte,
headersPool HeadersPool,
headersStorer storage.Storer,
marshaller marshaling.Marshalizer,
) (data.HeaderHandler, error) {
header, err := headersPool.GetHeaderByHash(headerHash)
if err == nil {
return header, nil
}

headerBytes, err := headersStorer.SearchFirst(headerHash)
if err != nil {
return nil, err
}

err = marshaller.Unmarshal(header, headerBytes)
if err != nil {
return nil, err
}

return header, nil
}
3 changes: 3 additions & 0 deletions common/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ var ErrNilWasmChangeLocker = errors.New("nil wasm change locker")

// ErrNilStateSyncNotifierSubscriber signals that a nil state sync notifier subscriber has been provided
var ErrNilStateSyncNotifierSubscriber = errors.New("nil state sync notifier subscriber")

// ErrInvalidHeaderProof signals that an invalid equivalent proof has been provided
var ErrInvalidHeaderProof = errors.New("invalid equivalent proof")
5 changes: 5 additions & 0 deletions common/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,3 +379,8 @@ type ChainParametersSubscriptionHandler interface {
ChainParametersChanged(chainParameters config.ChainParametersByEpochConfig)
IsInterfaceNil() bool
}

// HeadersPool defines what a headers pool structure can perform
type HeadersPool interface {
GetHeaderByHash(hash []byte) (data.HeaderHandler, error)
}
33 changes: 21 additions & 12 deletions consensus/spos/bls/v2/subroundBlock.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,19 +389,27 @@ func isProofEmpty(proof data.HeaderProofHandler) bool {
len(proof.GetHeaderHash()) == 0
}

func (sr *subroundBlock) saveProofForPreviousHeaderIfNeeded(header data.HeaderHandler) {
func (sr *subroundBlock) saveProofForPreviousHeaderIfNeeded(header data.HeaderHandler, prevHeader data.HeaderHandler) {
hasProof := sr.EquivalentProofsPool().HasProof(sr.ShardCoordinator().SelfId(), header.GetPrevHash())
if hasProof {
log.Debug("saveProofForPreviousHeaderIfNeeded: no need to set proof since it is already saved")
return
}

proof := header.GetPreviousProof()
err := sr.EquivalentProofsPool().AddProof(proof)
err := common.VerifyProofAgainstHeader(proof, prevHeader)
if err != nil {
log.Debug("saveProofForPreviousHeaderIfNeeded: invalid proof, %w", err)
return
}

err = sr.EquivalentProofsPool().AddProof(proof)
if err != nil {
log.Debug("saveProofForPreviousHeaderIfNeeded: failed to add proof, %w", err)
return
}

return

Check failure on line 412 in consensus/spos/bls/v2/subroundBlock.go

View workflow job for this annotation

GitHub Actions / golangci linter

S1023: redundant `return` statement (gosimple)
}

// receivedBlockBody method is called when a block body is received through the block body channel
Expand Down Expand Up @@ -445,30 +453,30 @@ func (sr *subroundBlock) receivedBlockBody(ctx context.Context, cnsDta *consensu
return blockProcessedWithSuccess
}

func (sr *subroundBlock) isHeaderForCurrentConsensus(header data.HeaderHandler) bool {
func (sr *subroundBlock) isHeaderForCurrentConsensus(header data.HeaderHandler) (bool, data.HeaderHandler) {
if check.IfNil(header) {
return false
return false, nil
}
if header.GetShardID() != sr.ShardCoordinator().SelfId() {
return false
return false, nil
}
if header.GetRound() != uint64(sr.RoundHandler().Index()) {
return false
return false, nil
}

prevHeader, prevHash := sr.getPrevHeaderAndHash()
if check.IfNil(prevHeader) {
return false
return false, nil
}
if !bytes.Equal(header.GetPrevHash(), prevHash) {
return false
return false, nil
}
if header.GetNonce() != prevHeader.GetNonce()+1 {
return false
return false, nil
}
prevRandSeed := prevHeader.GetRandSeed()

return bytes.Equal(header.GetPrevRandSeed(), prevRandSeed)
return bytes.Equal(header.GetPrevRandSeed(), prevRandSeed), prevHeader
}

func (sr *subroundBlock) getLeaderForHeader(headerHandler data.HeaderHandler) ([]byte, error) {
Expand All @@ -495,7 +503,8 @@ func (sr *subroundBlock) receivedBlockHeader(headerHandler data.HeaderHandler) {
return
}

if !sr.isHeaderForCurrentConsensus(headerHandler) {
isHeaderForCurrentConsensus, prevHeader := sr.isHeaderForCurrentConsensus(headerHandler)
if !isHeaderForCurrentConsensus {
return
}

Expand Down Expand Up @@ -539,7 +548,7 @@ func (sr *subroundBlock) receivedBlockHeader(headerHandler data.HeaderHandler) {
sr.SetData(sr.Hasher().Compute(string(marshalledHeader)))
sr.SetHeader(headerHandler)

sr.saveProofForPreviousHeaderIfNeeded(headerHandler)
sr.saveProofForPreviousHeaderIfNeeded(headerHandler, prevHeader)

log.Debug("step 1: block header has been received",
"nonce", sr.GetHeader().GetNonce(),
Expand Down
11 changes: 10 additions & 1 deletion process/block/baseProcess.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,16 @@ func (bp *baseProcessor) checkBlockValidity(
return process.ErrEpochDoesNotMatch
}

return nil
return bp.checkPrevProofValidity(currentBlockHeader, headerHandler)
}

func (bp *baseProcessor) checkPrevProofValidity(prevHeader, headerHandler data.HeaderHandler) error {
if !common.ShouldBlockHavePrevProof(headerHandler, bp.enableEpochsHandler, common.EquivalentMessagesFlag) {
return nil
}

prevProof := headerHandler.GetPreviousProof()
return common.VerifyProofAgainstHeader(prevProof, prevHeader)
}

// checkScheduledRootHash checks if the scheduled root hash from the given header is the same with the current user accounts state root hash
Expand Down
45 changes: 45 additions & 0 deletions process/block/interceptedBlocks/interceptedEquivalentProof.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package interceptedBlocks

import (
"encoding/hex"
"fmt"

"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/core/check"
"github.com/multiversx/mx-chain-core-go/data"
"github.com/multiversx/mx-chain-core-go/data/block"
"github.com/multiversx/mx-chain-core-go/marshal"
"github.com/multiversx/mx-chain-go/common"
"github.com/multiversx/mx-chain-go/consensus"
"github.com/multiversx/mx-chain-go/dataRetriever"
proofscache "github.com/multiversx/mx-chain-go/dataRetriever/dataPool/proofsCache"
"github.com/multiversx/mx-chain-go/process"
"github.com/multiversx/mx-chain-go/sharding"
"github.com/multiversx/mx-chain-go/storage"
logger "github.com/multiversx/mx-chain-logger-go"
"github.com/multiversx/mx-chain-vm-v1_2-go/ipc/marshaling"
)

const interceptedEquivalentProofType = "intercepted equivalent proof"
Expand All @@ -25,13 +29,18 @@ type ArgInterceptedEquivalentProof struct {
ShardCoordinator sharding.Coordinator
HeaderSigVerifier consensus.HeaderSigVerifier
Proofs dataRetriever.ProofsPool
Headers dataRetriever.HeadersPool
Storage dataRetriever.StorageService
}

type interceptedEquivalentProof struct {
proof *block.HeaderProof
isForCurrentShard bool
headerSigVerifier consensus.HeaderSigVerifier
proofsPool dataRetriever.ProofsPool
headersPool dataRetriever.HeadersPool
storage dataRetriever.StorageService
marshaller marshaling.Marshalizer
}

// NewInterceptedEquivalentProof returns a new instance of interceptedEquivalentProof
Expand All @@ -51,6 +60,9 @@ func NewInterceptedEquivalentProof(args ArgInterceptedEquivalentProof) (*interce
isForCurrentShard: extractIsForCurrentShard(args.ShardCoordinator, equivalentProof),
headerSigVerifier: args.HeaderSigVerifier,
proofsPool: args.Proofs,
headersPool: args.Headers,
marshaller: args.Marshaller,
storage: args.Storage,
}, nil
}

Expand All @@ -70,6 +82,12 @@ func checkArgInterceptedEquivalentProof(args ArgInterceptedEquivalentProof) erro
if check.IfNil(args.Proofs) {
return process.ErrNilProofsPool
}
if check.IfNil(args.Headers) {
return process.ErrNilHeadersDataPool
}
if check.IfNil(args.Storage) {
return process.ErrNilStore
}

return nil
}
Expand Down Expand Up @@ -115,9 +133,28 @@ func (iep *interceptedEquivalentProof) CheckValidity() error {
return proofscache.ErrAlreadyExistingEquivalentProof
}

err = iep.checkHeaderParamsFromProof()
if err != nil {
return err
}

return iep.headerSigVerifier.VerifyHeaderProof(iep.proof)
}

func (iep *interceptedEquivalentProof) checkHeaderParamsFromProof() error {
headersStorer, err := iep.getHeadersStorer(iep.proof.GetHeaderShardId())
if err != nil {
return err
}

header, err := common.GetHeader(iep.proof.GetHeaderHash(), iep.headersPool, headersStorer, iep.marshaller)
if err != nil {
return fmt.Errorf("%w while getting header for proof hash %s", err, hex.EncodeToString(iep.proof.GetHeaderHash()))
}

return common.VerifyProofAgainstHeader(iep.proof, header)
}

func (iep *interceptedEquivalentProof) integrity() error {
isProofValid := len(iep.proof.AggregatedSignature) > 0 &&
len(iep.proof.PubKeysBitmap) > 0 &&
Expand All @@ -129,6 +166,14 @@ func (iep *interceptedEquivalentProof) integrity() error {
return nil
}

func (iep *interceptedEquivalentProof) getHeadersStorer(shardID uint32) (storage.Storer, error) {
if shardID == core.MetachainShardId {
return iep.storage.GetStorer(dataRetriever.MetaBlockUnit)
}

return iep.storage.GetStorer(dataRetriever.BlockHeaderUnit)
}

// GetProof returns the underlying intercepted header proof
func (iep *interceptedEquivalentProof) GetProof() data.HeaderProofHandler {
return iep.proof
Expand Down
Loading

0 comments on commit c3333bb

Please sign in to comment.