From ff6b430b2cbeacdecffe90b7dc412f40174a27f4 Mon Sep 17 00:00:00 2001 From: camilbancioiu Date: Wed, 14 Aug 2019 17:25:58 +0300 Subject: [PATCH] feat/EN-3483-merge-header-interceptors (#344) * Merge structs HeaderInterceptor, HeaderInterceptorBase and ShardHeaderInterceptor into one struct and remove HeaderInterceptorBase and ShardHeaderInterceptor * Add some extra tests from headerInterceptorBase_test.go (WORK IN PROGRESS) * Merge tests from headerInterceptorBase_test.go and shardHeaderInterceptor_test.go into headerInterceptor_test.go * Unexport function CheckHeaderForCurrentShard() * Fix failing test and update comment * Add extra tests for the constructor NewHeaderInterceptor() --- .../block/interceptors/headerInterceptor.go | 98 ++++- .../interceptors/headerInterceptorBase.go | 101 ----- .../headerInterceptorBase_test.go | 268 ------------- .../interceptors/headerInterceptor_test.go | 360 ++++++++++++++++++ .../metachain/interceptorsContainerFactory.go | 3 +- process/metablock/shardHeaderInterceptor.go | 99 ----- .../metablock/shardHeaderInterceptor_test.go | 297 --------------- 7 files changed, 438 insertions(+), 788 deletions(-) delete mode 100644 process/block/interceptors/headerInterceptorBase.go delete mode 100644 process/block/interceptors/headerInterceptorBase_test.go delete mode 100644 process/metablock/shardHeaderInterceptor.go delete mode 100644 process/metablock/shardHeaderInterceptor_test.go diff --git a/process/block/interceptors/headerInterceptor.go b/process/block/interceptors/headerInterceptor.go index 85b52a3817e..768f4b97fba 100644 --- a/process/block/interceptors/headerInterceptor.go +++ b/process/block/interceptors/headerInterceptor.go @@ -15,10 +15,15 @@ import ( // HeaderInterceptor represents an interceptor used for block headers type HeaderInterceptor struct { - hdrInterceptorBase *HeaderInterceptorBase - headers storage.Cacher - headersNonces dataRetriever.Uint64SyncMapCacher - shardCoordinator sharding.Coordinator + marshalizer marshal.Marshalizer + storer storage.Storer + multiSigVerifier crypto.MultiSigVerifier + hasher hashing.Hasher + chronologyValidator process.ChronologyValidator + headers storage.Cacher + headersNonces dataRetriever.Uint64SyncMapCacher + headerValidator process.HeaderValidator + shardCoordinator sharding.Coordinator } // NewHeaderInterceptor hooks a new interceptor for block headers @@ -34,38 +39,81 @@ func NewHeaderInterceptor( chronologyValidator process.ChronologyValidator, ) (*HeaderInterceptor, error) { + if marshalizer == nil { + return nil, process.ErrNilMarshalizer + } if headersNonces == nil { return nil, process.ErrNilHeadersNoncesDataPool } if headers == nil { return nil, process.ErrNilHeadersDataPool } - hdrBaseInterceptor, err := NewHeaderInterceptorBase( - marshalizer, - headerValidator, - multiSigVerifier, - hasher, - shardCoordinator, - chronologyValidator, - ) + if headerValidator == nil { + return nil, process.ErrNilHeaderHandlerValidator + } + if multiSigVerifier == nil { + return nil, process.ErrNilMultiSigVerifier + } + if hasher == nil { + return nil, process.ErrNilHasher + } + if shardCoordinator == nil { + return nil, process.ErrNilShardCoordinator + } + if chronologyValidator == nil { + return nil, process.ErrNilChronologyValidator + } + + hdrInterceptor := &HeaderInterceptor{ + marshalizer: marshalizer, + multiSigVerifier: multiSigVerifier, + hasher: hasher, + shardCoordinator: shardCoordinator, + chronologyValidator: chronologyValidator, + headers: headers, + headersNonces: headersNonces, + headerValidator: headerValidator, + } + + return hdrInterceptor, nil +} + +// ParseReceivedMessage will transform the received p2p.Message in an InterceptedHeader. +// If the header hash is present in storage it will output an error +func (hi *HeaderInterceptor) ParseReceivedMessage(message p2p.MessageP2P) (*block.InterceptedHeader, error) { + if message == nil { + return nil, process.ErrNilMessage + } + if message.Data() == nil { + return nil, process.ErrNilDataToProcess + } + + hdrIntercepted := block.NewInterceptedHeader(hi.multiSigVerifier, hi.chronologyValidator) + err := hi.marshalizer.Unmarshal(hdrIntercepted, message.Data()) + if err != nil { + return nil, err + } + + hashWithSig := hi.hasher.Compute(string(message.Data())) + hdrIntercepted.SetHash(hashWithSig) + + err = hdrIntercepted.IntegrityAndValidity(hi.shardCoordinator) if err != nil { return nil, err } - hdrIntercept := &HeaderInterceptor{ - hdrInterceptorBase: hdrBaseInterceptor, - headers: headers, - headersNonces: headersNonces, - shardCoordinator: shardCoordinator, + err = hdrIntercepted.VerifySig() + if err != nil { + return nil, err } - return hdrIntercept, nil + return hdrIntercepted, nil } // ProcessReceivedMessage will be the callback func from the p2p.Messenger and will be called each time a new message was received // (for the topic this validator was registered to) func (hi *HeaderInterceptor) ProcessReceivedMessage(message p2p.MessageP2P) error { - hdrIntercepted, err := hi.hdrInterceptorBase.ParseReceivedMessage(message) + hdrIntercepted, err := hi.ParseReceivedMessage(message) if err != nil { return err } @@ -75,12 +123,20 @@ func (hi *HeaderInterceptor) ProcessReceivedMessage(message p2p.MessageP2P) erro return nil } +// checkHeaderForCurrentShard checks if the header is for current shard +func (hi *HeaderInterceptor) checkHeaderForCurrentShard(interceptedHdr *block.InterceptedHeader) bool { + isHeaderForCurrentShard := hi.shardCoordinator.SelfId() == interceptedHdr.GetHeader().ShardId + isMetachainShardCoordinator := hi.shardCoordinator.SelfId() == sharding.MetachainShardId + + return isHeaderForCurrentShard || isMetachainShardCoordinator +} + func (hi *HeaderInterceptor) processHeader(hdrIntercepted *block.InterceptedHeader) { - if !hi.hdrInterceptorBase.CheckHeaderForCurrentShard(hdrIntercepted) { + if !hi.checkHeaderForCurrentShard(hdrIntercepted) { return } - isHeaderOkForProcessing := hi.hdrInterceptorBase.headerValidator.IsHeaderValidForProcessing(hdrIntercepted.Header) + isHeaderOkForProcessing := hi.headerValidator.IsHeaderValidForProcessing(hdrIntercepted.Header) if !isHeaderOkForProcessing { log.Debug("intercepted block header can not be processed") return diff --git a/process/block/interceptors/headerInterceptorBase.go b/process/block/interceptors/headerInterceptorBase.go deleted file mode 100644 index afb3e89f011..00000000000 --- a/process/block/interceptors/headerInterceptorBase.go +++ /dev/null @@ -1,101 +0,0 @@ -package interceptors - -import ( - "github.com/ElrondNetwork/elrond-go/crypto" - "github.com/ElrondNetwork/elrond-go/hashing" - "github.com/ElrondNetwork/elrond-go/marshal" - "github.com/ElrondNetwork/elrond-go/p2p" - "github.com/ElrondNetwork/elrond-go/process" - "github.com/ElrondNetwork/elrond-go/process/block" - "github.com/ElrondNetwork/elrond-go/sharding" -) - -// HeaderInterceptorBase is the "abstract class" extended in HeaderInterceptor and ShardHeaderInterceptor -type HeaderInterceptorBase struct { - marshalizer marshal.Marshalizer - headerValidator process.HeaderValidator - multiSigVerifier crypto.MultiSigVerifier - hasher hashing.Hasher - shardCoordinator sharding.Coordinator - chronologyValidator process.ChronologyValidator -} - -// NewHeaderInterceptorBase creates a new HeaderIncterceptorBase instance -func NewHeaderInterceptorBase( - marshalizer marshal.Marshalizer, - headerValidator process.HeaderValidator, - multiSigVerifier crypto.MultiSigVerifier, - hasher hashing.Hasher, - shardCoordinator sharding.Coordinator, - chronologyValidator process.ChronologyValidator, -) (*HeaderInterceptorBase, error) { - if marshalizer == nil { - return nil, process.ErrNilMarshalizer - } - if headerValidator == nil { - return nil, process.ErrNilHeaderHandlerValidator - } - if multiSigVerifier == nil { - return nil, process.ErrNilMultiSigVerifier - } - if hasher == nil { - return nil, process.ErrNilHasher - } - if shardCoordinator == nil { - return nil, process.ErrNilShardCoordinator - } - if chronologyValidator == nil { - return nil, process.ErrNilChronologyValidator - } - - hdrIntercept := &HeaderInterceptorBase{ - marshalizer: marshalizer, - headerValidator: headerValidator, - multiSigVerifier: multiSigVerifier, - hasher: hasher, - shardCoordinator: shardCoordinator, - chronologyValidator: chronologyValidator, - } - - return hdrIntercept, nil -} - -// ParseReceivedMessage will transform the received p2p.Message in an InterceptedHeader. -// If the header hash is present in storage it will output an error -func (hib *HeaderInterceptorBase) ParseReceivedMessage(message p2p.MessageP2P) (*block.InterceptedHeader, error) { - if message == nil { - return nil, process.ErrNilMessage - } - if message.Data() == nil { - return nil, process.ErrNilDataToProcess - } - - hdrIntercepted := block.NewInterceptedHeader(hib.multiSigVerifier, hib.chronologyValidator) - err := hib.marshalizer.Unmarshal(hdrIntercepted, message.Data()) - if err != nil { - return nil, err - } - - hashWithSig := hib.hasher.Compute(string(message.Data())) - hdrIntercepted.SetHash(hashWithSig) - - err = hdrIntercepted.IntegrityAndValidity(hib.shardCoordinator) - if err != nil { - return nil, err - } - - err = hdrIntercepted.VerifySig() - if err != nil { - return nil, err - } - - return hdrIntercepted, nil -} - -// CheckHeaderForCurrentShard checks if the header is for current shard -func (hib *HeaderInterceptorBase) CheckHeaderForCurrentShard(interceptedHdr *block.InterceptedHeader) bool { - isHeaderForCurrentShard := hib.shardCoordinator.SelfId() == interceptedHdr.GetHeader().ShardId - isMetachainShardCoordinator := hib.shardCoordinator.SelfId() == sharding.MetachainShardId - - return isHeaderForCurrentShard || isMetachainShardCoordinator -} diff --git a/process/block/interceptors/headerInterceptorBase_test.go b/process/block/interceptors/headerInterceptorBase_test.go deleted file mode 100644 index bd20f797cc6..00000000000 --- a/process/block/interceptors/headerInterceptorBase_test.go +++ /dev/null @@ -1,268 +0,0 @@ -package interceptors_test - -import ( - "errors" - "testing" - - "github.com/ElrondNetwork/elrond-go/data" - dataBlock "github.com/ElrondNetwork/elrond-go/data/block" - "github.com/ElrondNetwork/elrond-go/process" - "github.com/ElrondNetwork/elrond-go/process/block" - "github.com/ElrondNetwork/elrond-go/process/block/interceptors" - "github.com/ElrondNetwork/elrond-go/process/mock" - "github.com/stretchr/testify/assert" -) - -//------- NewHeaderInterceptorBase - -func TestNewHeaderInterceptorBase_NilMarshalizerShouldErr(t *testing.T) { - t.Parallel() - - hi, err := interceptors.NewHeaderInterceptorBase( - nil, - &mock.HeaderValidatorStub{}, - mock.NewMultiSigner(), - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - assert.Equal(t, process.ErrNilMarshalizer, err) - assert.Nil(t, hi) -} - -func TestNewHeaderInterceptorBase_NilHeaderHandlerValidatorShouldErr(t *testing.T) { - t.Parallel() - - hi, err := interceptors.NewHeaderInterceptorBase( - &mock.MarshalizerMock{}, - nil, - mock.NewMultiSigner(), - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - assert.Equal(t, process.ErrNilHeaderHandlerValidator, err) - assert.Nil(t, hi) -} - -func TestNewHeaderInterceptorBase_NilMultiSignerShouldErr(t *testing.T) { - t.Parallel() - - hi, err := interceptors.NewHeaderInterceptorBase( - &mock.MarshalizerMock{}, - &mock.HeaderValidatorStub{}, - nil, - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - assert.Nil(t, hi) - assert.Equal(t, process.ErrNilMultiSigVerifier, err) -} - -func TestNewHeaderInterceptorBase_NilHasherShouldErr(t *testing.T) { - t.Parallel() - - headerValidator := &mock.HeaderValidatorStub{} - hi, err := interceptors.NewHeaderInterceptorBase( - &mock.MarshalizerMock{}, - headerValidator, - mock.NewMultiSigner(), - nil, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - assert.Equal(t, process.ErrNilHasher, err) - assert.Nil(t, hi) -} - -func TestNewHeaderInterceptorBase_NilShardCoordinatorShouldErr(t *testing.T) { - t.Parallel() - - headerValidator := &mock.HeaderValidatorStub{} - hi, err := interceptors.NewHeaderInterceptorBase( - &mock.MarshalizerMock{}, - headerValidator, - mock.NewMultiSigner(), - mock.HasherMock{}, - nil, - &mock.ChronologyValidatorStub{}, - ) - - assert.Equal(t, process.ErrNilShardCoordinator, err) - assert.Nil(t, hi) -} - -func TestNewHeaderInterceptorBase_OkValsShouldWork(t *testing.T) { - t.Parallel() - - headerValidator := &mock.HeaderValidatorStub{} - hib, err := interceptors.NewHeaderInterceptorBase( - &mock.MarshalizerMock{}, - headerValidator, - mock.NewMultiSigner(), - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - assert.Nil(t, err) - assert.NotNil(t, hib) -} - -//------- ProcessReceivedMessage - -func TestHeaderInterceptorBase_ParseReceivedMessageNilMessageShouldErr(t *testing.T) { - t.Parallel() - - headerValidator := &mock.HeaderValidatorStub{} - hib, _ := interceptors.NewHeaderInterceptorBase( - &mock.MarshalizerMock{}, - headerValidator, - mock.NewMultiSigner(), - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - hdr, err := hib.ParseReceivedMessage(nil) - - assert.Nil(t, hdr) - assert.Equal(t, process.ErrNilMessage, err) -} - -func TestHeaderInterceptorBase_ParseReceivedMessageNilDataToProcessShouldErr(t *testing.T) { - t.Parallel() - - headerValidator := &mock.HeaderValidatorStub{} - hib, _ := interceptors.NewHeaderInterceptorBase( - &mock.MarshalizerMock{}, - headerValidator, - mock.NewMultiSigner(), - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - msg := &mock.P2PMessageMock{} - hdr, err := hib.ParseReceivedMessage(msg) - - assert.Nil(t, hdr) - assert.Equal(t, process.ErrNilDataToProcess, err) -} - -func TestHeaderInterceptorBase_ParseReceivedMessageMarshalizerErrorsAtUnmarshalingShouldErr(t *testing.T) { - t.Parallel() - - errMarshalizer := errors.New("marshalizer error") - - headerValidator := &mock.HeaderValidatorStub{} - hib, _ := interceptors.NewHeaderInterceptorBase( - &mock.MarshalizerStub{ - UnmarshalCalled: func(obj interface{}, buff []byte) error { - return errMarshalizer - }, - }, - headerValidator, - mock.NewMultiSigner(), - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - msg := &mock.P2PMessageMock{ - DataField: make([]byte, 0), - } - hdr, err := hib.ParseReceivedMessage(msg) - - assert.Nil(t, hdr) - assert.Equal(t, errMarshalizer, err) -} - -func TestHeaderInterceptorBase_ParseReceivedMessageSanityCheckFailedShouldErr(t *testing.T) { - t.Parallel() - - headerValidator := &mock.HeaderValidatorStub{} - marshalizer := &mock.MarshalizerMock{} - multisigner := mock.NewMultiSigner() - chronologyValidator := &mock.ChronologyValidatorStub{ - ValidateReceivedBlockCalled: func(shardID uint32, epoch uint32, nonce uint64, round uint64) error { - return nil - }, - } - hib, _ := interceptors.NewHeaderInterceptorBase( - marshalizer, - headerValidator, - multisigner, - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - chronologyValidator, - ) - - hdr := block.NewInterceptedHeader(multisigner, chronologyValidator) - buff, _ := marshalizer.Marshal(hdr) - msg := &mock.P2PMessageMock{ - DataField: buff, - } - hdr, err := hib.ParseReceivedMessage(msg) - - assert.Nil(t, hdr) - assert.Equal(t, process.ErrNilPubKeysBitmap, err) -} - -func TestHeaderInterceptorBase_ParseReceivedMessageValsOkShouldWork(t *testing.T) { - t.Parallel() - - marshalizer := &mock.MarshalizerMock{} - testedNonce := uint64(67) - multisigner := mock.NewMultiSigner() - chronologyValidator := &mock.ChronologyValidatorStub{ - ValidateReceivedBlockCalled: func(shardID uint32, epoch uint32, nonce uint64, round uint64) error { - return nil - }, - } - headerValidator := &mock.HeaderValidatorStub{ - IsHeaderValidForProcessingCalled: func(headerHandler data.HeaderHandler) bool { - return true - }, - } - hib, _ := interceptors.NewHeaderInterceptorBase( - marshalizer, - headerValidator, - multisigner, - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - chronologyValidator, - ) - - hdr := block.NewInterceptedHeader(multisigner, chronologyValidator) - hdr.Nonce = testedNonce - hdr.ShardId = 0 - hdr.PrevHash = make([]byte, 0) - hdr.PubKeysBitmap = make([]byte, 0) - hdr.BlockBodyType = dataBlock.TxBlock - hdr.Signature = make([]byte, 0) - hdr.SetHash([]byte("aaa")) - hdr.RootHash = make([]byte, 0) - hdr.PrevRandSeed = make([]byte, 0) - hdr.RandSeed = make([]byte, 0) - hdr.MiniBlockHeaders = make([]dataBlock.MiniBlockHeader, 0) - - buff, _ := marshalizer.Marshal(hdr) - msg := &mock.P2PMessageMock{ - DataField: buff, - } - - hdrIntercepted, err := hib.ParseReceivedMessage(msg) - if hdrIntercepted != nil { - //hdrIntercepted will have a "real" hash computed - hdrIntercepted.SetHash(hdr.Hash()) - } - - assert.Equal(t, hdr, hdrIntercepted) - assert.Nil(t, err) -} diff --git a/process/block/interceptors/headerInterceptor_test.go b/process/block/interceptors/headerInterceptor_test.go index 027a229147f..7e5d84b9e9f 100644 --- a/process/block/interceptors/headerInterceptor_test.go +++ b/process/block/interceptors/headerInterceptor_test.go @@ -2,6 +2,7 @@ package interceptors_test import ( "bytes" + "errors" "sync" "testing" "time" @@ -84,6 +85,115 @@ func TestNewHeaderInterceptor_NilHeadersNoncesShouldErr(t *testing.T) { assert.Nil(t, hi) } +func TestNewHeaderInterceptor_NilHeaderHandlerValidatorShouldErr(t *testing.T) { + t.Parallel() + + headers := &mock.CacherStub{} + headersNonces := &mock.Uint64SyncMapCacherStub{} + + hi, err := interceptors.NewHeaderInterceptor( + &mock.MarshalizerMock{}, + headers, + headersNonces, + nil, + mock.NewMultiSigner(), + mock.HasherMock{}, + mock.NewOneShardCoordinatorMock(), + &mock.ChronologyValidatorStub{}, + ) + + assert.Equal(t, process.ErrNilHeaderHandlerValidator, err) + assert.Nil(t, hi) +} + +func TestNewHeaderInterceptor_NilMultiSignerShouldErr(t *testing.T) { + t.Parallel() + + headers := &mock.CacherStub{} + headersNonces := &mock.Uint64SyncMapCacherStub{} + headerValidator := &mock.HeaderValidatorStub{} + + hi, err := interceptors.NewHeaderInterceptor( + &mock.MarshalizerMock{}, + headers, + headersNonces, + headerValidator, + nil, + mock.HasherMock{}, + mock.NewOneShardCoordinatorMock(), + &mock.ChronologyValidatorStub{}, + ) + + assert.Equal(t, process.ErrNilMultiSigVerifier, err) + assert.Nil(t, hi) +} + +func TestNewHeaderInterceptor_NilHasherShouldErr(t *testing.T) { + t.Parallel() + + headers := &mock.CacherStub{} + headersNonces := &mock.Uint64SyncMapCacherStub{} + headerValidator := &mock.HeaderValidatorStub{} + + hi, err := interceptors.NewHeaderInterceptor( + &mock.MarshalizerMock{}, + headers, + headersNonces, + headerValidator, + mock.NewMultiSigner(), + nil, + mock.NewOneShardCoordinatorMock(), + &mock.ChronologyValidatorStub{}, + ) + + assert.Equal(t, process.ErrNilHasher, err) + assert.Nil(t, hi) +} + +func TestNewHeaderInterceptor_NilShardCoordinatorShouldErr(t *testing.T) { + t.Parallel() + + headers := &mock.CacherStub{} + headersNonces := &mock.Uint64SyncMapCacherStub{} + headerValidator := &mock.HeaderValidatorStub{} + + hi, err := interceptors.NewHeaderInterceptor( + &mock.MarshalizerMock{}, + headers, + headersNonces, + headerValidator, + mock.NewMultiSigner(), + mock.HasherMock{}, + nil, + &mock.ChronologyValidatorStub{}, + ) + + assert.Equal(t, process.ErrNilShardCoordinator, err) + assert.Nil(t, hi) +} + +func TestNewHeaderInterceptor_NilChronologyValidatorShouldErr(t *testing.T) { + t.Parallel() + + headers := &mock.CacherStub{} + headersNonces := &mock.Uint64SyncMapCacherStub{} + headerValidator := &mock.HeaderValidatorStub{} + + hi, err := interceptors.NewHeaderInterceptor( + &mock.MarshalizerMock{}, + headers, + headersNonces, + headerValidator, + mock.NewMultiSigner(), + mock.HasherMock{}, + mock.NewOneShardCoordinatorMock(), + nil, + ) + + assert.Equal(t, process.ErrNilChronologyValidator, err) + assert.Nil(t, hi) +} + func TestNewHeaderInterceptor_OkValsShouldWork(t *testing.T) { t.Parallel() @@ -106,6 +216,187 @@ func TestNewHeaderInterceptor_OkValsShouldWork(t *testing.T) { assert.NotNil(t, hi) } +//------- ParseReceivedMessage + +func TestHeaderInterceptor_ParseReceivedMessageNilMessageShouldErr(t *testing.T) { + t.Parallel() + + headers := &mock.CacherStub{} + headersNonces := &mock.Uint64SyncMapCacherStub{} + + headerValidator := &mock.HeaderValidatorStub{} + + hi, _ := interceptors.NewHeaderInterceptor( + &mock.MarshalizerMock{}, + headers, + headersNonces, + headerValidator, + mock.NewMultiSigner(), + mock.HasherMock{}, + mock.NewOneShardCoordinatorMock(), + &mock.ChronologyValidatorStub{}, + ) + + hdr, err := hi.ParseReceivedMessage(nil) + + assert.Nil(t, hdr) + assert.Equal(t, process.ErrNilMessage, err) +} + +func TestHeaderInterceptor_ParseReceivedMessageNilDataToProcessShouldErr(t *testing.T) { + t.Parallel() + + headers := &mock.CacherStub{} + headersNonces := &mock.Uint64SyncMapCacherStub{} + headerValidator := &mock.HeaderValidatorStub{} + + hi, _ := interceptors.NewHeaderInterceptor( + &mock.MarshalizerMock{}, + headers, + headersNonces, + headerValidator, + mock.NewMultiSigner(), + mock.HasherMock{}, + mock.NewOneShardCoordinatorMock(), + &mock.ChronologyValidatorStub{}, + ) + + msg := &mock.P2PMessageMock{} + hdr, err := hi.ParseReceivedMessage(msg) + + assert.Nil(t, hdr) + assert.Equal(t, process.ErrNilDataToProcess, err) +} + +func TestHeaderInterceptor_ParseReceivedMessageMarshalizerErrorsAtUnmarshalingShouldErr(t *testing.T) { + t.Parallel() + + errMarshalizer := errors.New("marshalizer error") + + headers := &mock.CacherStub{} + headersNonces := &mock.Uint64SyncMapCacherStub{} + headerValidator := &mock.HeaderValidatorStub{} + + hi, _ := interceptors.NewHeaderInterceptor( + &mock.MarshalizerStub{ + UnmarshalCalled: func(obj interface{}, buff []byte) error { + return errMarshalizer + }, + }, + headers, + headersNonces, + headerValidator, + mock.NewMultiSigner(), + mock.HasherMock{}, + mock.NewOneShardCoordinatorMock(), + &mock.ChronologyValidatorStub{}, + ) + + msg := &mock.P2PMessageMock{ + DataField: make([]byte, 0), + } + hdr, err := hi.ParseReceivedMessage(msg) + + assert.Nil(t, hdr) + assert.Equal(t, errMarshalizer, err) +} + +func TestHeaderInterceptor_ParseReceivedMessageSanityCheckFailedShouldErr(t *testing.T) { + t.Parallel() + + headerValidator := &mock.HeaderValidatorStub{} + marshalizer := &mock.MarshalizerMock{} + multisigner := mock.NewMultiSigner() + headers := &mock.CacherStub{} + headersNonces := &mock.Uint64SyncMapCacherStub{} + chronologyValidator := &mock.ChronologyValidatorStub{ + ValidateReceivedBlockCalled: func(shardID uint32, epoch uint32, nonce uint64, round uint64) error { + return nil + }, + } + + hi, _ := interceptors.NewHeaderInterceptor( + marshalizer, + headers, + headersNonces, + headerValidator, + multisigner, + mock.HasherMock{}, + mock.NewOneShardCoordinatorMock(), + chronologyValidator, + ) + + hdr := block.NewInterceptedHeader(multisigner, chronologyValidator) + buff, _ := marshalizer.Marshal(hdr) + msg := &mock.P2PMessageMock{ + DataField: buff, + } + hdr, err := hi.ParseReceivedMessage(msg) + + assert.Nil(t, hdr) + assert.Equal(t, process.ErrNilPubKeysBitmap, err) +} + +func TestHeaderInterceptor_ParseReceivedMessageValsOkShouldWork(t *testing.T) { + t.Parallel() + + testedNonce := uint64(67) + + headerValidator := &mock.HeaderValidatorStub{ + IsHeaderValidForProcessingCalled: func(headerHandler data.HeaderHandler) bool { + return true + }, + } + + marshalizer := &mock.MarshalizerMock{} + multisigner := mock.NewMultiSigner() + headers := &mock.CacherStub{} + headersNonces := &mock.Uint64SyncMapCacherStub{} + chronologyValidator := &mock.ChronologyValidatorStub{ + ValidateReceivedBlockCalled: func(shardID uint32, epoch uint32, nonce uint64, round uint64) error { + return nil + }, + } + + hi, _ := interceptors.NewHeaderInterceptor( + marshalizer, + headers, + headersNonces, + headerValidator, + multisigner, + mock.HasherMock{}, + mock.NewOneShardCoordinatorMock(), + chronologyValidator, + ) + + hdr := block.NewInterceptedHeader(multisigner, chronologyValidator) + hdr.Nonce = testedNonce + hdr.ShardId = 0 + hdr.PrevHash = make([]byte, 0) + hdr.PubKeysBitmap = make([]byte, 0) + hdr.BlockBodyType = dataBlock.TxBlock + hdr.Signature = make([]byte, 0) + hdr.SetHash([]byte("aaa")) + hdr.RootHash = make([]byte, 0) + hdr.PrevRandSeed = make([]byte, 0) + hdr.RandSeed = make([]byte, 0) + hdr.MiniBlockHeaders = make([]dataBlock.MiniBlockHeader, 0) + + buff, _ := marshalizer.Marshal(hdr) + msg := &mock.P2PMessageMock{ + DataField: buff, + } + + hdrIntercepted, err := hi.ParseReceivedMessage(msg) + if hdrIntercepted != nil { + //hdrIntercepted will have a "real" hash computed + hdrIntercepted.SetHash(hdr.Hash()) + } + + assert.Equal(t, hdr, hdrIntercepted) + assert.Nil(t, err) +} + //------- ProcessReceivedMessage func TestHeaderInterceptor_ProcessReceivedMessageNilMessageShouldErr(t *testing.T) { @@ -208,6 +499,75 @@ func TestHeaderInterceptor_ProcessReceivedMessageValsOkShouldWork(t *testing.T) } } +func TestHeaderInterceptor_ProcessReceivedMessageTestHdrNonces(t *testing.T) { + t.Parallel() + + marshalizer := &mock.MarshalizerMock{} + chanDone := make(chan struct{}, 1) + testedNonce := uint64(67) + headers := &mock.CacherStub{} + multisigner := mock.NewMultiSigner() + chronologyValidator := &mock.ChronologyValidatorStub{ + ValidateReceivedBlockCalled: func(shardID uint32, epoch uint32, nonce uint64, round uint64) error { + return nil + }, + } + + headerValidator := &mock.HeaderValidatorStub{ + IsHeaderValidForProcessingCalled: func(headerHandler data.HeaderHandler) bool { + return true + }, + } + + hdrsNonces := &mock.Uint64SyncMapCacherStub{} + + hi, _ := interceptors.NewHeaderInterceptor( + marshalizer, + headers, + hdrsNonces, + headerValidator, + multisigner, + mock.HasherMock{}, + mock.NewMultiShardsCoordinatorMock(2), + chronologyValidator, + ) + + hdr := block.NewInterceptedHeader(multisigner, chronologyValidator) + hdr.Nonce = testedNonce + hdr.ShardId = 0 + hdr.PrevHash = make([]byte, 0) + hdr.PubKeysBitmap = make([]byte, 0) + hdr.BlockBodyType = dataBlock.TxBlock + hdr.Signature = make([]byte, 0) + hdr.SetHash([]byte("aaa")) + hdr.RootHash = make([]byte, 0) + hdr.PrevRandSeed = make([]byte, 0) + hdr.RandSeed = make([]byte, 0) + hdr.MiniBlockHeaders = make([]dataBlock.MiniBlockHeader, 0) + + buff, _ := marshalizer.Marshal(hdr) + msg := &mock.P2PMessageMock{ + DataField: buff, + } + + headers.HasOrAddCalled = func(key []byte, value interface{}) (ok, evicted bool) { + return false, false + } + + hdrsNonces.MergeCalled = func(nonce uint64, src dataRetriever.ShardIdHashMap) { + if testedNonce == nonce { + chanDone <- struct{}{} + } + } + + assert.Nil(t, hi.ProcessReceivedMessage(msg)) + select { + case <-chanDone: + case <-time.After(durTimeout): + assert.Fail(t, "timeout while waiting for block to be inserted in the pool") + } +} + func TestHeaderInterceptor_ProcessReceivedMessageIsNotValidShouldNotAdd(t *testing.T) { t.Parallel() diff --git a/process/factory/metachain/interceptorsContainerFactory.go b/process/factory/metachain/interceptorsContainerFactory.go index 990bbd8141b..b6f92d89b69 100644 --- a/process/factory/metachain/interceptorsContainerFactory.go +++ b/process/factory/metachain/interceptorsContainerFactory.go @@ -11,7 +11,6 @@ import ( "github.com/ElrondNetwork/elrond-go/process/dataValidators" "github.com/ElrondNetwork/elrond-go/process/factory" "github.com/ElrondNetwork/elrond-go/process/factory/containers" - "github.com/ElrondNetwork/elrond-go/process/metablock" "github.com/ElrondNetwork/elrond-go/sharding" ) @@ -180,7 +179,7 @@ func (icf *interceptorsContainerFactory) createOneShardHeaderInterceptor(identif return nil, err } - interceptor, err := metablock.NewShardHeaderInterceptor( + interceptor, err := interceptors.NewHeaderInterceptor( icf.marshalizer, icf.dataPool.ShardHeaders(), icf.dataPool.HeadersNonces(), diff --git a/process/metablock/shardHeaderInterceptor.go b/process/metablock/shardHeaderInterceptor.go deleted file mode 100644 index fa6f5b81e7f..00000000000 --- a/process/metablock/shardHeaderInterceptor.go +++ /dev/null @@ -1,99 +0,0 @@ -package metablock - -import ( - "github.com/ElrondNetwork/elrond-go/core/logger" - "github.com/ElrondNetwork/elrond-go/crypto" - "github.com/ElrondNetwork/elrond-go/dataRetriever" - "github.com/ElrondNetwork/elrond-go/dataRetriever/dataPool" - "github.com/ElrondNetwork/elrond-go/hashing" - "github.com/ElrondNetwork/elrond-go/marshal" - "github.com/ElrondNetwork/elrond-go/p2p" - "github.com/ElrondNetwork/elrond-go/process" - "github.com/ElrondNetwork/elrond-go/process/block" - "github.com/ElrondNetwork/elrond-go/process/block/interceptors" - "github.com/ElrondNetwork/elrond-go/sharding" - "github.com/ElrondNetwork/elrond-go/storage" -) - -var log = logger.DefaultLogger() - -// ShardHeaderInterceptor represents an interceptor used for shard block headers by metachain nodes -type ShardHeaderInterceptor struct { - hdrInterceptorBase *interceptors.HeaderInterceptorBase - headers storage.Cacher - hdrsNonces dataRetriever.Uint64SyncMapCacher - headerValidator process.HeaderValidator -} - -// NewShardHeaderInterceptor hooks a new interceptor for shard block headers by metachain nodes -// Fetched block headers will be placed in a data pool -func NewShardHeaderInterceptor( - marshalizer marshal.Marshalizer, - headers storage.Cacher, - hdrsNonces dataRetriever.Uint64SyncMapCacher, - headerValidator process.HeaderValidator, - multiSigVerifier crypto.MultiSigVerifier, - hasher hashing.Hasher, - shardCoordinator sharding.Coordinator, - chronologyValidator process.ChronologyValidator, -) (*ShardHeaderInterceptor, error) { - - if headers == nil { - return nil, process.ErrNilHeadersDataPool - } - if hdrsNonces == nil { - return nil, process.ErrNilHeadersNoncesDataPool - } - - hdrBaseInterceptor, err := interceptors.NewHeaderInterceptorBase( - marshalizer, - headerValidator, - multiSigVerifier, - hasher, - shardCoordinator, - chronologyValidator, - ) - if err != nil { - return nil, err - } - - return &ShardHeaderInterceptor{ - hdrInterceptorBase: hdrBaseInterceptor, - headers: headers, - hdrsNonces: hdrsNonces, - headerValidator: headerValidator, - }, nil -} - -// ProcessReceivedMessage will be the callback func from the p2p.Messenger and will be called each time a new message was received -// (for the topic this validator was registered to) -func (shi *ShardHeaderInterceptor) ProcessReceivedMessage(message p2p.MessageP2P) error { - hdrIntercepted, err := shi.hdrInterceptorBase.ParseReceivedMessage(message) - if err != nil { - return err - } - - go shi.processHeader(hdrIntercepted) - - return nil -} - -func (shi *ShardHeaderInterceptor) processHeader(hdrIntercepted *block.InterceptedHeader) { - if !shi.hdrInterceptorBase.CheckHeaderForCurrentShard(hdrIntercepted) { - return - } - - isHeaderOkForProcessing := shi.headerValidator.IsHeaderValidForProcessing(hdrIntercepted.Header) - if !isHeaderOkForProcessing { - log.Debug("intercepted block header is not valid for processing") - return - } - - shi.headers.HasOrAdd(hdrIntercepted.Hash(), hdrIntercepted.GetHeader()) - - nonce := hdrIntercepted.GetHeader().GetNonce() - - syncMap := &dataPool.ShardIdHashSyncMap{} - syncMap.Store(hdrIntercepted.GetHeader().GetShardID(), hdrIntercepted.Hash()) - shi.hdrsNonces.Merge(nonce, syncMap) -} diff --git a/process/metablock/shardHeaderInterceptor_test.go b/process/metablock/shardHeaderInterceptor_test.go deleted file mode 100644 index 1c46e72a060..00000000000 --- a/process/metablock/shardHeaderInterceptor_test.go +++ /dev/null @@ -1,297 +0,0 @@ -package metablock_test - -import ( - "bytes" - "testing" - "time" - - "github.com/ElrondNetwork/elrond-go/data" - dataBlock "github.com/ElrondNetwork/elrond-go/data/block" - "github.com/ElrondNetwork/elrond-go/dataRetriever" - "github.com/ElrondNetwork/elrond-go/process" - "github.com/ElrondNetwork/elrond-go/process/block" - "github.com/ElrondNetwork/elrond-go/process/metablock" - "github.com/ElrondNetwork/elrond-go/process/mock" - "github.com/stretchr/testify/assert" -) - -var durTimeout = time.Second - -//------- NewShardHeaderInterceptor - -func TestNewShardHeaderInterceptor_NilMarshalizerShouldErr(t *testing.T) { - t.Parallel() - - headers := &mock.CacherStub{} - headerValidator := &mock.HeaderValidatorStub{} - hi, err := metablock.NewShardHeaderInterceptor( - nil, - headers, - &mock.Uint64SyncMapCacherStub{}, - headerValidator, - mock.NewMultiSigner(), - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - assert.Equal(t, process.ErrNilMarshalizer, err) - assert.Nil(t, hi) -} - -func TestNewShardHeaderInterceptor_NilHeadersShouldErr(t *testing.T) { - t.Parallel() - - headerValidator := &mock.HeaderValidatorStub{} - hi, err := metablock.NewShardHeaderInterceptor( - &mock.MarshalizerMock{}, - nil, - &mock.Uint64SyncMapCacherStub{}, - headerValidator, - mock.NewMultiSigner(), - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - assert.Equal(t, process.ErrNilHeadersDataPool, err) - assert.Nil(t, hi) -} - -func TestNewShardHeaderInterceptor_OkValsShouldWork(t *testing.T) { - t.Parallel() - - headers := &mock.CacherStub{} - headerValidator := &mock.HeaderValidatorStub{} - hi, err := metablock.NewShardHeaderInterceptor( - &mock.MarshalizerMock{}, - headers, - &mock.Uint64SyncMapCacherStub{}, - headerValidator, - mock.NewMultiSigner(), - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - assert.Nil(t, err) - assert.NotNil(t, hi) -} - -//------- ProcessReceivedMessage - -func TestShardHeaderInterceptor_ProcessReceivedMessageNilMessageShouldErr(t *testing.T) { - t.Parallel() - - headers := &mock.CacherStub{} - headerValidator := &mock.HeaderValidatorStub{} - hi, _ := metablock.NewShardHeaderInterceptor( - &mock.MarshalizerMock{}, - headers, - &mock.Uint64SyncMapCacherStub{}, - headerValidator, - mock.NewMultiSigner(), - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - &mock.ChronologyValidatorStub{}, - ) - - assert.Equal(t, process.ErrNilMessage, hi.ProcessReceivedMessage(nil)) -} - -func TestShardHeaderInterceptor_ProcessReceivedMessageValsOkShouldWork(t *testing.T) { - t.Parallel() - - marshalizer := &mock.MarshalizerMock{} - chanDone := make(chan struct{}, 1) - testedNonce := uint64(67) - headers := &mock.CacherStub{} - multisigner := mock.NewMultiSigner() - chronologyValidator := &mock.ChronologyValidatorStub{ - ValidateReceivedBlockCalled: func(shardID uint32, epoch uint32, nonce uint64, round uint64) error { - return nil - }, - } - headerValidator := &mock.HeaderValidatorStub{ - IsHeaderValidForProcessingCalled: func(headerHandler data.HeaderHandler) bool { - return true - }, - } - hdrsNonces := &mock.Uint64SyncMapCacherStub{ - MergeCalled: func(nonce uint64, src dataRetriever.ShardIdHashMap) {}, - } - - hi, _ := metablock.NewShardHeaderInterceptor( - marshalizer, - headers, - hdrsNonces, - headerValidator, - multisigner, - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - chronologyValidator, - ) - - hdr := block.NewInterceptedHeader(multisigner, chronologyValidator) - hdr.Nonce = testedNonce - hdr.ShardId = 0 - hdr.PrevHash = make([]byte, 0) - hdr.PubKeysBitmap = make([]byte, 0) - hdr.BlockBodyType = dataBlock.TxBlock - hdr.Signature = make([]byte, 0) - hdr.SetHash([]byte("aaa")) - hdr.RootHash = make([]byte, 0) - hdr.PrevRandSeed = make([]byte, 0) - hdr.RandSeed = make([]byte, 0) - hdr.MiniBlockHeaders = make([]dataBlock.MiniBlockHeader, 0) - - buff, _ := marshalizer.Marshal(hdr) - msg := &mock.P2PMessageMock{ - DataField: buff, - } - - headers.HasOrAddCalled = func(key []byte, value interface{}) (ok, evicted bool) { - aaaHash := mock.HasherMock{}.Compute(string(buff)) - if bytes.Equal(aaaHash, key) { - chanDone <- struct{}{} - } - return false, false - } - - assert.Nil(t, hi.ProcessReceivedMessage(msg)) - select { - case <-chanDone: - case <-time.After(durTimeout): - assert.Fail(t, "timeout while waiting for block to be inserted in the pool") - } -} - -func TestShardHeaderInterceptor_ProcessReceivedMessageTestHdrNonces(t *testing.T) { - t.Parallel() - - marshalizer := &mock.MarshalizerMock{} - chanDone := make(chan struct{}, 1) - testedNonce := uint64(67) - headers := &mock.CacherStub{} - multisigner := mock.NewMultiSigner() - chronologyValidator := &mock.ChronologyValidatorStub{ - ValidateReceivedBlockCalled: func(shardID uint32, epoch uint32, nonce uint64, round uint64) error { - return nil - }, - } - headerValidator := &mock.HeaderValidatorStub{ - IsHeaderValidForProcessingCalled: func(headerHandler data.HeaderHandler) bool { - return true - }, - } - hdrsNonces := &mock.Uint64SyncMapCacherStub{} - - hi, _ := metablock.NewShardHeaderInterceptor( - marshalizer, - headers, - hdrsNonces, - headerValidator, - multisigner, - mock.HasherMock{}, - mock.NewMultiShardsCoordinatorMock(2), - chronologyValidator, - ) - - hdr := block.NewInterceptedHeader(multisigner, chronologyValidator) - hdr.Nonce = testedNonce - hdr.ShardId = 0 - hdr.PrevHash = make([]byte, 0) - hdr.PubKeysBitmap = make([]byte, 0) - hdr.BlockBodyType = dataBlock.TxBlock - hdr.Signature = make([]byte, 0) - hdr.SetHash([]byte("aaa")) - hdr.RootHash = make([]byte, 0) - hdr.PrevRandSeed = make([]byte, 0) - hdr.RandSeed = make([]byte, 0) - hdr.MiniBlockHeaders = make([]dataBlock.MiniBlockHeader, 0) - - buff, _ := marshalizer.Marshal(hdr) - msg := &mock.P2PMessageMock{ - DataField: buff, - } - - headers.HasOrAddCalled = func(key []byte, value interface{}) (ok, evicted bool) { - return false, false - } - - hdrsNonces.MergeCalled = func(nonce uint64, src dataRetriever.ShardIdHashMap) { - if testedNonce == nonce { - chanDone <- struct{}{} - } - } - - assert.Nil(t, hi.ProcessReceivedMessage(msg)) - select { - case <-chanDone: - case <-time.After(durTimeout): - assert.Fail(t, "timeout while waiting for block to be inserted in the pool") - } -} - -func TestShardHeaderInterceptor_ProcessReceivedMessageIsNotValidShouldNotAdd(t *testing.T) { - t.Parallel() - - marshalizer := &mock.MarshalizerMock{} - chanDone := make(chan struct{}, 1) - testedNonce := uint64(67) - headers := &mock.CacherStub{} - multisigner := mock.NewMultiSigner() - chronologyValidator := &mock.ChronologyValidatorStub{ - ValidateReceivedBlockCalled: func(shardID uint32, epoch uint32, nonce uint64, round uint64) error { - return nil - }, - } - headerValidator := &mock.HeaderValidatorStub{ - IsHeaderValidForProcessingCalled: func(headerHandler data.HeaderHandler) bool { - return false - }, - } - hi, _ := metablock.NewShardHeaderInterceptor( - marshalizer, - headers, - &mock.Uint64SyncMapCacherStub{}, - headerValidator, - multisigner, - mock.HasherMock{}, - mock.NewOneShardCoordinatorMock(), - chronologyValidator, - ) - - hdr := block.NewInterceptedHeader(multisigner, chronologyValidator) - hdr.Nonce = testedNonce - hdr.ShardId = 0 - hdr.PrevHash = make([]byte, 0) - hdr.PubKeysBitmap = make([]byte, 0) - hdr.BlockBodyType = dataBlock.TxBlock - hdr.Signature = make([]byte, 0) - hdr.RootHash = make([]byte, 0) - hdr.PrevRandSeed = make([]byte, 0) - hdr.RandSeed = make([]byte, 0) - hdr.SetHash([]byte("aaa")) - hdr.MiniBlockHeaders = make([]dataBlock.MiniBlockHeader, 0) - - buff, _ := marshalizer.Marshal(hdr) - msg := &mock.P2PMessageMock{ - DataField: buff, - } - - headers.HasOrAddCalled = func(key []byte, value interface{}) (ok, evicted bool) { - aaaHash := mock.HasherMock{}.Compute(string(buff)) - if bytes.Equal(aaaHash, key) { - chanDone <- struct{}{} - } - return false, false - } - - assert.Nil(t, hi.ProcessReceivedMessage(msg)) - select { - case <-chanDone: - assert.Fail(t, "should have not add block in pool") - case <-time.After(durTimeout): - } -}