From 8e31a8edb7a7c04452a2f26ef7740e6003b81fbf Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 15 Aug 2023 18:08:41 +0400 Subject: [PATCH 01/16] [Audit Suggestion 1] Do not use panics on fork (#1100) * Do not use panics on fork * Change error text --- operator/fork.go | 16 ++++++++++------ operator/node.go | 15 ++++++++++++--- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/operator/fork.go b/operator/fork.go index baaff8d309..f22368fa62 100644 --- a/operator/fork.go +++ b/operator/fork.go @@ -1,6 +1,8 @@ package operator import ( + "fmt" + "github.com/attestantio/go-eth2-client/spec/phase0" "go.uber.org/zap" @@ -14,10 +16,10 @@ func (n *operatorNode) getForkVersion(slot phase0.Slot) forksprotocol.ForkVersio } // listenForCurrentSlot updates forkVersion and checks if a fork is needed -func (n *operatorNode) setFork(logger *zap.Logger, slot phase0.Slot) { +func (n *operatorNode) setFork(logger *zap.Logger, slot phase0.Slot) error { currentVersion := n.getForkVersion(slot) if currentVersion == n.forkVersion { - return + return nil } logger = logger.With(zap.String("previousFork", string(n.forkVersion)), zap.String("currentFork", string(currentVersion))) @@ -28,18 +30,20 @@ func (n *operatorNode) setFork(logger *zap.Logger, slot phase0.Slot) { // set network fork netHandler, ok := n.net.(forksprotocol.ForkHandler) if !ok { - logger.Panic("network instance is not a fork handler") + return fmt.Errorf("network instance is not a fork handler") } if err := netHandler.OnFork(logger, currentVersion); err != nil { - logger.Panic("could not fork network", zap.Error(err)) + return fmt.Errorf("could not fork network: %w", err) } // set validator controller fork vCtrlHandler, ok := n.validatorsCtrl.(forksprotocol.ForkHandler) if !ok { - logger.Panic("network instance is not a fork handler") + return fmt.Errorf("network instance is not a fork handler") } if err := vCtrlHandler.OnFork(logger, currentVersion); err != nil { - logger.Panic("could not fork network", zap.Error(err)) + return fmt.Errorf("could not fork network: %w", err) } + + return nil } diff --git a/operator/node.go b/operator/node.go index 963248f31f..713a786e84 100644 --- a/operator/node.go +++ b/operator/node.go @@ -149,7 +149,11 @@ func (n *operatorNode) Start(logger *zap.Logger) error { }() go n.ticker.Start(logger) - go n.listenForCurrentSlot(logger) + go func() { + if err := n.listenForCurrentSlot(logger); err != nil { + logger.Fatal("unexpected error while listening for current slot", zap.Error(err)) + } + }() n.validatorsCtrl.StartNetworkHandlers() n.validatorsCtrl.StartValidators() go n.net.UpdateSubnets(logger) @@ -172,12 +176,17 @@ func (n *operatorNode) Start(logger *zap.Logger) error { } // listenForCurrentSlot listens to current slot and trigger relevant components if needed -func (n *operatorNode) listenForCurrentSlot(logger *zap.Logger) { +func (n *operatorNode) listenForCurrentSlot(logger *zap.Logger) error { tickerChan := make(chan phase0.Slot, 32) n.ticker.Subscribe(tickerChan) + for slot := range tickerChan { - n.setFork(logger, slot) + if err := n.setFork(logger, slot); err != nil { + return err + } } + + return nil } // HealthCheck returns a list of issues regards the state of the operator node From 888db7c6359d7a7a04d0ff4f8d964f99a5479e1b Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 15 Aug 2023 18:09:03 +0400 Subject: [PATCH 02/16] [Audit Issue C] Limit decoded share size (#1098) * Limit decoded share size * Add tests * Increase factor --- protocol/v2/types/ssvshare.go | 9 +++ registry/storage/shares_test.go | 101 +++++++++++++++++++++----------- 2 files changed, 75 insertions(+), 35 deletions(-) diff --git a/protocol/v2/types/ssvshare.go b/protocol/v2/types/ssvshare.go index 08bd541ef3..2866082975 100644 --- a/protocol/v2/types/ssvshare.go +++ b/protocol/v2/types/ssvshare.go @@ -15,6 +15,11 @@ import ( beaconprotocol "github.com/bloxapp/ssv/protocol/v2/blockchain/beacon" ) +const ( + MaxPossibleShareSize = 1245 + MaxAllowedShareSize = MaxPossibleShareSize * 8 // Leaving some room for protocol updates and calculation mistakes. +) + // SSVShare is a combination of spectypes.Share and its Metadata. type SSVShare struct { spectypes.Share @@ -34,6 +39,10 @@ func (s *SSVShare) Encode() ([]byte, error) { // Decode decodes SSVShare using gob. func (s *SSVShare) Decode(data []byte) error { + if len(data) > MaxAllowedShareSize { + return fmt.Errorf("share size is too big, got %v, max allowed %v", len(data), MaxAllowedShareSize) + } + d := gob.NewDecoder(bytes.NewReader(data)) if err := d.Decode(s); err != nil { return fmt.Errorf("decode SSVShare: %w", err) diff --git a/registry/storage/shares_test.go b/registry/storage/shares_test.go index 3a90c76aa1..5e684147b4 100644 --- a/registry/storage/shares_test.go +++ b/registry/storage/shares_test.go @@ -1,18 +1,22 @@ package storage import ( + "bytes" "encoding/hex" + "sort" + "strconv" "testing" spectypes "github.com/bloxapp/ssv-spec/types" - "github.com/bloxapp/ssv/logging" "github.com/ethereum/go-ethereum/common" "github.com/herumi/bls-eth-go-binary/bls" "github.com/stretchr/testify/require" "go.uber.org/zap" + "github.com/bloxapp/ssv/logging" + "github.com/bloxapp/ssv/networkconfig" beaconprotocol "github.com/bloxapp/ssv/protocol/v2/blockchain/beacon" - "github.com/bloxapp/ssv/protocol/v2/types" + ssvtypes "github.com/bloxapp/ssv/protocol/v2/types" ssvstorage "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" "github.com/bloxapp/ssv/utils/threshold" @@ -24,7 +28,7 @@ func TestValidatorSerializer(t *testing.T) { sk := &bls.SecretKey{} sk.SetByCSPRNG() - const keysCount = 4 + const keysCount = 13 splitKeys, err := threshold.Create(sk.Serialize(), keysCount-1, keysCount) require.NoError(t, err) @@ -37,7 +41,7 @@ func TestValidatorSerializer(t *testing.T) { Key: validatorShare.ValidatorPubKey, Value: b, } - v1 := &types.SSVShare{} + v1 := &ssvtypes.SSVShare{} require.NoError(t, v1.Decode(obj.Value)) require.NotNil(t, v1.ValidatorPubKey) require.Equal(t, hex.EncodeToString(v1.ValidatorPubKey), hex.EncodeToString(validatorShare.ValidatorPubKey)) @@ -46,6 +50,20 @@ func TestValidatorSerializer(t *testing.T) { require.Equal(t, v1.BeaconMetadata, validatorShare.BeaconMetadata) require.Equal(t, v1.OwnerAddress, validatorShare.OwnerAddress) require.Equal(t, v1.Liquidated, validatorShare.Liquidated) + + tooBigEncodedShare := bytes.Repeat(obj.Value, 20) + require.ErrorContains(t, v1.Decode(tooBigEncodedShare), + "share size is too big, got "+strconv.Itoa(len(tooBigEncodedShare))+", max allowed "+strconv.Itoa(ssvtypes.MaxAllowedShareSize)) +} + +func TestMaxPossibleShareSize(t *testing.T) { + s, err := generateMaxPossibleShare() + require.NoError(t, err) + + b, err := s.Encode() + require.NoError(t, err) + + require.Equal(t, ssvtypes.MaxPossibleShareSize, len(b)) } func TestSaveAndGetValidatorStorage(t *testing.T) { @@ -84,7 +102,7 @@ func TestSaveAndGetValidatorStorage(t *testing.T) { require.Nil(t, share) } -func generateRandomValidatorShare(splitKeys map[uint64]*bls.SecretKey) (*types.SSVShare, *bls.SecretKey) { +func generateRandomValidatorShare(splitKeys map[uint64]*bls.SecretKey) (*ssvtypes.SSVShare, *bls.SecretKey) { threshold.Init() sk1 := bls.SecretKey{} @@ -93,41 +111,37 @@ func generateRandomValidatorShare(splitKeys map[uint64]*bls.SecretKey) (*types.S sk2 := bls.SecretKey{} sk2.SetByCSPRNG() - ibftCommittee := []*spectypes.Operator{ - { - OperatorID: 1, - PubKey: splitKeys[1].Serialize(), - }, - { - OperatorID: 2, - PubKey: splitKeys[2].Serialize(), - }, - { - OperatorID: 3, - PubKey: splitKeys[3].Serialize(), - }, - { - OperatorID: 4, - PubKey: splitKeys[4].Serialize(), - }, + var ibftCommittee []*spectypes.Operator + for operatorID, sk := range splitKeys { + ibftCommittee = append(ibftCommittee, &spectypes.Operator{ + OperatorID: operatorID, + PubKey: sk.Serialize(), + }) } + sort.Slice(ibftCommittee, func(i, j int) bool { + return ibftCommittee[i].OperatorID < ibftCommittee[j].OperatorID + }) - return &types.SSVShare{ + quorum, partialQuorum := ssvtypes.ComputeQuorumAndPartialQuorum(len(splitKeys)) + + return &ssvtypes.SSVShare{ Share: spectypes.Share{ - OperatorID: 1, - ValidatorPubKey: sk1.GetPublicKey().Serialize(), - SharePubKey: sk2.GetPublicKey().Serialize(), - Committee: ibftCommittee, - Quorum: 3, - PartialQuorum: 2, - DomainType: types.GetDefaultDomain(), - Graffiti: nil, + OperatorID: 1, + ValidatorPubKey: sk1.GetPublicKey().Serialize(), + SharePubKey: sk2.GetPublicKey().Serialize(), + Committee: ibftCommittee, + Quorum: quorum, + PartialQuorum: partialQuorum, + DomainType: networkconfig.TestNetwork.Domain, + FeeRecipientAddress: common.HexToAddress("0xFeedB14D8b2C76FdF808C29818b06b830E8C2c0e"), + Graffiti: bytes.Repeat([]byte{0x01}, 32), }, - Metadata: types.Metadata{ + Metadata: ssvtypes.Metadata{ BeaconMetadata: &beaconprotocol.ValidatorMetadata{ - Balance: 1, - Status: 2, - Index: 3, + Balance: 1, + Status: 2, + Index: 3, + ActivationEpoch: 4, }, OwnerAddress: common.HexToAddress("0xFeedB14D8b2C76FdF808C29818b06b830E8C2c0e"), Liquidated: true, @@ -135,6 +149,23 @@ func generateRandomValidatorShare(splitKeys map[uint64]*bls.SecretKey) (*types.S }, &sk1 } +func generateMaxPossibleShare() (*ssvtypes.SSVShare, error) { + threshold.Init() + + sk := &bls.SecretKey{} + sk.SetByCSPRNG() + + const keysCount = 13 + + splitKeys, err := threshold.Create(sk.Serialize(), keysCount-1, keysCount) + if err != nil { + return nil, err + } + + validatorShare, _ := generateRandomValidatorShare(splitKeys) + return validatorShare, nil +} + func newShareStorageForTest(logger *zap.Logger) (Shares, func()) { db, err := ssvstorage.GetStorageFactory(logger, basedb.Options{ Type: "badger-memory", From 0bef1fccbdfeee1cb528e669266a7ac92de7a0e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Aug 2023 17:09:41 +0300 Subject: [PATCH 03/16] chore(deps): bump github.com/libp2p/go-libp2p from 0.28.1 to 0.28.2 (#1096) Bumps [github.com/libp2p/go-libp2p](https://github.com/libp2p/go-libp2p) from 0.28.1 to 0.28.2. - [Release notes](https://github.com/libp2p/go-libp2p/releases) - [Changelog](https://github.com/libp2p/go-libp2p/blob/master/CHANGELOG.md) - [Commits](https://github.com/libp2p/go-libp2p/compare/v0.28.1...v0.28.2) --- updated-dependencies: - dependency-name: github.com/libp2p/go-libp2p dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: Lior Rutenberg Co-authored-by: olegshmuelov <45327364+olegshmuelov@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 0047f90f56..19c0a0f894 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/herumi/bls-eth-go-binary v1.29.1 github.com/ilyakaznacheev/cleanenv v1.4.2 github.com/jellydator/ttlcache/v3 v3.0.1 - github.com/libp2p/go-libp2p v0.28.1 + github.com/libp2p/go-libp2p v0.28.2 github.com/libp2p/go-libp2p-kad-dht v0.23.0 github.com/libp2p/go-libp2p-pubsub v0.9.3 github.com/multiformats/go-multiaddr v0.9.0 @@ -163,8 +163,8 @@ require ( github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.2 // indirect - github.com/quic-go/qtls-go1-20 v0.2.2 // indirect + github.com/quic-go/qtls-go1-19 v0.3.3 // indirect + github.com/quic-go/qtls-go1-20 v0.2.3 // indirect github.com/quic-go/quic-go v0.33.0 // indirect github.com/quic-go/webtransport-go v0.5.3 // indirect github.com/r3labs/sse/v2 v2.7.4 // indirect diff --git a/go.sum b/go.sum index e98c7888c4..dca30223cb 100644 --- a/go.sum +++ b/go.sum @@ -418,8 +418,8 @@ github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38y github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.28.1 h1:YurK+ZAI6cKfASLJBVFkpVBdl3wGhFi6fusOt725ii8= -github.com/libp2p/go-libp2p v0.28.1/go.mod h1:s3Xabc9LSwOcnv9UD4nORnXKTsWkPMkIMB/JIGXVnzk= +github.com/libp2p/go-libp2p v0.28.2 h1:lO/g0ccVru6nUVHyLE7C1VRr7B2AFp9cvHhf+l+Te6w= +github.com/libp2p/go-libp2p v0.28.2/go.mod h1:fOLgCNgLiWFdmtXyQBwmuCpukaYOA+yw4rnBiScDNmI= github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s= github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w= github.com/libp2p/go-libp2p-kad-dht v0.23.0 h1:sxE6LxLopp79eLeV695n7+c77V/Vn4AMF28AdM/XFqM= @@ -619,10 +619,10 @@ github.com/prysmaticlabs/prysm/v4 v4.0.5 h1:w3f9E83TO3F/iFnhrshOSyCy2C+Jeq7wb3Ux github.com/prysmaticlabs/prysm/v4 v4.0.5/go.mod h1:N6fIW+iomS71FgWfzzsSbybJehJVVXvCwBvHcpsCXPA= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= -github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= -github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/quic-go/qtls-go1-19 v0.3.3 h1:wznEHvJwd+2X3PqftRha0SUKmGsnb6dfArMhy9PeJVE= +github.com/quic-go/qtls-go1-19 v0.3.3/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.2.3 h1:m575dovXn1y2ATOb1XrRFcrv0F+EQmlowTkoraNkDPI= +github.com/quic-go/qtls-go1-20 v0.2.3/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0= github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA= github.com/quic-go/webtransport-go v0.5.3 h1:5XMlzemqB4qmOlgIus5zB45AcZ2kCgCy2EptUrfOPWU= From 7047d0deb2802b53561182e10799b8f5617ba487 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 15 Aug 2023 19:03:24 +0400 Subject: [PATCH 04/16] [Audit Suggestion 3] Prevent Badger InMemory From Running in Production. (#1092) * Explicit function for in-memory BadgerDB * Imports cleanup --------- Co-authored-by: Lior Rutenberg --- cli/operator/node.go | 5 ++--- ekm/signer_storage_test.go | 8 +++---- eth/eventhandler/event_handler_test.go | 17 +++++--------- eth/eventsyncer/event_syncer_test.go | 11 +++------ exporter/api/query_handlers_test.go | 7 ++---- ibft/storage/store_test.go | 9 ++++---- identity/store_test.go | 11 +++------ integration/qbft/tests/scenario_test.go | 7 ++---- migrations/migrations_test.go | 14 +++++------- operator/fee_recipient/controller_test.go | 9 ++------ operator/storage/storage_test.go | 24 +++++--------------- protocol/v2/qbft/testing/storage.go | 9 +++----- protocol/v2/testing/test_utils.go | 12 ---------- registry/storage/operators_test.go | 7 ++---- registry/storage/recipients_test.go | 8 +++---- registry/storage/shares_test.go | 10 ++++----- storage/basedb/storage.go | 3 +-- storage/kv/badger.go | 13 +++++++++-- storage/kv/badger_test.go | 27 ++++++----------------- storage/main.go | 23 ------------------- 20 files changed, 70 insertions(+), 164 deletions(-) delete mode 100644 storage/main.go diff --git a/cli/operator/node.go b/cli/operator/node.go index b95c0d34f4..5dc91247c0 100644 --- a/cli/operator/node.go +++ b/cli/operator/node.go @@ -49,7 +49,6 @@ import ( beaconprotocol "github.com/bloxapp/ssv/protocol/v2/blockchain/beacon" "github.com/bloxapp/ssv/protocol/v2/types" registrystorage "github.com/bloxapp/ssv/registry/storage" - "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" "github.com/bloxapp/ssv/storage/kv" "github.com/bloxapp/ssv/utils/commons" @@ -320,7 +319,7 @@ func setupGlobal(cmd *cobra.Command) (*zap.Logger, error) { } func setupDB(logger *zap.Logger, eth2Network beaconprotocol.Network) (*kv.BadgerDB, error) { - db, err := storage.GetStorageFactory(logger, cfg.DBOptions) + db, err := kv.New(logger, cfg.DBOptions) if err != nil { return nil, errors.Wrap(err, "failed to open db") } @@ -328,7 +327,7 @@ func setupDB(logger *zap.Logger, eth2Network beaconprotocol.Network) (*kv.Badger if err := db.Close(); err != nil { return errors.Wrap(err, "failed to close db") } - db, err = storage.GetStorageFactory(logger, cfg.DBOptions) + db, err = kv.New(logger, cfg.DBOptions) return errors.Wrap(err, "failed to reopen db") } diff --git a/ekm/signer_storage_test.go b/ekm/signer_storage_test.go index f4eb837b50..abdfd485e1 100644 --- a/ekm/signer_storage_test.go +++ b/ekm/signer_storage_test.go @@ -18,8 +18,8 @@ import ( "github.com/bloxapp/ssv/logging" "github.com/bloxapp/ssv/networkconfig" + "github.com/bloxapp/ssv/storage/kv" - ssvstorage "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" "github.com/bloxapp/ssv/utils/threshold" ) @@ -30,10 +30,7 @@ func _byteArray(input string) []byte { } func getBaseStorage(logger *zap.Logger) (basedb.Database, error) { - return ssvstorage.GetStorageFactory(logger, basedb.Options{ - Type: "badger-memory", - Path: "", - }) + return kv.NewInMemory(logger, basedb.Options{}) } func newStorageForTest(t *testing.T) (Storage, func()) { @@ -42,6 +39,7 @@ func newStorageForTest(t *testing.T) (Storage, func()) { if err != nil { return nil, func() {} } + s := NewSignerStorage(db, networkconfig.TestNetwork.Beacon.GetNetwork(), logger) return s, func() { db.Close() diff --git a/eth/eventhandler/event_handler_test.go b/eth/eventhandler/event_handler_test.go index 794a53ab8c..a44fc7364e 100644 --- a/eth/eventhandler/event_handler_test.go +++ b/eth/eventhandler/event_handler_test.go @@ -5,7 +5,6 @@ import ( "encoding/base64" "encoding/json" "fmt" - "github.com/bloxapp/ssv/utils/rsaencryption" "math/big" "net/http/httptest" "strings" @@ -26,7 +25,6 @@ import ( "github.com/bloxapp/ssv/ekm" "github.com/bloxapp/ssv/eth/contract" - "github.com/bloxapp/ssv/eth/eventparser" "github.com/bloxapp/ssv/eth/executionclient" "github.com/bloxapp/ssv/eth/simulator" @@ -38,9 +36,10 @@ import ( "github.com/bloxapp/ssv/protocol/v2/blockchain/beacon" ssvtypes "github.com/bloxapp/ssv/protocol/v2/types" registrystorage "github.com/bloxapp/ssv/registry/storage" - ssvstorage "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" "github.com/bloxapp/ssv/utils/blskeygen" + "github.com/bloxapp/ssv/utils/rsaencryption" "github.com/bloxapp/ssv/utils/threshold" ) @@ -349,15 +348,9 @@ func TestHandleBlockEventsStream(t *testing.T) { } func setupEventHandler(t *testing.T, ctx context.Context, logger *zap.Logger) (*EventHandler, error) { - options := basedb.Options{ - Type: "badger-memory", - Path: "", - Reporting: false, - GCInterval: 0, - Ctx: ctx, - } - - db, err := ssvstorage.GetStorageFactory(logger, options) + db, err := kv.NewInMemory(logger, basedb.Options{ + Ctx: ctx, + }) require.NoError(t, err) storageMap := ibftstorage.NewStores() diff --git a/eth/eventsyncer/event_syncer_test.go b/eth/eventsyncer/event_syncer_test.go index 35d519b152..4bd33eacc2 100644 --- a/eth/eventsyncer/event_syncer_test.go +++ b/eth/eventsyncer/event_syncer_test.go @@ -131,14 +131,9 @@ func TestEventSyncer(t *testing.T) { } func setupEventHandler(t *testing.T, ctx context.Context, logger *zap.Logger) *eventhandler.EventHandler { - options := basedb.Options{ - Type: "badger-memory", - Path: "", - Reporting: false, - Ctx: ctx, - } - - db, err := kv.New(logger, options) + db, err := kv.NewInMemory(logger, basedb.Options{ + Ctx: ctx, + }) require.NoError(t, err) storageMap := ibftstorage.NewStores() diff --git a/exporter/api/query_handlers_test.go b/exporter/api/query_handlers_test.go index 90b1c95fda..3a70a1c116 100644 --- a/exporter/api/query_handlers_test.go +++ b/exporter/api/query_handlers_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/bloxapp/ssv/logging" + "github.com/bloxapp/ssv/storage/kv" specqbft "github.com/bloxapp/ssv-spec/qbft" spectypes "github.com/bloxapp/ssv-spec/types" @@ -18,7 +19,6 @@ import ( forksprotocol "github.com/bloxapp/ssv/protocol/forks" protocoltesting "github.com/bloxapp/ssv/protocol/v2/testing" "github.com/bloxapp/ssv/protocol/v2/types" - ssvstorage "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" ) @@ -183,10 +183,7 @@ func newDecidedAPIMsg(pk string, role spectypes.BeaconRole, from, to uint64) *Ne } func newDBAndLoggerForTest(logger *zap.Logger) (basedb.Database, *zap.Logger, func()) { - db, err := ssvstorage.GetStorageFactory(logger, basedb.Options{ - Type: "badger-memory", - Path: "", - }) + db, err := kv.NewInMemory(logger, basedb.Options{}) if err != nil { return nil, nil, func() {} } diff --git a/ibft/storage/store_test.go b/ibft/storage/store_test.go index d4f8ee5340..f7a8ec0edd 100644 --- a/ibft/storage/store_test.go +++ b/ibft/storage/store_test.go @@ -5,15 +5,15 @@ import ( specqbft "github.com/bloxapp/ssv-spec/qbft" spectypes "github.com/bloxapp/ssv-spec/types" - "github.com/bloxapp/ssv/logging" "github.com/stretchr/testify/require" "go.uber.org/zap" + "github.com/bloxapp/ssv/logging" forksprotocol "github.com/bloxapp/ssv/protocol/forks" qbftstorage "github.com/bloxapp/ssv/protocol/v2/qbft/storage" "github.com/bloxapp/ssv/protocol/v2/types" - ssvstorage "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" ) func TestCleanInstances(t *testing.T) { @@ -171,13 +171,12 @@ func TestSaveAndFetchState(t *testing.T) { } func newTestIbftStorage(logger *zap.Logger, prefix string, forkVersion forksprotocol.ForkVersion) (qbftstorage.QBFTStore, error) { - db, err := ssvstorage.GetStorageFactory(logger.Named(logging.NameBadgerDBLog), basedb.Options{ - Type: "badger-memory", - Path: "", + db, err := kv.NewInMemory(logger.Named(logging.NameBadgerDBLog), basedb.Options{ Reporting: true, }) if err != nil { return nil, err } + return New(db, prefix, forkVersion), nil } diff --git a/identity/store_test.go b/identity/store_test.go index 78d954b729..4fe7da535a 100644 --- a/identity/store_test.go +++ b/identity/store_test.go @@ -4,13 +4,13 @@ import ( "encoding/hex" "testing" - "github.com/bloxapp/ssv/logging" gcrypto "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" + "github.com/bloxapp/ssv/logging" "github.com/bloxapp/ssv/network/commons" - ssvstorage "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" ) var ( @@ -51,12 +51,7 @@ func TestSetupPrivateKey(t *testing.T) { for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { - options := basedb.Options{ - Type: "badger-memory", - Path: "", - } - - db, err := ssvstorage.GetStorageFactory(logging.TestLogger(t), options) + db, err := kv.NewInMemory(logging.TestLogger(t), basedb.Options{}) require.NoError(t, err) defer db.Close() diff --git a/integration/qbft/tests/scenario_test.go b/integration/qbft/tests/scenario_test.go index c2994efb67..4699bb60af 100644 --- a/integration/qbft/tests/scenario_test.go +++ b/integration/qbft/tests/scenario_test.go @@ -28,8 +28,8 @@ import ( protocolvalidator "github.com/bloxapp/ssv/protocol/v2/ssv/validator" "github.com/bloxapp/ssv/protocol/v2/sync/handlers" "github.com/bloxapp/ssv/protocol/v2/types" - "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" ) var ( @@ -168,10 +168,7 @@ func quorum(committee int) int { } func newStores(logger *zap.Logger) *qbftstorage.QBFTStores { - db, err := storage.GetStorageFactory(logger, basedb.Options{ - Type: "badger-memory", - Path: "", - }) + db, err := kv.NewInMemory(logger, basedb.Options{}) if err != nil { panic(err) } diff --git a/migrations/migrations_test.go b/migrations/migrations_test.go index a4876bbcdd..ff16d58add 100644 --- a/migrations/migrations_test.go +++ b/migrations/migrations_test.go @@ -5,23 +5,21 @@ import ( "fmt" "testing" - "github.com/bloxapp/ssv/logging" - "github.com/bloxapp/ssv/storage/basedb" - "github.com/bloxapp/ssv/storage/kv" "github.com/pkg/errors" "github.com/stretchr/testify/require" "go.uber.org/zap" + + "github.com/bloxapp/ssv/logging" + "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" ) func setupOptions(ctx context.Context, t *testing.T) (Options, error) { // Create in-memory test DB. - options := basedb.Options{ - Type: "badger-memory", - Path: "", + db, err := kv.NewInMemory(logging.TestLogger(t), basedb.Options{ Reporting: true, Ctx: ctx, - } - db, err := kv.New(logging.TestLogger(t), options) + }) if err != nil { return Options{}, err } diff --git a/operator/fee_recipient/controller_test.go b/operator/fee_recipient/controller_test.go index fa9c0a343e..02bf4144dd 100644 --- a/operator/fee_recipient/controller_test.go +++ b/operator/fee_recipient/controller_test.go @@ -23,8 +23,8 @@ import ( "github.com/bloxapp/ssv/protocol/v2/blockchain/beacon" "github.com/bloxapp/ssv/protocol/v2/types" registrystorage "github.com/bloxapp/ssv/registry/storage" - "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" ) func TestSubmitProposal(t *testing.T) { @@ -105,12 +105,7 @@ func TestSubmitProposal(t *testing.T) { func createStorage(t *testing.T) (basedb.Database, registrystorage.Shares, registrystorage.Recipients) { logger := logging.TestLogger(t) - options := basedb.Options{ - Type: "badger-memory", - Path: "", - } - - db, err := storage.GetStorageFactory(logger, options) + db, err := kv.NewInMemory(logger, basedb.Options{}) require.NoError(t, err) shareStorage, err := registrystorage.NewSharesStorage(logger, db, []byte("test")) diff --git a/operator/storage/storage_test.go b/operator/storage/storage_test.go index 651d195d92..d35a0de216 100644 --- a/operator/storage/storage_test.go +++ b/operator/storage/storage_test.go @@ -11,12 +11,13 @@ import ( "github.com/bloxapp/ssv/logging" "github.com/bloxapp/ssv/protocol/v2/types" + "github.com/bloxapp/ssv/storage/kv" - ssvstorage "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" "github.com/bloxapp/ssv/utils/rsaencryption" spectypes "github.com/bloxapp/ssv-spec/types" + registrystorage "github.com/bloxapp/ssv/registry/storage" ) @@ -28,12 +29,7 @@ var ( func TestSaveAndGetPrivateKey(t *testing.T) { logger := logging.TestLogger(t) - options := basedb.Options{ - Type: "badger-memory", - Path: "", - } - - db, err := ssvstorage.GetStorageFactory(logger, options) + db, err := kv.NewInMemory(logger, basedb.Options{}) require.NoError(t, err) defer db.Close() @@ -94,13 +90,8 @@ func TestSetupPrivateKey(t *testing.T) { for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { - options := basedb.Options{ - Type: "badger-memory", - Path: "", - } - logger := logging.TestLogger(t) - db, err := ssvstorage.GetStorageFactory(logger, options) + db, err := kv.NewInMemory(logger, basedb.Options{}) require.NoError(t, err) defer db.Close() @@ -154,14 +145,11 @@ func TestSetupPrivateKey(t *testing.T) { } func TestDropRegistryData(t *testing.T) { - options := basedb.Options{ - Type: "badger-memory", - Path: "", - } logger := logging.TestLogger(t) - db, err := ssvstorage.GetStorageFactory(logger, options) + db, err := kv.NewInMemory(logger, basedb.Options{}) require.NoError(t, err) defer db.Close() + storage, err := NewNodeStorage(logger, db) require.NoError(t, err) diff --git a/protocol/v2/qbft/testing/storage.go b/protocol/v2/qbft/testing/storage.go index ec9e757073..d6db099202 100644 --- a/protocol/v2/qbft/testing/storage.go +++ b/protocol/v2/qbft/testing/storage.go @@ -8,8 +8,8 @@ import ( "go.uber.org/zap" qbftstorage "github.com/bloxapp/ssv/ibft/storage" - "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" ) var db basedb.Database @@ -17,11 +17,8 @@ var dbOnce sync.Once func getDB(logger *zap.Logger) basedb.Database { dbOnce.Do(func() { - dbInstance, err := storage.GetStorageFactory(logger, basedb.Options{ - Type: "badger-memory", - Path: "", - Reporting: false, - Ctx: context.TODO(), + dbInstance, err := kv.NewInMemory(logger, basedb.Options{ + Ctx: context.TODO(), }) if err != nil { panic(err) diff --git a/protocol/v2/testing/test_utils.go b/protocol/v2/testing/test_utils.go index 0081e49509..2b2f79e4c1 100644 --- a/protocol/v2/testing/test_utils.go +++ b/protocol/v2/testing/test_utils.go @@ -12,14 +12,11 @@ import ( "github.com/herumi/bls-eth-go-binary/bls" "github.com/pkg/errors" "github.com/stretchr/testify/require" - "go.uber.org/zap" "golang.org/x/mod/modfile" "golang.org/x/mod/module" qbftstorage "github.com/bloxapp/ssv/protocol/v2/qbft/storage" "github.com/bloxapp/ssv/protocol/v2/types" - "github.com/bloxapp/ssv/storage/basedb" - "github.com/bloxapp/ssv/storage/kv" ) var ( @@ -147,15 +144,6 @@ func AggregateInvalidSign(t *testing.T, sks map[spectypes.OperatorID]*bls.Secret return sigend } -// NewInMemDb returns basedb.Database with in-memory type -func NewInMemDb(logger *zap.Logger) basedb.Database { - db, _ := kv.New(logger, basedb.Options{ - Type: "badger-memory", - Path: "", - }) - return db -} - func GetSpecTestJSON(path string, module string) ([]byte, error) { goModFile, err := getGoModFile(path) if err != nil { diff --git a/registry/storage/operators_test.go b/registry/storage/operators_test.go index 5fcdeec137..4fff91d262 100644 --- a/registry/storage/operators_test.go +++ b/registry/storage/operators_test.go @@ -11,8 +11,8 @@ import ( "github.com/bloxapp/ssv/logging" "github.com/bloxapp/ssv/registry/storage" - ssvstorage "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" "github.com/bloxapp/ssv/utils/blskeygen" "github.com/bloxapp/ssv/utils/rsaencryption" ) @@ -144,10 +144,7 @@ func TestStorage_ListOperators(t *testing.T) { } func newOperatorStorageForTest(logger *zap.Logger) (storage.Operators, func()) { - db, err := ssvstorage.GetStorageFactory(logger, basedb.Options{ - Type: "badger-memory", - Path: "", - }) + db, err := kv.NewInMemory(logger, basedb.Options{}) if err != nil { return nil, func() {} } diff --git a/registry/storage/recipients_test.go b/registry/storage/recipients_test.go index f72abd1b24..786c479ca0 100644 --- a/registry/storage/recipients_test.go +++ b/registry/storage/recipients_test.go @@ -11,8 +11,8 @@ import ( "github.com/bloxapp/ssv/logging" "github.com/bloxapp/ssv/registry/storage" - ssvstorage "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" ) func TestStorage_SaveAndGetRecipientData(t *testing.T) { @@ -338,13 +338,11 @@ func TestStorage_SaveAndGetRecipientData(t *testing.T) { } func newRecipientStorageForTest(logger *zap.Logger) (storage.Recipients, func()) { - db, err := ssvstorage.GetStorageFactory(logger, basedb.Options{ - Type: "badger-memory", - Path: "", - }) + db, err := kv.NewInMemory(logger, basedb.Options{}) if err != nil { return nil, func() {} } + s := storage.NewRecipientsStorage(logger, db, []byte("test")) return s, func() { db.Close() diff --git a/registry/storage/shares_test.go b/registry/storage/shares_test.go index 5e684147b4..58fb6af59b 100644 --- a/registry/storage/shares_test.go +++ b/registry/storage/shares_test.go @@ -17,8 +17,9 @@ import ( "github.com/bloxapp/ssv/networkconfig" beaconprotocol "github.com/bloxapp/ssv/protocol/v2/blockchain/beacon" ssvtypes "github.com/bloxapp/ssv/protocol/v2/types" - ssvstorage "github.com/bloxapp/ssv/storage" + "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" "github.com/bloxapp/ssv/utils/threshold" ) @@ -167,17 +168,16 @@ func generateMaxPossibleShare() (*ssvtypes.SSVShare, error) { } func newShareStorageForTest(logger *zap.Logger) (Shares, func()) { - db, err := ssvstorage.GetStorageFactory(logger, basedb.Options{ - Type: "badger-memory", - Path: "", - }) + db, err := kv.NewInMemory(logger, basedb.Options{}) if err != nil { return nil, func() {} } + s, err := NewSharesStorage(logger, db, []byte("test")) if err != nil { return nil, func() {} } + return s, func() { db.Close() } diff --git a/storage/basedb/storage.go b/storage/basedb/storage.go index 209961a248..1f021d84a7 100644 --- a/storage/basedb/storage.go +++ b/storage/basedb/storage.go @@ -7,11 +7,10 @@ import ( // Options for creating all db type type Options struct { - Type string `yaml:"Type" env:"DB_TYPE" env-default:"badger-db" env-description:"Type of db badger-db or badger-memory"` + Ctx context.Context Path string `yaml:"Path" env:"DB_PATH" env-default:"./data/db" env-description:"Path for storage"` Reporting bool `yaml:"Reporting" env:"DB_REPORTING" env-default:"false" env-description:"Flag to run on-off db size reporting"` GCInterval time.Duration `yaml:"GCInterval" env:"DB_GC_INTERVAL" env-default:"6m" env-description:"Interval between garbage collection cycles. Set to 0 to disable."` - Ctx context.Context } // Reader is a read-only accessor to the database. diff --git a/storage/kv/badger.go b/storage/kv/badger.go index 0a18ce0f6b..0b1dd0492a 100644 --- a/storage/kv/badger.go +++ b/storage/kv/badger.go @@ -30,13 +30,22 @@ type BadgerDB struct { gcMutex sync.Mutex } -// New create new instance of Badger db +// New creates a persistent DB instance. func New(logger *zap.Logger, options basedb.Options) (*BadgerDB, error) { + return createDB(logger, options, false) +} + +// NewInMemory creates an in-memory DB instance. +func NewInMemory(logger *zap.Logger, options basedb.Options) (*BadgerDB, error) { + return createDB(logger, options, true) +} + +func createDB(logger *zap.Logger, options basedb.Options, inMemory bool) (*BadgerDB, error) { // Open the Badger database located in the /tmp/badger directory. // It will be created if it doesn't exist. opt := badger.DefaultOptions(options.Path) - if options.Type == "badger-memory" { + if inMemory { opt.InMemory = true opt.Dir = "" opt.ValueDir = "" diff --git a/storage/kv/badger_test.go b/storage/kv/badger_test.go index 25096c859c..3ab394602b 100644 --- a/storage/kv/badger_test.go +++ b/storage/kv/badger_test.go @@ -19,16 +19,15 @@ import ( func TestBadgerEndToEnd(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + zapCore, observedLogs := observer.New(zap.DebugLevel) logger := zap.New(zapCore) options := basedb.Options{ - Type: "badger-memory", - Path: "", Reporting: true, Ctx: ctx, } - db, err := New(logger, options) + db, err := NewInMemory(logger, options) require.NoError(t, err) toSave := []struct { @@ -95,13 +94,9 @@ func TestBadgerEndToEnd(t *testing.T) { func TestBadgerDb_GetAll(t *testing.T) { logger := logging.TestLogger(t) - options := basedb.Options{ - Type: "badger-memory", - Path: "", - } t.Run("100_items", func(t *testing.T) { - db, err := New(logger, options) + db, err := NewInMemory(logger, basedb.Options{}) require.NoError(t, err) defer db.Close() @@ -109,7 +104,7 @@ func TestBadgerDb_GetAll(t *testing.T) { }) t.Run("10K_items", func(t *testing.T) { - db, err := New(logger, options) + db, err := NewInMemory(logger, basedb.Options{}) require.NoError(t, err) defer db.Close() @@ -117,7 +112,7 @@ func TestBadgerDb_GetAll(t *testing.T) { }) t.Run("100K_items", func(t *testing.T) { - db, err := New(logger, options) + db, err := NewInMemory(logger, basedb.Options{}) require.NoError(t, err) defer db.Close() @@ -127,11 +122,7 @@ func TestBadgerDb_GetAll(t *testing.T) { func TestBadgerDb_GetMany(t *testing.T) { logger := logging.TestLogger(t) - options := basedb.Options{ - Type: "badger-memory", - Path: "", - } - db, err := New(logger, options) + db, err := NewInMemory(logger, basedb.Options{}) require.NoError(t, err) defer db.Close() @@ -154,11 +145,7 @@ func TestBadgerDb_GetMany(t *testing.T) { func TestBadgerDb_SetMany(t *testing.T) { logger := logging.TestLogger(t) - options := basedb.Options{ - Type: "badger-memory", - Path: "", - } - db, err := New(logger, options) + db, err := NewInMemory(logger, basedb.Options{}) require.NoError(t, err) defer db.Close() diff --git a/storage/main.go b/storage/main.go deleted file mode 100644 index 1cba4175b5..0000000000 --- a/storage/main.go +++ /dev/null @@ -1,23 +0,0 @@ -package storage - -import ( - "fmt" - - "go.uber.org/zap" - - "github.com/bloxapp/ssv/storage/basedb" - "github.com/bloxapp/ssv/storage/kv" -) - -// GetStorageFactory resolve and returns db instance based on db type -func GetStorageFactory(logger *zap.Logger, options basedb.Options) (*kv.BadgerDB, error) { - switch options.Type { - case "badger-db": - db, err := kv.New(logger, options) - return db, err - case "badger-memory": - db, err := kv.New(logger, options) - return db, err - } - return nil, fmt.Errorf("unsupported storage type passed") -} From 7229ef574f1e3298e3dbac58f0aecd83a321ffce Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 15 Aug 2023 19:20:21 +0400 Subject: [PATCH 05/16] [Audit Issues A&B] Validate ValidatorAddedEvent operators (#964) * Validate ValidatorAddedEvent operators * Cleanup * Adjust operator validation to recent changes * Fix issues after merging * Check if operator exists in DB * Fix TestHandleLocalEvent and TestHandleBlockEventsStreamWithExecution * go fmt * Move canBeQuorum * Improve TestValidCommitteeSize * Improve readability of condition --- eth/eventhandler/handlers.go | 28 +--- eth/eventhandler/local_events_test.go | 17 ++ eth/eventhandler/task_executor_test.go | 29 +++- eth/eventhandler/validation.go | 73 +++++++++ eth/eventhandler/validation_test.go | 149 ++++++++++++++++++ .../peers/connections/mock/mock_storage.go | 5 + operator/storage/storage.go | 4 + protocol/v2/types/ssvshare.go | 5 + protocol/v2/types/ssvshare_test.go | 28 ++++ registry/storage/operators.go | 33 ++++ 10 files changed, 343 insertions(+), 28 deletions(-) create mode 100644 eth/eventhandler/validation.go create mode 100644 eth/eventhandler/validation_test.go diff --git a/eth/eventhandler/handlers.go b/eth/eventhandler/handlers.go index deb923e956..7c25d7e6f4 100644 --- a/eth/eventhandler/handlers.go +++ b/eth/eventhandler/handlers.go @@ -9,7 +9,6 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/bloxapp/ssv-spec/types" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" "github.com/herumi/bls-eth-go-binary/bls" "go.uber.org/zap" @@ -144,6 +143,10 @@ func (eh *EventHandler) handleValidatorAdded(txn basedb.Txn, event *contract.Con return nil, err } + if err := eh.validateOperators(txn, event.OperatorIds); err != nil { + return nil, &MalformedEventError{Err: err} + } + // Calculate the expected length of constructed shares based on the number of operator IDs, // signature length, public key length, and encrypted key length. operatorCount := len(event.OperatorIds) @@ -466,29 +469,6 @@ func splitBytes(buf []byte, lim int) [][]byte { return chunks } -// verify signature of the ValidatorAddedEvent shares data -// todo(align-contract-v0.3.1-rc.0): move to crypto package in ssv protocol? -func verifySignature(sig []byte, owner ethcommon.Address, pubKey []byte, nonce registrystorage.Nonce) error { - data := fmt.Sprintf("%s:%d", owner.String(), nonce) - hash := crypto.Keccak256([]byte(data)) - - sign := &bls.Sign{} - if err := sign.Deserialize(sig); err != nil { - return fmt.Errorf("failed to deserialize signature: %w", err) - } - - pk := &bls.PublicKey{} - if err := pk.Deserialize(pubKey); err != nil { - return fmt.Errorf("failed to deserialize public key: %w", err) - } - - if res := sign.VerifyByte(pk, hash); !res { - return errors.New("failed to verify signature") - } - - return nil -} - // processClusterEvent handles registry contract event for cluster func (eh *EventHandler) processClusterEvent( txn basedb.Txn, diff --git a/eth/eventhandler/local_events_test.go b/eth/eventhandler/local_events_test.go index b81ed79774..c01c45877a 100644 --- a/eth/eventhandler/local_events_test.go +++ b/eth/eventhandler/local_events_test.go @@ -2,14 +2,18 @@ package eventhandler import ( "context" + "encoding/binary" "testing" + spectypes "github.com/bloxapp/ssv-spec/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" "gopkg.in/yaml.v3" "github.com/bloxapp/ssv/eth/contract" "github.com/bloxapp/ssv/eth/localevents" + "github.com/bloxapp/ssv/registry/storage" ) func TestHandleLocalEvent(t *testing.T) { @@ -57,6 +61,7 @@ func TestHandleLocalEvent(t *testing.T) { OperatorIds: [1, 2, 3, 4] Shares: 0x8d9205986a9f0505daadeb124a4e89814e9174e471da0c8e5a3684c1b2bc7bfb36aca0abe4bf3c619268ce9bdac839d113ae2053f3ce8acbfd5793558efd44709282d423e9b03a1d37a70d27cc4f2a10677448879e6f45a5f8b259e08718b902b52de097cf98c9f6a5355a2060f827e320b1decfbbd974000277de3c65fdeebc4da212ec1def8ef298e7e1459a6ea912b04c8f48f50b65bf2475255cbf4c39b9d1d4dcc34b2959d7b07ed7c493edd22f290483f65f56038c1602d6210a0ad78cb5764bffb0972bc98de742d5f27cd714bbecaae9e398c5322a9b7ca7711c3ce5e952246090e05787f2f91aa2693e118b82bc1b261018b0eb9dcd3c737ccbffb55d726d72d3560d38525b83f882879065badd7cb9504b2e95a205b81c11334e7bab1a5a75539c0cca11e5cf44f51bd989a3ff5c17a68fab85a1f2ea702b667dd3e4526f476c97ad9d2826f291352ebbb8bf1cbd53d47b49ae3f16d75a6eff52184b06caf6662d61c04aca80c9f05e9cdaca8544292df8617a327d519057ace77fe72ba975d6d953d217208d644e5f9a8527f575296b712872c1932492d6bc5519eee9891b22cead112b35c7316070a6ab4c9225559023a3e57d19d7fcd9d9f1641c87d9693389ad50cc335f57f587c3ba4a18760eaea5026d217871192d58a156279b5c764476abe19af43d714474a3bc70af3fc16b0334ec0e411207290b80bd5d61b007e025cd7c640d4637a174e073bf8c357645450f85f614bf42b81dda5f1ebd165717d1c1f4da684f9520dae3702044d0fe84abda960aa1b58127a2aecbe819a9f70d9adbace7c555ec85b4e78b15d50c0b9564d9e0b6abb5e2ed249a8dca3c35fc23c1c71ae045316e95fe19cd24b960f4e1b4f498776dcd244823b5c15ca5000a7990519114dddba550fd457b2438b70ac2d8d62128536a3c5d086a1314a6129157eec322249c82084f2fed4cc6d702e06553c4288dd500463068949401543240bb2d90a57384c0c8a39e004c7ea2ca0f475dc0a0daa330d891198120ff6577c9938e2197c6fecb3974793965fda888bbe94ce6acb1a981e25ef4026d518794cad49e3bd96f7295b526389581b5f5f25de97475eb8c636bdcd4049bbd7bbc4bd8e021d8de33304d586ffb7f5d87f8000372de396d20db43458c91f7ef3e5da35177b1e438426c54235838fa3400fc85f5f5f9e49062ab082db0965e70ed163fa74ce045265c60ec2d86845028dec08e06359b0cd1ccfdf48b0b901cc8d23eecfb5cb6f558277200fffc560282260998a3d510f0e41ced979f5c7e402e41dce60628a23fa7ba68fe2a42921357de525b44d6932e57e65e084e4305bf4524fd06aa825a85ed9ad7db737db963db5deac3a5456a41c75e2848651fbcb04adb0e9c675cf9954f5a56fe3d4cc665b39b63b0011799c7a9a3e01f9a37d4885c05e49f2d5f0fa7559192b0287ad7882c09a08254e56bc4a2f9dc37d6640159596ff468697cd9fe41c1851a4adb92dd4ae8e23e2963adfed4a3a91c916f67e726f1f735a4b5b4309b923817edb668b94bf8462c6c99247e567c4a4ae0475c1c5c116b2622fd961eaf64ea4c9a6aa80f847e7c4a04eb5588d1c969be7bb23ed668e046e7ac14e72427b4cf27f37b44b4037d8cef02321d7b9beb1d7e7c1c08c4083d42c3bf579a97028d85b09aebb3f88aba882fedf8bfdbbb12c1d7221881d8688b95806800bbf1a32b08a81e629ff624fc865558dc6303bae0c74c04aa513b01248d4f22d732f60f7148080a7ccb5388f27fd902ef581b3131932e3997cfa551d61913f3c7a3ce1901ba77a2e61fd5025c4f5762e7d54048d4a9995f0ad6a6e5 `) + var parsedData []localevents.Event require.NoError(t, yaml.Unmarshal(input, &parsedData)) @@ -69,6 +74,18 @@ func TestHandleLocalEvent(t *testing.T) { t.Fatal(err) } + for _, id := range []spectypes.OperatorID{1, 2, 3, 4} { + od := &storage.OperatorData{ + PublicKey: binary.LittleEndian.AppendUint64(nil, id), + OwnerAddress: common.Address{}, + ID: id, + } + + found, err := eh.nodeStorage.SaveOperatorData(nil, od) + require.NoError(t, err) + require.False(t, found) + } + require.ErrorIs(t, eh.HandleLocalEvents(parsedData), ErrSignatureVerification) }) } diff --git a/eth/eventhandler/task_executor_test.go b/eth/eventhandler/task_executor_test.go index 69e43ac716..1e86226b09 100644 --- a/eth/eventhandler/task_executor_test.go +++ b/eth/eventhandler/task_executor_test.go @@ -2,6 +2,7 @@ package eventhandler import ( "context" + "encoding/binary" "testing" spectypes "github.com/bloxapp/ssv-spec/types" @@ -14,6 +15,7 @@ import ( "github.com/bloxapp/ssv/eth/executionclient" beaconprotocol "github.com/bloxapp/ssv/protocol/v2/blockchain/beacon" ssvtypes "github.com/bloxapp/ssv/protocol/v2/types" + "github.com/bloxapp/ssv/registry/storage" ) // const rawOperatorAdded = `{ @@ -137,26 +139,45 @@ func TestExecuteTask(t *testing.T) { func TestHandleBlockEventsStreamWithExecution(t *testing.T) { logger, observedLogs := setupLogsCapture() - logValidatorAdded := unmarshalLog(t, rawValidatorAdded) - events := []ethtypes.Log{ - logValidatorAdded, - } + ctx, cancel := context.WithCancel(context.Background()) defer cancel() + eh, err := setupEventHandler(t, ctx, logger) if err != nil { t.Fatal(err) } + + for _, id := range []spectypes.OperatorID{1, 2, 3, 4} { + od := &storage.OperatorData{ + PublicKey: binary.LittleEndian.AppendUint64(nil, id), + OwnerAddress: ethcommon.Address{}, + ID: id, + } + + found, err := eh.nodeStorage.SaveOperatorData(nil, od) + require.NoError(t, err) + require.False(t, found) + } + eventsCh := make(chan executionclient.BlockLogs) go func() { defer close(eventsCh) + + logValidatorAdded := unmarshalLog(t, rawValidatorAdded) + events := []ethtypes.Log{ + logValidatorAdded, + } + for _, blockLogs := range executionclient.PackLogs(events) { eventsCh <- blockLogs } }() + lastProcessedBlock, err := eh.HandleBlockEventsStream(eventsCh, true) require.Equal(t, uint64(0x89EBFF), lastProcessedBlock) require.NoError(t, err) + var observedLogsFlow []string for _, entry := range observedLogs.All() { observedLogsFlow = append(observedLogsFlow, entry.Message) diff --git a/eth/eventhandler/validation.go b/eth/eventhandler/validation.go new file mode 100644 index 0000000000..015eafb409 --- /dev/null +++ b/eth/eventhandler/validation.go @@ -0,0 +1,73 @@ +package eventhandler + +import ( + "fmt" + + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/herumi/bls-eth-go-binary/bls" + + ssvtypes "github.com/bloxapp/ssv/protocol/v2/types" + registrystorage "github.com/bloxapp/ssv/registry/storage" + "github.com/bloxapp/ssv/storage/basedb" +) + +const maxOperators = 13 + +func (eh *EventHandler) validateOperators(txn basedb.Txn, operators []uint64) error { + operatorCount := len(operators) + + if operatorCount > maxOperators { + return fmt.Errorf("too many operators (%d)", operatorCount) + } + + if operatorCount == 0 { + return fmt.Errorf("no operators") + } + + if !ssvtypes.ValidCommitteeSize(len(operators)) { + return fmt.Errorf("given operator count (%d) cannot build a 3f+1 quorum", operatorCount) + } + + seenOperators := map[uint64]struct{}{} + for _, operatorID := range operators { + if _, ok := seenOperators[operatorID]; ok { + return fmt.Errorf("duplicated operator ID (%d)", operatorID) + } + seenOperators[operatorID] = struct{}{} + } + + exist, err := eh.nodeStorage.OperatorsExist(txn, operators) + if err != nil { + return fmt.Errorf("storage: %w", err) + } + + if !exist { + return fmt.Errorf("not all operators exist") + } + + return nil +} + +// verify signature of the ValidatorAddedEvent shares data +// todo(align-contract-v0.3.1-rc.0): move to crypto package in ssv protocol? +func verifySignature(sig []byte, owner ethcommon.Address, pubKey []byte, nonce registrystorage.Nonce) error { + data := fmt.Sprintf("%s:%d", owner.String(), nonce) + hash := crypto.Keccak256([]byte(data)) + + sign := &bls.Sign{} + if err := sign.Deserialize(sig); err != nil { + return fmt.Errorf("failed to deserialize signature: %w", err) + } + + pk := &bls.PublicKey{} + if err := pk.Deserialize(pubKey); err != nil { + return fmt.Errorf("failed to deserialize public key: %w", err) + } + + if res := sign.VerifyByte(pk, hash); !res { + return fmt.Errorf("failed to verify signature") + } + + return nil +} diff --git a/eth/eventhandler/validation_test.go b/eth/eventhandler/validation_test.go new file mode 100644 index 0000000000..9e17642071 --- /dev/null +++ b/eth/eventhandler/validation_test.go @@ -0,0 +1,149 @@ +package eventhandler + +import ( + "encoding/binary" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" + + operatorstorage "github.com/bloxapp/ssv/operator/storage" + "github.com/bloxapp/ssv/registry/storage" + ssvstorage "github.com/bloxapp/ssv/storage" + "github.com/bloxapp/ssv/storage/basedb" +) + +func Test_validateValidatorAddedEvent(t *testing.T) { + logger := zaptest.NewLogger(t) + + db, err := ssvstorage.GetStorageFactory(logger, basedb.Options{ + Type: "badger-memory", + Path: "", + }) + require.NoError(t, err) + + nodeStorage, err := operatorstorage.NewNodeStorage(logger, db) + require.NoError(t, err) + + eh := &EventHandler{ + nodeStorage: nodeStorage, + } + + generateOperators := func(count uint64) []uint64 { + result := make([]uint64, 0) + for i := uint64(1); i <= count; i++ { + result = append(result, i) + } + return result + } + + tt := []struct { + name string + operators []uint64 + saved bool + err string + }{ + { + name: "4 operators", + operators: generateOperators(4), + saved: true, + err: "", + }, + { + name: "7 operators", + operators: generateOperators(7), + saved: true, + err: "", + }, + { + name: "10 operators", + operators: generateOperators(10), + saved: true, + err: "", + }, + { + name: "13 operators", + operators: generateOperators(13), + saved: true, + err: "", + }, + { + name: "14 operators", + operators: generateOperators(14), + saved: true, + err: "too many operators (14)", + }, + { + name: "0 operators", + operators: generateOperators(0), + saved: true, + err: "no operators", + }, + { + name: "1 operator", + operators: generateOperators(1), + saved: true, + err: "given operator count (1) cannot build a 3f+1 quorum", + }, + { + name: "2 operators", + operators: generateOperators(2), + saved: true, + err: "given operator count (2) cannot build a 3f+1 quorum", + }, + { + name: "3 operators", + operators: generateOperators(3), + saved: true, + err: "given operator count (3) cannot build a 3f+1 quorum", + }, + { + name: "5 operators", + operators: generateOperators(5), + saved: true, + err: "given operator count (5) cannot build a 3f+1 quorum", + }, + { + name: "duplicated operator", + operators: []uint64{1, 2, 3, 3}, + saved: true, + err: "duplicated operator ID (3)", + }, + { + name: "4 operators not saved", + operators: generateOperators(4), + saved: false, + err: "not all operators exist", + }, + } + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + if tc.saved { + for _, operator := range tc.operators { + od := &storage.OperatorData{ + PublicKey: binary.LittleEndian.AppendUint64(nil, operator), + OwnerAddress: common.Address{}, + ID: operator, + } + + _, err := nodeStorage.SaveOperatorData(nil, od) + require.NoError(t, err) + } + + defer func() { + require.NoError(t, nodeStorage.DropOperators()) + }() + } + + err := eh.validateOperators(nil, tc.operators) + if tc.err == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tc.err) + } + }) + } +} diff --git a/network/peers/connections/mock/mock_storage.go b/network/peers/connections/mock/mock_storage.go index 686548c5ba..b0130c608d 100644 --- a/network/peers/connections/mock/mock_storage.go +++ b/network/peers/connections/mock/mock_storage.go @@ -72,6 +72,11 @@ func (m NodeStorage) GetOperatorData(txn basedb.Reader, id spectypes.OperatorID) panic("implement me") } +func (m NodeStorage) OperatorsExist(r basedb.Reader, ids []spectypes.OperatorID) (bool, error) { + //TODO implement me + panic("implement me") +} + func (m NodeStorage) SaveOperatorData(txn basedb.ReadWriter, operatorData *registrystorage.OperatorData) (bool, error) { //TODO implement me panic("implement me") diff --git a/operator/storage/storage.go b/operator/storage/storage.go index 796491fff5..bf753876ef 100644 --- a/operator/storage/storage.go +++ b/operator/storage/storage.go @@ -91,6 +91,10 @@ func (s *storage) GetOperatorData(r basedb.Reader, id spectypes.OperatorID) (*re return s.operatorStore.GetOperatorData(r, id) } +func (s *storage) OperatorsExist(r basedb.Reader, ids []spectypes.OperatorID) (bool, error) { + return s.operatorStore.OperatorsExist(r, ids) +} + func (s *storage) SaveOperatorData(rw basedb.ReadWriter, operatorData *registrystorage.OperatorData) (bool, error) { return s.operatorStore.SaveOperatorData(rw, operatorData) } diff --git a/protocol/v2/types/ssvshare.go b/protocol/v2/types/ssvshare.go index 2866082975..6dad2af123 100644 --- a/protocol/v2/types/ssvshare.go +++ b/protocol/v2/types/ssvshare.go @@ -93,6 +93,11 @@ func ComputeQuorumAndPartialQuorum(committeeSize int) (quorum uint64, partialQuo return uint64(f*2 + 1), uint64(f + 1) } +func ValidCommitteeSize(committeeSize int) bool { + f := (committeeSize - 1) / 3 + return (committeeSize-1)%3 == 0 && f >= 1 && f <= 4 +} + // Metadata represents metadata of SSVShare. type Metadata struct { BeaconMetadata *beaconprotocol.ValidatorMetadata diff --git a/protocol/v2/types/ssvshare_test.go b/protocol/v2/types/ssvshare_test.go index 468e269a52..848f3b369e 100644 --- a/protocol/v2/types/ssvshare_test.go +++ b/protocol/v2/types/ssvshare_test.go @@ -58,3 +58,31 @@ func TestSSVShare_HasBeaconMetadata(t *testing.T) { }) } } + +func TestValidCommitteeSize(t *testing.T) { + tt := []struct { + name string + valid bool + sizes []int + }{ + { + name: "valid", + valid: true, + sizes: []int{4, 7, 10, 13}, + }, + { + name: "invalid", + valid: false, + sizes: []int{0, 1, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19, -1, -4, -7}, + }, + } + + for _, tc := range tt { + tc := tc + t.Run(tc.name, func(t *testing.T) { + for _, size := range tc.sizes { + require.Equal(t, tc.valid, ValidCommitteeSize(size)) + } + }) + } +} diff --git a/registry/storage/operators.go b/registry/storage/operators.go index c74494c644..5847d0a778 100644 --- a/registry/storage/operators.go +++ b/registry/storage/operators.go @@ -33,6 +33,7 @@ type GetOperatorData = func(index uint64) (*OperatorData, bool, error) type Operators interface { GetOperatorDataByPubKey(r basedb.Reader, operatorPubKey []byte) (*OperatorData, bool, error) GetOperatorData(r basedb.Reader, id spectypes.OperatorID) (*OperatorData, bool, error) + OperatorsExist(r basedb.Reader, ids []spectypes.OperatorID) (bool, error) SaveOperatorData(rw basedb.ReadWriter, operatorData *OperatorData) (bool, error) DeleteOperatorData(rw basedb.ReadWriter, id spectypes.OperatorID) error ListOperators(r basedb.Reader, from uint64, to uint64) ([]OperatorData, error) @@ -85,6 +86,17 @@ func (s *operatorsStorage) GetOperatorData( return s.getOperatorData(r, id) } +// OperatorsExist returns if operators exist +func (s *operatorsStorage) OperatorsExist( + r basedb.Reader, + ids []spectypes.OperatorID, +) (bool, error) { + s.lock.RLock() + defer s.lock.RUnlock() + + return s.operatorsExist(r, ids) +} + // GetOperatorDataByPubKey returns data of the given operator by public key func (s *operatorsStorage) GetOperatorDataByPubKey( r basedb.Reader, @@ -129,6 +141,27 @@ func (s *operatorsStorage) getOperatorData( return &operatorInformation, found, err } +func (s *operatorsStorage) operatorsExist( + r basedb.Reader, + ids []spectypes.OperatorID, +) (bool, error) { + var keys [][]byte + for _, id := range ids { + keys = append(keys, buildOperatorKey(id)) + } + + seen := 0 + err := s.db.UsingReader(r).GetMany(s.prefix, keys, func(obj basedb.Obj) error { + seen++ + return nil + }) + if err != nil { + return false, err + } + + return seen == len(ids), nil +} + func (s *operatorsStorage) listOperators(r basedb.Reader, from, to uint64) ([]OperatorData, error) { var operators []OperatorData err := s.db.UsingReader(r). From 36e4e881383a61ff6a8e13a855feeed46e9dedae Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 15 Aug 2023 19:47:27 +0400 Subject: [PATCH 06/16] [Audit Issue D] Crash on config breaking changes (#1097) * Crash on config breaking changes * Add storage tests * Add tests for ensureNoConfigBreakingChanges * Sort imports * Code review requests * Update config_lock.go * Fix linter * Rename verifyConfig * Rename test * Update node.go * Fix Test_verifyConfig * Fix lint --------- Co-authored-by: Lior Rutenberg --- cli/operator/node.go | 35 ++++- cli/operator/node_test.go | 138 ++++++++++++++++++ .../peers/connections/mock/mock_storage.go | 12 ++ operator/storage/config_lock.go | 27 ++++ operator/storage/config_lock_test.go | 65 +++++++++ operator/storage/storage.go | 41 ++++++ operator/storage/storage_test.go | 47 +++++- 7 files changed, 353 insertions(+), 12 deletions(-) create mode 100644 cli/operator/node_test.go create mode 100644 operator/storage/config_lock.go create mode 100644 operator/storage/config_lock_test.go diff --git a/cli/operator/node.go b/cli/operator/node.go index 5dc91247c0..cc57d323f1 100644 --- a/cli/operator/node.go +++ b/cli/operator/node.go @@ -100,7 +100,7 @@ var StartNodeCmd = &cobra.Command{ defer logging.CapturePanic(logger) networkConfig, forkVersion, err := setupSSVNetwork(logger) if err != nil { - log.Fatal("could not setup network", err) + logger.Fatal("could not setup network", zap.Error(err)) } cfg.DBOptions.Ctx = cmd.Context() db, err := setupDB(logger, networkConfig.Beacon.GetNetwork()) @@ -110,9 +110,10 @@ var StartNodeCmd = &cobra.Command{ nodeStorage, operatorData := setupOperatorStorage(logger, db) - if err != nil { - logger.Fatal("could not run post storage migrations", zap.Error(err)) - } + usingLocalEvents := len(cfg.LocalEventsPath) != 0 + + verifyConfig(logger, nodeStorage, networkConfig.Name, usingLocalEvents) + operatorKey, _, _ := nodeStorage.GetPrivateKey() keyBytes := x509.MarshalPKCS1PrivateKey(operatorKey) hashedKey, _ := rsaencryption.HashRsaKey(keyBytes) @@ -249,7 +250,6 @@ var StartNodeCmd = &cobra.Command{ validatorCtrl, storageMap, metricsReporter, - nodeProber, networkConfig, nodeStorage, ) @@ -292,6 +292,30 @@ var StartNodeCmd = &cobra.Command{ }, } +func verifyConfig(logger *zap.Logger, nodeStorage operatorstorage.Storage, networkName string, usingLocalEvents bool) { + storedConfig, foundConfig, err := nodeStorage.GetConfig(nil) + if err != nil { + logger.Fatal("could not check saved local events config", zap.Error(err)) + } + + currentConfig := &operatorstorage.ConfigLock{ + NetworkName: networkName, + UsingLocalEvents: usingLocalEvents, + } + + if foundConfig { + if err := storedConfig.EnsureSameWith(currentConfig); err != nil { + err = fmt.Errorf("incompatible config change: %w", err) + logger.Fatal(err.Error()) + } + } else { + if err := nodeStorage.SaveConfig(nil, currentConfig); err != nil { + err = fmt.Errorf("failed to store config: %w", err) + logger.Fatal(err.Error()) + } + } +} + func init() { global_config.ProcessArgs(&cfg, &globalArgs, StartNodeCmd) } @@ -482,7 +506,6 @@ func setupEventHandling( validatorCtrl validator.Controller, storageMap *ibftstorage.QBFTStores, metricsReporter *metricsreporter.MetricsReporter, - nodeProber *nodeprobe.Prober, networkConfig networkconfig.NetworkConfig, nodeStorage operatorstorage.Storage, ) { diff --git a/cli/operator/node_test.go b/cli/operator/node_test.go new file mode 100644 index 0000000000..58eb7e8164 --- /dev/null +++ b/cli/operator/node_test.go @@ -0,0 +1,138 @@ +package operator + +import ( + "testing" + + "github.com/stretchr/testify/require" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + + "github.com/bloxapp/ssv/networkconfig" + operatorstorage "github.com/bloxapp/ssv/operator/storage" + "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" +) + +func Test_verifyConfig(t *testing.T) { + logger := zap.New(zapcore.NewNopCore(), zap.WithFatalHook(zapcore.WriteThenPanic)) + + db, err := kv.NewInMemory(logger, basedb.Options{}) + require.NoError(t, err) + + nodeStorage, err := operatorstorage.NewNodeStorage(logger, db) + require.NoError(t, err) + + testNetworkName := networkconfig.TestNetwork.Name + + t.Run("no config in DB", func(t *testing.T) { + c := &operatorstorage.ConfigLock{ + NetworkName: testNetworkName, + UsingLocalEvents: true, + } + verifyConfig(logger, nodeStorage, c.NetworkName, c.UsingLocalEvents) + + storedConfig, found, err := nodeStorage.GetConfig(nil) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, c, storedConfig) + + require.NoError(t, nodeStorage.DeleteConfig(nil)) + }) + + t.Run("has same config in DB", func(t *testing.T) { + c := &operatorstorage.ConfigLock{ + NetworkName: testNetworkName, + UsingLocalEvents: true, + } + require.NoError(t, nodeStorage.SaveConfig(nil, c)) + + verifyConfig(logger, nodeStorage, testNetworkName, true) + + storedConfig, found, err := nodeStorage.GetConfig(nil) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, c, storedConfig) + + require.NoError(t, nodeStorage.DeleteConfig(nil)) + }) + + t.Run("has different network name and events type in DB", func(t *testing.T) { + c := &operatorstorage.ConfigLock{ + NetworkName: testNetworkName + "1", + UsingLocalEvents: false, + } + require.NoError(t, nodeStorage.SaveConfig(nil, c)) + + require.PanicsWithValue(t, + "incompatible config change: can't change network from \"testnet1\" to \"testnet\" in an existing database, it must be removed first", + func() { verifyConfig(logger, nodeStorage, testNetworkName, true) }, + ) + + storedConfig, found, err := nodeStorage.GetConfig(nil) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, c, storedConfig) + + require.NoError(t, nodeStorage.DeleteConfig(nil)) + }) + + t.Run("has different network name in DB", func(t *testing.T) { + c := &operatorstorage.ConfigLock{ + NetworkName: testNetworkName + "1", + UsingLocalEvents: true, + } + require.NoError(t, nodeStorage.SaveConfig(nil, c)) + + require.PanicsWithValue(t, + "incompatible config change: can't change network from \"testnet1\" to \"testnet\" in an existing database, it must be removed first", + func() { verifyConfig(logger, nodeStorage, testNetworkName, true) }, + ) + + storedConfig, found, err := nodeStorage.GetConfig(nil) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, c, storedConfig) + + require.NoError(t, nodeStorage.DeleteConfig(nil)) + }) + + t.Run("has real events in DB but runs with local events", func(t *testing.T) { + c := &operatorstorage.ConfigLock{ + NetworkName: testNetworkName, + UsingLocalEvents: false, + } + require.NoError(t, nodeStorage.SaveConfig(nil, c)) + + require.PanicsWithValue(t, + "incompatible config change: can't switch on localevents, database must be removed first", + func() { verifyConfig(logger, nodeStorage, testNetworkName, true) }, + ) + + storedConfig, found, err := nodeStorage.GetConfig(nil) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, c, storedConfig) + + require.NoError(t, nodeStorage.DeleteConfig(nil)) + }) + + t.Run("has local events in DB but runs with real events", func(t *testing.T) { + c := &operatorstorage.ConfigLock{ + NetworkName: testNetworkName, + UsingLocalEvents: true, + } + require.NoError(t, nodeStorage.SaveConfig(nil, c)) + + require.PanicsWithValue(t, + "incompatible config change: can't switch off localevents, database must be removed first", + func() { verifyConfig(logger, nodeStorage, testNetworkName, false) }, + ) + + storedConfig, found, err := nodeStorage.GetConfig(nil) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, c, storedConfig) + + require.NoError(t, nodeStorage.DeleteConfig(nil)) + }) +} diff --git a/network/peers/connections/mock/mock_storage.go b/network/peers/connections/mock/mock_storage.go index b0130c608d..dc85870cad 100644 --- a/network/peers/connections/mock/mock_storage.go +++ b/network/peers/connections/mock/mock_storage.go @@ -154,3 +154,15 @@ func (m NodeStorage) SetupPrivateKey(operatorKeyBase64 string) ([]byte, error) { //TODO implement me panic("implement me") } + +func (m NodeStorage) GetConfig(rw basedb.ReadWriter) (*storage.ConfigLock, bool, error) { + panic("implement me") +} + +func (m NodeStorage) SaveConfig(rw basedb.ReadWriter, config *storage.ConfigLock) error { + panic("implement me") +} + +func (m NodeStorage) DeleteConfig(rw basedb.ReadWriter) error { + panic("implement me") +} diff --git a/operator/storage/config_lock.go b/operator/storage/config_lock.go new file mode 100644 index 0000000000..5d43c74aad --- /dev/null +++ b/operator/storage/config_lock.go @@ -0,0 +1,27 @@ +package storage + +import ( + "fmt" +) + +type ConfigLock struct { + NetworkName string `json:"network_name"` + UsingLocalEvents bool `json:"using_local_events"` +} + +func (stored *ConfigLock) EnsureSameWith(current *ConfigLock) error { + if stored.NetworkName != current.NetworkName { + return fmt.Errorf("can't change network from %q to %q in an existing database, it must be removed first", + stored.NetworkName, current.NetworkName) + } + + if stored.UsingLocalEvents && !current.UsingLocalEvents { + return fmt.Errorf("can't switch off localevents, database must be removed first") + } + + if !stored.UsingLocalEvents && current.UsingLocalEvents { + return fmt.Errorf("can't switch on localevents, database must be removed first") + } + + return nil +} diff --git a/operator/storage/config_lock_test.go b/operator/storage/config_lock_test.go new file mode 100644 index 0000000000..435751c605 --- /dev/null +++ b/operator/storage/config_lock_test.go @@ -0,0 +1,65 @@ +package storage + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestConfigLock(t *testing.T) { + t.Run("same configs", func(t *testing.T) { + c1 := &ConfigLock{ + NetworkName: "test", + UsingLocalEvents: true, + } + + c2 := &ConfigLock{ + NetworkName: "test", + UsingLocalEvents: true, + } + + require.NoError(t, c1.EnsureSameWith(c2)) + }) + + t.Run("all fields are different", func(t *testing.T) { + c1 := &ConfigLock{ + NetworkName: "test", + UsingLocalEvents: true, + } + + c2 := &ConfigLock{ + NetworkName: "test2", + UsingLocalEvents: false, + } + + require.Error(t, c1.EnsureSameWith(c2)) + }) + + t.Run("only network name is different", func(t *testing.T) { + c1 := &ConfigLock{ + NetworkName: "test", + UsingLocalEvents: true, + } + + c2 := &ConfigLock{ + NetworkName: "test2", + UsingLocalEvents: true, + } + + require.Error(t, c1.EnsureSameWith(c2)) + }) + + t.Run("only local events usage is different", func(t *testing.T) { + c1 := &ConfigLock{ + NetworkName: "test", + UsingLocalEvents: true, + } + + c2 := &ConfigLock{ + NetworkName: "test", + UsingLocalEvents: false, + } + + require.Error(t, c1.EnsureSameWith(c2)) + }) +} diff --git a/operator/storage/storage.go b/operator/storage/storage.go index bf753876ef..12e8c1a7f6 100644 --- a/operator/storage/storage.go +++ b/operator/storage/storage.go @@ -3,6 +3,8 @@ package storage import ( "crypto/rsa" "encoding/base64" + "encoding/json" + "fmt" "math/big" "github.com/attestantio/go-eth2-client/spec/bellatrix" @@ -23,6 +25,7 @@ var HashedPrivateKey = "hashed-private-key" var ( storagePrefix = []byte("operator/") lastProcessedBlockKey = []byte("syncOffset") // TODO: temporarily left as syncOffset for compatibility, consider renaming and adding a migration for that + configKey = []byte("config") ) // Storage represents the interface for ssv node storage @@ -35,6 +38,10 @@ type Storage interface { SaveLastProcessedBlock(rw basedb.ReadWriter, offset *big.Int) error GetLastProcessedBlock(r basedb.Reader) (*big.Int, bool, error) + GetConfig(rw basedb.ReadWriter) (*ConfigLock, bool, error) + SaveConfig(rw basedb.ReadWriter, config *ConfigLock) error + DeleteConfig(rw basedb.ReadWriter) error + registry.RegistryStore registrystorage.Operators @@ -297,3 +304,37 @@ func (s *storage) savePrivateKey(operatorKey string) error { func (s *storage) UpdateValidatorMetadata(pk string, metadata *beacon.ValidatorMetadata) error { return s.shareStore.UpdateValidatorMetadata(pk, metadata) } + +func (s *storage) GetConfig(rw basedb.ReadWriter) (*ConfigLock, bool, error) { + obj, found, err := s.db.Using(rw).Get(storagePrefix, configKey) + if err != nil { + return nil, false, fmt.Errorf("db: %w", err) + } + if !found { + return nil, false, nil + } + + config := &ConfigLock{} + if err := json.Unmarshal(obj.Value, &config); err != nil { + return nil, false, fmt.Errorf("unmarshal: %w", err) + } + + return config, true, nil +} + +func (s *storage) SaveConfig(rw basedb.ReadWriter, config *ConfigLock) error { + b, err := json.Marshal(config) + if err != nil { + return fmt.Errorf("marshal: %w", err) + } + + if err := s.db.Using(rw).Set(storagePrefix, configKey, b); err != nil { + return fmt.Errorf("db: %w", err) + } + + return nil +} + +func (s *storage) DeleteConfig(rw basedb.ReadWriter) error { + return s.db.Using(rw).Delete(storagePrefix, configKey) +} diff --git a/operator/storage/storage_test.go b/operator/storage/storage_test.go index d35a0de216..f2d333ff08 100644 --- a/operator/storage/storage_test.go +++ b/operator/storage/storage_test.go @@ -5,20 +5,18 @@ import ( "testing" "github.com/attestantio/go-eth2-client/spec/bellatrix" + spectypes "github.com/bloxapp/ssv-spec/types" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" "github.com/bloxapp/ssv/logging" + "github.com/bloxapp/ssv/networkconfig" "github.com/bloxapp/ssv/protocol/v2/types" - "github.com/bloxapp/ssv/storage/kv" - + registrystorage "github.com/bloxapp/ssv/registry/storage" "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" "github.com/bloxapp/ssv/utils/rsaencryption" - - spectypes "github.com/bloxapp/ssv-spec/types" - - registrystorage "github.com/bloxapp/ssv/registry/storage" ) var ( @@ -220,3 +218,40 @@ func TestDropRegistryData(t *testing.T) { storage, err = NewNodeStorage(logger, db) require.NoError(t, err) } + +func TestNetworkAndLocalEventsConfig(t *testing.T) { + logger := logging.TestLogger(t) + db, err := kv.NewInMemory(logger, basedb.Options{}) + require.NoError(t, err) + defer db.Close() + + storage, err := NewNodeStorage(logger, db) + require.NoError(t, err) + + storedCfg, found, err := storage.GetConfig(nil) + require.NoError(t, err) + require.False(t, found) + require.Nil(t, storedCfg) + + c1 := &ConfigLock{ + NetworkName: networkconfig.TestNetwork.Name, + UsingLocalEvents: false, + } + require.NoError(t, storage.SaveConfig(nil, c1)) + + storedCfg, found, err = storage.GetConfig(nil) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, c1, storedCfg) + + c2 := &ConfigLock{ + NetworkName: networkconfig.TestNetwork.Name + "1", + UsingLocalEvents: false, + } + require.NoError(t, storage.SaveConfig(nil, c2)) + + storedCfg, found, err = storage.GetConfig(nil) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, c2, storedCfg) +} From 8431edf5e6b8f87c022762d59a3946acb350811f Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 15 Aug 2023 20:05:53 +0400 Subject: [PATCH 07/16] Fix CI (#1103) --- eth/eventhandler/validation_test.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/eth/eventhandler/validation_test.go b/eth/eventhandler/validation_test.go index 9e17642071..e68614418d 100644 --- a/eth/eventhandler/validation_test.go +++ b/eth/eventhandler/validation_test.go @@ -10,17 +10,14 @@ import ( operatorstorage "github.com/bloxapp/ssv/operator/storage" "github.com/bloxapp/ssv/registry/storage" - ssvstorage "github.com/bloxapp/ssv/storage" "github.com/bloxapp/ssv/storage/basedb" + "github.com/bloxapp/ssv/storage/kv" ) func Test_validateValidatorAddedEvent(t *testing.T) { logger := zaptest.NewLogger(t) - db, err := ssvstorage.GetStorageFactory(logger, basedb.Options{ - Type: "badger-memory", - Path: "", - }) + db, err := kv.NewInMemory(logger, basedb.Options{}) require.NoError(t, err) nodeStorage, err := operatorstorage.NewNodeStorage(logger, db) From 6370bb36eb408bb5968205ec9483fcb3f42c20d3 Mon Sep 17 00:00:00 2001 From: moshe-blox <89339422+moshe-blox@users.noreply.github.com> Date: Wed, 16 Aug 2023 13:55:02 +0300 Subject: [PATCH 08/16] deployment: enable `BuilderProposals` in jato-v2 (#1105) --- .k8/production/prater/ssv-node-prater-1-deployment.yml | 2 ++ .k8/production/prater/ssv-node-prater-2-deployment.yml | 2 ++ .k8/production/prater/ssv-node-prater-3-deployment.yml | 2 ++ .k8/production/prater/ssv-node-prater-4-deployment.yml | 2 ++ 4 files changed, 8 insertions(+) diff --git a/.k8/production/prater/ssv-node-prater-1-deployment.yml b/.k8/production/prater/ssv-node-prater-1-deployment.yml index b67363312c..73c26db625 100644 --- a/.k8/production/prater/ssv-node-prater-1-deployment.yml +++ b/.k8/production/prater/ssv-node-prater-1-deployment.yml @@ -110,6 +110,8 @@ spec: value: "16011" - name: ENABLE_PROFILE value: "true" + - name: BUILDER_PROPOSALS + value: "true" volumeMounts: - mountPath: /data name: ssv-node-prater-1 diff --git a/.k8/production/prater/ssv-node-prater-2-deployment.yml b/.k8/production/prater/ssv-node-prater-2-deployment.yml index 0f54d1e0ff..4cb17b317a 100644 --- a/.k8/production/prater/ssv-node-prater-2-deployment.yml +++ b/.k8/production/prater/ssv-node-prater-2-deployment.yml @@ -110,6 +110,8 @@ spec: value: "16012" - name: ENABLE_PROFILE value: "true" + - name: BUILDER_PROPOSALS + value: "true" volumeMounts: - mountPath: /data name: ssv-node-prater-2 diff --git a/.k8/production/prater/ssv-node-prater-3-deployment.yml b/.k8/production/prater/ssv-node-prater-3-deployment.yml index 66b9073d69..c14d51220f 100644 --- a/.k8/production/prater/ssv-node-prater-3-deployment.yml +++ b/.k8/production/prater/ssv-node-prater-3-deployment.yml @@ -110,6 +110,8 @@ spec: value: "16013" - name: ENABLE_PROFILE value: "true" + - name: BUILDER_PROPOSALS + value: "true" volumeMounts: - mountPath: /data name: ssv-node-prater-3 diff --git a/.k8/production/prater/ssv-node-prater-4-deployment.yml b/.k8/production/prater/ssv-node-prater-4-deployment.yml index fb9fe3cefa..0a8d4e4fd5 100644 --- a/.k8/production/prater/ssv-node-prater-4-deployment.yml +++ b/.k8/production/prater/ssv-node-prater-4-deployment.yml @@ -110,6 +110,8 @@ spec: value: "16014" - name: ENABLE_PROFILE value: "true" + - name: BUILDER_PROPOSALS + value: "true" volumeMounts: - mountPath: /data name: ssv-node-prater-4 From 4d9bf1c9caf930ba89c533d41fb561f8202ee33f Mon Sep 17 00:00:00 2001 From: moshe-blox <89339422+moshe-blox@users.noreply.github.com> Date: Wed, 16 Aug 2023 14:32:07 +0300 Subject: [PATCH 09/16] Revamp `config.example.yaml` (#1104) * Revamp `config.example.yaml` * comment * comment * comment --- config/config.example.yaml | 44 ++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/config/config.example.yaml b/config/config.example.yaml index 3557762582..92779ee019 100644 --- a/config/config.example.yaml +++ b/config/config.example.yaml @@ -1,34 +1,42 @@ global: + # Console log level (debug, info, warn, error, fatal, panic) LogLevel: info + + # Debug logs file path LogFilePath: ./data/debug.log db: + # Path to a persistent directory to store the node's database. Path: ./data/db +ssv: + # The SSV network to join to + # Mainnet = Network: mainnet (default) + # Testnet = Network: jato-v2 + Network: mainnet + eth2: - BeaconNodeAddr: example.url + # HTTP URL of the Beacon node to connect to. + BeaconNodeAddr: http://example.url:5052 + + ValidatorOptions: + # Whether to enable MEV block production. Requires the connected Beacon node to be MEV-enabled. + BuilderProposals: false eth1: - # ETH1 node WebSocket address - ETH1Addr: example.url + # WebSocket URL of the Eth1 node to connect to. + ETH1Addr: ws://example.url:8546/ws p2p: - # replace with your ip -# HostAddress: example.ip -# TcpPort: -# UdpPort: -# mdns for local network setup -# Discovery: mdns + # Optionally specify the external IP address of the node, if it cannot be determined automatically. + # HostAddress: 192.168.1.1 -ssv: - GenesisEpoch: - ValidatorOptions: - SignatureCollectionTimeout: 5s + # Optionally override the default TCP & UDP ports of the node. + # TcpPort: 13001 + # UdpPort: 12001 +# Note: Operator private key can be generated with the `generate-operator-keys` command. OperatorPrivateKey: -bootnode: - ExternalIP: - PrivateKey: - -LocalEventsPath: # path to local events. used for running the node with custom local events +# This enables monitoring at the specified port, see https://github.com/bloxapp/ssv/tree/main/monitoring +MetricsAPIPort: 15000 \ No newline at end of file From cff4647aed2c355f5529ad4810c016c7ba0eda0c Mon Sep 17 00:00:00 2001 From: Lior Rutenberg Date: Mon, 21 Aug 2023 13:22:51 +0300 Subject: [PATCH 10/16] Add public key of HellmanAlert full node to the WhitelistedOperatorKeys (#1110) Co-authored-by: mingming-tang <32962819+mingming-tang@users.noreply.github.com> --- networkconfig/mainnet.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/networkconfig/mainnet.go b/networkconfig/mainnet.go index 1fb66ecc80..2326420cde 100644 --- a/networkconfig/mainnet.go +++ b/networkconfig/mainnet.go @@ -35,5 +35,9 @@ var Mainnet = NetworkConfig{ // ssvscan.io (DragonStake) "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdlMzclA0QWRoSklqK0J1Qm84QmsKK0RTemZ1TDFaNit0b2ZyYWVHbW90N1ltUVFUZHhaRGEwWE9haVhJNU9mWERJbEQ5VUp0SC9yZWlWSFhTNTJuRwp5K2NvY3NuNnZNdnRtdUlvS1JYRGxnYnI4UStod0lpR004K1RrWGFxOVpCRVVSNHpLUnZ1YlpSanZBemhjeDZ3CnU4TzJER1F5MyswTVY1WmtYL0FEYkhpVlJRcWpXWGZWUm1oNmV3S3hhVDNqNC9lei9EMnNPNUtLTXBWUFRXUHMKT2ZFZEdjZjJFSnpoU1Zha0hZOFpuZ0JUMEhIK0ZMeVVVT1prcTRBa25UWVByS1ZyVlBMVmlUaG1Va0hSTUs5VwpVRnNPbFliZlpyeTRHTTdWcEtnSzZGcDd2K1NmZEZuYWUvU0d6d3MzSndIMjFRK0NjV1hRbEFZOGNPbFI0dko4CkpRSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K", + + // HellmanAlert + "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBcU5Sd0xWSHNWMEloUjdjdUJkb1AKZnVwNTkydEJFSG0vRllDREZQbERMR2NVZ2NzZ29PdHBsV2hMRjBGSzIwQ3ppVi83WVZzcWpxcDh3VDExM3pBbQoxOTZZRlN6WmUzTFhOQXFRWlBwbDlpOVJxdVJJMGlBT2xiWUp0ampJRjd2ZVZLbVdybzMwWTZDV3JPcHpVQ1BPClRGVEpGZ0hvZmtQT2pabmprNURtdDg2ZURveUxzenJQZWQ0LzlyR2NNVUp4WnJBSjEvbFR1ajNaWWVJUk0wS04KUVQ0eitPb3p0T0dBeDVVcUk2THpQL3NGOWRJM3BzM3BIb3dXOWF2RHp3Qm94Y3hWam14NWhRMXowOTN4MnlkYgpWcjgxNDgzTzdqUkt6eFpXeEduOFJzZUROZkxwSi93VFJiQ0lVOFhwUC9IKzd6TWNGMG1HbVlUcjAvcWR1bVNsCjNRSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K", + "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdmRWVVJ0OFgxbFA5VDVSUUdYdVkKcFpZWjVBb3VuSEdUakMvQ1FoTmQ5RC9kT2kvSDUwVW1PdVBpTzhYYUF4UFRGcGIrZ2xCeGJRRHVQUGN1cENPdQpKN09lVTBvdzdsQjVMclZlWWt3RExnSHY3bDQwcjRWVTM3NlFueGhuS0JyVHNkaWdmZHJYUWZveGRhajVQQ0VYCnFjK1ozNXFPUmpCZ3dublRlbEJjc2NLMHorSkJaQzU0OXFOWThMbm9aMTBuRFptdW1YVDlac3dISCtJVkZacDYKMEZTY0k0V1V5U1gxVnJJT2tSandoSWlCSFk3YkhrZ01Bci9xeStuRmlFUUVRV2Q2VXAwOWtkS0hNVmdtVFp4KwprQXZRbFZ0Z3luYkFPWkNMeng0Ymo1Yi9MQklIejNiTk9zWlNtR3AxWi9hWDFkd1BaMlhOai83elovNGpuM095CkdRSURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K", }, } From 47c312b815c5c3171caf1d91da6ab230880d1cd2 Mon Sep 17 00:00:00 2001 From: moshe-blox <89339422+moshe-blox@users.noreply.github.com> Date: Mon, 21 Aug 2023 13:23:39 +0300 Subject: [PATCH 11/16] feat: retry standard block after Prysm fails to retrieve blinded (#1108) * deploy to 5-8 * logs * refactors & logs * better logs * spec-alignment * fix spec test * revert gitlab * refactor * Revert "revert gitlab" This reverts commit d8ec6eb7d5340e9215fd816d3415324d4ed2fd9a. * Revert "Revert "revert gitlab"" This reverts commit b02de3e93f4a0d2ae3de71d467879e7238c215cb. * log block proposal as INFO * comments * update spectest JSONs * Revert "update spectest JSONs" This reverts commit 7fea0646f09834f18d02518ced00c5e9970dbe16. * change condition to if the node is a Prysm * log * add log & redeploy * spec align --- .gitlab-ci.yml | 4 +- beacon/goclient/goclient.go | 54 +++++++++++++- beacon/goclient/proposer.go | 32 --------- protocol/v2/ssv/runner/proposer.go | 86 ++++++++++++++++++++--- scripts/spec-alignment/differ.config.yaml | 2 +- 5 files changed, 131 insertions(+), 47 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1b575794ff..750df4c128 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -40,7 +40,7 @@ Build stage Docker image: - docker tag $IMAGE_NAME:$CI_COMMIT_SHA $DOCKER_REPO_INFRA_STAGE:$CI_COMMIT_SHA - $DOCKER_LOGIN_TO_INFRA_STAGE_REPO && docker push $DOCKER_REPO_INFRA_STAGE:$CI_COMMIT_SHA only: - - stage + - try-prysm-mev Deploy nodes to stage: stage: deploy @@ -69,7 +69,7 @@ Deploy nodes to stage: # █▓▒░ Keep commented unless you're testing the bootnode ░▒▓█ # - .k8/stage/scripts/deploy-boot-nodes.sh $DOCKER_REPO_INFRA_STAGE $CI_COMMIT_SHA ssv $APP_REPLICAS_INFRA_STAGE blox-infra-stage kubernetes-admin@blox-infra stage.ssv.network $K8S_API_VERSION $STAGE_HEALTH_CHECK_IMAGE 1000m 1000m only: - - stage + - try-prysm-mev Deploy exporter to stage: stage: deploy diff --git a/beacon/goclient/goclient.go b/beacon/goclient/goclient.go index dc7b9b4ade..1f278c563b 100644 --- a/beacon/goclient/goclient.go +++ b/beacon/goclient/goclient.go @@ -3,6 +3,7 @@ package goclient import ( "context" "math" + "strings" "sync" "time" @@ -66,9 +67,33 @@ func init() { } } +// NodeClient is the type of the Beacon node. +type NodeClient string + +const ( + NodeLighthouse NodeClient = "lighthouse" + NodePrysm NodeClient = "prysm" + NodeUnknown NodeClient = "unknown" +) + +// ParseNodeClient derives the client from node's version string. +func ParseNodeClient(version string) NodeClient { + version = strings.ToLower(version) + switch { + case strings.Contains(version, "lighthouse"): + return NodeLighthouse + case strings.Contains(version, "prysm"): + return NodePrysm + default: + return NodeUnknown + } +} + // Client defines all go-eth2-client interfaces used in ssv type Client interface { eth2client.Service + eth2client.NodeVersionProvider + eth2client.NodeClientProvider eth2client.AttestationDataProvider eth2client.AggregateAttestationProvider @@ -99,12 +124,20 @@ type Client interface { eth2client.ValidatorRegistrationsSubmitter } +type NodeClientProvider interface { + NodeClient() NodeClient +} + +var _ NodeClientProvider = (*goClient)(nil) + // goClient implementing Beacon struct type goClient struct { log *zap.Logger ctx context.Context network beaconprotocol.Network client Client + nodeVersion string + nodeClient NodeClient graffiti []byte gasLimit uint64 operatorID spectypes.OperatorID @@ -128,8 +161,6 @@ func New(logger *zap.Logger, opt beaconprotocol.Options, operatorID spectypes.Op return nil, errors.WithMessage(err, "failed to create http client") } - logger.Info("consensus client: connected", fields.Name(httpClient.Name()), fields.Address(httpClient.Address())) - tickerChan := make(chan phase0.Slot, 32) slotTicker.Subscribe(tickerChan) @@ -144,11 +175,30 @@ func New(logger *zap.Logger, opt beaconprotocol.Options, operatorID spectypes.Op registrationCache: map[phase0.BLSPubKey]*api.VersionedSignedValidatorRegistration{}, } + // Get the node's version and client. + client.nodeVersion, err = client.client.NodeVersion(opt.Context) + if err != nil { + return nil, errors.Wrap(err, "failed to get node version") + } + client.nodeClient = ParseNodeClient(client.nodeVersion) + + logger.Info("consensus client connected", + fields.Name(httpClient.Name()), + fields.Address(httpClient.Address()), + zap.String("client", string(client.nodeClient)), + zap.String("version", client.nodeVersion), + ) + + // Start registration submitter. go client.registrationSubmitter(tickerChan) return client, nil } +func (gc *goClient) NodeClient() NodeClient { + return gc.nodeClient +} + // IsReady returns if beacon node is currently ready: responds to requests, not in the syncing state, not optimistic // (for optimistic see https://github.com/ethereum/consensus-specs/blob/dev/sync/optimistic.md#block-production). func (gc *goClient) IsReady(ctx context.Context) (bool, error) { diff --git a/beacon/goclient/proposer.go b/beacon/goclient/proposer.go index c01e5b1041..cb48d5e33c 100644 --- a/beacon/goclient/proposer.go +++ b/beacon/goclient/proposer.go @@ -58,10 +58,6 @@ func (gc *goClient) GetBeaconBlock(slot phase0.Slot, graffiti, randao []byte) (s if beaconBlock.Bellatrix.Body.ExecutionPayload == nil { return nil, DataVersionNil, fmt.Errorf("bellatrix block execution payload is nil") } - gc.log.Info("got beacon block", - fields.BlockHash(beaconBlock.Bellatrix.Body.ExecutionPayload.BlockHash), - fields.BlockVersion(beaconBlock.Version), - fields.Slot(beaconBlock.Bellatrix.Slot)) return beaconBlock.Bellatrix, beaconBlock.Version, nil case spec.DataVersionCapella: if beaconBlock.Capella.Body == nil { @@ -70,10 +66,6 @@ func (gc *goClient) GetBeaconBlock(slot phase0.Slot, graffiti, randao []byte) (s if beaconBlock.Capella.Body.ExecutionPayload == nil { return nil, DataVersionNil, fmt.Errorf("capella block execution payload is nil") } - gc.log.Info("got beacon block", - fields.BlockHash(beaconBlock.Capella.Body.ExecutionPayload.BlockHash), - fields.BlockVersion(beaconBlock.Version), - fields.Slot(beaconBlock.Capella.Slot)) return beaconBlock.Capella, beaconBlock.Version, nil default: return nil, DataVersionNil, fmt.Errorf("beacon block version %s not supported", beaconBlock.Version) @@ -104,10 +96,6 @@ func (gc *goClient) GetBlindedBeaconBlock(slot phase0.Slot, graffiti, randao []b if beaconBlock.Bellatrix.Body.ExecutionPayloadHeader == nil { return nil, DataVersionNil, fmt.Errorf("bellatrix block execution payload header is nil") } - gc.log.Info("got blinded beacon block", - fields.BlockHash(beaconBlock.Bellatrix.Body.ExecutionPayloadHeader.BlockHash), - fields.BlockVersion(beaconBlock.Version), - fields.Slot(beaconBlock.Bellatrix.Slot)) return beaconBlock.Bellatrix, beaconBlock.Version, nil case spec.DataVersionCapella: if beaconBlock.Capella.Body == nil { @@ -116,10 +104,6 @@ func (gc *goClient) GetBlindedBeaconBlock(slot phase0.Slot, graffiti, randao []b if beaconBlock.Capella.Body.ExecutionPayloadHeader == nil { return nil, DataVersionNil, fmt.Errorf("capella block execution payload header is nil") } - gc.log.Info("got blinded beacon block", - fields.BlockHash(beaconBlock.Capella.Body.ExecutionPayloadHeader.BlockHash), - fields.BlockVersion(beaconBlock.Version), - fields.Slot(beaconBlock.Capella.Slot)) return beaconBlock.Capella, beaconBlock.Version, nil default: return nil, DataVersionNil, fmt.Errorf("beacon block version %s not supported", beaconBlock.Version) @@ -139,10 +123,6 @@ func (gc *goClient) SubmitBlindedBeaconBlock(block *api.VersionedBlindedBeaconBl Message: block.Bellatrix, } copy(signedBlock.Bellatrix.Signature[:], sig[:]) - gc.log.Info("submitting blinded beacon block", - fields.BlockHash(block.Bellatrix.Body.ExecutionPayloadHeader.BlockHash), - fields.BlockVersion(block.Version), - fields.Slot(block.Bellatrix.Slot)) case spec.DataVersionCapella: if block.Capella == nil { return errors.New("capella blinded block is nil") @@ -151,10 +131,6 @@ func (gc *goClient) SubmitBlindedBeaconBlock(block *api.VersionedBlindedBeaconBl Message: block.Capella, } copy(signedBlock.Capella.Signature[:], sig[:]) - gc.log.Info("submitting blinded beacon block", - fields.BlockHash(block.Capella.Body.ExecutionPayloadHeader.BlockHash), - fields.BlockVersion(block.Version), - fields.Slot(block.Capella.Slot)) default: return errors.New("unknown block version") } @@ -192,10 +168,6 @@ func (gc *goClient) SubmitBeaconBlock(block *spec.VersionedBeaconBlock, sig phas Message: block.Bellatrix, } copy(signedBlock.Bellatrix.Signature[:], sig[:]) - gc.log.Info("submitting block", - fields.BlockHash(block.Bellatrix.Body.ExecutionPayload.BlockHash), - fields.BlockVersion(block.Version), - fields.Slot(block.Bellatrix.Slot)) case spec.DataVersionCapella: if block.Capella == nil { return errors.New("capella block is nil") @@ -204,10 +176,6 @@ func (gc *goClient) SubmitBeaconBlock(block *spec.VersionedBeaconBlock, sig phas Message: block.Capella, } copy(signedBlock.Capella.Signature[:], sig[:]) - gc.log.Info("submitting block", - fields.BlockHash(block.Capella.Body.ExecutionPayload.BlockHash), - fields.BlockVersion(block.Version), - fields.Slot(block.Capella.Slot)) default: return errors.New("unknown block version") } diff --git a/protocol/v2/ssv/runner/proposer.go b/protocol/v2/ssv/runner/proposer.go index c9fdbff1fa..39bf97b6f0 100644 --- a/protocol/v2/ssv/runner/proposer.go +++ b/protocol/v2/ssv/runner/proposer.go @@ -5,6 +5,9 @@ import ( "encoding/json" "time" + "github.com/attestantio/go-eth2-client/api" + apiv1capella "github.com/attestantio/go-eth2-client/api/v1/capella" + "github.com/attestantio/go-eth2-client/spec/capella" "github.com/attestantio/go-eth2-client/spec/phase0" specqbft "github.com/bloxapp/ssv-spec/qbft" specssv "github.com/bloxapp/ssv-spec/ssv" @@ -15,6 +18,7 @@ import ( "github.com/attestantio/go-eth2-client/spec" + "github.com/bloxapp/ssv/beacon/goclient" "github.com/bloxapp/ssv/logging/fields" "github.com/bloxapp/ssv/protocol/v2/qbft/controller" "github.com/bloxapp/ssv/protocol/v2/ssv/runner/metrics" @@ -105,20 +109,35 @@ func (r *ProposerRunner) ProcessPreConsensus(logger *zap.Logger, signedMsg *spec // get block data obj, ver, err = r.GetBeaconNode().GetBlindedBeaconBlock(duty.Slot, r.GetShare().Graffiti, fullSig) if err != nil { - // Prysm currently doesn’t support MEV. - // TODO: Check Prysm MEV support after https://github.com/prysmaticlabs/prysm/issues/12103 is resolved. - return errors.Wrap(err, "failed to get Beacon block") + // Prysm workaround: when Prysm can't retrieve an MEV block, it responds with an error + // saying the block isn't blinded, implying to request a standard block instead. + // https://github.com/prysmaticlabs/prysm/issues/12103 + if nodeClientProvider, ok := r.GetBeaconNode().(goclient.NodeClientProvider); ok && + nodeClientProvider.NodeClient() == goclient.NodePrysm { + logger.Debug("failed to get blinded beacon block, falling back to standard block") + obj, ver, err = r.GetBeaconNode().GetBeaconBlock(duty.Slot, r.GetShare().Graffiti, fullSig) + if err != nil { + return errors.Wrap(err, "failed falling back from blinded to standard beacon block") + } + } else { + return errors.Wrap(err, "failed to get blinded beacon block") + } } } else { // get block data obj, ver, err = r.GetBeaconNode().GetBeaconBlock(duty.Slot, r.GetShare().Graffiti, fullSig) if err != nil { - return errors.Wrap(err, "failed to get Beacon block") + return errors.Wrap(err, "failed to get beacon block") } } - logger.Debug("🧊 got beacon block", - zap.Duration("took", time.Since(start))) + // Log essentials about the retrieved block. + blockSummary, summarizeErr := summarizeBlock(obj) + logger.Info("🧊 got beacon block proposal", + zap.String("block_hash", blockSummary.Hash.String()), + zap.Bool("blinded", blockSummary.Blinded), + zap.Duration("took", time.Since(start)), + zap.NamedError("summarize_err", summarizeErr)) byts, err := obj.MarshalSSZ() if err != nil { @@ -222,12 +241,13 @@ func (r *ProposerRunner) ProcessPostConsensus(logger *zap.Logger, signedMsg *spe blockSubmissionEnd := r.metrics.StartBeaconSubmission() start := time.Now() - decidedBlockIsBlinded := r.decidedBlindedBlock() - if decidedBlockIsBlinded { + var blk any + if r.decidedBlindedBlock() { vBlindedBlk, _, err := r.GetState().DecidedValue.GetBlindedBlockData() if err != nil { return errors.Wrap(err, "could not get blinded block") } + blk = vBlindedBlk if err := r.GetBeaconNode().SubmitBlindedBeaconBlock(vBlindedBlk, specSig); err != nil { r.metrics.RoleSubmissionFailed() @@ -239,6 +259,7 @@ func (r *ProposerRunner) ProcessPostConsensus(logger *zap.Logger, signedMsg *spe if err != nil { return errors.Wrap(err, "could not get block") } + blk = vBlk if err := r.GetBeaconNode().SubmitBeaconBlock(vBlk, specSig); err != nil { r.metrics.RoleSubmissionFailed() @@ -251,12 +272,15 @@ func (r *ProposerRunner) ProcessPostConsensus(logger *zap.Logger, signedMsg *spe r.metrics.EndDutyFullFlow(r.GetState().RunningInstance.State.Round) r.metrics.RoleSubmitted() + blockSummary, summarizeErr := summarizeBlock(blk) logger.Info("✅ successfully submitted block proposal", fields.Slot(signedMsg.Message.Slot), fields.Height(r.BaseRunner.QBFTController.Height), fields.Round(r.GetState().RunningInstance.State.Round), - fields.BuilderProposals(decidedBlockIsBlinded), - zap.Duration("took", time.Since(start))) + zap.String("block_hash", blockSummary.Hash.String()), + zap.Bool("blinded", blockSummary.Blinded), + zap.Duration("took", time.Since(start)), + zap.NamedError("summarize_err", summarizeErr)) } r.GetState().Finished = true return nil @@ -390,3 +414,45 @@ func (r *ProposerRunner) GetRoot() ([32]byte, error) { ret := sha256.Sum256(marshaledRoot) return ret, nil } + +// blockSummary contains essentials about a block. Useful for logging. +type blockSummary struct { + Hash phase0.Hash32 + Blinded bool + Version spec.DataVersion +} + +// summarizeBlock returns a blockSummary for the given block. +func summarizeBlock(block any) (summary blockSummary, err error) { + if block == nil { + return summary, errors.New("block is nil") + } + switch b := block.(type) { + case *api.VersionedBlindedBeaconBlock: + switch b.Version { + case spec.DataVersionCapella: + return summarizeBlock(b.Capella) + } + case *spec.VersionedBeaconBlock: + switch b.Version { + case spec.DataVersionCapella: + return summarizeBlock(b.Capella) + } + + case *capella.BeaconBlock: + if b == nil || b.Body == nil || b.Body.ExecutionPayload == nil { + return summary, errors.New("block, body or execution payload is nil") + } + summary.Hash = b.Body.ExecutionPayload.BlockHash + summary.Version = spec.DataVersionCapella + + case *apiv1capella.BlindedBeaconBlock: + if b == nil || b.Body == nil || b.Body.ExecutionPayloadHeader == nil { + return summary, errors.New("block, body or execution payload header is nil") + } + summary.Hash = b.Body.ExecutionPayloadHeader.BlockHash + summary.Blinded = true + summary.Version = spec.DataVersionCapella + } + return +} diff --git a/scripts/spec-alignment/differ.config.yaml b/scripts/spec-alignment/differ.config.yaml index 2259e21e50..641ad31360 100644 --- a/scripts/spec-alignment/differ.config.yaml +++ b/scripts/spec-alignment/differ.config.yaml @@ -8,7 +8,7 @@ ApprovedChanges: ["256a3dc0f1eb7abf","22b66e9a63ba145b","12c1c3a1622fb7cc","1c44 "db32f358b6e8e2bb","f372e174e1f34c3b","bc47b3d202e8cd0d","86a6abca1a1c16d6","1655d21d5a4cad4","ac4e427097fc5533","6b4d5a114f8066ff", "9482fb9b6a953c48","5778a05e0976a6eb","24e2c7f54d5dd1d","2a8937e50d20faa9","587c629a67ef07ed","9d06d8e0ee4e1113","e624ec802068e711", "943be3ce709a99d3","5b3bb2d2262fe8be","c20c4c7ed8d1711d","b10c6fc7dd9eee7","c121cdaab6c1c698","e12b17f3910be26b","e47bf52e962c90af", - "90b8a0c8d2c30e95","e8292a58d2eb08ab","17cf3119ac6879f2","3f31546191c9e6b2"] + "90b8a0c8d2c30e95","e8292a58d2eb08ab","17cf3119ac6879f2","3f31546191c9e6b2","29c96f90edc2458d","f29db2624fd63635","dff6fea2c2d32a5f"] IgnoredIdentifiers: - logger ReducedPackageNames: From b0b40e03aeb5bbf639cd82ed8920c9eed07b909f Mon Sep 17 00:00:00 2001 From: moshe-blox <89339422+moshe-blox@users.noreply.github.com> Date: Mon, 21 Aug 2023 13:24:04 +0300 Subject: [PATCH 12/16] chore: remove unused `value_check.go` (#1107) --- ibft/valcheck/README.md | 4 --- ibft/valcheck/value_check.go | 7 ------ utils/dataval/bytesval/equal_bytes.go | 30 ----------------------- utils/dataval/bytesval/not_equal_bytes.go | 30 ----------------------- 4 files changed, 71 deletions(-) delete mode 100644 ibft/valcheck/README.md delete mode 100644 ibft/valcheck/value_check.go delete mode 100644 utils/dataval/bytesval/equal_bytes.go delete mode 100644 utils/dataval/bytesval/not_equal_bytes.go diff --git a/ibft/valcheck/README.md b/ibft/valcheck/README.md deleted file mode 100644 index 2b37e4e805..0000000000 --- a/ibft/valcheck/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Value check - -IBFT tests a received value via an interface called ValueCheck. -This is a simple interface which passes a byte slice to an implementation, for SSV we can check AttestationData/ ProposalData and so on. \ No newline at end of file diff --git a/ibft/valcheck/value_check.go b/ibft/valcheck/value_check.go deleted file mode 100644 index 5b4a11a719..0000000000 --- a/ibft/valcheck/value_check.go +++ /dev/null @@ -1,7 +0,0 @@ -package valcheck - -// ValueCheck is an interface which validates the proposal value passed to the node. -// It's kept minimal to allow the implementation to have all the check logic. -type ValueCheck interface { - Check(value []byte) error -} diff --git a/utils/dataval/bytesval/equal_bytes.go b/utils/dataval/bytesval/equal_bytes.go deleted file mode 100644 index 0ca58e9c17..0000000000 --- a/utils/dataval/bytesval/equal_bytes.go +++ /dev/null @@ -1,30 +0,0 @@ -package bytesval - -import ( - "bytes" - "errors" - - "github.com/bloxapp/ssv/ibft/valcheck" -) - -// bytesValidation implements val.ValueImplementation interface -// The logic is to compare bytes from the input with the original ones. -type bytesValidation struct { - val []byte -} - -// NewEqualBytes is the constructor of bytesValidation -func NewEqualBytes(val []byte) valcheck.ValueCheck { - return &bytesValidation{ - val: val, - } -} - -// Validate implements dataval.ValidatorStorage interface -func (c *bytesValidation) Check(value []byte) error { - if !bytes.Equal(value, c.val) { - return errors.New("msg value is wrong") - } - - return nil -} diff --git a/utils/dataval/bytesval/not_equal_bytes.go b/utils/dataval/bytesval/not_equal_bytes.go deleted file mode 100644 index 07105a9312..0000000000 --- a/utils/dataval/bytesval/not_equal_bytes.go +++ /dev/null @@ -1,30 +0,0 @@ -package bytesval - -import ( - "bytes" - "errors" - - "github.com/bloxapp/ssv/ibft/valcheck" -) - -// notEqualBytesValidation implements val.ValueImplementation interface -// The logic is to compare bytes from the input with the original ones, if not equal return true. -type notEqualBytesValidation struct { - val []byte -} - -// NewNotEqualBytes is the constructor of bytesValidation -func NewNotEqualBytes(val []byte) valcheck.ValueCheck { - return ¬EqualBytesValidation{ - val: val, - } -} - -// Validate implements dataval.ValidatorStorage interface -func (c *notEqualBytesValidation) Check(value []byte) error { - if bytes.Equal(value, c.val) { - return errors.New("msg value is wrong") - } - - return nil -} From 336b0843e1a0a7ef5912b6c6391e9cf3d3bca9ec Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Mon, 21 Aug 2023 14:24:34 +0400 Subject: [PATCH 13/16] Pin package versions in Dockerfile (#1102) --- Dockerfile | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index c6692a3f7d..b440f2987e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,19 @@ # # STEP 1: Prepare environment # -FROM golang:1.19 AS preparer +FROM golang:1.19.12 AS preparer RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \ - curl git zip unzip wget g++ gcc-aarch64-linux-gnu bzip2 make \ + curl=7.88.1-10+deb12u1 \ + git=1:2.39.2-1.1 \ + zip=3.0-13 \ + unzip=6.0-28 \ + wget=1.21.3-1+b1 \ + g++=4:12.2.0-3 \ + gcc-aarch64-linux-gnu=4:12.2.0-3 \ + bzip2=1.0.8-5+b1 \ + make=4.3-4.1 \ && rm -rf /var/lib/apt/lists/* # install jemalloc WORKDIR /tmp/jemalloc-temp @@ -45,10 +53,14 @@ RUN --mount=type=cache,target=/root/.cache/go-build \ # # STEP 3: Prepare image to run the binary # -FROM alpine:3.12 AS runner +FROM alpine:3.18.3 AS runner # Install ca-certificates, bash -RUN apk -v --update add ca-certificates bash make bind-tools && \ +RUN apk -v --update add \ + ca-certificates=20230506-r0 \ + bash=5.2.15-r5 \ + make=4.4.1-r1 \ + bind-tools=9.18.16-r0 && \ rm /var/cache/apk/* COPY --from=builder /go/bin/ssvnode /go/bin/ssvnode From d20b8c0e383eee9d8e63fbf5696c7b9c3b941cd0 Mon Sep 17 00:00:00 2001 From: moshe-blox <89339422+moshe-blox@users.noreply.github.com> Date: Mon, 21 Aug 2023 13:26:23 +0300 Subject: [PATCH 14/16] fix: don't increment connections after ignoring (#1072) --- network/peers/connections/conn_handler.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/network/peers/connections/conn_handler.go b/network/peers/connections/conn_handler.go index a96e88c78b..f7f01de505 100644 --- a/network/peers/connections/conn_handler.go +++ b/network/peers/connections/conn_handler.go @@ -71,13 +71,14 @@ func (ch *connHandler) Handle(logger *zap.Logger) *libp2pnetwork.NotifyBundle { delete(ongoingHandshakes, pid) } + var ignoredConnection = errors.New("ignored connection") acceptConnection := func(logger *zap.Logger, net libp2pnetwork.Network, conn libp2pnetwork.Conn) error { pid := conn.RemotePeer() if !beginHandshake(pid) { // Another connection with the same peer is already being handled. logger.Debug("peer is already being handled") - return nil + return ignoredConnection } defer func() { // Unset this peer as being handled. @@ -87,7 +88,7 @@ func (ch *connHandler) Handle(logger *zap.Logger) *libp2pnetwork.NotifyBundle { switch ch.peerInfos.State(pid) { case peers.StateConnected, peers.StateConnecting: logger.Debug("peer is already connected or connecting") - return nil + return ignoredConnection } ch.peerInfos.AddPeerInfo(pid, conn.RemoteMultiaddr(), conn.Stat().Direction) @@ -162,6 +163,9 @@ func (ch *connHandler) Handle(logger *zap.Logger) *libp2pnetwork.NotifyBundle { err = errors.New("reached peers limit") } } + if errors.Is(err, ignoredConnection) { + return + } if err != nil { disconnect(logger, net, conn) logger.Debug("failed to accept connection", zap.Error(err)) From 0e830e251bf49420a8aa89619e220f97116dbcb0 Mon Sep 17 00:00:00 2001 From: moshe-blox <89339422+moshe-blox@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:53:59 +0300 Subject: [PATCH 15/16] revert gitlab (#1111) --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 750df4c128..1b575794ff 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -40,7 +40,7 @@ Build stage Docker image: - docker tag $IMAGE_NAME:$CI_COMMIT_SHA $DOCKER_REPO_INFRA_STAGE:$CI_COMMIT_SHA - $DOCKER_LOGIN_TO_INFRA_STAGE_REPO && docker push $DOCKER_REPO_INFRA_STAGE:$CI_COMMIT_SHA only: - - try-prysm-mev + - stage Deploy nodes to stage: stage: deploy @@ -69,7 +69,7 @@ Deploy nodes to stage: # █▓▒░ Keep commented unless you're testing the bootnode ░▒▓█ # - .k8/stage/scripts/deploy-boot-nodes.sh $DOCKER_REPO_INFRA_STAGE $CI_COMMIT_SHA ssv $APP_REPLICAS_INFRA_STAGE blox-infra-stage kubernetes-admin@blox-infra stage.ssv.network $K8S_API_VERSION $STAGE_HEALTH_CHECK_IMAGE 1000m 1000m only: - - try-prysm-mev + - stage Deploy exporter to stage: stage: deploy From 814e093618a96cbff776e6f348bbd17ebd49fccc Mon Sep 17 00:00:00 2001 From: moshe-blox <89339422+moshe-blox@users.noreply.github.com> Date: Mon, 21 Aug 2023 15:25:08 +0300 Subject: [PATCH 16/16] chore: update package versions in Dockerfile (#1112) --- Dockerfile | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index b440f2987e..4a08d6c7ac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,16 +5,17 @@ FROM golang:1.19.12 AS preparer RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \ - curl=7.88.1-10+deb12u1 \ - git=1:2.39.2-1.1 \ - zip=3.0-13 \ - unzip=6.0-28 \ - wget=1.21.3-1+b1 \ - g++=4:12.2.0-3 \ - gcc-aarch64-linux-gnu=4:12.2.0-3 \ - bzip2=1.0.8-5+b1 \ - make=4.3-4.1 \ + curl=7.88.1-10+deb12u1 \ + git=1:2.39.2-1.1 \ + zip=3.0-13 \ + unzip=6.0-28 \ + wget=1.21.3-1+b2 \ + g++=4:12.2.0-3 \ + gcc-aarch64-linux-gnu=4:12.2.0-3 \ + bzip2=1.0.8-5+b1 \ + make=4.3-4.1 \ && rm -rf /var/lib/apt/lists/* + # install jemalloc WORKDIR /tmp/jemalloc-temp RUN curl -s -L "https://github.com/jemalloc/jemalloc/releases/download/5.2.1/jemalloc-5.2.1.tar.bz2" -o jemalloc.tar.bz2 \ @@ -57,10 +58,10 @@ FROM alpine:3.18.3 AS runner # Install ca-certificates, bash RUN apk -v --update add \ - ca-certificates=20230506-r0 \ - bash=5.2.15-r5 \ - make=4.4.1-r1 \ - bind-tools=9.18.16-r0 && \ + ca-certificates=20230506-r0 \ + bash=5.2.15-r5 \ + make=4.4.1-r1 \ + bind-tools=9.18.16-r0 && \ rm /var/cache/apk/* COPY --from=builder /go/bin/ssvnode /go/bin/ssvnode