Skip to content

Commit d3b2f27

Browse files
committed
Merge branch 'master' of https://github.com/multiversx/mx-chain-go into rc/supernova
# Conflicts: # consensus/spos/bls/v2/errors.go # consensus/spos/bls/v2/subroundEndRound.go
2 parents eb0e473 + 3bc92ba commit d3b2f27

19 files changed

Lines changed: 313 additions & 16 deletions

consensus/spos/bls/proxy/subroundsHandler_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func getDefaultArgumentsSubroundHandler() (*SubroundsHandlerArgs, *spos.Consensu
8181
consensusCore.SetScheduledProcessor(&consensus.ScheduledProcessorStub{})
8282
consensusCore.SetMessageSigningHandler(&mock2.MessageSigningHandlerStub{})
8383
consensusCore.SetPeerBlacklistHandler(&mock2.PeerBlacklistHandlerStub{})
84+
consensusCore.SetPeerSignatureHandler(&cryptoMocks.PeerSignatureHandlerStub{})
8485
consensusCore.SetSigningHandler(&consensus.SigningHandlerStub{})
8586
consensusCore.SetEnableEpochsHandler(epochsEnable)
8687
consensusCore.SetEnableRoundsHandler(&testscommon.EnableRoundsHandlerStub{})

consensus/spos/bls/v2/common.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package v2
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/multiversx/mx-chain-core-go/core"
9+
10+
"github.com/multiversx/mx-chain-go/consensus/spos"
11+
)
12+
13+
func checkGoRoutinesThrottler(ctx context.Context, throttler core.Throttler) error {
14+
for {
15+
if throttler.CanProcess() {
16+
break
17+
}
18+
19+
select {
20+
case <-time.After(time.Millisecond):
21+
continue
22+
case <-ctx.Done():
23+
return fmt.Errorf("%w while checking the throttler", spos.ErrTimeIsOut)
24+
}
25+
}
26+
return nil
27+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package v2
2+
3+
import (
4+
"context"
5+
"sync/atomic"
6+
"testing"
7+
"time"
8+
9+
"github.com/stretchr/testify/assert"
10+
11+
dataRetrieverMock "github.com/multiversx/mx-chain-go/dataRetriever/mock"
12+
)
13+
14+
func TestCheckGoRoutinesThrottler(t *testing.T) {
15+
t.Parallel()
16+
17+
t.Run("throttler can process should return nil immediately", func(t *testing.T) {
18+
t.Parallel()
19+
20+
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
21+
defer cancel()
22+
23+
throttler := &dataRetrieverMock.ThrottlerStub{
24+
CanProcessCalled: func() bool {
25+
return true
26+
},
27+
}
28+
29+
err := checkGoRoutinesThrottler(ctx, throttler)
30+
assert.Nil(t, err)
31+
})
32+
33+
t.Run("throttler cannot process for a period of time, then can process, should return nil", func(t *testing.T) {
34+
t.Parallel()
35+
36+
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
37+
defer cancel()
38+
39+
var numCalls int32
40+
throttler := &dataRetrieverMock.ThrottlerStub{
41+
CanProcessCalled: func() bool {
42+
return atomic.AddInt32(&numCalls, 1) >= 5
43+
},
44+
}
45+
46+
err := checkGoRoutinesThrottler(ctx, throttler)
47+
assert.Nil(t, err)
48+
assert.GreaterOrEqual(t, atomic.LoadInt32(&numCalls), int32(5))
49+
})
50+
51+
t.Run("throttler cannot process should return error when context is done", func(t *testing.T) {
52+
t.Parallel()
53+
54+
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
55+
defer cancel()
56+
57+
var numCalls int32
58+
throttler := &dataRetrieverMock.ThrottlerStub{
59+
CanProcessCalled: func() bool {
60+
atomic.AddInt32(&numCalls, 1)
61+
return false
62+
},
63+
}
64+
65+
err := checkGoRoutinesThrottler(ctx, throttler)
66+
assert.NotNil(t, err)
67+
assert.ErrorContains(t, err, "time is out")
68+
assert.ErrorContains(t, err, "while checking the throttler")
69+
assert.Greater(t, atomic.LoadInt32(&numCalls), int32(1))
70+
})
71+
72+
t.Run("context already canceled and throttler cannot process should return error without retrying", func(t *testing.T) {
73+
t.Parallel()
74+
75+
ctx, cancel := context.WithCancel(context.Background())
76+
cancel()
77+
78+
var numCalls int32
79+
throttler := &dataRetrieverMock.ThrottlerStub{
80+
CanProcessCalled: func() bool {
81+
atomic.AddInt32(&numCalls, 1)
82+
return false
83+
},
84+
}
85+
86+
err := checkGoRoutinesThrottler(ctx, throttler)
87+
assert.NotNil(t, err)
88+
assert.ErrorContains(t, err, "time is out")
89+
})
90+
}

consensus/spos/bls/v2/errors.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ var ErrValidSignatureFromInvalidSigner = errors.New("valid signature from invali
1717
// ErrHeaderHashMismatch signals that header hash does not match
1818
var ErrHeaderHashMismatch = errors.New("header hash does not match")
1919

20+
// ErrPublicKeyMismatch signals that the BLS public key in the message does not belong to the transport sender
21+
var ErrPublicKeyMismatch = errors.New("public key does not match the message sender")
22+
23+
// ErrSignerNotInConsensusGroup signals that the signer is not part of the current consensus group
24+
var ErrSignerNotInConsensusGroup = errors.New("signer is not part of the consensus group")
25+
2026
// ErrNilRoundSyncController signals that a nil round sync controller has been provided
2127
var ErrNilRoundSyncController = errors.New("nil round sync controller")
2228

consensus/spos/bls/v2/subroundEndRound.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type subroundEndRound struct {
3434
mutProcessingEndRound sync.Mutex
3535
sentSignatureTracker spos.SentSignaturesTracker
3636
worker spos.WorkerHandler
37+
signatureThrottler core.Throttler
3738
}
3839

3940
// NewSubroundEndRound creates a subroundEndRound object
@@ -43,6 +44,7 @@ func NewSubroundEndRound(
4344
appStatusHandler core.AppStatusHandler,
4445
sentSignatureTracker spos.SentSignaturesTracker,
4546
worker spos.WorkerHandler,
47+
signatureThrottler core.Throttler,
4648
) (*subroundEndRound, error) {
4749
err := checkNewSubroundEndRoundParams(baseSubround)
4850
if err != nil {
@@ -57,6 +59,9 @@ func NewSubroundEndRound(
5759
if check.IfNil(worker) {
5860
return nil, spos.ErrNilWorker
5961
}
62+
if check.IfNil(signatureThrottler) {
63+
return nil, spos.ErrNilThrottler
64+
}
6065

6166
srEndRound := subroundEndRound{
6267
Subround: baseSubround,
@@ -65,6 +70,7 @@ func NewSubroundEndRound(
6570
mutProcessingEndRound: sync.Mutex{},
6671
sentSignatureTracker: sentSignatureTracker,
6772
worker: worker,
73+
signatureThrottler: signatureThrottler,
6874
}
6975
srEndRound.Job = srEndRound.doEndRoundJob
7076
srEndRound.Check = srEndRound.doEndRoundConsensusCheck
@@ -224,11 +230,20 @@ func (sr *subroundEndRound) verifyInvalidSigner(
224230
return "", spos.ErrInvalidMessageType
225231
}
226232

233+
if !sr.IsNodeInConsensusGroup(string(cnsMsg.PubKey)) {
234+
return "", ErrSignerNotInConsensusGroup
235+
}
236+
227237
err = sr.MessageSigningHandler().Verify(msg)
228238
if err != nil {
229239
return "", err
230240
}
231241

242+
err = sr.PeerSignatureHandler().VerifyPeerSignature(cnsMsg.PubKey, msg.Peer(), cnsMsg.Signature)
243+
if err != nil {
244+
return "", ErrPublicKeyMismatch
245+
}
246+
232247
if !bytes.Equal(headerHash, cnsMsg.BlockHeaderHash) {
233248
return "", ErrHeaderHashMismatch
234249
}
@@ -476,6 +491,10 @@ func (sr *subroundEndRound) aggregateSigsAndHandleInvalidSigners(bitmap []byte,
476491
return bitmap, sig, nil
477492
}
478493

494+
func (sr *subroundEndRound) checkGoRoutinesThrottler(ctx context.Context) error {
495+
return checkGoRoutinesThrottler(ctx, sr.signatureThrottler)
496+
}
497+
479498
// verifySignature implements parallel signature verification
480499
func (sr *subroundEndRound) verifySignature(i int, pk string, sigShare []byte) error {
481500
err := sr.SigningHandler().VerifySignatureShare(uint16(i), sigShare, sr.GetData(), sr.GetHeader().GetEpoch())

consensus/spos/bls/v2/subroundEndRound_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/multiversx/mx-chain-go/testscommon"
3535
consensusMocks "github.com/multiversx/mx-chain-go/testscommon/consensus"
3636
"github.com/multiversx/mx-chain-go/testscommon/consensus/initializers"
37+
"github.com/multiversx/mx-chain-go/testscommon/cryptoMocks"
3738
"github.com/multiversx/mx-chain-go/testscommon/dataRetriever"
3839
"github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock"
3940
"github.com/multiversx/mx-chain-go/testscommon/p2pmocks"
@@ -1898,6 +1899,43 @@ func TestVerifyInvalidSigners(t *testing.T) {
18981899
require.Equal(t, expectedErr, err)
18991900
})
19001901

1902+
t.Run("peer signature binding fails should error", func(t *testing.T) {
1903+
t.Parallel()
1904+
1905+
container := consensusMocks.InitConsensusCore()
1906+
1907+
consensusMsg := &consensus.Message{
1908+
BlockHeaderHash: headerHash,
1909+
PubKey: pubKey,
1910+
MsgType: int64(bls.MtSignature),
1911+
}
1912+
consensusMsgBytes, _ := container.Marshalizer().Marshal(consensusMsg)
1913+
1914+
invalidSigners := []p2p.MessageP2P{&factory.Message{
1915+
FromField: []byte("attackerPid"),
1916+
DataField: consensusMsgBytes,
1917+
}}
1918+
invalidSignersBytes, _ := container.Marshalizer().Marshal(invalidSigners)
1919+
1920+
messageSigningHandler := &mock.MessageSigningHandlerStub{
1921+
DeserializeCalled: func(messagesBytes []byte) ([]p2p.MessageP2P, error) {
1922+
return invalidSigners, nil
1923+
},
1924+
}
1925+
container.SetMessageSigningHandler(messageSigningHandler)
1926+
1927+
container.SetPeerSignatureHandler(&cryptoMocks.PeerSignatureHandlerStub{
1928+
VerifyPeerSignatureCalled: func(pk []byte, pid core.PeerID, signature []byte) error {
1929+
return expectedErr
1930+
},
1931+
})
1932+
1933+
sr := initSubroundEndRoundWithContainer(container, &statusHandler.AppStatusHandlerStub{})
1934+
1935+
_, err := sr.VerifyInvalidSigners(headerHash, invalidSignersBytes)
1936+
require.Equal(t, v2.ErrPublicKeyMismatch, err)
1937+
})
1938+
19011939
t.Run("invalid message type should err", func(t *testing.T) {
19021940
t.Parallel()
19031941

@@ -1940,6 +1978,37 @@ func TestVerifyInvalidSigners(t *testing.T) {
19401978
require.False(t, wasCalled)
19411979
})
19421980

1981+
t.Run("signer not in consensus group should err", func(t *testing.T) {
1982+
t.Parallel()
1983+
1984+
container := consensusMocks.InitConsensusCore()
1985+
1986+
unknownPubKey := []byte("unknownKey")
1987+
consensusMsg := &consensus.Message{
1988+
PubKey: unknownPubKey,
1989+
MsgType: int64(bls.MtSignature),
1990+
}
1991+
consensusMsgBytes, _ := container.Marshalizer().Marshal(consensusMsg)
1992+
1993+
invalidSigners := []p2p.MessageP2P{&factory.Message{
1994+
FromField: []byte("from"),
1995+
DataField: consensusMsgBytes,
1996+
}}
1997+
invalidSignersBytes, _ := container.Marshalizer().Marshal(invalidSigners)
1998+
1999+
messageSigningHandler := &mock.MessageSigningHandlerStub{
2000+
DeserializeCalled: func(messagesBytes []byte) ([]p2p.MessageP2P, error) {
2001+
return invalidSigners, nil
2002+
},
2003+
}
2004+
container.SetMessageSigningHandler(messageSigningHandler)
2005+
2006+
sr := initSubroundEndRoundWithContainer(container, &statusHandler.AppStatusHandlerStub{})
2007+
2008+
_, err := sr.VerifyInvalidSigners(headerHash, invalidSignersBytes)
2009+
require.Equal(t, v2.ErrSignerNotInConsensusGroup, err)
2010+
})
2011+
19432012
t.Run("failed to verify signature share", func(t *testing.T) {
19442013
t.Parallel()
19452014

consensus/spos/bls/v2/subroundSignature.go

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package v2
33
import (
44
"bytes"
55
"context"
6-
"fmt"
76
"sync"
87
"sync/atomic"
98
"time"
@@ -290,18 +289,7 @@ func (sr *subroundSignature) sendSignatureForManagedKey(_ context.Context, idx i
290289
}
291290

292291
func (sr *subroundSignature) checkGoRoutinesThrottler(ctx context.Context) error {
293-
for {
294-
if sr.signatureThrottler.CanProcess() {
295-
break
296-
}
297-
select {
298-
case <-time.After(timeSpentBetweenChecks):
299-
continue
300-
case <-ctx.Done():
301-
return fmt.Errorf("%w while checking the throttler", spos.ErrTimeIsOut)
302-
}
303-
}
304-
return nil
292+
return checkGoRoutinesThrottler(ctx, sr.signatureThrottler)
305293
}
306294

307295
func (sr *subroundSignature) doSignatureJobForSingleKey(_ context.Context) bool {

consensus/spos/consensusCore.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/multiversx/mx-chain-core-go/data"
55
"github.com/multiversx/mx-chain-core-go/hashing"
66
"github.com/multiversx/mx-chain-core-go/marshal"
7+
crypto "github.com/multiversx/mx-chain-crypto-go"
78

89
"github.com/multiversx/mx-chain-go/common"
910
cryptoCommon "github.com/multiversx/mx-chain-go/common/crypto"
@@ -40,6 +41,7 @@ type ConsensusCore struct {
4041
scheduledProcessor consensus.ScheduledProcessor
4142
messageSigningHandler consensus.P2PSigningHandler
4243
peerBlacklistHandler consensus.PeerBlacklistHandler
44+
peerSignatureHandler crypto.PeerSignatureHandler
4345
signingHandler consensus.SigningHandler
4446
enableEpochsHandler common.EnableEpochsHandler
4547
enableRoundsHandler common.EnableRoundsHandler
@@ -74,6 +76,7 @@ type ConsensusCoreArgs struct {
7476
ScheduledProcessor consensus.ScheduledProcessor
7577
MessageSigningHandler consensus.P2PSigningHandler
7678
PeerBlacklistHandler consensus.PeerBlacklistHandler
79+
PeerSignatureHandler crypto.PeerSignatureHandler
7780
SigningHandler consensus.SigningHandler
7881
EnableEpochsHandler common.EnableEpochsHandler
7982
EnableRoundsHandler common.EnableRoundsHandler
@@ -111,6 +114,7 @@ func NewConsensusCore(
111114
scheduledProcessor: args.ScheduledProcessor,
112115
messageSigningHandler: args.MessageSigningHandler,
113116
peerBlacklistHandler: args.PeerBlacklistHandler,
117+
peerSignatureHandler: args.PeerSignatureHandler,
114118
signingHandler: args.SigningHandler,
115119
enableEpochsHandler: args.EnableEpochsHandler,
116120
enableRoundsHandler: args.EnableRoundsHandler,
@@ -244,6 +248,11 @@ func (cc *ConsensusCore) PeerBlacklistHandler() consensus.PeerBlacklistHandler {
244248
return cc.peerBlacklistHandler
245249
}
246250

251+
// PeerSignatureHandler will return the peer signature handler
252+
func (cc *ConsensusCore) PeerSignatureHandler() crypto.PeerSignatureHandler {
253+
return cc.peerSignatureHandler
254+
}
255+
247256
// SigningHandler will return the signing handler component
248257
func (cc *ConsensusCore) SigningHandler() consensus.SigningHandler {
249258
return cc.signingHandler
@@ -364,6 +373,11 @@ func (cc *ConsensusCore) SetPeerBlacklistHandler(peerBlacklistHandler consensus.
364373
cc.peerBlacklistHandler = peerBlacklistHandler
365374
}
366375

376+
// SetPeerSignatureHandler sets peer signature handler
377+
func (cc *ConsensusCore) SetPeerSignatureHandler(peerSignatureHandler crypto.PeerSignatureHandler) {
378+
cc.peerSignatureHandler = peerSignatureHandler
379+
}
380+
367381
// SetHeaderSigVerifier sets header sig verifier
368382
func (cc *ConsensusCore) SetHeaderSigVerifier(headerSigVerifier consensus.HeaderSigVerifier) {
369383
cc.headerSigVerifier = headerSigVerifier

consensus/spos/consensusCoreValidator.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ func ValidateConsensusCore(container ConsensusCoreHandler) error {
7676
if check.IfNil(container.PeerBlacklistHandler()) {
7777
return ErrNilPeerBlacklistHandler
7878
}
79+
if check.IfNil(container.PeerSignatureHandler()) {
80+
return ErrNilPeerSignatureHandler
81+
}
7982
if check.IfNil(container.SigningHandler()) {
8083
return ErrNilSigningHandler
8184
}

0 commit comments

Comments
 (0)