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

test: run consensus with several validators #28

Merged
merged 1 commit into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 12 additions & 17 deletions nil/cmd/exporter/internal/fetch_block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

"github.com/NilFoundation/nil/nil/client/rpc"
"github.com/NilFoundation/nil/nil/common/logging"
"github.com/NilFoundation/nil/nil/internal/db"
"github.com/NilFoundation/nil/nil/internal/types"
"github.com/NilFoundation/nil/nil/services/nilservice"
rpctest "github.com/NilFoundation/nil/nil/services/rpc"
Expand All @@ -17,6 +16,7 @@ import (
type SuiteFetchBlock struct {
suite.Suite

server tests.RpcSuite
nShards uint32
cfg Cfg
context context.Context
Expand Down Expand Up @@ -57,23 +57,18 @@ func (s *SuiteFetchBlock) SetupSuite() {
Client: rpc.NewClient(url, logger),
}

database, err := db.NewBadgerDbInMemory()
s.Require().NoError(err)

cfg := nilservice.NewDefaultConfig()
cfg.NShards = s.nShards
cfg.HttpUrl = url
cfg.CollatorTickPeriodMs = 100

tmpDir := s.T().TempDir()
cfg.ValidatorKeysPath = tmpDir + "/validator-keys.yaml"
cfg.NetworkKeysPath = tmpDir + "/network-keys.yaml"
cfg.MainKeysOutPath = tmpDir + "/main-keys.yaml"

go nilservice.Run(s.context, cfg, database, nil)
tests.WaitBlock(s.T(), s.context, s.cfg.Client, types.MainShardId, 1)
cfg := &nilservice.Config{
NShards: s.nShards,
HttpUrl: url,
CollatorTickPeriodMs: 100,
}
s.server.SetT(s.T())
s.server.ShardsNum = s.nShards
s.server.Context = s.context
s.server.CtxCancel = s.cancel
s.server.Start(cfg)
}

func (s *SuiteFetchBlock) TearDownSuite() {
s.cancel()
s.server.Cancel()
}
40 changes: 23 additions & 17 deletions nil/internal/consensus/ibft/ibft.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/NilFoundation/nil/nil/go-ibft/core"
"github.com/NilFoundation/nil/nil/go-ibft/messages"
protoIBFT "github.com/NilFoundation/nil/nil/go-ibft/messages/proto"
"github.com/NilFoundation/nil/nil/internal/config"
"github.com/NilFoundation/nil/nil/internal/db"
"github.com/NilFoundation/nil/nil/internal/execution"
"github.com/NilFoundation/nil/nil/internal/network"
Expand All @@ -24,6 +25,7 @@ type ConsensusParams struct {
Validator validator
NetManager *network.Manager
PrivateKey *ecdsa.PrivateKey
Validators []config.ValidatorInfo
}

type validator interface {
Expand All @@ -33,15 +35,16 @@ type validator interface {
}

type backendIBFT struct {
ctx context.Context
db db.DB
consensus *core.IBFT
shardId types.ShardId
validator validator
logger zerolog.Logger
nm *network.Manager
transport transport
signer *Signer
ctx context.Context
db db.DB
consensus *core.IBFT
shardId types.ShardId
validator validator
logger zerolog.Logger
nm *network.Manager
transport transport
signer *Signer
validators []config.ValidatorInfo
}

var _ core.Backend = &backendIBFT{}
Expand Down Expand Up @@ -99,20 +102,23 @@ func NewConsensus(cfg *ConsensusParams) *backendIBFT {
}

backend := &backendIBFT{
db: cfg.Db,
shardId: cfg.ShardId,
validator: cfg.Validator,
logger: logger,
nm: cfg.NetManager,
signer: NewSigner(cfg.PrivateKey),
db: cfg.Db,
shardId: cfg.ShardId,
validator: cfg.Validator,
logger: logger,
nm: cfg.NetManager,
signer: NewSigner(cfg.PrivateKey),
validators: cfg.Validators,
}
backend.consensus = core.NewIBFT(l, backend, backend)
return backend
}

func (i *backendIBFT) GetVotingPowers(height uint64) (map[string]*big.Int, error) {
result := make(map[string]*big.Int)
result[string(i.ID())] = big.NewInt(1)
result := make(map[string]*big.Int, len(i.validators))
for _, v := range i.validators {
result[string(v.PublicKey[:])] = big.NewInt(1)
}
return result, nil
}

Expand Down
4 changes: 2 additions & 2 deletions nil/internal/consensus/ibft/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ func (s *Signer) Sign(data []byte) (types.Signature, error) {
}

func (s *Signer) Verify(data []byte, signature types.Signature) bool {
return s.verifyWithKey(s.rawPublicKey, data, signature)
return s.VerifyWithKey(s.rawPublicKey, data, signature)
}

func (s *Signer) verifyWithKey(publicKey []byte, data []byte, signature types.Signature) bool {
func (s *Signer) VerifyWithKey(publicKey []byte, data []byte, signature types.Signature) bool {
return len(signature) >= 64 && crypto.VerifySignature(publicKey, getHash(data), signature[:64])
}

Expand Down
10 changes: 10 additions & 0 deletions nil/internal/consensus/ibft/validators.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ibft

import (
"github.com/NilFoundation/nil/nil/internal/config"
)

func (i *backendIBFT) calcProposer(height, round uint64) config.ValidatorInfo {
index := (height + round) % uint64(len(i.validators))
return i.validators[index]
}
27 changes: 23 additions & 4 deletions nil/internal/consensus/ibft/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package ibft

import (
"bytes"
"slices"

"github.com/NilFoundation/nil/nil/common/logging"
"github.com/NilFoundation/nil/nil/go-ibft/messages"
protoIBFT "github.com/NilFoundation/nil/nil/go-ibft/messages/proto"
"github.com/NilFoundation/nil/nil/internal/config"
)

func (i *backendIBFT) IsValidProposal(rawProposal []byte) bool {
Expand All @@ -24,8 +26,24 @@ func (i *backendIBFT) IsValidValidator(msg *protoIBFT.IbftMessage) bool {
return false
}

if !i.signer.Verify(msgNoSig, msg.Signature) {
event := i.logger.Error().Stringer(logging.FieldType, msg.GetType())
index := slices.IndexFunc(i.validators, func(v config.ValidatorInfo) bool {
return bytes.Equal(v.PublicKey[:], msg.From)
})
if index == -1 {
event := i.logger.Error().
Hex("key", msg.From)

if view := msg.GetView(); view != nil {
event = event.Uint64(logging.FieldHeight, view.Height).
Uint64(logging.FieldRound, view.Round)
}
event.Msg("Key not found in validators list")
return false
}

validator := i.validators[index]
if !i.signer.VerifyWithKey(validator.PublicKey[:], msgNoSig, msg.Signature) {
event := i.logger.Error()
if view := msg.GetView(); view != nil {
event = event.Uint64(logging.FieldHeight, view.Height).
Uint64(logging.FieldRound, view.Round)
Expand All @@ -38,7 +56,8 @@ func (i *backendIBFT) IsValidValidator(msg *protoIBFT.IbftMessage) bool {
}

func (i *backendIBFT) IsProposer(id []byte, height, round uint64) bool {
return true
proposer := i.calcProposer(height, round)
return bytes.Equal(proposer.PublicKey[:], id)
}

func (i *backendIBFT) IsValidProposalHash(proposal *protoIBFT.Proposal, hash []byte) bool {
Expand Down Expand Up @@ -66,7 +85,7 @@ func (i *backendIBFT) IsValidProposalHash(proposal *protoIBFT.Proposal, hash []b
}

func (i *backendIBFT) IsValidCommittedSeal(
proposalHash []byte,
_ []byte,
committedSeal *messages.CommittedSeal,
) bool {
return true
Expand Down
29 changes: 19 additions & 10 deletions nil/services/nilservice/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ func NewDefaultConfig() *Config {
GracefulShutdown: true,
Topology: collate.TrivialShardTopologyId,

Validators: make(map[types.ShardId][]config.ValidatorInfo),

Network: network.NewDefaultConfig(),
Telemetry: telemetry.NewDefaultConfig(),
Replay: NewDefaultReplayConfig(),
Expand Down Expand Up @@ -171,25 +173,32 @@ func (c *Config) Validate() error {
return nil
}

func (c *Config) LoadValidatorPrivateKey() (key *ecdsa.PrivateKey, err error) {
defer func() {
if err == nil {
Logger.Trace().
Hex(logging.FieldPublicKey, crypto.FromECDSAPub(&key.PublicKey)).
Msg("Loaded validator key")
}
}()
func (c *Config) loadValidatorKeys() error {
if c.ValidatorKeysPath == "" {
return execution.MainPrivateKey, nil
return nil
}

if c.ValidatorKeysManager == nil {
c.ValidatorKeysManager = keys.NewValidatorKeyManager(c.ValidatorKeysPath)
if err := c.ValidatorKeysManager.InitKey(); err != nil {
return nil, err
return err
}
}

return nil
}

func (c *Config) LoadValidatorPrivateKey() (key *ecdsa.PrivateKey, err error) {
defer func() {
if err == nil {
Logger.Trace().
Hex(logging.FieldPublicKey, crypto.FromECDSAPub(&key.PublicKey)).
Msg("Loaded validator key")
}
}()
if err := c.loadValidatorKeys(); err != nil {
return nil, err
}
return c.ValidatorKeysManager.GetKey()
}

Expand Down
14 changes: 14 additions & 0 deletions nil/services/nilservice/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/NilFoundation/nil/nil/common/concurrent"
"github.com/NilFoundation/nil/nil/common/logging"
"github.com/NilFoundation/nil/nil/internal/collate"
"github.com/NilFoundation/nil/nil/internal/config"
"github.com/NilFoundation/nil/nil/internal/consensus/ibft"
"github.com/NilFoundation/nil/nil/internal/db"
"github.com/NilFoundation/nil/nil/internal/execution"
Expand Down Expand Up @@ -471,6 +472,18 @@ func createShards(
return nil, nil, err
}

if !cfg.SplitShards && len(cfg.Validators) == 0 {
pubkey, err := cfg.ValidatorKeysManager.GetPublicKey()
if err != nil {
return nil, nil, err
}
for i := range cfg.NShards {
cfg.Validators[types.ShardId(i)] = []config.ValidatorInfo{
{PublicKey: config.Pubkey(pubkey)},
}
}
}

for i := range cfg.NShards {
shardId := types.ShardId(i)

Expand Down Expand Up @@ -526,6 +539,7 @@ func createShards(
Validator: collator.Validator(),
NetManager: networkManager,
PrivateKey: pKey,
Validators: cfg.Validators[shardId],
})
if err := consensus.Init(ctx); err != nil {
return nil, nil, err
Expand Down
46 changes: 9 additions & 37 deletions nil/services/synccommittee/core/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,55 +6,31 @@ import (
"testing"
"time"

"github.com/NilFoundation/nil/nil/client/rpc"
"github.com/NilFoundation/nil/nil/internal/collate"
"github.com/NilFoundation/nil/nil/internal/db"
"github.com/NilFoundation/nil/nil/internal/types"
"github.com/NilFoundation/nil/nil/services/nilservice"
rpctest "github.com/NilFoundation/nil/nil/services/rpc"
"github.com/NilFoundation/nil/nil/services/rpc/transport"
"github.com/NilFoundation/nil/nil/services/synccommittee/internal/rollupcontract"
"github.com/rs/zerolog"
"github.com/NilFoundation/nil/nil/tests"
"github.com/stretchr/testify/suite"
)

type SyncCommitteeTestSuite struct {
suite.Suite

server tests.RpcSuite
nShards uint32
syncCommittee *SyncCommittee
nilCancel context.CancelFunc
doneChan chan interface{} // to track when nilservice has finished
ctx context.Context
nilDb db.DB
scDb db.DB
}

func (s *SyncCommitteeTestSuite) waitZerostrate(endpoint string) {
s.T().Helper()
client := rpc.NewClient(endpoint, zerolog.Nop())
const (
zeroStateWaitTimeout = 5 * time.Second
zeroStatePollInterval = time.Second
)
for i := range s.nShards {
s.Require().Eventually(func() bool {
block, err := client.GetBlock(s.ctx, types.ShardId(i), transport.BlockNumber(0), false)
return err == nil && block != nil
}, zeroStateWaitTimeout, zeroStatePollInterval)
}
}

func (s *SyncCommitteeTestSuite) SetupSuite() {
s.nShards = 4
s.ctx = context.Background()

url := rpctest.GetSockPath(s.T())

var err error
s.nilDb, err = db.NewBadgerDbInMemory()
s.Require().NoError(err)

// Setup nilservice
nilserviceCfg := &nilservice.Config{
NShards: s.nShards,
Expand All @@ -63,19 +39,17 @@ func (s *SyncCommitteeTestSuite) SetupSuite() {
CollatorTickPeriodMs: 100,
GasBasePrice: 10,
}
var nilContext context.Context
nilContext, s.nilCancel = context.WithCancel(context.Background())
s.doneChan = make(chan interface{})
go func() {
nilservice.Run(nilContext, nilserviceCfg, s.nilDb, nil)
s.doneChan <- nil
}()

s.waitZerostrate(url)
nilContext, nilCancel := context.WithCancel(s.ctx)
s.server.SetT(s.T())
s.server.Context = nilContext
s.server.CtxCancel = nilCancel
s.server.Start(nilserviceCfg)

cfg := NewDefaultConfig()
cfg.RpcEndpoint = url

var err error
s.scDb, err = db.NewBadgerDbInMemory()
s.Require().NoError(err)
ethClientMock := &rollupcontract.EthClientMock{ChainIDFunc: func(ctx context.Context) (*big.Int, error) { return big.NewInt(0), nil }}
Expand All @@ -84,9 +58,7 @@ func (s *SyncCommitteeTestSuite) SetupSuite() {
}

func (s *SyncCommitteeTestSuite) TearDownSuite() {
s.nilCancel()
<-s.doneChan // Wait for nilservice to shutdown
s.nilDb.Close()
s.server.Cancel()
s.scDb.Close()
}

Expand Down
2 changes: 1 addition & 1 deletion nil/services/txnpool/txnpool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ func (s *SuiteTxnPool) TestNetwork() {
has, err := pool2.IdHashKnown(txn.Hash())
s.Require().NoError(err)
return has
}, 10*time.Second, 100*time.Millisecond)
}, 20*time.Second, 200*time.Millisecond)
}

func TestSuiteTxnpool(t *testing.T) {
Expand Down
Loading