From ca8d35a8425e0454be0226123bff2de73ec82da9 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Fri, 11 Apr 2025 22:35:04 -0300 Subject: [PATCH 01/34] networkconfig: split beacon and ssv configs --- ekm/signer_key_manager_test.go | 7 +++-- eth/eventhandler/event_handler_test.go | 10 +++---- message/validation/validation_test.go | 10 +++---- network/discovery/dv5_service_test.go | 8 ++++-- network/discovery/util_test.go | 18 ++++++++----- networkconfig/beacon.go | 12 +++++++++ networkconfig/config.go | 17 +++--------- networkconfig/holesky-e2e.go | 18 ++++++++----- networkconfig/holesky-stage.go | 28 +++++++++++--------- networkconfig/holesky.go | 24 ++++++++++------- networkconfig/hoodi-stage.go | 24 ++++++++++------- networkconfig/hoodi.go | 24 ++++++++++------- networkconfig/local-testnet.go | 18 ++++++++----- networkconfig/mainnet.go | 36 ++++++++++++++------------ networkconfig/sepolia.go | 24 ++++++++++------- networkconfig/ssv.go | 15 +++++++++++ networkconfig/test-network.go | 20 ++++++++------ operator/duties/scheduler_test.go | 5 ++-- 18 files changed, 186 insertions(+), 132 deletions(-) create mode 100644 networkconfig/beacon.go create mode 100644 networkconfig/ssv.go diff --git a/ekm/signer_key_manager_test.go b/ekm/signer_key_manager_test.go index e31d6796da..481c669560 100644 --- a/ekm/signer_key_manager_test.go +++ b/ekm/signer_key_manager_test.go @@ -48,10 +48,9 @@ func testKeyManager(t *testing.T, network *networkconfig.NetworkConfig) KeyManag require.NoError(t, err) if network == nil { - network = &networkconfig.NetworkConfig{ - Beacon: utils.SetupMockBeaconNetwork(t, nil), - DomainType: networkconfig.TestNetwork.DomainType, - } + network = &networkconfig.NetworkConfig{} + network.Beacon = utils.SetupMockBeaconNetwork(t, nil) + network.DomainType = networkconfig.TestNetwork.DomainType } km, err := NewETHKeyManagerSigner(logger, db, *network, "") diff --git a/eth/eventhandler/event_handler_test.go b/eth/eventhandler/event_handler_test.go index d327bf3c27..fdbb1ddd3f 100644 --- a/eth/eventhandler/event_handler_test.go +++ b/eth/eventhandler/event_handler_test.go @@ -71,9 +71,8 @@ func TestHandleBlockEventsStream(t *testing.T) { currentSlot := &utils.SlotValue{} mockBeaconNetwork := utils.SetupMockBeaconNetwork(t, currentSlot) - mockNetworkConfig := &networkconfig.NetworkConfig{ - Beacon: mockBeaconNetwork, - } + mockNetworkConfig := &networkconfig.NetworkConfig{} + mockNetworkConfig.Beacon = mockBeaconNetwork eh, _, err := setupEventHandler(t, ctx, logger, mockNetworkConfig, ops[0], false) if err != nil { @@ -1360,9 +1359,8 @@ func setupEventHandler(t *testing.T, ctx context.Context, logger *zap.Logger, ne operatorDataStore := operatordatastore.New(operatorData) if network == nil { - network = &networkconfig.NetworkConfig{ - Beacon: utils.SetupMockBeaconNetwork(t, &utils.SlotValue{}), - } + network = &networkconfig.NetworkConfig{} + network.Beacon = utils.SetupMockBeaconNetwork(t, &utils.SlotValue{}) } keyManager, err := ekm.NewETHKeyManagerSigner(logger, db, *network, "") diff --git a/message/validation/validation_test.go b/message/validation/validation_test.go index dfcd4a44a7..0e56aa78a1 100644 --- a/message/validation/validation_test.go +++ b/message/validation/validation_test.go @@ -628,9 +628,8 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("accept pre-consensus randao message when epoch duties are not set", func(t *testing.T) { currentSlot := &utils.SlotValue{} - mockNetworkConfig := networkconfig.NetworkConfig{ - Beacon: utils.SetupMockBeaconNetwork(t, currentSlot), - } + mockNetworkConfig := networkconfig.NetworkConfig{} + mockNetworkConfig.Beacon = utils.SetupMockBeaconNetwork(t, currentSlot) const epoch = 1 currentSlot.SetSlot(netCfg.Beacon.FirstSlotAtEpoch(epoch)) @@ -663,9 +662,8 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("reject pre-consensus randao message when epoch duties are set", func(t *testing.T) { currentSlot := &utils.SlotValue{} - mockNetworkConfig := networkconfig.NetworkConfig{ - Beacon: utils.SetupMockBeaconNetwork(t, currentSlot), - } + mockNetworkConfig := networkconfig.NetworkConfig{} + mockNetworkConfig.Beacon = utils.SetupMockBeaconNetwork(t, currentSlot) const epoch = 1 currentSlot.SetSlot(mockNetworkConfig.Beacon.FirstSlotAtEpoch(epoch)) diff --git a/network/discovery/dv5_service_test.go b/network/discovery/dv5_service_test.go index 05066cca51..2c4c0622be 100644 --- a/network/discovery/dv5_service_test.go +++ b/network/discovery/dv5_service_test.go @@ -25,8 +25,12 @@ import ( ) var TestNetwork = networkconfig.NetworkConfig{ - Beacon: beacon.NewNetwork(spectypes.BeaconTestNetwork), - DomainType: spectypes.DomainType{0x1, 0x2, 0x3, 0x4}, + BeaconConfig: networkconfig.BeaconConfig{ + Beacon: beacon.NewNetwork(spectypes.BeaconTestNetwork), + }, + SSVConfig: networkconfig.SSVConfig{ + DomainType: spectypes.DomainType{0x1, 0x2, 0x3, 0x4}, + }, } func TestCheckPeer(t *testing.T) { diff --git a/network/discovery/util_test.go b/network/discovery/util_test.go index 448bb4438a..473ab72638 100644 --- a/network/discovery/util_test.go +++ b/network/discovery/util_test.go @@ -95,13 +95,17 @@ func testingDiscovery(t *testing.T) *DiscV5Service { func testingNetConfigWithForkEpoch(forkEpoch phase0.Epoch) networkconfig.NetworkConfig { n := networkconfig.HoleskyStage return networkconfig.NetworkConfig{ - Name: n.Name, - Beacon: n.Beacon, - DomainType: n.DomainType, - GenesisEpoch: n.GenesisEpoch, - RegistrySyncOffset: n.RegistrySyncOffset, - RegistryContractAddr: n.RegistryContractAddr, - Bootnodes: n.Bootnodes, + Name: n.Name, + BeaconConfig: networkconfig.BeaconConfig{ + Beacon: n.Beacon, + GenesisEpoch: n.GenesisEpoch, + }, + SSVConfig: networkconfig.SSVConfig{ + DomainType: n.DomainType, + RegistrySyncOffset: n.RegistrySyncOffset, + RegistryContractAddr: n.RegistryContractAddr, + Bootnodes: n.Bootnodes, + }, } } diff --git a/networkconfig/beacon.go b/networkconfig/beacon.go new file mode 100644 index 0000000000..6b619a6bb5 --- /dev/null +++ b/networkconfig/beacon.go @@ -0,0 +1,12 @@ +package networkconfig + +import ( + "github.com/attestantio/go-eth2-client/spec/phase0" + + "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" +) + +type BeaconConfig struct { + Beacon beacon.BeaconNetwork + GenesisEpoch phase0.Epoch +} diff --git a/networkconfig/config.go b/networkconfig/config.go index 7dac15ec89..6d290ed244 100644 --- a/networkconfig/config.go +++ b/networkconfig/config.go @@ -3,13 +3,7 @@ package networkconfig import ( "encoding/json" "fmt" - "math/big" "time" - - "github.com/attestantio/go-eth2-client/spec/phase0" - spectypes "github.com/ssvlabs/ssv-spec/types" - - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) var SupportedConfigs = map[string]NetworkConfig{ @@ -34,14 +28,9 @@ func GetNetworkConfigByName(name string) (NetworkConfig, error) { } type NetworkConfig struct { - Name string - Beacon beacon.BeaconNetwork - DomainType spectypes.DomainType - GenesisEpoch phase0.Epoch - RegistrySyncOffset *big.Int - RegistryContractAddr string // TODO: ethcommon.Address - Bootnodes []string - DiscoveryProtocolID [6]byte + Name string + BeaconConfig + SSVConfig } func (n NetworkConfig) String() string { diff --git a/networkconfig/holesky-e2e.go b/networkconfig/holesky-e2e.go index 0f962b83ff..11808a3966 100644 --- a/networkconfig/holesky-e2e.go +++ b/networkconfig/holesky-e2e.go @@ -9,11 +9,15 @@ import ( ) var HoleskyE2E = NetworkConfig{ - Name: "holesky-e2e", - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), - DomainType: spectypes.DomainType{0x0, 0x0, 0xee, 0x1}, - GenesisEpoch: 1, - RegistryContractAddr: "0x58410bef803ecd7e63b23664c586a6db72daf59c", - RegistrySyncOffset: big.NewInt(405579), - Bootnodes: []string{}, + Name: "holesky-e2e", + BeaconConfig: BeaconConfig{ + Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + GenesisEpoch: 1, + }, + SSVConfig: SSVConfig{ + DomainType: spectypes.DomainType{0x0, 0x0, 0xee, 0x1}, + RegistryContractAddr: "0x58410bef803ecd7e63b23664c586a6db72daf59c", + RegistrySyncOffset: big.NewInt(405579), + Bootnodes: []string{}, + }, } diff --git a/networkconfig/holesky-stage.go b/networkconfig/holesky-stage.go index a8a8c90d31..313859930e 100644 --- a/networkconfig/holesky-stage.go +++ b/networkconfig/holesky-stage.go @@ -9,18 +9,22 @@ import ( ) var HoleskyStage = NetworkConfig{ - Name: "holesky-stage", - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), - DomainType: [4]byte{0x00, 0x00, 0x31, 0x13}, - GenesisEpoch: 1, - RegistrySyncOffset: new(big.Int).SetInt64(84599), - RegistryContractAddr: "0x0d33801785340072C452b994496B19f196b7eE15", - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // Public bootnode: - // "enr:-Ja4QDYHVgUs9NvlMqq93ot6VNqbmrIlMrwKnq4X3DPRgyUNB4ospDp8ubMvsf-KsgqY8rzpZKy4GbE1DLphabpRBc-GAY_diLjngmlkgnY0gmlwhDQrLYqJc2VjcDI1NmsxoQKnAiuSlgSR8asjCH0aYoVKM8uPbi4noFuFHZHaAHqknYNzc3YBg3RjcIITiYN1ZHCCD6E", + Name: "holesky-stage", + BeaconConfig: BeaconConfig{ + Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + GenesisEpoch: 1, + }, + SSVConfig: SSVConfig{ + DomainType: [4]byte{0x00, 0x00, 0x31, 0x13}, + RegistrySyncOffset: new(big.Int).SetInt64(84599), + RegistryContractAddr: "0x0d33801785340072C452b994496B19f196b7eE15", + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // Public bootnode: + // "enr:-Ja4QDYHVgUs9NvlMqq93ot6VNqbmrIlMrwKnq4X3DPRgyUNB4ospDp8ubMvsf-KsgqY8rzpZKy4GbE1DLphabpRBc-GAY_diLjngmlkgnY0gmlwhDQrLYqJc2VjcDI1NmsxoQKnAiuSlgSR8asjCH0aYoVKM8uPbi4noFuFHZHaAHqknYNzc3YBg3RjcIITiYN1ZHCCD6E", - // Private bootnode: - "enr:-Ja4QDRUBjWOvVfGxpxvv3FqaCy3psm7IsKu5ETb1GXiexGYDFppD33t7AHRfmQddoAkBiyb7pt4t7ZN0sNB9CsW4I-GAZGOmChMgmlkgnY0gmlwhAorXxuJc2VjcDI1NmsxoQP_bBE-ZYvaXKBR3dRYMN5K_lZP-q-YsBzDZEtxH_4T_YNzc3YBg3RjcIITioN1ZHCCD6I", + // Private bootnode: + "enr:-Ja4QDRUBjWOvVfGxpxvv3FqaCy3psm7IsKu5ETb1GXiexGYDFppD33t7AHRfmQddoAkBiyb7pt4t7ZN0sNB9CsW4I-GAZGOmChMgmlkgnY0gmlwhAorXxuJc2VjcDI1NmsxoQP_bBE-ZYvaXKBR3dRYMN5K_lZP-q-YsBzDZEtxH_4T_YNzc3YBg3RjcIITioN1ZHCCD6I", + }, }, } diff --git a/networkconfig/holesky.go b/networkconfig/holesky.go index 5f94dfce68..d46823df1f 100644 --- a/networkconfig/holesky.go +++ b/networkconfig/holesky.go @@ -9,15 +9,19 @@ import ( ) var Holesky = NetworkConfig{ - Name: "holesky", - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), - DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x2}, - GenesisEpoch: 1, - RegistrySyncOffset: new(big.Int).SetInt64(181612), - RegistryContractAddr: "0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA", - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // SSV Labs - "enr:-Ja4QKFD3u5tZob7xukp-JKX9QJMFqqI68cItsE4tBbhsOyDR0M_1UUjb35hbrqvTP3bnXO_LnKh-jNLTeaUqN4xiduGAZKaP_sagmlkgnY0gmlwhDb0fh6Jc2VjcDI1NmsxoQMw_H2anuiqP9NmEaZwbUfdvPFog7PvcKmoVByDa576SINzc3YBg3RjcIITioN1ZHCCD6I", + Name: "holesky", + BeaconConfig: BeaconConfig{ + Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + GenesisEpoch: 1, + }, + SSVConfig: SSVConfig{ + DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x2}, + RegistrySyncOffset: new(big.Int).SetInt64(181612), + RegistryContractAddr: "0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA", + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // SSV Labs + "enr:-Ja4QKFD3u5tZob7xukp-JKX9QJMFqqI68cItsE4tBbhsOyDR0M_1UUjb35hbrqvTP3bnXO_LnKh-jNLTeaUqN4xiduGAZKaP_sagmlkgnY0gmlwhDb0fh6Jc2VjcDI1NmsxoQMw_H2anuiqP9NmEaZwbUfdvPFog7PvcKmoVByDa576SINzc3YBg3RjcIITioN1ZHCCD6I", + }, }, } diff --git a/networkconfig/hoodi-stage.go b/networkconfig/hoodi-stage.go index f5a9c8d5b8..e98e58453a 100644 --- a/networkconfig/hoodi-stage.go +++ b/networkconfig/hoodi-stage.go @@ -9,15 +9,19 @@ import ( ) var HoodiStage = NetworkConfig{ - Name: "hoodi-stage", - Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), - DomainType: [4]byte{0x00, 0x00, 0x31, 0x14}, - GenesisEpoch: 1, - RegistrySyncOffset: new(big.Int).SetInt64(1004), - RegistryContractAddr: "0x0aaace4e8affc47c6834171c88d342a4abd8f105", - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // SSV Labs - "enr:-Ja4QJZcaYfS0GpX-5xREVBa26a-E-QHMFek-EndsJdgM6loIM7pfbJwPDCNK1VzPkUhMjwcTTuNASiHU6X-sjsrxFmGAZWjNu06gmlkgnY0gmlwhErcGnyJc2VjcDI1NmsxoQP_bBE-ZYvaXKBR3dRYMN5K_lZP-q-YsBzDZEtxH_4T_YNzc3YBg3RjcIITioN1ZHCCD6I", + Name: "hoodi-stage", + BeaconConfig: BeaconConfig{ + Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), + GenesisEpoch: 1, + }, + SSVConfig: SSVConfig{ + DomainType: [4]byte{0x00, 0x00, 0x31, 0x14}, + RegistrySyncOffset: new(big.Int).SetInt64(1004), + RegistryContractAddr: "0x0aaace4e8affc47c6834171c88d342a4abd8f105", + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // SSV Labs + "enr:-Ja4QJZcaYfS0GpX-5xREVBa26a-E-QHMFek-EndsJdgM6loIM7pfbJwPDCNK1VzPkUhMjwcTTuNASiHU6X-sjsrxFmGAZWjNu06gmlkgnY0gmlwhErcGnyJc2VjcDI1NmsxoQP_bBE-ZYvaXKBR3dRYMN5K_lZP-q-YsBzDZEtxH_4T_YNzc3YBg3RjcIITioN1ZHCCD6I", + }, }, } diff --git a/networkconfig/hoodi.go b/networkconfig/hoodi.go index 0429be82c1..02bcf15805 100644 --- a/networkconfig/hoodi.go +++ b/networkconfig/hoodi.go @@ -9,15 +9,19 @@ import ( ) var Hoodi = NetworkConfig{ - Name: "hoodi", - Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), - DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x3}, - GenesisEpoch: 1, - RegistrySyncOffset: new(big.Int).SetInt64(1065), - RegistryContractAddr: "0x58410Bef803ECd7E63B23664C586A6DB72DAf59c", - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // SSV Labs - "enr:-Ja4QIKlyNFuFtTOnVoavqwmpgSJXfhSmhpdSDOUhf5-FBr7bBxQRvG6VrpUvlkr8MtpNNuMAkM33AseduSaOhd9IeWGAZWjRbnvgmlkgnY0gmlwhCNVVTCJc2VjcDI1NmsxoQNTTyiJPoZh502xOZpHSHAfR-94NaXLvi5J4CNHMh2tjoNzc3YBg3RjcIITioN1ZHCCD6I", + Name: "hoodi", + BeaconConfig: BeaconConfig{ + Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), + GenesisEpoch: 1, + }, + SSVConfig: SSVConfig{ + DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x3}, + RegistrySyncOffset: new(big.Int).SetInt64(1065), + RegistryContractAddr: "0x58410Bef803ECd7E63B23664C586A6DB72DAf59c", + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // SSV Labs + "enr:-Ja4QIKlyNFuFtTOnVoavqwmpgSJXfhSmhpdSDOUhf5-FBr7bBxQRvG6VrpUvlkr8MtpNNuMAkM33AseduSaOhd9IeWGAZWjRbnvgmlkgnY0gmlwhCNVVTCJc2VjcDI1NmsxoQNTTyiJPoZh502xOZpHSHAfR-94NaXLvi5J4CNHMh2tjoNzc3YBg3RjcIITioN1ZHCCD6I", + }, }, } diff --git a/networkconfig/local-testnet.go b/networkconfig/local-testnet.go index e25a7ff2d2..3e8bad9dc2 100644 --- a/networkconfig/local-testnet.go +++ b/networkconfig/local-testnet.go @@ -7,12 +7,16 @@ import ( ) var LocalTestnet = NetworkConfig{ - Name: "local-testnet", - Beacon: beacon.NewLocalTestNetwork(spectypes.PraterNetwork), - DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoV2NetworkID.Byte(), 0x2}, - GenesisEpoch: 1, - RegistryContractAddr: "0xC3CD9A0aE89Fff83b71b58b6512D43F8a41f363D", - Bootnodes: []string{ - "enr:-Li4QLR4Y1VbwiqFYKy6m-WFHRNDjhMDZ_qJwIABu2PY9BHjIYwCKpTvvkVmZhu43Q6zVA29sEUhtz10rQjDJkK3Hd-GAYiGrW2Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhCLdu_SJc2VjcDI1NmsxoQJTcI7GHPw-ZqIflPZYYDK_guurp_gsAFF5Erns3-PAvIN0Y3CCE4mDdWRwgg-h", + Name: "local-testnet", + BeaconConfig: BeaconConfig{ + Beacon: beacon.NewLocalTestNetwork(spectypes.PraterNetwork), + GenesisEpoch: 1, + }, + SSVConfig: SSVConfig{ + DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoV2NetworkID.Byte(), 0x2}, + RegistryContractAddr: "0xC3CD9A0aE89Fff83b71b58b6512D43F8a41f363D", + Bootnodes: []string{ + "enr:-Li4QLR4Y1VbwiqFYKy6m-WFHRNDjhMDZ_qJwIABu2PY9BHjIYwCKpTvvkVmZhu43Q6zVA29sEUhtz10rQjDJkK3Hd-GAYiGrW2Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhCLdu_SJc2VjcDI1NmsxoQJTcI7GHPw-ZqIflPZYYDK_guurp_gsAFF5Erns3-PAvIN0Y3CCE4mDdWRwgg-h", + }, }, } diff --git a/networkconfig/mainnet.go b/networkconfig/mainnet.go index f884e6dcf2..2700b24b0e 100644 --- a/networkconfig/mainnet.go +++ b/networkconfig/mainnet.go @@ -9,24 +9,28 @@ import ( ) var Mainnet = NetworkConfig{ - Name: "mainnet", - Beacon: beacon.NewNetwork(spectypes.MainNetwork), - DomainType: spectypes.AlanMainnet, - GenesisEpoch: 218450, - RegistrySyncOffset: new(big.Int).SetInt64(17507487), - RegistryContractAddr: "0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1", - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // SSV Labs - "enr:-Ja4QAbDe5XANqJUDyJU1GmtS01qqMwDYx9JNZgymjBb55fMaha80E2HznRYoUGy6NFVSvs1u1cFqSM0MgJI-h1QKLeGAZKaTo7LgmlkgnY0gmlwhDQrfraJc2VjcDI1NmsxoQNEj0Pgq9-VxfeX83LPDOUPyWiTVzdI-DnfMdO1n468u4Nzc3YBg3RjcIITioN1ZHCCD6I", + Name: "mainnet", + BeaconConfig: BeaconConfig{ + Beacon: beacon.NewNetwork(spectypes.MainNetwork), + GenesisEpoch: 218450, + }, + SSVConfig: SSVConfig{ + DomainType: spectypes.AlanMainnet, + RegistrySyncOffset: new(big.Int).SetInt64(17507487), + RegistryContractAddr: "0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1", + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // SSV Labs + "enr:-Ja4QAbDe5XANqJUDyJU1GmtS01qqMwDYx9JNZgymjBb55fMaha80E2HznRYoUGy6NFVSvs1u1cFqSM0MgJI-h1QKLeGAZKaTo7LgmlkgnY0gmlwhDQrfraJc2VjcDI1NmsxoQNEj0Pgq9-VxfeX83LPDOUPyWiTVzdI-DnfMdO1n468u4Nzc3YBg3RjcIITioN1ZHCCD6I", - // 0NEinfra bootnode - "enr:-Li4QDwrOuhEq5gBJBzFUPkezoYiy56SXZUwkSD7bxYo8RAhPnHyS0de0nOQrzl-cL47RY9Jg8k6Y_MgaUd9a5baYXeGAYnfZE76h2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhDaTS0mJc2VjcDI1NmsxoQMZzUHaN3eClRgF9NAqRNc-ilGpJDDJxdenfo4j-zWKKYN0Y3CCE4iDdWRwgg-g", + // 0NEinfra bootnode + "enr:-Li4QDwrOuhEq5gBJBzFUPkezoYiy56SXZUwkSD7bxYo8RAhPnHyS0de0nOQrzl-cL47RY9Jg8k6Y_MgaUd9a5baYXeGAYnfZE76h2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhDaTS0mJc2VjcDI1NmsxoQMZzUHaN3eClRgF9NAqRNc-ilGpJDDJxdenfo4j-zWKKYN0Y3CCE4iDdWRwgg-g", - // Eridian (eridianalpha.com) - "enr:-Li4QIzHQ2H82twhvsu8EePZ6CA1gl0_B0WWsKaT07245TkHUqXay-MXEgObJB7BxMFl8TylFxfnKNxQyGTXh-2nAlOGAYuraxUEh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBKCzUSJc2VjcDI1NmsxoQNKskkQ6-mBdBWr_ORJfyHai5uD0vL6Fuw90X0sPwmRsoN0Y3CCE4iDdWRwgg-g", + // Eridian (eridianalpha.com) + "enr:-Li4QIzHQ2H82twhvsu8EePZ6CA1gl0_B0WWsKaT07245TkHUqXay-MXEgObJB7BxMFl8TylFxfnKNxQyGTXh-2nAlOGAYuraxUEh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBKCzUSJc2VjcDI1NmsxoQNKskkQ6-mBdBWr_ORJfyHai5uD0vL6Fuw90X0sPwmRsoN0Y3CCE4iDdWRwgg-g", - // CryptoManufaktur - "enr:-Li4QH7FwJcL8gJj0zHAITXqghMkG-A5bfWh2-3Q7vosy9D1BS8HZk-1ITuhK_rfzG3v_UtBDI6uNJZWpdcWfrQFCxKGAYnQ1DRCh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLb3g2Jc2VjcDI1NmsxoQKeSDcZWSaY9FC723E9yYX1Li18bswhLNlxBZdLfgOKp4N0Y3CCE4mDdWRwgg-h", + // CryptoManufaktur + "enr:-Li4QH7FwJcL8gJj0zHAITXqghMkG-A5bfWh2-3Q7vosy9D1BS8HZk-1ITuhK_rfzG3v_UtBDI6uNJZWpdcWfrQFCxKGAYnQ1DRCh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLb3g2Jc2VjcDI1NmsxoQKeSDcZWSaY9FC723E9yYX1Li18bswhLNlxBZdLfgOKp4N0Y3CCE4mDdWRwgg-h", + }, }, } diff --git a/networkconfig/sepolia.go b/networkconfig/sepolia.go index d66426caeb..d17cfbbf71 100644 --- a/networkconfig/sepolia.go +++ b/networkconfig/sepolia.go @@ -9,15 +9,19 @@ import ( ) var Sepolia = NetworkConfig{ - Name: "sepolia", - Beacon: beacon.NewNetwork(spectypes.SepoliaNetwork), - DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x69}, - GenesisEpoch: 1, - RegistrySyncOffset: new(big.Int).SetInt64(7795814), - RegistryContractAddr: "0x261419B48F36EdF420743E9f91bABF4856e76f99", - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // SSV Labs - "enr:-Ja4QIE0Ml0a8Pq9zD-0g9KYGN3jAMPJ0CAP0i16fK-PSHfLeORl-Z5p8odoP1oS5S2E8IsF5jNG7gqTKhjVsHR-Z_CGAZXrnTJrgmlkgnY0gmlwhCOjXGWJc2VjcDI1NmsxoQKCRDQsIdFsJDmu_ZU2H6b2_HRJbuUneDXHLfFkSQH9O4Nzc3YBg3RjcIITioN1ZHCCD6I", + Name: "sepolia", + BeaconConfig: BeaconConfig{ + Beacon: beacon.NewNetwork(spectypes.SepoliaNetwork), + GenesisEpoch: 1, + }, + SSVConfig: SSVConfig{ + DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x69}, + RegistrySyncOffset: new(big.Int).SetInt64(7795814), + RegistryContractAddr: "0x261419B48F36EdF420743E9f91bABF4856e76f99", + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // SSV Labs + "enr:-Ja4QIE0Ml0a8Pq9zD-0g9KYGN3jAMPJ0CAP0i16fK-PSHfLeORl-Z5p8odoP1oS5S2E8IsF5jNG7gqTKhjVsHR-Z_CGAZXrnTJrgmlkgnY0gmlwhCOjXGWJc2VjcDI1NmsxoQKCRDQsIdFsJDmu_ZU2H6b2_HRJbuUneDXHLfFkSQH9O4Nzc3YBg3RjcIITioN1ZHCCD6I", + }, }, } diff --git a/networkconfig/ssv.go b/networkconfig/ssv.go new file mode 100644 index 0000000000..6ae33b78e9 --- /dev/null +++ b/networkconfig/ssv.go @@ -0,0 +1,15 @@ +package networkconfig + +import ( + "math/big" + + spectypes "github.com/ssvlabs/ssv-spec/types" +) + +type SSVConfig struct { + DomainType spectypes.DomainType + RegistrySyncOffset *big.Int + RegistryContractAddr string // TODO: ethcommon.Address + Bootnodes []string + DiscoveryProtocolID [6]byte +} diff --git a/networkconfig/test-network.go b/networkconfig/test-network.go index 09a9486773..998d8d8fb4 100644 --- a/networkconfig/test-network.go +++ b/networkconfig/test-network.go @@ -9,13 +9,17 @@ import ( ) var TestNetwork = NetworkConfig{ - Name: "testnet", - Beacon: beacon.NewNetwork(spectypes.BeaconTestNetwork), - DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoNetworkID.Byte(), 0x2}, - GenesisEpoch: 152834, - RegistrySyncOffset: new(big.Int).SetInt64(9015219), - RegistryContractAddr: "0x4B133c68A084B8A88f72eDCd7944B69c8D545f03", - Bootnodes: []string{ - "enr:-Li4QFIQzamdvTxGJhvcXG_DFmCeyggSffDnllY5DiU47pd_K_1MRnSaJimWtfKJ-MD46jUX9TwgW5Jqe0t4pH41RYWGAYuFnlyth2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhCLdu_SJc2VjcDI1NmsxoQN4v-N9zFYwEqzGPBBX37q24QPFvAVUtokIo1fblIsmTIN0Y3CCE4uDdWRwgg-j", + Name: "testnet", + BeaconConfig: BeaconConfig{ + Beacon: beacon.NewNetwork(spectypes.BeaconTestNetwork), + GenesisEpoch: 152834, + }, + SSVConfig: SSVConfig{ + DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoNetworkID.Byte(), 0x2}, + RegistrySyncOffset: new(big.Int).SetInt64(9015219), + RegistryContractAddr: "0x4B133c68A084B8A88f72eDCd7944B69c8D545f03", + Bootnodes: []string{ + "enr:-Li4QFIQzamdvTxGJhvcXG_DFmCeyggSffDnllY5DiU47pd_K_1MRnSaJimWtfKJ-MD46jUX9TwgW5Jqe0t4pH41RYWGAYuFnlyth2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhCLdu_SJc2VjcDI1NmsxoQN4v-N9zFYwEqzGPBBX37q24QPFvAVUtokIo1fblIsmTIN0Y3CCE4uDdWRwgg-j", + }, }, } diff --git a/operator/duties/scheduler_test.go b/operator/duties/scheduler_test.go index 531f24d620..0cd26b59e8 100644 --- a/operator/duties/scheduler_test.go +++ b/operator/duties/scheduler_test.go @@ -86,9 +86,8 @@ func setupSchedulerAndMocks(t *testing.T, handlers []dutyHandler, currentSlot *S mockValidatorController := NewMockValidatorController(ctrl) mockDutyExecutor := NewMockDutyExecutor(ctrl) mockSlotService := &mockSlotTickerService{} - mockNetworkConfig := networkconfig.NetworkConfig{ - Beacon: mocknetwork.NewMockBeaconNetwork(ctrl), - } + mockNetworkConfig := networkconfig.NetworkConfig{} + mockNetworkConfig.Beacon = mocknetwork.NewMockBeaconNetwork(ctrl) opts := &SchedulerOptions{ Ctx: ctx, From 4a7b18f4b3e4343bcd383cea62e678923f5a467f Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Fri, 11 Apr 2025 23:30:08 -0300 Subject: [PATCH 02/34] move most parameters outside of BeaconNetwork interface --- cli/operator/node.go | 6 +- doppelganger/doppelganger.go | 8 +- e2e/cmd/ssv-e2e/beacon_proxy.go | 2 +- eth/eventhandler/handlers.go | 4 +- message/validation/common_checks.go | 24 +- message/validation/consensus_validation.go | 4 +- message/validation/logger_fields.go | 4 +- message/validation/partial_validation.go | 2 +- message/validation/pubsub_validation.go | 2 +- message/validation/validation.go | 7 +- message/validation/validation_test.go | 308 +++++++++--------- network/discovery/util_test.go | 4 +- network/p2p/p2p.go | 4 +- network/p2p/p2p_test.go | 4 +- networkconfig/beacon.go | 103 +++++- networkconfig/config.go | 21 -- networkconfig/holesky-e2e.go | 10 +- networkconfig/holesky-stage.go | 10 +- networkconfig/holesky.go | 10 +- networkconfig/hoodi-stage.go | 10 +- networkconfig/hoodi.go | 10 +- networkconfig/local-testnet.go | 11 +- networkconfig/mainnet.go | 10 +- networkconfig/sepolia.go | 10 +- networkconfig/test-network.go | 10 +- operator/duties/attester.go | 30 +- operator/duties/attester_test.go | 2 +- operator/duties/committee.go | 12 +- operator/duties/committee_test.go | 34 +- operator/duties/proposer.go | 18 +- operator/duties/scheduler.go | 30 +- operator/duties/scheduler_test.go | 4 +- operator/duties/sync_committee.go | 48 +-- operator/duties/sync_committee_test.go | 20 +- operator/duties/validatorregistration.go | 10 +- operator/duties/voluntary_exit.go | 5 +- operator/duties/voluntary_exit_test.go | 3 +- operator/fee_recipient/controller.go | 2 +- operator/fee_recipient/controller_test.go | 12 +- operator/validator/controller.go | 3 +- protocol/v2/blockchain/beacon/network.go | 4 +- .../ssv/validator/non_committee_validator.go | 2 +- 42 files changed, 485 insertions(+), 352 deletions(-) diff --git a/cli/operator/node.go b/cli/operator/node.go index 7313889f5e..ec91f026db 100644 --- a/cli/operator/node.go +++ b/cli/operator/node.go @@ -196,8 +196,8 @@ var StartNodeCmd = &cobra.Command{ slotTickerProvider := func() slotticker.SlotTicker { return slotticker.New(logger, slotticker.Config{ - SlotDuration: networkConfig.SlotDurationSec(), - GenesisTime: networkConfig.GetGenesisTime(), + SlotDuration: networkConfig.SlotDuration, + GenesisTime: networkConfig.GenesisTime, }) } @@ -324,7 +324,7 @@ var StartNodeCmd = &cobra.Command{ if cfg.SSVOptions.ValidatorOptions.Exporter { retain := cfg.SSVOptions.ValidatorOptions.ExporterRetainSlots - threshold := cfg.SSVOptions.Network.Beacon.EstimatedCurrentSlot() + threshold := cfg.SSVOptions.Network.EstimatedCurrentSlot() initSlotPruning(cmd.Context(), logger, storageMap, slotTickerProvider, threshold, retain) } diff --git a/doppelganger/doppelganger.go b/doppelganger/doppelganger.go index 12e361c85e..e845ad19c4 100644 --- a/doppelganger/doppelganger.go +++ b/doppelganger/doppelganger.go @@ -176,7 +176,7 @@ func (h *handler) Start(ctx context.Context) error { var startEpoch, previousEpoch phase0.Epoch firstRun := true ticker := h.slotTickerProvider() - slotsPerEpoch := h.network.Beacon.SlotsPerEpoch() + slotsPerEpoch := h.network.SlotsPerEpoch for { select { @@ -184,7 +184,7 @@ func (h *handler) Start(ctx context.Context) error { return ctx.Err() case <-ticker.Next(): currentSlot := ticker.Slot() - currentEpoch := h.network.Beacon.EstimatedEpochAtSlot(currentSlot) + currentEpoch := h.network.EstimatedEpochAtSlot(currentSlot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, currentSlot, currentSlot%32+1) h.logger.Debug("🛠 ticker event", zap.String("epoch_slot_pos", buildStr)) @@ -196,7 +196,7 @@ func (h *handler) Start(ctx context.Context) error { // Perform liveness checks during the first run or at the last slot of the epoch. // This ensures that the beacon node has had enough time to observe blocks and attestations, // preventing delays in marking a validator as safe. - if (!firstRun && uint64(currentSlot)%slotsPerEpoch != slotsPerEpoch-1) || startEpoch == currentEpoch { + if (!firstRun && currentSlot%slotsPerEpoch != slotsPerEpoch-1) || startEpoch == currentEpoch { continue } @@ -233,7 +233,7 @@ func (h *handler) Start(ctx context.Context) error { func (h *handler) checkLiveness(ctx context.Context, slot phase0.Slot, epoch phase0.Epoch) { // Set a deadline until the start of the next slot, with a 100ms safety margin - ctx, cancel := context.WithDeadline(ctx, h.network.Beacon.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) + ctx, cancel := context.WithDeadline(ctx, h.network.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) defer cancel() h.mu.RLock() diff --git a/e2e/cmd/ssv-e2e/beacon_proxy.go b/e2e/cmd/ssv-e2e/beacon_proxy.go index 99cf2d072e..a60b40af1a 100644 --- a/e2e/cmd/ssv-e2e/beacon_proxy.go +++ b/e2e/cmd/ssv-e2e/beacon_proxy.go @@ -124,7 +124,7 @@ func (cmd *BeaconProxyCmd) Run(logger *zap.Logger, globals Globals) error { networkCfg := networkconfig.HoleskyE2E const startEpochDelay = 1 // TODO: change to 2 after debugging is done - startEpoch := networkCfg.Beacon.EstimatedCurrentEpoch() + startEpochDelay + startEpoch := networkCfg.EstimatedCurrentEpoch() + startEpochDelay interceptor := slashinginterceptor.New(logger, networkCfg.Beacon.GetNetwork(), startEpoch, true, maps.Values(validatorsData)) go interceptor.WatchSubmissions() diff --git a/eth/eventhandler/handlers.go b/eth/eventhandler/handlers.go index 8bbf514405..7f5c836d7f 100644 --- a/eth/eventhandler/handlers.go +++ b/eth/eventhandler/handlers.go @@ -249,7 +249,7 @@ func (eh *EventHandler) handleShareCreation( // Note: The current epoch can differ from the epoch set in slashing protection // due to the passage of time between saving slashing protection data and setting // the minimum participation epoch - share.SetMinParticipationEpoch(eh.networkConfig.Beacon.EstimatedCurrentEpoch() + contractParticipationDelay) + share.SetMinParticipationEpoch(eh.networkConfig.EstimatedCurrentEpoch() + contractParticipationDelay) } // Save share to DB. @@ -443,7 +443,7 @@ func (eh *EventHandler) handleClusterReactivated(txn basedb.Txn, event *contract // Note: The current epoch can differ from the epoch set in slashing protection // due to the passage of time between saving slashing protection data and setting // the minimum participation epoch - share.SetMinParticipationEpoch(eh.networkConfig.Beacon.EstimatedCurrentEpoch() + contractParticipationDelay) + share.SetMinParticipationEpoch(eh.networkConfig.EstimatedCurrentEpoch() + contractParticipationDelay) } if len(enabledPubKeys) > 0 { diff --git a/message/validation/common_checks.go b/message/validation/common_checks.go index 11e36ddb9f..1b8c5227e7 100644 --- a/message/validation/common_checks.go +++ b/message/validation/common_checks.go @@ -30,7 +30,7 @@ func (mv *messageValidator) validateSlotTime(messageSlot phase0.Slot, role spect // messageEarliness returns how early message is or 0 if it's not func (mv *messageValidator) messageEarliness(slot phase0.Slot, receivedAt time.Time) time.Duration { - return mv.netCfg.Beacon.GetSlotStartTime(slot).Sub(receivedAt) + return mv.netCfg.GetSlotStartTime(slot).Sub(receivedAt) } // messageLateness returns how late message is or 0 if it's not @@ -40,12 +40,12 @@ func (mv *messageValidator) messageLateness(slot phase0.Slot, role spectypes.Run case spectypes.RoleProposer, spectypes.RoleSyncCommitteeContribution: ttl = 1 + LateSlotAllowance case spectypes.RoleCommittee, spectypes.RoleAggregator: - ttl = phase0.Slot(mv.netCfg.Beacon.SlotsPerEpoch()) + LateSlotAllowance + ttl = mv.netCfg.SlotsPerEpoch + LateSlotAllowance case spectypes.RoleValidatorRegistration, spectypes.RoleVoluntaryExit: return 0 } - deadline := mv.netCfg.Beacon.GetSlotStartTime(slot + ttl). + deadline := mv.netCfg.GetSlotStartTime(slot + ttl). Add(lateMessageMargin) return receivedAt.Sub(deadline) @@ -57,7 +57,7 @@ func (mv *messageValidator) validateDutyCount( validatorIndices []phase0.ValidatorIndex, signerStateBySlot *OperatorState, ) error { - dutyCount := signerStateBySlot.DutyCount(mv.netCfg.Beacon.EstimatedEpochAtSlot(msgSlot)) + dutyCount := signerStateBySlot.DutyCount(mv.netCfg.EstimatedEpochAtSlot(msgSlot)) dutyLimit, exists := mv.dutyLimit(msgID, msgSlot, validatorIndices) if !exists { @@ -90,23 +90,23 @@ func (mv *messageValidator) dutyLimit(msgID spectypes.MessageID, slot phase0.Slo case spectypes.RoleCommittee: validatorIndexCount := uint64(len(validatorIndices)) - slotsPerEpoch := mv.netCfg.Beacon.SlotsPerEpoch() + slotsPerEpoch := mv.netCfg.SlotsPerEpoch // Skip duty search if validators * 2 exceeds slots per epoch, // as the maximum duties per epoch is capped at the number of slots. // This avoids unnecessary checks. - if validatorIndexCount < slotsPerEpoch/2 { + if validatorIndexCount < uint64(slotsPerEpoch)/2 { // Check if there is at least one validator in the sync committee. // If so, the duty limit is equal to the number of slots per epoch. - period := mv.netCfg.Beacon.EstimatedSyncCommitteePeriodAtEpoch(mv.netCfg.Beacon.EstimatedEpochAtSlot(slot)) + period := mv.netCfg.EstimatedSyncCommitteePeriodAtEpoch(mv.netCfg.EstimatedEpochAtSlot(slot)) for _, i := range validatorIndices { if mv.dutyStore.SyncCommittee.Duty(period, i) != nil { - return slotsPerEpoch, true + return uint64(slotsPerEpoch), true } } } - return min(slotsPerEpoch, 2*validatorIndexCount), true + return min(uint64(slotsPerEpoch), 2*validatorIndexCount), true default: return 0, false @@ -119,7 +119,7 @@ func (mv *messageValidator) validateBeaconDuty( indices []phase0.ValidatorIndex, randaoMsg bool, ) error { - epoch := mv.netCfg.Beacon.EstimatedEpochAtSlot(slot) + epoch := mv.netCfg.EstimatedEpochAtSlot(slot) // Rule: For a proposal duty message, we check if the validator is assigned to it if role == spectypes.RoleProposer { @@ -127,7 +127,7 @@ func (mv *messageValidator) validateBeaconDuty( // while duties are still being fetched from the Beacon node. // // Note: we allow current slot to be lower because of the ErrEarlyMessage rule. - if randaoMsg && mv.netCfg.Beacon.IsFirstSlotOfEpoch(slot) && mv.netCfg.Beacon.EstimatedCurrentSlot() <= slot { + if randaoMsg && mv.netCfg.IsFirstSlotOfEpoch(slot) && mv.netCfg.EstimatedCurrentSlot() <= slot { if !mv.dutyStore.Proposer.IsEpochSet(epoch) { return nil } @@ -142,7 +142,7 @@ func (mv *messageValidator) validateBeaconDuty( // Rule: For a sync committee aggregation duty message, we check if the validator is assigned to it if role == spectypes.RoleSyncCommitteeContribution { - period := mv.netCfg.Beacon.EstimatedSyncCommitteePeriodAtEpoch(epoch) + period := mv.netCfg.EstimatedSyncCommitteePeriodAtEpoch(epoch) // Non-committee roles always have one validator index. validatorIndex := indices[0] if mv.dutyStore.SyncCommittee.Duty(period, validatorIndex) == nil { diff --git a/message/validation/consensus_validation.go b/message/validation/consensus_validation.go index ae3176198b..a194c38e02 100644 --- a/message/validation/consensus_validation.go +++ b/message/validation/consensus_validation.go @@ -294,7 +294,7 @@ func (mv *messageValidator) validateQBFTMessageByDutyLogic( func (mv *messageValidator) updateConsensusState(signedSSVMessage *spectypes.SignedSSVMessage, consensusMessage *specqbft.Message, consensusState *consensusState) error { msgSlot := phase0.Slot(consensusMessage.Height) - msgEpoch := mv.netCfg.Beacon.EstimatedEpochAtSlot(msgSlot) + msgEpoch := mv.netCfg.EstimatedEpochAtSlot(msgSlot) for _, signer := range signedSSVMessage.OperatorIDs { stateBySlot := consensusState.GetOrCreate(signer) @@ -410,7 +410,7 @@ func (mv *messageValidator) roundBelongsToAllowedSpread( consensusMessage *specqbft.Message, receivedAt time.Time, ) error { - slotStartTime := mv.netCfg.Beacon.GetSlotStartTime(phase0.Slot(consensusMessage.Height)) /*. + slotStartTime := mv.netCfg.GetSlotStartTime(phase0.Slot(consensusMessage.Height)) /*. Add(mv.waitAfterSlotStart(role))*/ // TODO: not supported yet because first round is non-deterministic now sinceSlotStart := time.Duration(0) diff --git a/message/validation/logger_fields.go b/message/validation/logger_fields.go index 6060691303..e2a667dbd9 100644 --- a/message/validation/logger_fields.go +++ b/message/validation/logger_fields.go @@ -92,13 +92,13 @@ func (mv *messageValidator) addDutyIDField(lf *LoggerFields) { if lf.Role == spectypes.RoleCommittee { c, ok := mv.validatorStore.Committee(spectypes.CommitteeID(lf.DutyExecutorID[16:])) if ok { - lf.DutyID = fields.FormatCommitteeDutyID(c.Operators, mv.netCfg.Beacon.EstimatedEpochAtSlot(lf.Slot), lf.Slot) + lf.DutyID = fields.FormatCommitteeDutyID(c.Operators, mv.netCfg.EstimatedEpochAtSlot(lf.Slot), lf.Slot) } } else { // get the validator index from the msgid v, ok := mv.validatorStore.Validator(lf.DutyExecutorID) if ok { - lf.DutyID = fields.FormatDutyID(mv.netCfg.Beacon.EstimatedEpochAtSlot(lf.Slot), lf.Slot, lf.Role.String(), v.ValidatorIndex) + lf.DutyID = fields.FormatDutyID(mv.netCfg.EstimatedEpochAtSlot(lf.Slot), lf.Slot, lf.Role.String(), v.ValidatorIndex) } } } diff --git a/message/validation/partial_validation.go b/message/validation/partial_validation.go index 8e112d6447..e887f28ecb 100644 --- a/message/validation/partial_validation.go +++ b/message/validation/partial_validation.go @@ -231,7 +231,7 @@ func (mv *messageValidator) updatePartialSignatureState( ) error { stateBySlot := state.GetOrCreate(signer) messageSlot := partialSignatureMessages.Slot - messageEpoch := mv.netCfg.Beacon.EstimatedEpochAtSlot(messageSlot) + messageEpoch := mv.netCfg.EstimatedEpochAtSlot(messageSlot) signerState := stateBySlot.Get(messageSlot) if signerState == nil || signerState.Slot != messageSlot { diff --git a/message/validation/pubsub_validation.go b/message/validation/pubsub_validation.go index f97b7916b8..0e81040f8c 100644 --- a/message/validation/pubsub_validation.go +++ b/message/validation/pubsub_validation.go @@ -12,7 +12,7 @@ func (mv *messageValidator) validatePubSubMessage(pMsg *pubsub.Message) error { maxMsgSize := MaxEncodedMsgSizeBeforePectra - if mv.netCfg.Beacon.EstimatedCurrentEpoch() >= mv.pectraForkEpoch { + if mv.netCfg.EstimatedCurrentEpoch() >= mv.pectraForkEpoch { maxMsgSize = MaxEncodedMsgSize } diff --git a/message/validation/validation.go b/message/validation/validation.go index e5c5e4151a..c59c245f91 100644 --- a/message/validation/validation.go +++ b/message/validation/validation.go @@ -25,7 +25,6 @@ import ( "github.com/ssvlabs/ssv/operator/duties/dutystore" "github.com/ssvlabs/ssv/protocol/v2/ssv/queue" "github.com/ssvlabs/ssv/registry/storage" - "github.com/ssvlabs/ssv/utils/casts" ) // MessageValidator defines methods for validating pubsub messages. @@ -212,7 +211,7 @@ func (mv *messageValidator) getValidationLock(messageID spectypes.MessageID) *sy lock := &sync.Mutex{} - epochDuration := casts.DurationFromUint64(mv.netCfg.Beacon.SlotsPerEpoch()) * mv.netCfg.Beacon.SlotDurationSec() + epochDuration := time.Duration(mv.netCfg.SlotsPerEpoch) * mv.netCfg.SlotDuration // #nosec G115 - slots per epoch never exceeds math.MaxInt64 // validationLockTTL specifies how much time a particular validation lock is meant to // live. It must be large enough for validation lock to never expire while we still are // expecting to process messages targeting that same validation lock. For a message @@ -276,7 +275,7 @@ func (mv *messageValidator) getCommitteeAndValidatorIndices(msgID spectypes.Mess } // Rule: If validator is not active - if !share.IsAttesting(mv.netCfg.Beacon.EstimatedCurrentEpoch()) { + if !share.IsAttesting(mv.netCfg.EstimatedCurrentEpoch()) { e := ErrValidatorNotAttesting e.got = share.Status.String() return CommitteeInfo{}, e @@ -306,7 +305,7 @@ func (mv *messageValidator) consensusState(messageID spectypes.MessageID) *conse if _, ok := mv.consensusStateIndex[id]; !ok { cs := &consensusState{ state: make(map[spectypes.OperatorID]*OperatorState), - storedSlotCount: phase0.Slot(mv.netCfg.Beacon.SlotsPerEpoch()) * 2, // store last two epochs to calculate duty count + storedSlotCount: mv.netCfg.SlotsPerEpoch * 2, // store last two epochs to calculate duty count } mv.consensusStateIndex[id] = cs } diff --git a/message/validation/validation_test.go b/message/validation/validation_test.go index 0e56aa78a1..90a94e9264 100644 --- a/message/validation/validation_test.go +++ b/message/validation/validation_test.go @@ -127,10 +127,10 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("happy flow", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.NoError(t, err) @@ -140,7 +140,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("message counts", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) height := specqbft.Height(slot) msgID := committeeIdentifier @@ -152,7 +152,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := generateSignedMessage(ks, msgID, slot) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -195,7 +195,7 @@ func Test_ValidateSSVMessage(t *testing.T) { message.MsgType = specqbft.CommitMsgType }) signedSSVMessage.FullData = nil - _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt.Add(netCfg.Beacon.SlotDurationSec())) + _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt.Add(netCfg.SlotDuration)) require.NoError(t, err) storedState = stateBySlot.Get(phase0.Slot(height) + 1) @@ -203,11 +203,11 @@ func Test_ValidateSSVMessage(t *testing.T) { require.EqualValues(t, 1, storedState.Round) require.EqualValues(t, MessageCounts{Commit: 1}, storedState.MessageCounts) - _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt.Add(netCfg.Beacon.SlotDurationSec())) + _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt.Add(netCfg.SlotDuration)) require.ErrorContains(t, err, ErrDuplicatedMessage.Error()) signedSSVMessage = generateMultiSignedMessage(ks, msgID, slot+1) - _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt.Add(netCfg.Beacon.SlotDurationSec())) + _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt.Add(netCfg.SlotDuration)) require.NoError(t, err) require.NotNil(t, stateBySlot) require.EqualValues(t, 1, storedState.Round) @@ -218,11 +218,11 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("pubsub message has no data", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) pmsg := &pubsub.Message{} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) _, err := validator.handlePubsubMessage(pmsg, receivedAt) require.ErrorIs(t, err, ErrPubSubMessageHasNoData) @@ -232,7 +232,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("pubsub data too big", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) topic := commons.GetTopicFullName(commons.CommitteeTopicID(committeeID)[0]) msgSize := maxSignedMsgSizeBeforePectra*2 + MessageOffset @@ -245,7 +245,7 @@ func Test_ValidateSSVMessage(t *testing.T) { }, } - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) _, err = validator.handlePubsubMessage(pmsg, receivedAt) e := ErrPubSubDataTooBig @@ -257,7 +257,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("empty pubsub message", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) topic := commons.GetTopicFullName(commons.CommitteeTopicID(committeeID)[0]) pmsg := &pubsub.Message{ @@ -268,7 +268,7 @@ func Test_ValidateSSVMessage(t *testing.T) { }, } - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) _, err = validator.handlePubsubMessage(pmsg, receivedAt) require.ErrorContains(t, err, ErrMalformedPubSubMessage.Error()) @@ -278,12 +278,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("bad data format", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.SSVMessage.Data = bytes.Repeat([]byte{1}, 500) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -294,12 +294,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("no data", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.SSVMessage.Data = []byte{} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorIs(t, err, ErrEmptyData) @@ -313,14 +313,14 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("data too big", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) tooBigMsgSize := maxPayloadDataSize * 2 signedSSVMessage.SSVMessage.Data = bytes.Repeat([]byte{1}, tooBigMsgSize) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -334,12 +334,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("data size borderline / malformed message", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.SSVMessage.Data = bytes.Repeat([]byte{1}, maxPayloadDataSize) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -350,7 +350,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("invalid SSV message type", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.SSVMessage.MsgType = math.MaxUint64 @@ -364,7 +364,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("unknown validator", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) sk, err := eth2types.GenerateBLSPrivateKey() require.NoError(t, err) @@ -386,7 +386,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("unknown committee ID", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) unknownCommitteeID := bytes.Repeat([]byte{1}, 48) unknownIdentifier := spectypes.NewMsgID(netCfg.DomainType, unknownCommitteeID, committeeRole) @@ -403,14 +403,14 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("wrong domain", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) wrongDomain := spectypes.DomainType{math.MaxUint8, math.MaxUint8, math.MaxUint8, math.MaxUint8} badIdentifier := spectypes.NewMsgID(wrongDomain, encodedCommitteeID, committeeRole) signedSSVMessage := generateSignedMessage(ks, badIdentifier, slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) expectedErr := ErrWrongDomain expectedErr.got = hex.EncodeToString(wrongDomain[:]) @@ -423,13 +423,13 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("invalid role", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) badIdentifier := spectypes.NewMsgID(netCfg.DomainType, encodedCommitteeID, math.MaxInt32) signedSSVMessage := generateSignedMessage(ks, badIdentifier, slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorIs(t, err, ErrInvalidRole) }) @@ -438,13 +438,13 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("unexpected consensus message", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) badIdentifier := spectypes.NewMsgID(netCfg.DomainType, shares.active.ValidatorPubKey[:], spectypes.RoleValidatorRegistration) signedSSVMessage := generateSignedMessage(ks, badIdentifier, slot) topicID := commons.CommitteeTopicID(committeeID)[0] - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) expectedErr := ErrUnexpectedConsensusMessage expectedErr.got = spectypes.RoleValidatorRegistration @@ -462,13 +462,13 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("liquidated validator", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) liquidatedIdentifier := spectypes.NewMsgID(netCfg.DomainType, shares.liquidated.ValidatorPubKey[:], nonCommitteeRole) signedSSVMessage := generateSignedMessage(ks, liquidatedIdentifier, slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) expectedErr := ErrValidatorLiquidated require.ErrorIs(t, err, expectedErr) @@ -478,13 +478,13 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("unknown state validator", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) inactiveIdentifier := spectypes.NewMsgID(netCfg.DomainType, shares.inactive.ValidatorPubKey[:], nonCommitteeRole) signedSSVMessage := generateSignedMessage(ks, inactiveIdentifier, slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) expectedErr := ErrNoShareMetadata require.ErrorIs(t, err, expectedErr) @@ -494,12 +494,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("pending queued state validator", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) nonUpdatedMetadataNextEpochIdentifier := spectypes.NewMsgID(netCfg.DomainType, shares.nonUpdatedMetadataNextEpoch.ValidatorPubKey[:], nonCommitteeRole) signedSSVMessage := generateSignedMessage(ks, nonUpdatedMetadataNextEpochIdentifier, slot) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) expectedErr := ErrValidatorNotAttesting @@ -512,7 +512,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("active validator with pending queued state", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.EstimatedCurrentSlot() + slot := netCfg.EstimatedCurrentSlot() nonUpdatedMetadataIdentifier := spectypes.NewMsgID(netCfg.DomainType, shares.nonUpdatedMetadata.ValidatorPubKey[:], nonCommitteeRole) qbftMessage := &specqbft.Message{ @@ -530,7 +530,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := spectestingutils.SignQBFTMsg(ks.OperatorKeys[leader], leader, qbftMessage) signedSSVMessage.FullData = spectestingutils.TestingQBFTFullData - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(committeeID)[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.NoError(t, err) @@ -540,12 +540,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("no share metadata", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) noMetadataIdentifier := spectypes.NewMsgID(netCfg.DomainType, shares.noMetadata.ValidatorPubKey[:], nonCommitteeRole) signedSSVMessage := generateSignedMessage(ks, noMetadataIdentifier, slot) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorIs(t, err, ErrNoShareMetadata) @@ -556,7 +556,7 @@ func Test_ValidateSSVMessage(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) epoch := phase0.Epoch(1) - slot := netCfg.Beacon.FirstSlotAtEpoch(epoch) + slot := netCfg.FirstSlotAtEpoch(epoch) dutyStore.Proposer.Set(epoch, []dutystore.StoreDuty[eth2apiv1.ProposerDuty]{ {Slot: slot, ValidatorIndex: shares.active.ValidatorIndex, Duty: ð2apiv1.ProposerDuty{}, InCommittee: true}, @@ -570,39 +570,39 @@ func Test_ValidateSSVMessage(t *testing.T) { // First duty. topicID := commons.CommitteeTopicID(committeeID)[0] - _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.Beacon.GetSlotStartTime(slot)) + _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.GetSlotStartTime(slot)) require.NoError(t, err) // Second duty. signedSSVMessage = generateSignedMessage(ks, identifier, slot+4) - _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.Beacon.GetSlotStartTime(slot+4)) + _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.GetSlotStartTime(slot+4)) require.NoError(t, err) // Second duty (another message). signedSSVMessage = generateSignedMessage(ks, identifier, slot+4, func(qbftMessage *specqbft.Message) { qbftMessage.MsgType = specqbft.RoundChangeMsgType }) - _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.Beacon.GetSlotStartTime(slot+4)) + _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.GetSlotStartTime(slot+4)) require.NoError(t, err) // Third duty. // TODO: this should fail, see https://github.com/ssvlabs/ssv/pull/1758 signedSSVMessage = generateSignedMessage(ks, identifier, slot+8) - _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.Beacon.GetSlotStartTime(slot+8)) + _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.GetSlotStartTime(slot+8)) require.NoError(t, err) // Third duty (another message). signedSSVMessage = generateSignedMessage(ks, identifier, slot+8, func(qbftMessage *specqbft.Message) { qbftMessage.MsgType = specqbft.RoundChangeMsgType }) - _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.Beacon.GetSlotStartTime(slot+8)) + _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.GetSlotStartTime(slot+8)) require.ErrorContains(t, err, ErrTooManyDutiesPerEpoch.Error()) }) // Throw error if getting a message for proposal and see there is no message from beacon t.Run("no proposal duties", func(t *testing.T) { const epoch = 1 - slot := netCfg.Beacon.FirstSlotAtEpoch(epoch) + slot := netCfg.FirstSlotAtEpoch(epoch) ds := dutystore.New() ds.Proposer.Set(epoch, []dutystore.StoreDuty[eth2apiv1.ProposerDuty]{ @@ -614,7 +614,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := generateSignedMessage(ks, identifier, slot) topicID := commons.CommitteeTopicID(committeeID)[0] - _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.Beacon.GetSlotStartTime(slot)) + _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.GetSlotStartTime(slot)) require.ErrorContains(t, err, ErrNoDuty.Error()) ds = dutystore.New() @@ -622,7 +622,7 @@ func Test_ValidateSSVMessage(t *testing.T) { {Slot: slot, ValidatorIndex: shares.active.ValidatorIndex, Duty: ð2apiv1.ProposerDuty{}, InCommittee: true}, }) validator = New(netCfg, validatorStore, ds, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.Beacon.GetSlotStartTime(slot)) + _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, netCfg.GetSlotStartTime(slot)) require.NoError(t, err) }) @@ -632,7 +632,7 @@ func Test_ValidateSSVMessage(t *testing.T) { mockNetworkConfig.Beacon = utils.SetupMockBeaconNetwork(t, currentSlot) const epoch = 1 - currentSlot.SetSlot(netCfg.Beacon.FirstSlotAtEpoch(epoch)) + currentSlot.SetSlot(netCfg.FirstSlotAtEpoch(epoch)) ds := dutystore.New() @@ -651,7 +651,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := spectestingutils.SignedSSVMessageWithSigner(1, ks.OperatorKeys[1], ssvMessage) - receivedAt := mockNetworkConfig.Beacon.GetSlotStartTime(currentSlot.GetSlot()) + receivedAt := mockNetworkConfig.GetSlotStartTime(currentSlot.GetSlot()) topicID := commons.CommitteeTopicID(committeeID)[0] require.False(t, ds.Proposer.IsEpochSet(epoch)) @@ -666,7 +666,7 @@ func Test_ValidateSSVMessage(t *testing.T) { mockNetworkConfig.Beacon = utils.SetupMockBeaconNetwork(t, currentSlot) const epoch = 1 - currentSlot.SetSlot(mockNetworkConfig.Beacon.FirstSlotAtEpoch(epoch)) + currentSlot.SetSlot(mockNetworkConfig.FirstSlotAtEpoch(epoch)) ds := dutystore.New() ds.Proposer.Set(epoch, make([]dutystore.StoreDuty[eth2apiv1.ProposerDuty], 0)) @@ -686,7 +686,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := spectestingutils.SignedSSVMessageWithSigner(1, ks.OperatorKeys[1], ssvMessage) - receivedAt := mockNetworkConfig.Beacon.GetSlotStartTime(currentSlot.GetSlot()) + receivedAt := mockNetworkConfig.GetSlotStartTime(currentSlot.GetSlot()) topicID := commons.CommitteeTopicID(committeeID)[0] require.True(t, ds.Proposer.IsEpochSet(epoch)) @@ -697,7 +697,7 @@ func Test_ValidateSSVMessage(t *testing.T) { //// Get error when receiving a message with over 13 partial signatures t.Run("partial message too big", func(t *testing.T) { - // slot := netCfg.Beacon.FirstSlotAtEpoch(1) + // slot := netCfg.FirstSlotAtEpoch(1) msg := spectestingutils.PostConsensusAttestationMsg(ks.Shares[1], 1, spec.DataVersionPhase0) for i := 0; i < 1512; i++ { msg.Messages = append(msg.Messages, msg.Messages[0]) @@ -711,7 +711,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("signer ID not in committee", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.EstimatedCurrentSlot() + slot := netCfg.EstimatedCurrentSlot() qbftMessage := &specqbft.Message{ MsgType: specqbft.ProposalMsgType, @@ -727,7 +727,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := spectestingutils.SignQBFTMsg(ks.OperatorKeys[1], 5, qbftMessage) signedSSVMessage.FullData = spectestingutils.TestingQBFTFullData - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrSignerNotInCommittee.Error()) @@ -737,12 +737,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("partial zero signer ID", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) msg := spectestingutils.SignPartialSigSSVMessage(ks, spectestingutils.SSVMsgAggregator(nil, spectestingutils.PostConsensusAggregatorMsg(ks.Shares[1], 1, spec.DataVersionPhase0))) msg.OperatorIDs = []spectypes.OperatorID{0} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(msg.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(msg, topicID, receivedAt) require.ErrorIs(t, err, ErrZeroSigner) @@ -752,14 +752,14 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("partial inconsistent signer ID", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) ssvMessage := spectestingutils.SSVMsgAggregator(nil, spectestingutils.PostConsensusAggregatorMsg(ks.Shares[1], 1, spec.DataVersionPhase0)) ssvMessage.MsgID = committeeIdentifier partialSigSSVMessage := spectestingutils.SignPartialSigSSVMessage(ks, ssvMessage) partialSigSSVMessage.OperatorIDs = []spectypes.OperatorID{2} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(committeeID)[0] _, err = validator.handleSignedSSVMessage(partialSigSSVMessage, topicID, receivedAt) expectedErr := ErrInconsistentSigners @@ -772,7 +772,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("no partial signature messages", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) messages := spectestingutils.PostConsensusAggregatorMsg(ks.Shares[1], 1, spec.DataVersionPhase0) messages.Messages = nil @@ -780,7 +780,7 @@ func Test_ValidateSSVMessage(t *testing.T) { ssvMessage.MsgID = committeeIdentifier signedSSVMessage := spectestingutils.SignedSSVMessageWithSigner(1, ks.OperatorKeys[1], ssvMessage) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(committeeID)[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorIs(t, err, ErrNoPartialSignatureMessages) @@ -790,12 +790,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("partial wrong RSA signature size", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) partialSigSSVMessage := spectestingutils.SignPartialSigSSVMessage(ks, spectestingutils.SSVMsgAggregator(nil, spectestingutils.PostConsensusAggregatorMsg(ks.Shares[1], 1, spec.DataVersionPhase0))) partialSigSSVMessage.Signatures = [][]byte{{1}} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(partialSigSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(partialSigSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrWrongRSASignatureSize.Error()) @@ -848,7 +848,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := spectestingutils.SignedSSVMessageWithSigner(1, ks.OperatorKeys[1], ssvMessage) - receivedAt := netCfg.Beacon.GetSlotStartTime(spectestingutils.TestingDutySlot) + receivedAt := netCfg.GetSlotStartTime(spectestingutils.TestingDutySlot) topicID := commons.CommitteeTopicID(committeeID)[0] @@ -877,7 +877,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := spectestingutils.SignedSSVMessageWithSigner(1, ks.OperatorKeys[1], ssvMessage) - receivedAt := netCfg.Beacon.GetSlotStartTime(spectestingutils.TestingDutySlot) + receivedAt := netCfg.GetSlotStartTime(spectestingutils.TestingDutySlot) topicID := commons.CommitteeTopicID(committeeID)[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrInvalidPartialSignatureType.Error()) @@ -927,7 +927,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := spectestingutils.SignedSSVMessageWithSigner(1, ks.OperatorKeys[1], ssvMessage) - receivedAt := netCfg.Beacon.GetSlotStartTime(spectestingutils.TestingDutySlot) + receivedAt := netCfg.GetSlotStartTime(spectestingutils.TestingDutySlot) topicID := commons.CommitteeTopicID(committeeID)[0] t.Log(signedSSVMessage.SSVMessage.MsgID.GetDomain()) _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -942,12 +942,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("invalid QBFT message type", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.MsgType = math.MaxUint64 }) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) expectedErr := ErrUnknownQBFTMessageType @@ -958,11 +958,11 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("wrong signature size", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.Signatures = [][]byte{{0x1}} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrWrongRSASignatureSize.Error()) @@ -972,11 +972,11 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("no signers", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.OperatorIDs = nil - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorIs(t, err, ErrNoSigners) @@ -987,7 +987,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("more signers than committee size", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.OperatorIDs = []spectypes.OperatorID{1, 2, 3, 4, 5} signedSSVMessage.Signatures = [][]byte{ @@ -998,7 +998,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage.Signatures[0], } - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrSignerNotInCommittee.Error()) @@ -1008,11 +1008,11 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("consensus zero signer", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.OperatorIDs = []spectypes.OperatorID{0} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorIs(t, err, ErrZeroSigner) @@ -1022,11 +1022,11 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("non unique signer", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateMultiSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.OperatorIDs = []spectypes.OperatorID{1, 2, 2} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorIs(t, err, ErrDuplicatedSigner) @@ -1036,11 +1036,11 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("signers not sorted", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateMultiSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.OperatorIDs = []spectypes.OperatorID{3, 2, 1} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorIs(t, err, ErrSignersNotSorted) @@ -1050,11 +1050,11 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("wrong signers/signatures length", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateMultiSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.OperatorIDs = []spectypes.OperatorID{1, 2, 3, 4} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1065,12 +1065,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("decided too few signers", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateMultiSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.OperatorIDs = []spectypes.OperatorID{1, 2} signedSSVMessage.Signatures = signedSSVMessage.Signatures[:2] - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1081,12 +1081,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("non decided with multiple signers", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateMultiSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.MsgType = specqbft.ProposalMsgType }) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1098,7 +1098,7 @@ func Test_ValidateSSVMessage(t *testing.T) { // Send late message for all roles and receive late message error t.Run("late message", func(t *testing.T) { const epoch = 1 - slot := netCfg.Beacon.FirstSlotAtEpoch(epoch) + slot := netCfg.FirstSlotAtEpoch(epoch) ds := dutystore.New() ds.Proposer.Set(epoch, []dutystore.StoreDuty[eth2apiv1.ProposerDuty]{ @@ -1111,10 +1111,10 @@ func Test_ValidateSSVMessage(t *testing.T) { validator := New(netCfg, validatorStore, ds, signatureVerifier, phase0.Epoch(0)).(*messageValidator) tests := map[spectypes.RunnerRole]time.Time{ - spectypes.RoleCommittee: netCfg.Beacon.GetSlotStartTime(slot + 35), - spectypes.RoleAggregator: netCfg.Beacon.GetSlotStartTime(slot + 35), - spectypes.RoleProposer: netCfg.Beacon.GetSlotStartTime(slot + 4), - spectypes.RoleSyncCommitteeContribution: netCfg.Beacon.GetSlotStartTime(slot + 4), + spectypes.RoleCommittee: netCfg.GetSlotStartTime(slot + 35), + spectypes.RoleAggregator: netCfg.GetSlotStartTime(slot + 35), + spectypes.RoleProposer: netCfg.GetSlotStartTime(slot + 4), + spectypes.RoleSyncCommitteeContribution: netCfg.GetSlotStartTime(slot + 4), } for role, receivedAt := range tests { @@ -1139,10 +1139,10 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("early message", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot - 1) + receivedAt := netCfg.GetSlotStartTime(slot - 1) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1153,11 +1153,11 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("not a leader", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.OperatorIDs = []spectypes.OperatorID{2} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrSignerNotLeader.Error()) @@ -1167,13 +1167,13 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("malformed prepare justification", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.PrepareJustification = [][]byte{{1}} }) signedSSVMessage.OperatorIDs = []spectypes.OperatorID{2} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1184,7 +1184,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("non-proposal with prepare justification", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.PrepareJustification = spectestingutils.MarshalJustifications([]*spectypes.SignedSSVMessage{ @@ -1196,7 +1196,7 @@ func Test_ValidateSSVMessage(t *testing.T) { }) signedSSVMessage.FullData = nil - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1207,7 +1207,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("non-proposal with round change justification", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.RoundChangeJustification = spectestingutils.MarshalJustifications([]*spectypes.SignedSSVMessage{ @@ -1219,7 +1219,7 @@ func Test_ValidateSSVMessage(t *testing.T) { }) signedSSVMessage.FullData = nil - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1230,14 +1230,14 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("malformed round change justification", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.RoundChangeJustification = [][]byte{{1}} }) signedSSVMessage.FullData = nil - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1248,12 +1248,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("wrong root hash", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.FullData = []byte{1} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1265,11 +1265,11 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("double proposal with different data", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.NoError(t, err) @@ -1290,7 +1290,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("double prepare", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) identifier := spectypes.NewMsgID(netCfg.DomainType, ks.ValidatorPK.Serialize(), spectypes.RoleProposer) signedSSVMessage := generateSignedMessage(ks, identifier, slot, func(message *specqbft.Message) { @@ -1298,7 +1298,7 @@ func Test_ValidateSSVMessage(t *testing.T) { }) signedSSVMessage.FullData = nil - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(committeeID)[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.NoError(t, err) @@ -1313,14 +1313,14 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("double commit", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.MsgType = specqbft.CommitMsgType }) signedSSVMessage.FullData = nil - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.NoError(t, err) @@ -1335,14 +1335,14 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("double round change", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.MsgType = specqbft.RoundChangeMsgType }) signedSSVMessage.FullData = nil - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.NoError(t, err) @@ -1357,14 +1357,14 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("decided with same signers", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateMultiSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.MsgType = specqbft.CommitMsgType }) signedSSVMessage.FullData = nil - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1378,13 +1378,13 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("slot already advanced", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, nonCommitteeIdentifier, slot, func(message *specqbft.Message) { message.Height = 8 }) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(committeeID)[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.NoError(t, err) @@ -1401,13 +1401,13 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("round already advanced", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.Round = 5 }) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot).Add(5 * roundtimer.QuickTimeout) + receivedAt := netCfg.GetSlotStartTime(slot).Add(5 * roundtimer.QuickTimeout) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.NoError(t, err) @@ -1423,7 +1423,7 @@ func Test_ValidateSSVMessage(t *testing.T) { // Receive message from a round that is too high for that epoch should receive an error t.Run("round too high", func(t *testing.T) { const epoch = 1 - slot := netCfg.Beacon.FirstSlotAtEpoch(epoch) + slot := netCfg.FirstSlotAtEpoch(epoch) ds := dutystore.New() ds.Proposer.Set(epoch, []dutystore.StoreDuty[eth2apiv1.ProposerDuty]{ @@ -1469,7 +1469,7 @@ func Test_ValidateSSVMessage(t *testing.T) { sinceSlotStart += roundtimer.QuickTimeout } - receivedAt := netCfg.Beacon.GetSlotStartTime(slot).Add(sinceSlotStart) + receivedAt := netCfg.GetSlotStartTime(slot).Add(sinceSlotStart) _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrRoundTooHigh.Error()) }) @@ -1480,12 +1480,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("event message", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.SSVMessage.MsgType = message.SSVEventMsgType - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1496,13 +1496,13 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("unknown type message", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) unknownType := spectypes.MsgType(12345) signedSSVMessage.SSVMessage.MsgType = unknownType - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1513,11 +1513,11 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("wrong signature", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, wrongSignatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1528,11 +1528,11 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("incorrect topic", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := "incorrect" _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) @@ -1543,9 +1543,9 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("nil signed ssv message", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) _, err = validator.handleSignedSSVMessage(nil, "", receivedAt) require.ErrorContains(t, err, ErrNilSignedSSVMessage.Error()) @@ -1555,12 +1555,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("nil ssv message", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.SSVMessage = nil - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) _, err = validator.handleSignedSSVMessage(signedSSVMessage, "", receivedAt) require.ErrorContains(t, err, ErrNilSSVMessage.Error()) @@ -1570,13 +1570,13 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("zero round", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.Round = specqbft.NoRound }) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrZeroRound.Error()) @@ -1586,12 +1586,12 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("no signatures", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot) signedSSVMessage.Signatures = [][]byte{} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrNoSignatures.Error()) @@ -1601,7 +1601,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("mismatched identifier", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { wrongID := spectypes.NewMsgID(netCfg.DomainType, encodedCommitteeID[:], nonCommitteeRole) @@ -1609,7 +1609,7 @@ func Test_ValidateSSVMessage(t *testing.T) { }) signedSSVMessage.SSVMessage.MsgID = committeeIdentifier - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrMismatchedIdentifier.Error()) @@ -1619,13 +1619,13 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("prepare/commit with FullData", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) signedSSVMessage := generateSignedMessage(ks, committeeIdentifier, slot, func(message *specqbft.Message) { message.MsgType = specqbft.PrepareMsgType }) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrPrepareOrCommitWithFullData.Error()) @@ -1641,14 +1641,14 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("non-consensus with FullData", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) ssvMessage := spectestingutils.SSVMsgAggregator(nil, spectestingutils.PostConsensusAggregatorMsg(ks.Shares[1], 1, spec.DataVersionPhase0)) ssvMessage.MsgID = committeeIdentifier signedSSVMessage := spectestingutils.SignPartialSigSSVMessage(ks, ssvMessage) signedSSVMessage.FullData = []byte{1} - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(committeeID)[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorIs(t, err, ErrFullDataNotInConsensusMessage) @@ -1658,7 +1658,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("partial signature with multiple signers", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) ssvMessage := spectestingutils.SSVMsgAggregator(nil, spectestingutils.PostConsensusAggregatorMsg(ks.Shares[1], 1, spec.DataVersionPhase0)) ssvMessage.MsgID = committeeIdentifier @@ -1666,7 +1666,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage.OperatorIDs = []spectypes.OperatorID{1, 2} signedSSVMessage.Signatures = append(signedSSVMessage.Signatures, signedSSVMessage.Signatures[0]) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(committeeID)[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorIs(t, err, ErrPartialSigOneSigner) @@ -1676,7 +1676,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("partial signature with too many messages", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) messages := spectestingutils.PostConsensusAggregatorMsg(ks.Shares[1], 1, spec.DataVersionPhase0) for i := 0; i < 12; i++ { @@ -1694,7 +1694,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := spectestingutils.SignPartialSigSSVMessage(ks, ssvMessage) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrTooManyPartialSignatureMessages.Error()) @@ -1704,7 +1704,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("partial signature with triple validator index", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) messages := spectestingutils.PostConsensusAggregatorMsg(ks.Shares[1], 1, spec.DataVersionPhase0) for i := 0; i < 3; i++ { @@ -1722,7 +1722,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := spectestingutils.SignPartialSigSSVMessage(ks, ssvMessage) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(spectypes.CommitteeID(signedSSVMessage.SSVMessage.GetID().GetDutyExecutorID()[16:]))[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrTripleValidatorIndexInPartialSignatures.Error()) @@ -1732,7 +1732,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("partial signature with validator index mismatch", func(t *testing.T) { validator := New(netCfg, validatorStore, dutyStore, signatureVerifier, phase0.Epoch(0)).(*messageValidator) - slot := netCfg.Beacon.FirstSlotAtEpoch(1) + slot := netCfg.FirstSlotAtEpoch(1) messages := spectestingutils.PostConsensusAggregatorMsg(ks.Shares[1], 1, spec.DataVersionPhase0) messages.Messages[0].ValidatorIndex = math.MaxUint64 @@ -1748,7 +1748,7 @@ func Test_ValidateSSVMessage(t *testing.T) { signedSSVMessage := spectestingutils.SignPartialSigSSVMessage(ks, ssvMessage) - receivedAt := netCfg.Beacon.GetSlotStartTime(slot) + receivedAt := netCfg.GetSlotStartTime(slot) topicID := commons.CommitteeTopicID(committeeID)[0] _, err = validator.handleSignedSSVMessage(signedSSVMessage, topicID, receivedAt) require.ErrorContains(t, err, ErrValidatorIndexMismatch.Error()) @@ -1810,8 +1810,8 @@ func generateShares(t *testing.T, ks *spectestingutils.TestKeySet, ns storage.St copy(inactiveShare.ValidatorPubKey[:], inactiveSK.PublicKey().Marshal()) require.NoError(t, ns.Shares().Save(nil, inactiveShare)) - slot := netCfg.Beacon.EstimatedCurrentSlot() - activationEpoch := netCfg.Beacon.EstimatedEpochAtSlot(slot) + slot := netCfg.EstimatedCurrentSlot() + activationEpoch := netCfg.EstimatedEpochAtSlot(slot) exitEpoch := goclient.FarFutureEpoch nonUpdatedMetadataShare := &ssvtypes.SSVShare{ diff --git a/network/discovery/util_test.go b/network/discovery/util_test.go index 473ab72638..f19b4cd163 100644 --- a/network/discovery/util_test.go +++ b/network/discovery/util_test.go @@ -111,13 +111,13 @@ func testingNetConfigWithForkEpoch(forkEpoch phase0.Epoch) networkconfig.Network // NetworkConfig for staying in pre-fork func PreForkNetworkConfig() networkconfig.NetworkConfig { - forkEpoch := networkconfig.HoleskyStage.Beacon.EstimatedCurrentEpoch() + 1000 + forkEpoch := networkconfig.HoleskyStage.EstimatedCurrentEpoch() + 1000 return testingNetConfigWithForkEpoch(forkEpoch) } // NetworkConfig for staying in post-fork func PostForkNetworkConfig() networkconfig.NetworkConfig { - forkEpoch := networkconfig.HoleskyStage.Beacon.EstimatedCurrentEpoch() - 1000 + forkEpoch := networkconfig.HoleskyStage.EstimatedCurrentEpoch() - 1000 return testingNetConfigWithForkEpoch(forkEpoch) } diff --git a/network/p2p/p2p.go b/network/p2p/p2p.go index 04313e6682..7b1b43f9c3 100644 --- a/network/p2p/p2p.go +++ b/network/p2p/p2p.go @@ -589,9 +589,9 @@ func (n *p2pNetwork) UpdateScoreParams(logger *zap.Logger) { // function to get the starting time of the next epoch nextEpochStartingTime := func() time.Time { - currEpoch := n.cfg.Network.Beacon.EstimatedCurrentEpoch() + currEpoch := n.cfg.Network.EstimatedCurrentEpoch() nextEpoch := currEpoch + 1 - return n.cfg.Network.Beacon.EpochStartTime(nextEpoch) + return n.cfg.Network.EpochStartTime(nextEpoch) } // Create timer that triggers on the beginning of the next epoch diff --git a/network/p2p/p2p_test.go b/network/p2p/p2p_test.go index a037fbea43..11885419af 100644 --- a/network/p2p/p2p_test.go +++ b/network/p2p/p2p_test.go @@ -141,7 +141,7 @@ func generateValidatorMsg(ks *spectestingutils.TestKeySet, round specqbft.Round, panic("committee role shouldn't be used here") } netCfg := networkconfig.TestNetwork - height := specqbft.Height(netCfg.Beacon.EstimatedCurrentSlot()) + height := specqbft.Height(netCfg.EstimatedCurrentSlot()) fullData := spectestingutils.TestingQBFTFullData @@ -167,7 +167,7 @@ func generateValidatorMsg(ks *spectestingutils.TestKeySet, round specqbft.Round, func generateCommitteeMsg(ks *spectestingutils.TestKeySet, round specqbft.Round) *spectypes.SignedSSVMessage { netCfg := networkconfig.TestNetwork - height := specqbft.Height(netCfg.Beacon.EstimatedCurrentSlot()) + height := specqbft.Height(netCfg.EstimatedCurrentSlot()) share := &ssvtypes.SSVShare{ Share: *spectestingutils.TestingShare(ks, spectestingutils.TestingValidatorIndex), diff --git a/networkconfig/beacon.go b/networkconfig/beacon.go index 6b619a6bb5..3edac5f76d 100644 --- a/networkconfig/beacon.go +++ b/networkconfig/beacon.go @@ -1,12 +1,111 @@ package networkconfig import ( + "math" + "time" + "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) type BeaconConfig struct { - Beacon beacon.BeaconNetwork - GenesisEpoch phase0.Epoch + Beacon beacon.BeaconNetwork + GenesisEpoch phase0.Epoch + SlotDuration time.Duration + SlotsPerEpoch phase0.Slot + ForkVersion phase0.Version + GenesisTime time.Time +} + +// GetSlotStartTime returns the start time for the given slot +func (b BeaconConfig) GetSlotStartTime(slot phase0.Slot) time.Time { + if slot > math.MaxInt64 { + panic("slot out of range") + } + durationSinceGenesisStart := time.Duration(slot) * b.SlotDuration // #nosec G115: slot cannot exceed math.MaxInt64 + start := b.GenesisTime.Add(durationSinceGenesisStart) + return start +} + +// GetSlotEndTime returns the end time for the given slot +func (b BeaconConfig) GetSlotEndTime(slot phase0.Slot) time.Time { + return b.GetSlotStartTime(slot + 1) +} + +// EstimatedCurrentSlot returns the estimation of the current slot +func (b BeaconConfig) EstimatedCurrentSlot() phase0.Slot { + return b.EstimatedSlotAtTime(time.Now()) +} + +// EstimatedSlotAtTime estimates slot at the given time +func (b BeaconConfig) EstimatedSlotAtTime(time time.Time) phase0.Slot { + genesis := b.GenesisTime + if time.Before(genesis) { + return 0 + } + timeAfterGenesis := time.Sub(genesis) + return phase0.Slot(timeAfterGenesis / b.SlotDuration) // #nosec G115: genesis can't be negative +} + +// EstimatedCurrentEpoch estimates the current epoch +// https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#compute_start_slot_at_epoch +func (b BeaconConfig) EstimatedCurrentEpoch() phase0.Epoch { + return b.EstimatedEpochAtSlot(b.EstimatedCurrentSlot()) +} + +// EstimatedEpochAtSlot estimates epoch at the given slot +func (b BeaconConfig) EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch { + return phase0.Epoch(slot / b.SlotsPerEpoch) +} + +// IsFirstSlotOfEpoch estimates epoch at the given slot +func (b BeaconConfig) IsFirstSlotOfEpoch(slot phase0.Slot) bool { + return slot%b.SlotsPerEpoch == 0 +} + +// GetEpochFirstSlot returns the beacon node first slot in epoch +func (b BeaconConfig) GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot { + return phase0.Slot(epoch) * b.SlotsPerEpoch +} + +// EpochsPerSyncCommitteePeriod returns the number of epochs per sync committee period. +func (b BeaconConfig) EpochsPerSyncCommitteePeriod() phase0.Epoch { + return 256 +} + +// EstimatedSyncCommitteePeriodAtEpoch estimates the current sync committee period at the given Epoch +func (b BeaconConfig) EstimatedSyncCommitteePeriodAtEpoch(epoch phase0.Epoch) uint64 { + return uint64(epoch / b.EpochsPerSyncCommitteePeriod()) +} + +// FirstEpochOfSyncPeriod calculates the first epoch of the given sync period. +func (b BeaconConfig) FirstEpochOfSyncPeriod(period uint64) phase0.Epoch { + return phase0.Epoch(period) * b.EpochsPerSyncCommitteePeriod() +} + +// LastSlotOfSyncPeriod calculates the first epoch of the given sync period. +func (b BeaconConfig) LastSlotOfSyncPeriod(period uint64) phase0.Slot { + lastEpoch := b.FirstEpochOfSyncPeriod(period+1) - 1 + // If we are in the sync committee that ends at slot x we do not generate a message during slot x-1 + // as it will never be included, hence -1. + return b.GetEpochFirstSlot(lastEpoch+1) - 2 +} + +func (b BeaconConfig) FirstSlotAtEpoch(epoch phase0.Epoch) phase0.Slot { + return phase0.Slot(epoch) * b.SlotsPerEpoch +} + +func (b BeaconConfig) EpochStartTime(epoch phase0.Epoch) time.Time { + firstSlot := b.FirstSlotAtEpoch(epoch) + t := b.EstimatedTimeAtSlot(firstSlot) + return t +} + +func (b BeaconConfig) EstimatedTimeAtSlot(slot phase0.Slot) time.Time { + if slot > math.MaxInt64 { + panic("slot out of range") + } + d := time.Duration(slot) * b.SlotDuration // #nosec G115: slot cannot exceed math.MaxInt64 + return b.GenesisTime.Add(d) } diff --git a/networkconfig/config.go b/networkconfig/config.go index 6d290ed244..c208a2469b 100644 --- a/networkconfig/config.go +++ b/networkconfig/config.go @@ -3,7 +3,6 @@ package networkconfig import ( "encoding/json" "fmt" - "time" ) var SupportedConfigs = map[string]NetworkConfig{ @@ -45,23 +44,3 @@ func (n NetworkConfig) String() string { func (n NetworkConfig) NetworkName() string { return fmt.Sprintf("%s:%s", n.Name, forkName) } - -// ForkVersion returns the fork version of the network. -func (n NetworkConfig) ForkVersion() [4]byte { - return n.Beacon.ForkVersion() -} - -// SlotDurationSec returns slot duration -func (n NetworkConfig) SlotDurationSec() time.Duration { - return n.Beacon.SlotDurationSec() -} - -// SlotsPerEpoch returns number of slots per one epoch -func (n NetworkConfig) SlotsPerEpoch() uint64 { - return n.Beacon.SlotsPerEpoch() -} - -// GetGenesisTime returns the genesis time in unix time. -func (n NetworkConfig) GetGenesisTime() time.Time { - return time.Unix(n.Beacon.MinGenesisTime(), 0) -} diff --git a/networkconfig/holesky-e2e.go b/networkconfig/holesky-e2e.go index 11808a3966..344a3d1d88 100644 --- a/networkconfig/holesky-e2e.go +++ b/networkconfig/holesky-e2e.go @@ -2,7 +2,9 @@ package networkconfig import ( "math/big" + "time" + "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" @@ -11,8 +13,12 @@ import ( var HoleskyE2E = NetworkConfig{ Name: "holesky-e2e", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), - GenesisEpoch: 1, + Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + GenesisEpoch: 1, + SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), + SlotsPerEpoch: phase0.Slot(spectypes.HoleskyNetwork.SlotsPerEpoch()), + ForkVersion: spectypes.HoleskyNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0xee, 0x1}, diff --git a/networkconfig/holesky-stage.go b/networkconfig/holesky-stage.go index 313859930e..e8b1f5841b 100644 --- a/networkconfig/holesky-stage.go +++ b/networkconfig/holesky-stage.go @@ -2,7 +2,9 @@ package networkconfig import ( "math/big" + "time" + "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" @@ -11,8 +13,12 @@ import ( var HoleskyStage = NetworkConfig{ Name: "holesky-stage", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), - GenesisEpoch: 1, + Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + GenesisEpoch: 1, + SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), + SlotsPerEpoch: phase0.Slot(spectypes.HoleskyNetwork.SlotsPerEpoch()), + ForkVersion: spectypes.HoleskyNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, SSVConfig: SSVConfig{ DomainType: [4]byte{0x00, 0x00, 0x31, 0x13}, diff --git a/networkconfig/holesky.go b/networkconfig/holesky.go index d46823df1f..a0037109b0 100644 --- a/networkconfig/holesky.go +++ b/networkconfig/holesky.go @@ -2,7 +2,9 @@ package networkconfig import ( "math/big" + "time" + "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" @@ -11,8 +13,12 @@ import ( var Holesky = NetworkConfig{ Name: "holesky", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), - GenesisEpoch: 1, + Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + GenesisEpoch: 1, + SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), + SlotsPerEpoch: phase0.Slot(spectypes.HoleskyNetwork.SlotsPerEpoch()), + ForkVersion: spectypes.HoleskyNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x2}, diff --git a/networkconfig/hoodi-stage.go b/networkconfig/hoodi-stage.go index e98e58453a..4cf52822f6 100644 --- a/networkconfig/hoodi-stage.go +++ b/networkconfig/hoodi-stage.go @@ -2,7 +2,9 @@ package networkconfig import ( "math/big" + "time" + "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" @@ -11,8 +13,12 @@ import ( var HoodiStage = NetworkConfig{ Name: "hoodi-stage", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), - GenesisEpoch: 1, + Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), + GenesisEpoch: 1, + SlotDuration: spectypes.HoodiNetwork.SlotDurationSec(), + SlotsPerEpoch: phase0.Slot(spectypes.HoodiNetwork.SlotsPerEpoch()), + ForkVersion: spectypes.HoodiNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.HoodiNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, SSVConfig: SSVConfig{ DomainType: [4]byte{0x00, 0x00, 0x31, 0x14}, diff --git a/networkconfig/hoodi.go b/networkconfig/hoodi.go index 02bcf15805..83fb673985 100644 --- a/networkconfig/hoodi.go +++ b/networkconfig/hoodi.go @@ -2,7 +2,9 @@ package networkconfig import ( "math/big" + "time" + "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" @@ -11,8 +13,12 @@ import ( var Hoodi = NetworkConfig{ Name: "hoodi", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), - GenesisEpoch: 1, + Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), + GenesisEpoch: 1, + SlotDuration: spectypes.HoodiNetwork.SlotDurationSec(), + SlotsPerEpoch: phase0.Slot(spectypes.HoodiNetwork.SlotsPerEpoch()), + ForkVersion: spectypes.HoodiNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.HoodiNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x3}, diff --git a/networkconfig/local-testnet.go b/networkconfig/local-testnet.go index 3e8bad9dc2..d7001d638e 100644 --- a/networkconfig/local-testnet.go +++ b/networkconfig/local-testnet.go @@ -1,6 +1,9 @@ package networkconfig import ( + "time" + + "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" @@ -9,8 +12,12 @@ import ( var LocalTestnet = NetworkConfig{ Name: "local-testnet", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewLocalTestNetwork(spectypes.PraterNetwork), - GenesisEpoch: 1, + Beacon: beacon.NewLocalTestNetwork(spectypes.PraterNetwork), + GenesisEpoch: 1, + SlotDuration: spectypes.PraterNetwork.SlotDurationSec(), + SlotsPerEpoch: phase0.Slot(spectypes.PraterNetwork.SlotsPerEpoch()), + ForkVersion: spectypes.PraterNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.PraterNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoV2NetworkID.Byte(), 0x2}, diff --git a/networkconfig/mainnet.go b/networkconfig/mainnet.go index 2700b24b0e..3dd994ba05 100644 --- a/networkconfig/mainnet.go +++ b/networkconfig/mainnet.go @@ -2,7 +2,9 @@ package networkconfig import ( "math/big" + "time" + "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" @@ -11,8 +13,12 @@ import ( var Mainnet = NetworkConfig{ Name: "mainnet", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.MainNetwork), - GenesisEpoch: 218450, + Beacon: beacon.NewNetwork(spectypes.MainNetwork), + GenesisEpoch: 218450, + SlotDuration: spectypes.MainNetwork.SlotDurationSec(), + SlotsPerEpoch: phase0.Slot(spectypes.MainNetwork.SlotsPerEpoch()), + ForkVersion: spectypes.MainNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.MainNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, SSVConfig: SSVConfig{ DomainType: spectypes.AlanMainnet, diff --git a/networkconfig/sepolia.go b/networkconfig/sepolia.go index d17cfbbf71..da0be0866c 100644 --- a/networkconfig/sepolia.go +++ b/networkconfig/sepolia.go @@ -2,7 +2,9 @@ package networkconfig import ( "math/big" + "time" + "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" @@ -11,8 +13,12 @@ import ( var Sepolia = NetworkConfig{ Name: "sepolia", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.SepoliaNetwork), - GenesisEpoch: 1, + Beacon: beacon.NewNetwork(spectypes.SepoliaNetwork), + GenesisEpoch: 1, + SlotDuration: spectypes.SepoliaNetwork.SlotDurationSec(), + SlotsPerEpoch: phase0.Slot(spectypes.SepoliaNetwork.SlotsPerEpoch()), + ForkVersion: spectypes.SepoliaNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.SepoliaNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x69}, diff --git a/networkconfig/test-network.go b/networkconfig/test-network.go index 998d8d8fb4..dee9cb1d77 100644 --- a/networkconfig/test-network.go +++ b/networkconfig/test-network.go @@ -2,7 +2,9 @@ package networkconfig import ( "math/big" + "time" + "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" @@ -11,8 +13,12 @@ import ( var TestNetwork = NetworkConfig{ Name: "testnet", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.BeaconTestNetwork), - GenesisEpoch: 152834, + Beacon: beacon.NewNetwork(spectypes.BeaconTestNetwork), + GenesisEpoch: 152834, + SlotDuration: spectypes.BeaconTestNetwork.SlotDurationSec(), + SlotsPerEpoch: phase0.Slot(spectypes.BeaconTestNetwork.SlotsPerEpoch()), + ForkVersion: spectypes.BeaconTestNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.BeaconTestNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoNetworkID.Byte(), 0x2}, diff --git a/operator/duties/attester.go b/operator/duties/attester.go index d7012e7d90..547af7ab68 100644 --- a/operator/duties/attester.go +++ b/operator/duties/attester.go @@ -74,28 +74,28 @@ func (h *AttesterHandler) HandleDuties(ctx context.Context) { case <-next: slot := h.ticker.Slot() next = h.ticker.Next() - currentEpoch := h.network.Beacon.EstimatedEpochAtSlot(slot) + currentEpoch := h.network.EstimatedEpochAtSlot(slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, slot, slot%32+1) h.logger.Debug("🛠 ticker event", zap.String("epoch_slot_pos", buildStr)) h.processExecution(ctx, currentEpoch, slot) h.processFetching(ctx, currentEpoch, slot) - slotsPerEpoch := h.network.Beacon.SlotsPerEpoch() + slotsPerEpoch := h.network.SlotsPerEpoch // If we have reached the mid-point of the epoch, fetch the duties for the next epoch in the next slot. // This allows us to set them up at a time when the beacon node should be less busy. - if uint64(slot)%slotsPerEpoch == slotsPerEpoch/2-1 { + if slot%slotsPerEpoch == slotsPerEpoch/2-1 { h.fetchNextEpoch = true } // last slot of epoch - if uint64(slot)%slotsPerEpoch == slotsPerEpoch-1 { + if slot%slotsPerEpoch == slotsPerEpoch-1 { h.duties.ResetEpoch(currentEpoch - 1) } case reorgEvent := <-h.reorg: - currentEpoch := h.network.Beacon.EstimatedEpochAtSlot(reorgEvent.Slot) + currentEpoch := h.network.EstimatedEpochAtSlot(reorgEvent.Slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, reorgEvent.Slot, reorgEvent.Slot%32+1) h.logger.Info("🔀 reorg event received", zap.String("epoch_slot_pos", buildStr), zap.Any("event", reorgEvent)) @@ -119,8 +119,8 @@ func (h *AttesterHandler) HandleDuties(ctx context.Context) { } case <-h.indicesChange: - slot := h.network.Beacon.EstimatedCurrentSlot() - currentEpoch := h.network.Beacon.EstimatedEpochAtSlot(slot) + slot := h.network.EstimatedCurrentSlot() + currentEpoch := h.network.EstimatedEpochAtSlot(slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, slot, slot%32+1) h.logger.Info("🔁 indices change received", zap.String("epoch_slot_pos", buildStr)) @@ -135,16 +135,16 @@ func (h *AttesterHandler) HandleDuties(ctx context.Context) { } func (h *AttesterHandler) HandleInitialDuties(ctx context.Context) { - ctx, cancel := context.WithTimeout(ctx, h.network.Beacon.SlotDurationSec()/2) + ctx, cancel := context.WithTimeout(ctx, h.network.SlotDuration/2) defer cancel() - slot := h.network.Beacon.EstimatedCurrentSlot() - epoch := h.network.Beacon.EstimatedEpochAtSlot(slot) + slot := h.network.EstimatedCurrentSlot() + epoch := h.network.EstimatedEpochAtSlot(slot) h.processFetching(ctx, epoch, slot) } func (h *AttesterHandler) processFetching(ctx context.Context, epoch phase0.Epoch, slot phase0.Slot) { - ctx, cancel := context.WithDeadline(ctx, h.network.Beacon.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) + ctx, cancel := context.WithDeadline(ctx, h.network.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) defer cancel() if h.fetchCurrentEpoch { @@ -248,8 +248,8 @@ func (h *AttesterHandler) toSpecDuty(duty *eth2apiv1.AttesterDuty, role spectype } func (h *AttesterHandler) shouldExecute(duty *eth2apiv1.AttesterDuty) bool { - currentSlot := h.network.Beacon.EstimatedCurrentSlot() - currentEpoch := h.network.Beacon.EstimatedEpochAtSlot(currentSlot) + currentSlot := h.network.EstimatedCurrentSlot() + currentEpoch := h.network.EstimatedEpochAtSlot(currentSlot) v, exists := h.validatorProvider.Validator(duty.PubKey[:]) if !exists { @@ -267,7 +267,7 @@ func (h *AttesterHandler) shouldExecute(duty *eth2apiv1.AttesterDuty) bool { } // execute task if slot already began and not pass 1 epoch - var attestationPropagationSlotRange = phase0.Slot(h.network.Beacon.SlotsPerEpoch()) + var attestationPropagationSlotRange = h.network.SlotsPerEpoch if currentSlot >= duty.Slot && currentSlot-duty.Slot <= attestationPropagationSlotRange { return true } @@ -304,5 +304,5 @@ func toBeaconCommitteeSubscription(duty *eth2apiv1.AttesterDuty, role spectypes. } func (h *AttesterHandler) shouldFetchNexEpoch(slot phase0.Slot) bool { - return uint64(slot)%h.network.Beacon.SlotsPerEpoch() > h.network.Beacon.SlotsPerEpoch()/2-2 + return slot%h.network.SlotsPerEpoch > h.network.SlotsPerEpoch/2-2 } diff --git a/operator/duties/attester_test.go b/operator/duties/attester_test.go index 08197f625c..b502dd02df 100644 --- a/operator/duties/attester_test.go +++ b/operator/duties/attester_test.go @@ -888,7 +888,7 @@ func TestScheduler_Attester_Early_Block(t *testing.T) { } scheduler.HandleHeadEvent(logger)(e.Data.(*eth2apiv1.HeadEvent)) waitForDutiesExecution(t, logger, fetchDutiesCall, executeDutiesCall, timeout, expected) - require.Less(t, time.Since(startTime), scheduler.network.Beacon.SlotDurationSec()/3) + require.Less(t, time.Since(startTime), scheduler.network.SlotDuration/3) // Stop scheduler & wait for graceful exit. cancel() diff --git a/operator/duties/committee.go b/operator/duties/committee.go index 9bb0fe95fb..1bfab29c5f 100644 --- a/operator/duties/committee.go +++ b/operator/duties/committee.go @@ -55,8 +55,8 @@ func (h *CommitteeHandler) HandleDuties(ctx context.Context) { case <-next: slot := h.ticker.Slot() next = h.ticker.Next() - epoch := h.network.Beacon.EstimatedEpochAtSlot(slot) - period := h.network.Beacon.EstimatedSyncCommitteePeriodAtEpoch(epoch) + epoch := h.network.EstimatedEpochAtSlot(slot) + period := h.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) buildStr := fmt.Sprintf("p%v-e%v-s%v-#%v", period, epoch, slot, slot%32+1) h.logger.Debug("🛠 ticker event", zap.String("period_epoch_slot_pos", buildStr)) @@ -168,14 +168,14 @@ func (h *CommitteeHandler) toSpecSyncDuty(duty *eth2apiv1.SyncCommitteeDuty, slo } func (h *CommitteeHandler) shouldExecuteAtt(duty *eth2apiv1.AttesterDuty) bool { - currentSlot := h.network.Beacon.EstimatedCurrentSlot() + currentSlot := h.network.EstimatedCurrentSlot() if participates := h.canParticipate(duty.PubKey[:], currentSlot); !participates { return false } // execute task if slot already began and not pass 1 epoch - var attestationPropagationSlotRange = phase0.Slot(h.network.Beacon.SlotsPerEpoch()) + var attestationPropagationSlotRange = h.network.SlotsPerEpoch if currentSlot >= duty.Slot && currentSlot-duty.Slot <= attestationPropagationSlotRange { return true } @@ -187,7 +187,7 @@ func (h *CommitteeHandler) shouldExecuteAtt(duty *eth2apiv1.AttesterDuty) bool { } func (h *CommitteeHandler) shouldExecuteSync(duty *eth2apiv1.SyncCommitteeDuty, slot phase0.Slot) bool { - currentSlot := h.network.Beacon.EstimatedCurrentSlot() + currentSlot := h.network.EstimatedCurrentSlot() if participates := h.canParticipate(duty.PubKey[:], currentSlot); !participates { return false @@ -205,7 +205,7 @@ func (h *CommitteeHandler) shouldExecuteSync(duty *eth2apiv1.SyncCommitteeDuty, } func (h *CommitteeHandler) canParticipate(pubKey []byte, currentSlot phase0.Slot) bool { - currentEpoch := h.network.Beacon.EstimatedEpochAtSlot(currentSlot) + currentEpoch := h.network.EstimatedEpochAtSlot(currentSlot) v, exists := h.validatorProvider.Validator(pubKey) if !exists { diff --git a/operator/duties/committee_test.go b/operator/duties/committee_test.go index 6b3f6f6a4e..8b9422aca9 100644 --- a/operator/duties/committee_test.go +++ b/operator/duties/committee_test.go @@ -30,28 +30,28 @@ func setupCommitteeDutiesMock( s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().EstimatedSyncCommitteePeriodAtEpoch(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) uint64 { - return uint64(epoch) / s.network.Beacon.EpochsPerSyncCommitteePeriod() + return uint64(epoch / s.network.EpochsPerSyncCommitteePeriod()) }, ).AnyTimes() s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().FirstEpochOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Epoch { - return phase0.Epoch(period * s.network.Beacon.EpochsPerSyncCommitteePeriod()) + return phase0.Epoch(period) * s.network.EpochsPerSyncCommitteePeriod() }, ).AnyTimes() s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().GetEpochFirstSlot(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) phase0.Slot { - return phase0.Slot(uint64(epoch) * s.network.Beacon.SlotsPerEpoch()) + return phase0.Slot(epoch) * s.network.SlotsPerEpoch }, ).AnyTimes() s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().LastSlotOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Slot { - lastEpoch := s.network.Beacon.FirstEpochOfSyncPeriod(period+1) - 1 + lastEpoch := s.network.FirstEpochOfSyncPeriod(period+1) - 1 // If we are in the sync committee that ends at slot x we do not generate a message during slot x-1 // as it will never be included, hence -1. - return s.network.Beacon.GetEpochFirstSlot(lastEpoch+1) - 2 + return s.network.GetEpochFirstSlot(lastEpoch+1) - 2 }, ).AnyTimes() @@ -69,7 +69,7 @@ func setupCommitteeDutiesMock( if waitForDuties.Get() { fetchDutiesCall <- struct{}{} } - period := s.network.Beacon.EstimatedSyncCommitteePeriodAtEpoch(epoch) + period := s.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) duties, _ := syncDuties.Get(period) return duties, nil }).AnyTimes() @@ -108,7 +108,7 @@ func setupCommitteeDutiesMock( ValidatorIndex: duty.ValidatorIndex, }, } - firstEpoch := s.network.Beacon.FirstEpochOfSyncPeriod(period) + firstEpoch := s.network.FirstEpochOfSyncPeriod(period) if firstEpoch < minEpoch { minEpoch = firstEpoch ssvShare.SetMinParticipationEpoch(firstEpoch) @@ -183,7 +183,7 @@ func TestScheduler_Committee_Same_Slot_Attester_Only(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.Beacon.SlotDurationSec()/3, time.Since(startTime)) + require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -233,7 +233,7 @@ func TestScheduler_Committee_Same_Slot_SyncCommittee_Only(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.Beacon.SlotDurationSec()/3, time.Since(startTime)) + require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -291,7 +291,7 @@ func TestScheduler_Committee_Same_Slot(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.Beacon.SlotDurationSec()/3, time.Since(startTime)) + require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -347,7 +347,7 @@ func TestScheduler_Committee_Diff_Slot_Attester_Only(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.Beacon.SlotDurationSec()/3, time.Since(startTime)) + require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -449,7 +449,7 @@ func TestScheduler_Committee_Indices_Changed_Attester_Only(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.Beacon.SlotDurationSec()/3, time.Since(startTime)) + require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -551,7 +551,7 @@ func TestScheduler_Committee_Indices_Changed_Attester_Only_2(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.Beacon.SlotDurationSec()/3, time.Since(startTime)) + require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -643,7 +643,7 @@ func TestScheduler_Committee_Indices_Changed_Attester_Only_3(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.Beacon.SlotDurationSec()/3, time.Since(startTime)) + require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -1020,7 +1020,7 @@ func TestScheduler_Committee_Early_Block_Attester_Only(t *testing.T) { } scheduler.HandleHeadEvent(logger)(e.Data.(*eth2apiv1.HeadEvent)) waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) - require.Less(t, time.Since(startTime), scheduler.network.Beacon.SlotDurationSec()/3) + require.Less(t, time.Since(startTime), scheduler.network.SlotDuration/3) // Stop scheduler & wait for graceful exit. cancel() @@ -1076,7 +1076,7 @@ func TestScheduler_Committee_Early_Block(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.Beacon.SlotDurationSec()/3, time.Since(startTime)) + require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) // STEP 3: wait for attester duties to be executed faster than 1/3 of the slot duration when // Beacon head event is observed (block arrival) @@ -1094,7 +1094,7 @@ func TestScheduler_Committee_Early_Block(t *testing.T) { } scheduler.HandleHeadEvent(logger)(e.Data.(*eth2apiv1.HeadEvent)) waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) - require.Less(t, time.Since(startTime), scheduler.network.Beacon.SlotDurationSec()/3) + require.Less(t, time.Since(startTime), scheduler.network.SlotDuration/3) // Stop scheduler & wait for graceful exit. cancel() diff --git a/operator/duties/proposer.go b/operator/duties/proposer.go index c57488adde..8716daec4a 100644 --- a/operator/duties/proposer.go +++ b/operator/duties/proposer.go @@ -63,11 +63,11 @@ func (h *ProposerHandler) HandleDuties(ctx context.Context) { case <-next: slot := h.ticker.Slot() next = h.ticker.Next() - currentEpoch := h.network.Beacon.EstimatedEpochAtSlot(slot) + currentEpoch := h.network.EstimatedEpochAtSlot(slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, slot, slot%32+1) h.logger.Debug("🛠 ticker event", zap.String("epoch_slot_pos", buildStr)) - ctx, cancel := context.WithDeadline(ctx, h.network.Beacon.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) + ctx, cancel := context.WithDeadline(ctx, h.network.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) if h.fetchFirst { h.fetchFirst = false h.indicesChanged = false @@ -83,13 +83,13 @@ func (h *ProposerHandler) HandleDuties(ctx context.Context) { cancel() // last slot of epoch - if uint64(slot)%h.network.Beacon.SlotsPerEpoch() == h.network.Beacon.SlotsPerEpoch()-1 { + if slot%h.network.SlotsPerEpoch == h.network.SlotsPerEpoch-1 { h.duties.ResetEpoch(currentEpoch - 1) h.fetchFirst = true } case reorgEvent := <-h.reorg: - currentEpoch := h.network.Beacon.EstimatedEpochAtSlot(reorgEvent.Slot) + currentEpoch := h.network.EstimatedEpochAtSlot(reorgEvent.Slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, reorgEvent.Slot, reorgEvent.Slot%32+1) h.logger.Info("🔀 reorg event received", zap.String("epoch_slot_pos", buildStr), zap.Any("event", reorgEvent)) @@ -100,8 +100,8 @@ func (h *ProposerHandler) HandleDuties(ctx context.Context) { } case <-h.indicesChange: - slot := h.network.Beacon.EstimatedCurrentSlot() - currentEpoch := h.network.Beacon.EstimatedEpochAtSlot(slot) + slot := h.network.EstimatedCurrentSlot() + currentEpoch := h.network.EstimatedEpochAtSlot(slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, slot, slot%32+1) h.logger.Info("🔁 indices change received", zap.String("epoch_slot_pos", buildStr)) @@ -111,10 +111,10 @@ func (h *ProposerHandler) HandleDuties(ctx context.Context) { } func (h *ProposerHandler) HandleInitialDuties(ctx context.Context) { - ctx, cancel := context.WithTimeout(ctx, h.network.Beacon.SlotDurationSec()/2) + ctx, cancel := context.WithTimeout(ctx, h.network.SlotDuration/2) defer cancel() - epoch := h.network.Beacon.EstimatedCurrentEpoch() + epoch := h.network.EstimatedCurrentEpoch() h.processFetching(ctx, epoch) } @@ -200,7 +200,7 @@ func (h *ProposerHandler) toSpecDuty(duty *eth2apiv1.ProposerDuty, role spectype } func (h *ProposerHandler) shouldExecute(duty *eth2apiv1.ProposerDuty) bool { - currentSlot := h.network.Beacon.EstimatedCurrentSlot() + currentSlot := h.network.EstimatedCurrentSlot() // execute task if slot already began and not pass 1 slot if currentSlot == duty.Slot { return true diff --git a/operator/duties/scheduler.go b/operator/duties/scheduler.go index b9d1d4d5e3..34a834794e 100644 --- a/operator/duties/scheduler.go +++ b/operator/duties/scheduler.go @@ -287,8 +287,8 @@ func (s *Scheduler) SlotTicker(ctx context.Context) { case <-s.ticker.Next(): slot := s.ticker.Slot() - delay := s.network.SlotDurationSec() / casts.DurationFromUint64(goclient.IntervalsPerSlot) /* a third of the slot duration */ - finalTime := s.network.Beacon.GetSlotStartTime(slot).Add(delay) + delay := s.network.SlotDuration / casts.DurationFromUint64(goclient.IntervalsPerSlot) /* a third of the slot duration */ + finalTime := s.network.GetSlotStartTime(slot).Add(delay) waitDuration := time.Until(finalTime) if waitDuration > 0 { @@ -308,12 +308,12 @@ func (s *Scheduler) SlotTicker(ctx context.Context) { func (s *Scheduler) HandleHeadEvent(logger *zap.Logger) func(event *eth2apiv1.HeadEvent) { return func(event *eth2apiv1.HeadEvent) { var zeroRoot phase0.Root - if event.Slot != s.network.Beacon.EstimatedCurrentSlot() { + if event.Slot != s.network.EstimatedCurrentSlot() { return } // check for reorg - epoch := s.network.Beacon.EstimatedEpochAtSlot(event.Slot) + epoch := s.network.EstimatedEpochAtSlot(event.Slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", epoch, event.Slot, event.Slot%32+1) logger := logger.With(zap.String("epoch_slot_pos", buildStr)) if s.lastBlockEpoch != 0 { @@ -366,8 +366,8 @@ func (s *Scheduler) HandleHeadEvent(logger *zap.Logger) func(event *eth2apiv1.He s.currentDutyDependentRoot = event.CurrentDutyDependentRoot currentTime := time.Now() - delay := s.network.SlotDurationSec() / casts.DurationFromUint64(goclient.IntervalsPerSlot) /* a third of the slot duration */ - slotStartTimeWithDelay := s.network.Beacon.GetSlotStartTime(event.Slot).Add(delay) + delay := s.network.SlotDuration / casts.DurationFromUint64(goclient.IntervalsPerSlot) /* a third of the slot duration */ + slotStartTimeWithDelay := s.network.GetSlotStartTime(event.Slot).Add(delay) if currentTime.Before(slotStartTimeWithDelay) { logger.Debug("🏁 Head event: Block arrived before 1/3 slot", zap.Duration("time_saved", slotStartTimeWithDelay.Sub(currentTime))) @@ -388,7 +388,7 @@ func (s *Scheduler) ExecuteDuties(ctx context.Context, logger *zap.Logger, dutie for _, duty := range duties { duty := duty logger := s.loggerWithDutyContext(logger, duty) - slotDelay := time.Since(s.network.Beacon.GetSlotStartTime(duty.Slot)) + slotDelay := time.Since(s.network.GetSlotStartTime(duty.Slot)) if slotDelay >= 100*time.Millisecond { logger.Debug("⚠️ late duty execution", zap.Int64("slot_delay", slotDelay.Milliseconds())) } @@ -408,10 +408,10 @@ func (s *Scheduler) ExecuteCommitteeDuties(ctx context.Context, logger *zap.Logg for _, committee := range duties { duty := committee.duty logger := s.loggerWithCommitteeDutyContext(logger, committee) - dutyEpoch := s.network.Beacon.EstimatedEpochAtSlot(duty.Slot) + dutyEpoch := s.network.EstimatedEpochAtSlot(duty.Slot) logger.Debug("🔧 executing committee duty", fields.Duties(dutyEpoch, duty.ValidatorDuties)) - slotDelay := time.Since(s.network.Beacon.GetSlotStartTime(duty.Slot)) + slotDelay := time.Since(s.network.GetSlotStartTime(duty.Slot)) if slotDelay >= 100*time.Millisecond { logger.Debug("⚠️ late duty execution", zap.Int64("slot_delay", slotDelay.Milliseconds())) } @@ -429,27 +429,27 @@ func (s *Scheduler) loggerWithDutyContext(logger *zap.Logger, duty *spectypes.Va return logger. With(fields.BeaconRole(duty.Type)). With(zap.Uint64("committee_index", uint64(duty.CommitteeIndex))). - With(fields.CurrentSlot(s.network.Beacon.EstimatedCurrentSlot())). + With(fields.CurrentSlot(s.network.EstimatedCurrentSlot())). With(fields.Slot(duty.Slot)). - With(fields.Epoch(s.network.Beacon.EstimatedEpochAtSlot(duty.Slot))). + With(fields.Epoch(s.network.EstimatedEpochAtSlot(duty.Slot))). With(fields.PubKey(duty.PubKey[:])). - With(fields.StartTimeUnixMilli(s.network.Beacon.GetSlotStartTime(duty.Slot))) + With(fields.StartTimeUnixMilli(s.network.GetSlotStartTime(duty.Slot))) } // loggerWithCommitteeDutyContext returns an instance of logger with the given committee duty's information func (s *Scheduler) loggerWithCommitteeDutyContext(logger *zap.Logger, committeeDuty *committeeDuty) *zap.Logger { duty := committeeDuty.duty - dutyEpoch := s.network.Beacon.EstimatedEpochAtSlot(duty.Slot) + dutyEpoch := s.network.EstimatedEpochAtSlot(duty.Slot) committeeDutyID := fields.FormatCommitteeDutyID(committeeDuty.operatorIDs, dutyEpoch, duty.Slot) return logger. With(fields.CommitteeID(committeeDuty.id)). With(fields.DutyID(committeeDutyID)). With(fields.Role(duty.RunnerRole())). - With(fields.CurrentSlot(s.network.Beacon.EstimatedCurrentSlot())). + With(fields.CurrentSlot(s.network.EstimatedCurrentSlot())). With(fields.Slot(duty.Slot)). With(fields.Epoch(dutyEpoch)). - With(fields.StartTimeUnixMilli(s.network.Beacon.GetSlotStartTime(duty.Slot))) + With(fields.StartTimeUnixMilli(s.network.GetSlotStartTime(duty.Slot))) } // waitOneThirdOrValidBlock waits until one-third of the slot has transpired (SECONDS_PER_SLOT / 3 seconds after the start of slot) diff --git a/operator/duties/scheduler_test.go b/operator/duties/scheduler_test.go index 0cd26b59e8..27554242c6 100644 --- a/operator/duties/scheduler_test.go +++ b/operator/duties/scheduler_test.go @@ -121,7 +121,7 @@ func setupSchedulerAndMocks(t *testing.T, handlers []dutyHandler, currentSlot *S ).AnyTimes() mockNetworkConfig.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().EstimatedEpochAtSlot(gomock.Any()).DoAndReturn( func(slot phase0.Slot) phase0.Epoch { - return phase0.Epoch(uint64(slot) / s.network.SlotsPerEpoch()) + return phase0.Epoch(slot / s.network.SlotsPerEpoch) }, ).AnyTimes() @@ -133,7 +133,7 @@ func setupSchedulerAndMocks(t *testing.T, handlers []dutyHandler, currentSlot *S s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().EstimatedCurrentEpoch().DoAndReturn( func() phase0.Epoch { - return phase0.Epoch(uint64(currentSlot.Get()) / s.network.SlotsPerEpoch()) + return phase0.Epoch(currentSlot.Get() / s.network.SlotsPerEpoch) }, ).AnyTimes() diff --git a/operator/duties/sync_committee.go b/operator/duties/sync_committee.go index 75e7bace63..391c56c050 100644 --- a/operator/duties/sync_committee.go +++ b/operator/duties/sync_committee.go @@ -24,7 +24,7 @@ type SyncCommitteeHandler struct { // preparationSlots is the number of slots ahead of the sync committee // period change at which to prepare the relevant duties. - preparationSlots uint64 + preparationSlots phase0.Slot } func NewSyncCommitteeHandler(duties *dutystore.SyncCommitteeDuties) *SyncCommitteeHandler { @@ -65,9 +65,9 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { // Prepare relevant duties 1.5 epochs (48 slots) ahead of the sync committee period change. // The 1.5 epochs timing helps ensure setup occurs when the beacon node is likely less busy. - h.preparationSlots = h.network.Beacon.SlotsPerEpoch() * 3 / 2 + h.preparationSlots = h.network.SlotsPerEpoch * 3 / 2 - if h.shouldFetchNextPeriod(h.network.Beacon.EstimatedCurrentSlot()) { + if h.shouldFetchNextPeriod(h.network.EstimatedCurrentSlot()) { h.fetchNextPeriod = true } @@ -80,30 +80,30 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { case <-next: slot := h.ticker.Slot() next = h.ticker.Next() - epoch := h.network.Beacon.EstimatedEpochAtSlot(slot) - period := h.network.Beacon.EstimatedSyncCommitteePeriodAtEpoch(epoch) + epoch := h.network.EstimatedEpochAtSlot(slot) + period := h.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) buildStr := fmt.Sprintf("p%v-e%v-s%v-#%v", period, epoch, slot, slot%32+1) h.logger.Debug("🛠 ticker event", zap.String("period_epoch_slot_pos", buildStr)) - ctx, cancel := context.WithDeadline(ctx, h.network.Beacon.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) + ctx, cancel := context.WithDeadline(ctx, h.network.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) h.processExecution(ctx, period, slot) h.processFetching(ctx, period, true) cancel() // if we have reached the preparation slots -1, prepare the next period duties in the next slot. periodSlots := h.slotsPerPeriod() - if uint64(slot)%periodSlots == periodSlots-h.preparationSlots-1 { + if slot%periodSlots == periodSlots-h.preparationSlots-1 { h.fetchNextPeriod = true } // last slot of period - if slot == h.network.Beacon.LastSlotOfSyncPeriod(period) { + if slot == h.network.LastSlotOfSyncPeriod(period) { h.duties.Reset(period - 1) } case reorgEvent := <-h.reorg: - epoch := h.network.Beacon.EstimatedEpochAtSlot(reorgEvent.Slot) - period := h.network.Beacon.EstimatedSyncCommitteePeriodAtEpoch(epoch) + epoch := h.network.EstimatedEpochAtSlot(reorgEvent.Slot) + period := h.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) buildStr := fmt.Sprintf("p%v-e%v-s%v-#%v", period, epoch, reorgEvent.Slot, reorgEvent.Slot%32+1) h.logger.Info("🔀 reorg event received", zap.String("period_epoch_slot_pos", buildStr), zap.Any("event", reorgEvent)) @@ -115,9 +115,9 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { } case <-h.indicesChange: - slot := h.network.Beacon.EstimatedCurrentSlot() - epoch := h.network.Beacon.EstimatedEpochAtSlot(slot) - period := h.network.Beacon.EstimatedSyncCommitteePeriodAtEpoch(epoch) + slot := h.network.EstimatedCurrentSlot() + epoch := h.network.EstimatedEpochAtSlot(slot) + period := h.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) buildStr := fmt.Sprintf("p%v-e%v-s%v-#%v", period, epoch, slot, slot%32+1) h.logger.Info("🔁 indices change received", zap.String("period_epoch_slot_pos", buildStr)) @@ -132,11 +132,11 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { } func (h *SyncCommitteeHandler) HandleInitialDuties(ctx context.Context) { - ctx, cancel := context.WithTimeout(ctx, h.network.Beacon.SlotDurationSec()/2) + ctx, cancel := context.WithTimeout(ctx, h.network.SlotDuration/2) defer cancel() - epoch := h.network.Beacon.EstimatedCurrentEpoch() - period := h.network.Beacon.EstimatedSyncCommitteePeriodAtEpoch(epoch) + epoch := h.network.EstimatedCurrentEpoch() + period := h.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) h.processFetching(ctx, period, false) } @@ -180,12 +180,12 @@ func (h *SyncCommitteeHandler) processExecution(ctx context.Context, period uint func (h *SyncCommitteeHandler) fetchAndProcessDuties(ctx context.Context, period uint64, waitForInitial bool) error { start := time.Now() - firstEpoch := h.network.Beacon.FirstEpochOfSyncPeriod(period) - currentEpoch := h.network.Beacon.EstimatedCurrentEpoch() + firstEpoch := h.network.FirstEpochOfSyncPeriod(period) + currentEpoch := h.network.EstimatedCurrentEpoch() if firstEpoch < currentEpoch { firstEpoch = currentEpoch } - lastEpoch := h.network.Beacon.FirstEpochOfSyncPeriod(period+1) - 1 + lastEpoch := h.network.FirstEpochOfSyncPeriod(period+1) - 1 allActiveIndices := h.validatorController.AllActiveIndices(firstEpoch, waitForInitial) if len(allActiveIndices) == 0 { @@ -268,8 +268,8 @@ func (h *SyncCommitteeHandler) toSpecDuty(duty *eth2apiv1.SyncCommitteeDuty, slo } func (h *SyncCommitteeHandler) shouldExecute(duty *eth2apiv1.SyncCommitteeDuty, slot phase0.Slot) bool { - currentSlot := h.network.Beacon.EstimatedCurrentSlot() - currentEpoch := h.network.Beacon.EstimatedEpochAtSlot(currentSlot) + currentSlot := h.network.EstimatedCurrentSlot() + currentEpoch := h.network.EstimatedEpochAtSlot(currentSlot) v, exists := h.validatorProvider.Validator(duty.PubKey[:]) if !exists { @@ -313,9 +313,9 @@ func calculateSubscriptions(endEpoch phase0.Epoch, duties []*eth2apiv1.SyncCommi func (h *SyncCommitteeHandler) shouldFetchNextPeriod(slot phase0.Slot) bool { periodSlots := h.slotsPerPeriod() - return uint64(slot)%periodSlots > periodSlots-h.preparationSlots-2 + return slot%periodSlots > periodSlots-h.preparationSlots-2 } -func (h *SyncCommitteeHandler) slotsPerPeriod() uint64 { - return h.network.Beacon.EpochsPerSyncCommitteePeriod() * h.network.Beacon.SlotsPerEpoch() +func (h *SyncCommitteeHandler) slotsPerPeriod() phase0.Slot { + return phase0.Slot(h.network.EpochsPerSyncCommitteePeriod()) * h.network.SlotsPerEpoch } diff --git a/operator/duties/sync_committee_test.go b/operator/duties/sync_committee_test.go index 1e6812cf3a..98d94f2c6a 100644 --- a/operator/duties/sync_committee_test.go +++ b/operator/duties/sync_committee_test.go @@ -29,28 +29,28 @@ func setupSyncCommitteeDutiesMock( s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().EstimatedSyncCommitteePeriodAtEpoch(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) uint64 { - return uint64(epoch) / s.network.Beacon.EpochsPerSyncCommitteePeriod() + return uint64(epoch / s.network.EpochsPerSyncCommitteePeriod()) }, ).AnyTimes() s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().FirstEpochOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Epoch { - return phase0.Epoch(period * s.network.Beacon.EpochsPerSyncCommitteePeriod()) + return phase0.Epoch(period) * s.network.EpochsPerSyncCommitteePeriod() }, ).AnyTimes() s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().LastSlotOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Slot { - lastEpoch := s.network.Beacon.FirstEpochOfSyncPeriod(period+1) - 1 + lastEpoch := s.network.FirstEpochOfSyncPeriod(period+1) - 1 // If we are in the sync committee that ends at slot x we do not generate a message during slot x-1 // as it will never be included, hence -1. - return s.network.Beacon.GetEpochFirstSlot(lastEpoch+1) - 2 + return s.network.GetEpochFirstSlot(lastEpoch+1) - 2 }, ).AnyTimes() s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().GetEpochFirstSlot(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) phase0.Slot { - return phase0.Slot(uint64(epoch) * s.network.Beacon.SlotsPerEpoch()) + return phase0.Slot(epoch) * s.network.SlotsPerEpoch }, ).AnyTimes() @@ -59,7 +59,7 @@ func setupSyncCommitteeDutiesMock( if waitForDuties.Get() { fetchDutiesCall <- struct{}{} } - period := s.network.Beacon.EstimatedSyncCommitteePeriodAtEpoch(epoch) + period := s.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) duties, _ := dutiesMap.Get(period) return duties, nil }).AnyTimes() @@ -78,7 +78,7 @@ func setupSyncCommitteeDutiesMock( ValidatorIndex: duty.ValidatorIndex, }, } - firstEpoch := s.network.Beacon.FirstEpochOfSyncPeriod(period) + firstEpoch := s.network.FirstEpochOfSyncPeriod(period) if firstEpoch < minEpoch { minEpoch = firstEpoch ssvShare.SetMinParticipationEpoch(firstEpoch) @@ -161,7 +161,7 @@ func TestScheduler_SyncCommittee_Same_Period(t *testing.T) { waitForDutiesExecution(t, logger, fetchDutiesCall, executeDutiesCall, timeout, expected) // STEP 3: expect sync committee duties to be executed at the last slot of the period - currentSlot.Set(scheduler.network.Beacon.LastSlotOfSyncPeriod(0)) + currentSlot.Set(scheduler.network.LastSlotOfSyncPeriod(0)) duties, _ = dutiesMap.Get(0) expected = expectedExecutedSyncCommitteeDuties(handler, duties, currentSlot.Get()) setExecuteDutyFunc(scheduler, executeDutiesCall, len(expected)) @@ -170,7 +170,7 @@ func TestScheduler_SyncCommittee_Same_Period(t *testing.T) { waitForDutiesExecution(t, logger, fetchDutiesCall, executeDutiesCall, timeout, expected) // STEP 4: expect no action to be taken as we are in the next period - firstSlotOfNextPeriod := scheduler.network.Beacon.GetEpochFirstSlot(scheduler.network.Beacon.FirstEpochOfSyncPeriod(1)) + firstSlotOfNextPeriod := scheduler.network.GetEpochFirstSlot(scheduler.network.FirstEpochOfSyncPeriod(1)) currentSlot.Set(firstSlotOfNextPeriod) ticker.Send(currentSlot.Get()) waitForNoAction(t, logger, fetchDutiesCall, executeDutiesCall, timeout) @@ -685,7 +685,7 @@ func TestScheduler_SyncCommittee_Early_Block(t *testing.T) { } scheduler.HandleHeadEvent(logger)(e.Data.(*v1.HeadEvent)) waitForDutiesExecution(t, logger, fetchDutiesCall, executeDutiesCall, timeout, expected) - require.Greater(t, time.Since(startTime), time.Duration(float64(scheduler.network.Beacon.SlotDurationSec()/3)*0.90)) // 10% margin due to flakiness of the test + require.Greater(t, time.Since(startTime), time.Duration(float64(scheduler.network.SlotDuration/3)*0.90)) // 10% margin due to flakiness of the test // Stop scheduler & wait for graceful exit. cancel() diff --git a/operator/duties/validatorregistration.go b/operator/duties/validatorregistration.go index 338b9f7a89..ec5a90b93f 100644 --- a/operator/duties/validatorregistration.go +++ b/operator/duties/validatorregistration.go @@ -10,7 +10,7 @@ import ( ) // frequencyEpochs defines how frequently we want to submit validator-registrations. -const frequencyEpochs = uint64(10) +const frequencyEpochs = phase0.Epoch(10) type ValidatorRegistrationHandler struct { baseHandler @@ -38,7 +38,7 @@ func (h *ValidatorRegistrationHandler) HandleDuties(ctx context.Context) { defer h.logger.Info("duty handler exited") // validator should be registered within frequencyEpochs epochs time in a corresponding slot - registrationSlots := h.network.SlotsPerEpoch() * frequencyEpochs + registrationSlots := h.network.SlotsPerEpoch * phase0.Slot(frequencyEpochs) next := h.ticker.Next() for { @@ -49,12 +49,12 @@ func (h *ValidatorRegistrationHandler) HandleDuties(ctx context.Context) { case <-next: slot := h.ticker.Slot() next = h.ticker.Next() - epoch := h.network.Beacon.EstimatedEpochAtSlot(slot) - shares := h.validatorProvider.SelfParticipatingValidators(epoch + phase0.Epoch(frequencyEpochs)) + epoch := h.network.EstimatedEpochAtSlot(slot) + shares := h.validatorProvider.SelfParticipatingValidators(epoch + frequencyEpochs) var vrs []ValidatorRegistration for _, share := range shares { - if uint64(share.ValidatorIndex)%registrationSlots != uint64(slot)%registrationSlots { + if phase0.Slot(share.ValidatorIndex)%registrationSlots != slot%registrationSlots { continue } diff --git a/operator/duties/voluntary_exit.go b/operator/duties/voluntary_exit.go index 470e5718bc..863e5b387f 100644 --- a/operator/duties/voluntary_exit.go +++ b/operator/duties/voluntary_exit.go @@ -3,6 +3,7 @@ package duties import ( "context" "math/big" + "time" "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" @@ -114,7 +115,7 @@ func (h *VoluntaryExitHandler) processExecution(ctx context.Context, slot phase0 } h.dutyQueue = pendingDuties - h.duties.RemoveSlot(slot - phase0.Slot(h.network.SlotsPerEpoch())) + h.duties.RemoveSlot(slot - h.network.SlotsPerEpoch) if dutyCount := len(dutiesForExecution); dutyCount != 0 { h.dutiesExecutor.ExecuteDuties(ctx, h.logger, dutiesForExecution) @@ -137,7 +138,7 @@ func (h *VoluntaryExitHandler) blockSlot(ctx context.Context, blockNumber uint64 return 0, err } - blockSlot = h.network.Beacon.EstimatedSlotAtTime(int64(block.Time())) // #nosec G115 + blockSlot = h.network.EstimatedSlotAtTime(time.Unix(int64(block.Time()), 0)) // #nosec G115 h.blockSlots[blockNumber] = blockSlot for k, v := range h.blockSlots { diff --git a/operator/duties/voluntary_exit_test.go b/operator/duties/voluntary_exit_test.go index 5edebdd773..167e813721 100644 --- a/operator/duties/voluntary_exit_test.go +++ b/operator/duties/voluntary_exit_test.go @@ -5,6 +5,7 @@ import ( "math/big" "sync/atomic" "testing" + "time" "github.com/attestantio/go-eth2-client/spec/phase0" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -166,7 +167,7 @@ func assert1to1BlockSlotMapping(t *testing.T, scheduler *Scheduler) { require.NoError(t, err) require.NotNil(t, block) - slot := scheduler.network.Beacon.EstimatedSlotAtTime(int64(block.Time())) + slot := scheduler.network.EstimatedSlotAtTime(time.Unix(int64(block.Time()), 0)) require.EqualValues(t, blockNumber, slot) } diff --git a/operator/fee_recipient/controller.go b/operator/fee_recipient/controller.go index 46582a7a06..d37b919bdf 100644 --- a/operator/fee_recipient/controller.go +++ b/operator/fee_recipient/controller.go @@ -74,7 +74,7 @@ func (rc *recipientController) listenToTicker(logger *zap.Logger) { <-ticker.Next() slot := ticker.Slot() // submit if first time or if first slot in epoch - if firstTimeSubmitted && uint64(slot)%rc.network.SlotsPerEpoch() != (rc.network.SlotsPerEpoch()/2) { + if firstTimeSubmitted && slot%rc.network.SlotsPerEpoch != (rc.network.SlotsPerEpoch/2) { continue } firstTimeSubmitted = true diff --git a/operator/fee_recipient/controller_test.go b/operator/fee_recipient/controller_test.go index 0612f71730..a467371338 100644 --- a/operator/fee_recipient/controller_test.go +++ b/operator/fee_recipient/controller_test.go @@ -14,7 +14,7 @@ import ( "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/stretchr/testify/require" - gomock "go.uber.org/mock/gomock" + "go.uber.org/mock/gomock" "go.uber.org/zap" "github.com/ssvlabs/ssv/logging" @@ -80,11 +80,11 @@ func TestSubmitProposal(t *testing.T) { go frCtrl.Start(logger) slots := []phase0.Slot{ - 1, // first time - 2, // should not call submit - 20, // should not call submit - phase0.Slot(network.SlotsPerEpoch()) / 2, // halfway through epoch - 63, // should not call submit + 1, // first time + 2, // should not call submit + 20, // should not call submit + network.SlotsPerEpoch / 2, // halfway through epoch + 63, // should not call submit } for _, s := range slots { diff --git a/operator/validator/controller.go b/operator/validator/controller.go index db25e4618b..7ea3bf50a1 100644 --- a/operator/validator/controller.go +++ b/operator/validator/controller.go @@ -229,8 +229,7 @@ func NewController(logger *zap.Logger, options ControllerOptions) Controller { } } - beaconNetwork := options.NetworkConfig.Beacon - cacheTTL := beaconNetwork.SlotDurationSec() * time.Duration(beaconNetwork.SlotsPerEpoch()*2) // #nosec G115 + cacheTTL := options.NetworkConfig.SlotDuration * time.Duration(options.NetworkConfig.SlotsPerEpoch*2) // #nosec G115 ctrl := controller{ logger: logger.Named(logging.NameController), diff --git a/protocol/v2/blockchain/beacon/network.go b/protocol/v2/blockchain/beacon/network.go index 25d049ca96..30c87cfefb 100644 --- a/protocol/v2/blockchain/beacon/network.go +++ b/protocol/v2/blockchain/beacon/network.go @@ -20,11 +20,11 @@ type BeaconNetwork interface { MinGenesisTime() int64 SlotDurationSec() time.Duration SlotsPerEpoch() uint64 - EstimatedCurrentSlot() phase0.Slot + EstimatedCurrentSlot() phase0.Slot // TODO: use networkconfig's method instead EstimatedSlotAtTime(time int64) phase0.Slot EstimatedTimeAtSlot(slot phase0.Slot) int64 EstimatedCurrentEpoch() phase0.Epoch - EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch + EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch // TODO: use networkconfig's method instead FirstSlotAtEpoch(epoch phase0.Epoch) phase0.Slot EpochStartTime(epoch phase0.Epoch) time.Time diff --git a/protocol/v2/ssv/validator/non_committee_validator.go b/protocol/v2/ssv/validator/non_committee_validator.go index 1d86de5c44..310828f439 100644 --- a/protocol/v2/ssv/validator/non_committee_validator.go +++ b/protocol/v2/ssv/validator/non_committee_validator.go @@ -379,7 +379,7 @@ func (ncv *CommitteeObserver) saveSyncCommRoots(epoch phase0.Epoch, beaconVote * func (ncv *CommitteeObserver) postConsensusContainerCapacity() int { // #nosec G115 -- slots per epoch must be low epoch not to cause overflow - return int(ncv.networkConfig.SlotsPerEpoch()) + validation.LateSlotAllowance + return int(ncv.networkConfig.SlotsPerEpoch) + validation.LateSlotAllowance } func constructAttestationData(vote *spectypes.BeaconVote, slot phase0.Slot, committeeIndex phase0.CommitteeIndex) *phase0.AttestationData { From 5847a353614af0fdc2941998de82ffbbbfc07448 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 15 Apr 2025 21:31:14 -0300 Subject: [PATCH 03/34] get rid of BeaconNetwork interface --- beacon/goclient/aggregator.go | 6 +- beacon/goclient/attest_test.go | 6 +- beacon/goclient/events_test.go | 4 +- beacon/goclient/goclient.go | 39 +- beacon/goclient/goclient_test.go | 36 +- beacon/goclient/signing.go | 2 +- .../goclient/sync_committee_contribution.go | 4 +- beacon/goclient/validator.go | 4 +- cli/flags/export_keys_from_mnemonic.go | 2 +- cli/operator/node.go | 20 +- ekm/eth_key_manager_signer.go | 19 +- ekm/signer_key_manager_test.go | 10 +- ekm/signer_storage.go | 24 +- ekm/signer_storage_test.go | 2 +- eth/eventhandler/event_handler.go | 4 +- eth/eventhandler/event_handler_test.go | 29 +- eth/eventhandler/handlers.go | 2 +- go.mod | 2 + go.sum | 4 +- message/validation/common_checks.go | 4 +- message/validation/signed_ssv_message.go | 2 +- message/validation/validation.go | 8 +- message/validation/validation_test.go | 10 +- migrations/migrations.go | 12 +- network/discovery/dv5_service_test.go | 5 +- network/discovery/util_test.go | 7 +- network/topics/msg_validator_test.go | 2 +- networkconfig/beacon.go | 39 +- networkconfig/beacon_mock.go | 294 +++++++++++++++ networkconfig/config.go | 8 + networkconfig/config_mock.go | 323 +++++++++++++++++ networkconfig/holesky-e2e.go | 4 +- networkconfig/holesky-stage.go | 4 +- networkconfig/holesky.go | 4 +- networkconfig/hoodi-stage.go | 4 +- networkconfig/hoodi.go | 4 +- networkconfig/local-testnet.go | 4 +- networkconfig/mainnet.go | 4 +- networkconfig/sepolia.go | 4 +- networkconfig/ssv.go | 14 +- networkconfig/ssv_mock.go | 55 +++ networkconfig/test-network.go | 4 +- operator/duties/attester.go | 27 +- operator/duties/attester_test.go | 2 +- operator/duties/base_handler.go | 8 +- operator/duties/base_handler_mock.go | 9 +- operator/duties/committee.go | 12 +- operator/duties/committee_test.go | 44 +-- operator/duties/proposer.go | 18 +- operator/duties/scheduler.go | 38 +- operator/duties/scheduler_test.go | 29 +- operator/duties/sync_committee.go | 40 +-- operator/duties/sync_committee_test.go | 30 +- operator/duties/validatorregistration.go | 4 +- operator/duties/voluntary_exit.go | 4 +- operator/duties/voluntary_exit_test.go | 10 +- operator/fee_recipient/controller.go | 8 +- operator/fee_recipient/controller_test.go | 15 +- operator/node.go | 8 +- operator/validator/controller.go | 53 ++- operator/validator/controller_test.go | 5 - operator/validator/metadata/syncer.go | 11 +- operator/validator/metadata/syncer_test.go | 12 +- operator/validator/task_executor.go | 4 +- operator/validator/task_executor_test.go | 2 - protocol/v2/blockchain/beacon/client.go | 14 +- protocol/v2/blockchain/beacon/mock_client.go | 21 +- .../v2/blockchain/beacon/mocks/network.go | 337 ------------------ protocol/v2/blockchain/beacon/network.go | 163 --------- protocol/v2/blockchain/beacon/network_test.go | 19 - protocol/v2/qbft/roundtimer/timer.go | 27 +- protocol/v2/qbft/roundtimer/timer_test.go | 44 +-- protocol/v2/ssv/runner/aggregator.go | 13 +- protocol/v2/ssv/runner/committee.go | 19 +- protocol/v2/ssv/runner/proposer.go | 17 +- protocol/v2/ssv/runner/runner.go | 14 +- protocol/v2/ssv/runner/runner_signatures.go | 2 +- protocol/v2/ssv/runner/runner_validations.go | 2 +- .../ssv/runner/sync_committee_aggregator.go | 15 +- .../v2/ssv/runner/validator_registration.go | 13 +- protocol/v2/ssv/runner/voluntary_exit.go | 11 +- .../spectest/committee_msg_processing_type.go | 7 +- .../v2/ssv/spectest/msg_processing_type.go | 4 +- .../multi_start_new_runner_duty_type.go | 3 + protocol/v2/ssv/spectest/ssv_mapping_test.go | 9 +- protocol/v2/ssv/testing/runner.go | 42 +-- protocol/v2/ssv/validator/committee.go | 9 +- protocol/v2/ssv/validator/committee_queue.go | 3 +- .../ssv/validator/non_committee_validator.go | 13 +- protocol/v2/ssv/validator/opts.go | 2 +- protocol/v2/ssv/validator/startup.go | 2 +- protocol/v2/ssv/validator/validator.go | 4 +- protocol/v2/ssv/value_check.go | 18 +- utils/testutils.go | 40 +-- 94 files changed, 1224 insertions(+), 1094 deletions(-) create mode 100644 networkconfig/beacon_mock.go create mode 100644 networkconfig/config_mock.go create mode 100644 networkconfig/ssv_mock.go delete mode 100644 protocol/v2/blockchain/beacon/mocks/network.go delete mode 100644 protocol/v2/blockchain/beacon/network.go delete mode 100644 protocol/v2/blockchain/beacon/network_test.go diff --git a/beacon/goclient/aggregator.go b/beacon/goclient/aggregator.go index c9b24187c1..41935c8aff 100644 --- a/beacon/goclient/aggregator.go +++ b/beacon/goclient/aggregator.go @@ -34,7 +34,7 @@ func (gc *GoClient) SubmitAggregateSelectionProof(slot phase0.Slot, committeeInd if err != nil { return nil, DataVersionNil, fmt.Errorf("failed to get attestation data: %w", err) } - if gc.DataVersion(gc.network.EstimatedEpochAtSlot(attData.Slot)) < spec.DataVersionElectra { + if gc.DataVersion(gc.beaconConfig.EstimatedEpochAtSlot(attData.Slot)) < spec.DataVersionElectra { attData.Index = committeeIndex } @@ -193,9 +193,9 @@ func isAggregator(committeeCount uint64, slotSig []byte) (bool, error) { // waitToSlotTwoThirds waits until two-third of the slot has transpired (SECONDS_PER_SLOT * 2 / 3 seconds after the start of slot) func (gc *GoClient) waitToSlotTwoThirds(slot phase0.Slot) { - oneThird := gc.network.SlotDurationSec() / 3 /* one third of slot duration */ + oneThird := gc.beaconConfig.SlotDuration / 3 /* one third of slot duration */ - finalTime := gc.slotStartTime(slot).Add(2 * oneThird) + finalTime := gc.beaconConfig.GetSlotStartTime(slot).Add(2 * oneThird) wait := time.Until(finalTime) if wait <= 0 { return diff --git a/beacon/goclient/attest_test.go b/beacon/goclient/attest_test.go index f3e2523f63..4420d23255 100644 --- a/beacon/goclient/attest_test.go +++ b/beacon/goclient/attest_test.go @@ -15,10 +15,10 @@ import ( "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/sourcegraph/conc/pool" - "github.com/ssvlabs/ssv-spec/types" "github.com/stretchr/testify/require" "go.uber.org/zap" + "github.com/ssvlabs/ssv/networkconfig" operatordatastore "github.com/ssvlabs/ssv/operator/datastore" "github.com/ssvlabs/ssv/operator/slotticker" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" @@ -194,7 +194,7 @@ func TestGoClient_GetAttestationData_Simple(t *testing.T) { zap.NewNop(), beacon.Options{ Context: ctx, - Network: beacon.NewNetwork(types.MainNetwork), + BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: server.URL, CommonTimeout: 1 * time.Second, LongTimeout: 1 * time.Second, @@ -452,7 +452,7 @@ func createClient( client, err := New(zap.NewNop(), beacon.Options{ Context: ctx, - Network: beacon.NewNetwork(types.MainNetwork), + BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: beaconServerURL, CommonTimeout: defaultHardTimeout, LongTimeout: time.Second, diff --git a/beacon/goclient/events_test.go b/beacon/goclient/events_test.go index 0922372099..4c68cf1bf5 100644 --- a/beacon/goclient/events_test.go +++ b/beacon/goclient/events_test.go @@ -9,12 +9,12 @@ import ( "time" apiv1 "github.com/attestantio/go-eth2-client/api/v1" - "github.com/ssvlabs/ssv-spec/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "github.com/ssvlabs/ssv/beacon/goclient/tests" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) @@ -76,7 +76,7 @@ func eventsTestClient(t *testing.T, serverURL string) *GoClient { server, err := New(zap.NewNop(), beacon.Options{ BeaconNodeAddr: serverURL, Context: context.Background(), - Network: beacon.NewNetwork(types.MainNetwork), + BeaconConfig: networkconfig.Mainnet.BeaconConfig, }, tests.MockDataStore{}, tests.MockSlotTickerProvider) diff --git a/beacon/goclient/goclient.go b/beacon/goclient/goclient.go index 229b6fbace..a8e3e72f81 100644 --- a/beacon/goclient/goclient.go +++ b/beacon/goclient/goclient.go @@ -24,9 +24,9 @@ import ( "tailscale.com/util/singleflight" "github.com/ssvlabs/ssv/logging/fields" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/operator/slotticker" beaconprotocol "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" - "github.com/ssvlabs/ssv/utils/casts" ) const ( @@ -123,11 +123,11 @@ const ( // GoClient implementing Beacon struct type GoClient struct { - log *zap.Logger - ctx context.Context - network beaconprotocol.Network - clients []Client - multiClient MultiClient + log *zap.Logger + ctx context.Context + beaconConfig networkconfig.BeaconConfig + clients []Client + multiClient MultiClient specssv.VersionCalls syncDistanceTolerance phase0.Slot @@ -189,7 +189,9 @@ func New( operatorDataStore operatorDataStore, slotTickerProvider slotticker.Provider, ) (*GoClient, error) { - logger.Info("consensus client: connecting", fields.Address(opt.BeaconNodeAddr), fields.Network(string(opt.Network.BeaconNetwork))) + logger.Info("consensus client: connecting", + fields.Address(opt.BeaconNodeAddr), + fields.Network(opt.BeaconConfig.GetBeaconName())) commonTimeout := opt.CommonTimeout if commonTimeout == 0 { @@ -203,17 +205,17 @@ func New( client := &GoClient{ log: logger.Named("consensus_client"), ctx: opt.Context, - network: opt.Network, + beaconConfig: opt.BeaconConfig, syncDistanceTolerance: phase0.Slot(opt.SyncDistanceTolerance), operatorDataStore: operatorDataStore, registrations: map[phase0.BLSPubKey]*validatorRegistration{}, attestationDataCache: ttlcache.New( // we only fetch attestation data during the slot of the relevant duty (and never later), // hence caching it for 2 slots is sufficient - ttlcache.WithTTL[phase0.Slot, *phase0.AttestationData](2 * opt.Network.SlotDurationSec()), + ttlcache.WithTTL[phase0.Slot, *phase0.AttestationData](2 * opt.BeaconConfig.SlotDuration), ), blockRootToSlotCache: ttlcache.New(ttlcache.WithCapacity[phase0.Root, phase0.Slot]( - opt.Network.SlotsPerEpoch() * BlockRootToSlotCacheCapacityEpochs), + uint64(opt.BeaconConfig.SlotsPerEpoch) * BlockRootToSlotCacheCapacityEpochs), ), commonTimeout: commonTimeout, longTimeout: longTimeout, @@ -221,7 +223,7 @@ func New( weightedAttestationDataSoftTimeout: commonTimeout / 2, weightedAttestationDataHardTimeout: commonTimeout, supportedTopics: []EventTopic{EventTopicHead}, - genesisForkVersion: phase0.Version(opt.Network.ForkVersion()), + genesisForkVersion: opt.BeaconConfig.ForkVersion, // Initialize forks with FAR_FUTURE_EPOCH. ForkEpochAltair: math.MaxUint64, ForkEpochBellatrix: math.MaxUint64, @@ -372,7 +374,7 @@ func (gc *GoClient) singleClientHooks() *eth2clienthttp.Hooks { gc.ForkLock.RLock() gc.log.Info("retrieved fork epochs", zap.String("node_addr", s.Address()), - zap.Uint64("current_data_version", uint64(gc.DataVersion(gc.network.EstimatedCurrentEpoch()))), + zap.Uint64("current_data_version", uint64(gc.DataVersion(gc.beaconConfig.EstimatedCurrentEpoch()))), zap.Uint64("altair", uint64(gc.ForkEpochAltair)), zap.Uint64("bellatrix", uint64(gc.ForkEpochBellatrix)), zap.Uint64("capella", uint64(gc.ForkEpochCapella)), @@ -466,16 +468,3 @@ func (gc *GoClient) Healthy(ctx context.Context) error { return nil } - -// GetBeaconNetwork returns the beacon network the node is on -func (gc *GoClient) GetBeaconNetwork() spectypes.BeaconNetwork { - return gc.network.BeaconNetwork -} - -// SlotStartTime returns the start time in terms of its unix epoch -// value. -func (gc *GoClient) slotStartTime(slot phase0.Slot) time.Time { - duration := time.Second * casts.DurationFromUint64(uint64(slot)*uint64(gc.network.SlotDurationSec().Seconds())) - startTime := time.Unix(gc.network.MinGenesisTime(), 0).Add(duration) - return startTime -} diff --git a/beacon/goclient/goclient_test.go b/beacon/goclient/goclient_test.go index 8793c58be0..9b69a7202a 100644 --- a/beacon/goclient/goclient_test.go +++ b/beacon/goclient/goclient_test.go @@ -11,11 +11,11 @@ import ( "github.com/attestantio/go-eth2-client/api" v1 "github.com/attestantio/go-eth2-client/api/v1" "github.com/attestantio/go-eth2-client/spec/phase0" - "github.com/ssvlabs/ssv-spec/types" "github.com/stretchr/testify/require" "go.uber.org/zap" "github.com/ssvlabs/ssv/beacon/goclient/tests" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) @@ -157,11 +157,14 @@ func TestTimeouts(t *testing.T) { } func TestAssertSameGenesisVersionWhenSame(t *testing.T) { - networks := []types.BeaconNetwork{types.MainNetwork, types.HoleskyNetwork, types.PraterNetwork, types.BeaconTestNetwork} - - for _, network := range networks { - forkVersion := phase0.Version(beacon.NewNetwork(network).ForkVersion()) + networkConfigs := []networkconfig.NetworkConfig{ + networkconfig.Mainnet, + networkconfig.Holesky, + networkconfig.LocalTestnet, + networkconfig.TestNetwork, + } + for _, netCfg := range networkConfigs { ctx := context.Background() callback := func(r *http.Request, resp json.RawMessage) (json.RawMessage, error) { if r.URL.Path == "/eth/v1/beacon/genesis" { @@ -169,7 +172,7 @@ func TestAssertSameGenesisVersionWhenSame(t *testing.T) { "genesis_time": "1606824023", "genesis_validators_root": "0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95", "genesis_fork_version": "%s" - }}`, forkVersion)) + }}`, netCfg.ForkVersion)) return resp2, nil } return resp, nil @@ -177,47 +180,46 @@ func TestAssertSameGenesisVersionWhenSame(t *testing.T) { server := tests.MockServer(callback) defer server.Close() - t.Run(fmt.Sprintf("When genesis versions are the same (%s)", string(network)), func(t *testing.T) { - c, err := mockClientWithNetwork(ctx, server.URL, 100*time.Millisecond, 500*time.Millisecond, network) + t.Run(fmt.Sprintf("When genesis versions are the same (%s)", netCfg.BeaconName), func(t *testing.T) { + c, err := mockClientWithNetwork(ctx, server.URL, 100*time.Millisecond, 500*time.Millisecond, netCfg.BeaconConfig) require.NoError(t, err, "failed to create client") client := c.(*GoClient) - output, err := client.assertSameGenesisVersion(forkVersion) - require.Equal(t, forkVersion, output) + output, err := client.assertSameGenesisVersion(netCfg.ForkVersion) + require.Equal(t, netCfg.ForkVersion, output) require.NoError(t, err, "failed to assert same genesis version: %s", err) }) } } func TestAssertSameGenesisVersionWhenDifferent(t *testing.T) { - network := types.MainNetwork - networkVersion := phase0.Version(beacon.NewNetwork(network).ForkVersion()) + networkConfig := networkconfig.Mainnet t.Run("When genesis versions are different", func(t *testing.T) { ctx := context.Background() server := tests.MockServer(nil) defer server.Close() - c, err := mockClientWithNetwork(ctx, server.URL, 100*time.Millisecond, 500*time.Millisecond, network) + c, err := mockClientWithNetwork(ctx, server.URL, 100*time.Millisecond, 500*time.Millisecond, networkConfig.BeaconConfig) require.NoError(t, err, "failed to create client") client := c.(*GoClient) forkVersion := phase0.Version{0x01, 0x02, 0x03, 0x04} output, err := client.assertSameGenesisVersion(forkVersion) - require.Equal(t, networkVersion, output, "expected genesis version to be %s, got %s", networkVersion, output) + require.Equal(t, networkConfig.ForkVersion, output, "expected genesis version to be %s, got %s", networkConfig.ForkVersion, output) require.Error(t, err, "expected error when genesis versions are different") }) } func mockClient(ctx context.Context, serverURL string, commonTimeout, longTimeout time.Duration) (beacon.BeaconNode, error) { - return mockClientWithNetwork(ctx, serverURL, commonTimeout, longTimeout, types.MainNetwork) + return mockClientWithNetwork(ctx, serverURL, commonTimeout, longTimeout, networkconfig.Mainnet.BeaconConfig) } -func mockClientWithNetwork(ctx context.Context, serverURL string, commonTimeout, longTimeout time.Duration, network types.BeaconNetwork) (beacon.BeaconNode, error) { +func mockClientWithNetwork(ctx context.Context, serverURL string, commonTimeout, longTimeout time.Duration, beaconConfig networkconfig.BeaconConfig) (beacon.BeaconNode, error) { return New( zap.NewNop(), beacon.Options{ Context: ctx, - Network: beacon.NewNetwork(network), + BeaconConfig: beaconConfig, BeaconNodeAddr: serverURL, CommonTimeout: commonTimeout, LongTimeout: longTimeout, diff --git a/beacon/goclient/signing.go b/beacon/goclient/signing.go index 48f8b2942b..363f5efb41 100644 --- a/beacon/goclient/signing.go +++ b/beacon/goclient/signing.go @@ -99,7 +99,7 @@ func (gc *GoClient) DomainData(epoch phase0.Epoch, domain phase0.DomainType) (ph case spectypes.DomainApplicationBuilder: // no domain for DomainApplicationBuilder. need to create. https://github.com/bloxapp/ethereum2-validator/blob/v2-main/signing/keyvault/signer.go#L62 var appDomain phase0.Domain forkData := phase0.ForkData{ - CurrentVersion: gc.network.ForkVersion(), + CurrentVersion: gc.beaconConfig.ForkVersion, GenesisValidatorsRoot: phase0.Root{}, } root, err := forkData.HashTreeRoot() diff --git a/beacon/goclient/sync_committee_contribution.go b/beacon/goclient/sync_committee_contribution.go index 0c6cc1b57e..d594065bcc 100644 --- a/beacon/goclient/sync_committee_contribution.go +++ b/beacon/goclient/sync_committee_contribution.go @@ -144,8 +144,8 @@ func (gc *GoClient) SubmitSignedContributionAndProof(contribution *altair.Signed // waitForOneThirdSlotDuration waits until one-third of the slot has transpired (SECONDS_PER_SLOT / 3 seconds after the start of slot) func (gc *GoClient) waitForOneThirdSlotDuration(slot phase0.Slot) { - delay := gc.network.SlotDurationSec() / 3 /* a third of the slot duration */ - finalTime := gc.slotStartTime(slot).Add(delay) + delay := gc.beaconConfig.SlotDuration / 3 /* a third of the slot duration */ + finalTime := gc.beaconConfig.GetSlotStartTime(slot).Add(delay) wait := time.Until(finalTime) if wait <= 0 { return diff --git a/beacon/goclient/validator.go b/beacon/goclient/validator.go index 0663616b5b..698e1c2f9c 100644 --- a/beacon/goclient/validator.go +++ b/beacon/goclient/validator.go @@ -98,9 +98,9 @@ func (gc *GoClient) registrationSubmitter(slotTickerProvider slotticker.Provider } // Distribute the registrations evenly across the epoch based on the pubkeys. - slotInEpoch := uint64(currentSlot) % gc.network.SlotsPerEpoch() + slotInEpoch := currentSlot % gc.beaconConfig.SlotsPerEpoch validatorDescriptor := xxhash.Sum64(validatorPk[:]) - shouldSubmit := validatorDescriptor%gc.network.SlotsPerEpoch() == slotInEpoch + shouldSubmit := phase0.Slot(validatorDescriptor)%gc.beaconConfig.SlotsPerEpoch == slotInEpoch if r.new || shouldSubmit { r.new = false diff --git a/cli/flags/export_keys_from_mnemonic.go b/cli/flags/export_keys_from_mnemonic.go index 153ddd12f6..8219d925b3 100644 --- a/cli/flags/export_keys_from_mnemonic.go +++ b/cli/flags/export_keys_from_mnemonic.go @@ -36,7 +36,7 @@ func GetKeyIndexFlagValue(c *cobra.Command) (uint64, error) { // AddNetworkFlag adds the network key flag to the command func AddNetworkFlag(c *cobra.Command) { - cliflag.AddPersistentStringFlag(c, networkFlag, string(networkconfig.Mainnet.Beacon.GetBeaconNetwork()), "network", false) + cliflag.AddPersistentStringFlag(c, networkFlag, networkconfig.Mainnet.GetBeaconName(), "network", false) } // GetNetworkFlag gets the network key flag from the command diff --git a/cli/operator/node.go b/cli/operator/node.go index ec91f026db..3e68f43476 100644 --- a/cli/operator/node.go +++ b/cli/operator/node.go @@ -134,7 +134,7 @@ var StartNodeCmd = &cobra.Command{ logger.Fatal("could not setup network", zap.Error(err)) } cfg.DBOptions.Ctx = cmd.Context() - db, err := setupDB(logger, networkConfig.Beacon.GetNetwork()) + db, err := setupDB(logger, networkConfig.BeaconConfig) if err != nil { logger.Fatal("could not setup db", zap.Error(err)) } @@ -202,7 +202,7 @@ var StartNodeCmd = &cobra.Command{ } cfg.ConsensusClient.Context = cmd.Context() - cfg.ConsensusClient.Network = networkConfig.Beacon.GetNetwork() + cfg.ConsensusClient.BeaconConfig = networkConfig.BeaconConfig consensusClient := setupConsensusClient(logger, operatorDataStore, slotTickerProvider) @@ -282,7 +282,7 @@ var StartNodeCmd = &cobra.Command{ cfg.SSVOptions.DB = db cfg.SSVOptions.BeaconNode = consensusClient cfg.SSVOptions.ExecutionClient = executionClient - cfg.SSVOptions.Network = networkConfig + cfg.SSVOptions.NetworkConfig = networkConfig cfg.SSVOptions.P2PNetwork = p2pNetwork cfg.SSVOptions.ValidatorOptions.NetworkConfig = networkConfig cfg.SSVOptions.ValidatorOptions.Context = cmd.Context() @@ -324,7 +324,7 @@ var StartNodeCmd = &cobra.Command{ if cfg.SSVOptions.ValidatorOptions.Exporter { retain := cfg.SSVOptions.ValidatorOptions.ExporterRetainSlots - threshold := cfg.SSVOptions.Network.EstimatedCurrentSlot() + threshold := cfg.SSVOptions.NetworkConfig.EstimatedCurrentSlot() initSlotPruning(cmd.Context(), logger, storageMap, slotTickerProvider, threshold, retain) } @@ -348,7 +348,7 @@ var StartNodeCmd = &cobra.Command{ logger, nodeStorage.Shares(), nodeStorage.ValidatorStore().WithOperatorID(operatorDataStore.GetOperatorID), - networkConfig.Beacon, + networkConfig.BeaconConfig, consensusClient, fixedSubnets, metadata.WithSyncInterval(cfg.SSVOptions.ValidatorOptions.MetadataUpdateInterval), @@ -552,7 +552,7 @@ func setupGlobal() (*zap.Logger, error) { return zap.L(), nil } -func setupDB(logger *zap.Logger, eth2Network beaconprotocol.Network) (*kv.BadgerDB, error) { +func setupDB(logger *zap.Logger, beaconConfig networkconfig.Beacon) (*kv.BadgerDB, error) { db, err := kv.New(logger, cfg.DBOptions) if err != nil { return nil, errors.Wrap(err, "failed to open db") @@ -566,9 +566,9 @@ func setupDB(logger *zap.Logger, eth2Network beaconprotocol.Network) (*kv.Badger } migrationOpts := migrations.Options{ - Db: db, - DbPath: cfg.DBOptions.Path, - Network: eth2Network, + Db: db, + DbPath: cfg.DBOptions.Path, + BeaconConfig: beaconConfig, } applied, err := migrations.Run(cfg.DBOptions.Ctx, logger, migrationOpts) if err != nil { @@ -699,7 +699,7 @@ func setupSSVNetwork(logger *zap.Logger) (networkconfig.NetworkConfig, error) { fields.Network(networkConfig.Name), fields.Domain(networkConfig.DomainType), zap.String("nodeType", nodeType), - zap.Any("beaconNetwork", networkConfig.Beacon.GetNetwork().BeaconNetwork), + zap.Any("beaconNetwork", networkConfig.GetBeaconName()), zap.Uint64("genesisEpoch", uint64(networkConfig.GenesisEpoch)), zap.String("registryContract", networkConfig.RegistryContractAddr), ) diff --git a/ekm/eth_key_manager_signer.go b/ekm/eth_key_manager_signer.go index de2961c8f5..803022aee7 100644 --- a/ekm/eth_key_manager_signer.go +++ b/ekm/eth_key_manager_signer.go @@ -43,6 +43,7 @@ const ( ) type ethKeyManagerSigner struct { + netCfg networkconfig.Network wallet core.Wallet walletLock *sync.RWMutex signer signer.ValidatorSigner @@ -68,8 +69,13 @@ type KeyManager interface { } // NewETHKeyManagerSigner returns a new instance of ethKeyManagerSigner -func NewETHKeyManagerSigner(logger *zap.Logger, db basedb.Database, network networkconfig.NetworkConfig, encryptionKey string) (KeyManager, error) { - signerStore := NewSignerStorage(db, network.Beacon, logger) +func NewETHKeyManagerSigner( + logger *zap.Logger, + db basedb.Database, + netCfg networkconfig.Network, + encryptionKey string, +) (KeyManager, error) { + signerStore := NewSignerStorage(db, netCfg, logger) if encryptionKey != "" { err := signerStore.SetEncryptionKey(encryptionKey) if err != nil { @@ -96,14 +102,15 @@ func NewETHKeyManagerSigner(logger *zap.Logger, db basedb.Database, network netw } slashingProtector := slashingprotection.NewNormalProtection(signerStore) - beaconSigner := signer.NewSimpleSigner(wallet, slashingProtector, core.Network(network.Beacon.GetBeaconNetwork())) + beaconSigner := signer.NewSimpleSigner(wallet, slashingProtector, core.Network(netCfg.GetBeaconName())) return ðKeyManagerSigner{ + netCfg: netCfg, wallet: wallet, walletLock: &sync.RWMutex{}, signer: beaconSigner, storage: signerStore, - domain: network.DomainType, + domain: netCfg.GetDomainType(), slashingProtector: slashingProtector, }, nil } @@ -310,7 +317,7 @@ func (km *ethKeyManagerSigner) RemoveShare(pubKey string) error { // BumpSlashingProtection updates the slashing protection data for a given public key. func (km *ethKeyManagerSigner) BumpSlashingProtection(pubKey []byte) error { - currentSlot := km.storage.BeaconNetwork().EstimatedCurrentSlot() + currentSlot := km.netCfg.EstimatedCurrentSlot() // Update highest attestation data for slashing protection. if err := km.updateHighestAttestation(pubKey, currentSlot); err != nil { @@ -333,7 +340,7 @@ func (km *ethKeyManagerSigner) updateHighestAttestation(pubKey []byte, slot phas return fmt.Errorf("could not retrieve highest attestation: %w", err) } - currentEpoch := km.storage.BeaconNetwork().EstimatedEpochAtSlot(slot) + currentEpoch := km.netCfg.EstimatedEpochAtSlot(slot) minimalSP := km.computeMinimalAttestationSP(currentEpoch) // Check if the retrieved highest attestation data is valid and not outdated. diff --git a/ekm/signer_key_manager_test.go b/ekm/signer_key_manager_test.go index 481c669560..accf28b81c 100644 --- a/ekm/signer_key_manager_test.go +++ b/ekm/signer_key_manager_test.go @@ -39,7 +39,7 @@ const ( pk2Str = "8796fafa576051372030a75c41caafea149e4368aebaca21c9f90d9974b3973d5cee7d7874e4ec9ec59fb2c8945b3e01" ) -func testKeyManager(t *testing.T, network *networkconfig.NetworkConfig) KeyManager { +func testKeyManager(t *testing.T, network networkconfig.Network) KeyManager { threshold.Init() logger := logging.TestLogger(t) @@ -48,12 +48,10 @@ func testKeyManager(t *testing.T, network *networkconfig.NetworkConfig) KeyManag require.NoError(t, err) if network == nil { - network = &networkconfig.NetworkConfig{} - network.Beacon = utils.SetupMockBeaconNetwork(t, nil) - network.DomainType = networkconfig.TestNetwork.DomainType + network = utils.SetupMockNetworkConfig(t, networkconfig.TestNetwork.DomainType, nil) } - km, err := NewETHKeyManagerSigner(logger, db, *network, "") + km, err := NewETHKeyManagerSigner(logger, db, network, "") require.NoError(t, err) sk1 := &bls.SecretKey{} @@ -85,7 +83,7 @@ func TestEncryptedKeyManager(t *testing.T) { db, err := getBaseStorage(logger) require.NoError(t, err) - signerStorage := NewSignerStorage(db, networkconfig.TestNetwork.Beacon.GetNetwork(), logger) + signerStorage := NewSignerStorage(db, networkconfig.TestNetwork.BeaconConfig, logger) err = signerStorage.SetEncryptionKey(encryptionKey) require.NoError(t, err) diff --git a/ekm/signer_storage.go b/ekm/signer_storage.go index 0c39fa31be..74a469c83e 100644 --- a/ekm/signer_storage.go +++ b/ekm/signer_storage.go @@ -21,7 +21,7 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/logging" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" + "github.com/ssvlabs/ssv/networkconfig" registry "github.com/ssvlabs/ssv/protocol/v2/blockchain/eth1" "github.com/ssvlabs/ssv/storage/basedb" ) @@ -47,24 +47,22 @@ type Storage interface { SetEncryptionKey(newKey string) error ListAccountsTxn(r basedb.Reader) ([]core.ValidatorAccount, error) SaveAccountTxn(rw basedb.ReadWriter, account core.ValidatorAccount) error - - BeaconNetwork() beacon.BeaconNetwork } type storage struct { db basedb.Database - network beacon.BeaconNetwork + beaconConfig networkconfig.Beacon encryptionKey []byte logger *zap.Logger // struct logger is used because core.Storage does not support passing a logger lock sync.RWMutex } -func NewSignerStorage(db basedb.Database, network beacon.BeaconNetwork, logger *zap.Logger) Storage { +func NewSignerStorage(db basedb.Database, beaconConfig networkconfig.Beacon, logger *zap.Logger) Storage { return &storage{ - db: db, - network: network, - logger: logger.Named(logging.NameSignerStorage).Named(fmt.Sprintf("%sstorage", prefix)), - lock: sync.RWMutex{}, + db: db, + beaconConfig: beaconConfig, + logger: logger.Named(logging.NameSignerStorage).Named(fmt.Sprintf("%sstorage", prefix)), + lock: sync.RWMutex{}, } } @@ -89,7 +87,7 @@ func (s *storage) DropRegistryData() error { } func (s *storage) objPrefix(obj string) []byte { - return []byte(string(s.network.GetBeaconNetwork()) + obj) + return []byte(s.beaconConfig.GetBeaconName() + obj) } // Name returns storage name. @@ -99,7 +97,7 @@ func (s *storage) Name() string { // Network returns the network storage is related to. func (s *storage) Network() core.Network { - return core.Network(s.network.GetBeaconNetwork()) + return core.Network(s.beaconConfig.GetBeaconName()) } // SaveWallet stores the given wallet. @@ -409,7 +407,3 @@ func (s *storage) decrypt(data []byte) ([]byte, error) { // #nosec G407 false positive: https://github.com/securego/gosec/issues/1211 return gcm.Open(nil, nonce, ciphertext, nil) } - -func (s *storage) BeaconNetwork() beacon.BeaconNetwork { - return s.network -} diff --git a/ekm/signer_storage_test.go b/ekm/signer_storage_test.go index 5427b21782..e4fb11921b 100644 --- a/ekm/signer_storage_test.go +++ b/ekm/signer_storage_test.go @@ -39,7 +39,7 @@ func newStorageForTest(t *testing.T) (Storage, func()) { return nil, func() {} } - s := NewSignerStorage(db, networkconfig.TestNetwork.Beacon.GetNetwork(), logger) + s := NewSignerStorage(db, networkconfig.TestNetwork.BeaconConfig, logger) return s, func() { db.Close() } diff --git a/eth/eventhandler/event_handler.go b/eth/eventhandler/event_handler.go index fc64ef054a..f8618ff3d2 100644 --- a/eth/eventhandler/event_handler.go +++ b/eth/eventhandler/event_handler.go @@ -66,7 +66,7 @@ type EventHandler struct { nodeStorage nodestorage.Storage taskExecutor taskExecutor eventParser eventparser.Parser - networkConfig networkconfig.NetworkConfig + networkConfig networkconfig.Network operatorDataStore operatordatastore.OperatorDataStore operatorDecrypter keys.OperatorDecrypter keyManager ekm.KeyManager @@ -81,7 +81,7 @@ func New( nodeStorage nodestorage.Storage, eventParser eventparser.Parser, taskExecutor taskExecutor, - networkConfig networkconfig.NetworkConfig, + networkConfig networkconfig.Network, operatorDataStore operatordatastore.OperatorDataStore, operatorDecrypter keys.OperatorDecrypter, keyManager ekm.KeyManager, diff --git a/eth/eventhandler/event_handler_test.go b/eth/eventhandler/event_handler_test.go index fdbb1ddd3f..0479649a99 100644 --- a/eth/eventhandler/event_handler_test.go +++ b/eth/eventhandler/event_handler_test.go @@ -70,9 +70,7 @@ func TestHandleBlockEventsStream(t *testing.T) { operatorsCount += uint64(len(ops)) currentSlot := &utils.SlotValue{} - mockBeaconNetwork := utils.SetupMockBeaconNetwork(t, currentSlot) - mockNetworkConfig := &networkconfig.NetworkConfig{} - mockNetworkConfig.Beacon = mockBeaconNetwork + mockNetworkConfig := utils.SetupMockNetworkConfig(t, networkconfig.TestNetwork.DomainType, currentSlot) eh, _, err := setupEventHandler(t, ctx, logger, mockNetworkConfig, ops[0], false) if err != nil { @@ -967,8 +965,8 @@ func TestHandleBlockEventsStream(t *testing.T) { require.True(t, found) require.NotNil(t, highestAttestation) - require.Equal(t, highestAttestation.Source.Epoch, mockBeaconNetwork.EstimatedEpochAtSlot(currentSlot.GetSlot())-1) - require.Equal(t, highestAttestation.Target.Epoch, mockBeaconNetwork.EstimatedEpochAtSlot(currentSlot.GetSlot())) + require.Equal(t, highestAttestation.Source.Epoch, mockNetworkConfig.EstimatedEpochAtSlot(currentSlot.GetSlot())-1) + require.Equal(t, highestAttestation.Target.Epoch, mockNetworkConfig.EstimatedEpochAtSlot(currentSlot.GetSlot())) highestProposal, found, err := eh.keyManager.(ekm.StorageProvider).RetrieveHighestProposal(sharePubKey) require.NoError(t, err) @@ -1016,8 +1014,8 @@ func TestHandleBlockEventsStream(t *testing.T) { require.NoError(t, err) require.True(t, found) require.NotNil(t, highestAttestation) - require.Equal(t, highestAttestation.Source.Epoch, mockBeaconNetwork.EstimatedEpochAtSlot(currentSlot.GetSlot())-1) - require.Equal(t, highestAttestation.Target.Epoch, mockBeaconNetwork.EstimatedEpochAtSlot(currentSlot.GetSlot())) + require.Equal(t, highestAttestation.Source.Epoch, mockNetworkConfig.EstimatedEpochAtSlot(currentSlot.GetSlot())-1) + require.Equal(t, highestAttestation.Target.Epoch, mockNetworkConfig.EstimatedEpochAtSlot(currentSlot.GetSlot())) highestProposal, found, err := eh.keyManager.(ekm.StorageProvider).RetrieveHighestProposal(sharePubKey) require.NoError(t, err) @@ -1107,8 +1105,8 @@ func TestHandleBlockEventsStream(t *testing.T) { require.NoError(t, err) require.True(t, found) require.NotNil(t, highestAttestation) - require.Greater(t, highestAttestation.Source.Epoch, mockBeaconNetwork.EstimatedEpochAtSlot(currentSlot.GetSlot())-1) - require.Greater(t, highestAttestation.Target.Epoch, mockBeaconNetwork.EstimatedEpochAtSlot(currentSlot.GetSlot())) + require.Greater(t, highestAttestation.Source.Epoch, mockNetworkConfig.EstimatedEpochAtSlot(currentSlot.GetSlot())-1) + require.Greater(t, highestAttestation.Target.Epoch, mockNetworkConfig.EstimatedEpochAtSlot(currentSlot.GetSlot())) highestProposal, found, err := eh.keyManager.(ekm.StorageProvider).RetrieveHighestProposal(sharePubKey) require.NoError(t, err) @@ -1347,7 +1345,7 @@ func TestHandleBlockEventsStream(t *testing.T) { }) } -func setupEventHandler(t *testing.T, ctx context.Context, logger *zap.Logger, network *networkconfig.NetworkConfig, operator *testOperator, useMockCtrl bool) (*EventHandler, *mocks.MockController, error) { +func setupEventHandler(t *testing.T, ctx context.Context, logger *zap.Logger, network networkconfig.Network, operator *testOperator, useMockCtrl bool) (*EventHandler, *mocks.MockController, error) { db, err := kv.NewInMemory(logger, basedb.Options{ Ctx: ctx, }) @@ -1359,11 +1357,10 @@ func setupEventHandler(t *testing.T, ctx context.Context, logger *zap.Logger, ne operatorDataStore := operatordatastore.New(operatorData) if network == nil { - network = &networkconfig.NetworkConfig{} - network.Beacon = utils.SetupMockBeaconNetwork(t, &utils.SlotValue{}) + network = utils.SetupMockNetworkConfig(t, networkconfig.TestNetwork.DomainType, &utils.SlotValue{}) } - keyManager, err := ekm.NewETHKeyManagerSigner(logger, db, *network, "") + keyManager, err := ekm.NewETHKeyManagerSigner(logger, db, network, "") if err != nil { return nil, nil, err } @@ -1386,7 +1383,7 @@ func setupEventHandler(t *testing.T, ctx context.Context, logger *zap.Logger, ne nodeStorage, parser, validatorCtrl, - *network, + network, operatorDataStore, operator.privateKey, keyManager, @@ -1407,7 +1404,7 @@ func setupEventHandler(t *testing.T, ctx context.Context, logger *zap.Logger, ne bc := beacon.NewMockBeaconNode(ctrl) validatorCtrl := validator.NewController(logger, validator.ControllerOptions{ Context: ctx, - NetworkConfig: *network, + NetworkConfig: network, DB: db, RegistryStorage: nodeStorage, BeaconSigner: keyManager, @@ -1425,7 +1422,7 @@ func setupEventHandler(t *testing.T, ctx context.Context, logger *zap.Logger, ne nodeStorage, parser, validatorCtrl, - *network, + network, operatorDataStore, operator.privateKey, keyManager, diff --git a/eth/eventhandler/handlers.go b/eth/eventhandler/handlers.go index 7f5c836d7f..fdf7c86a4f 100644 --- a/eth/eventhandler/handlers.go +++ b/eth/eventhandler/handlers.go @@ -329,7 +329,7 @@ func (eh *EventHandler) validatorAddedEventToShare( } } - validatorShare.DomainType = eh.networkConfig.DomainType + validatorShare.DomainType = eh.networkConfig.GetDomainType() validatorShare.Committee = shareMembers return &validatorShare, shareSecret, nil diff --git a/go.mod b/go.mod index eec41973b1..8fe6246a82 100644 --- a/go.mod +++ b/go.mod @@ -254,3 +254,5 @@ require ( replace github.com/google/flatbuffers => github.com/google/flatbuffers v1.11.0 replace github.com/dgraph-io/ristretto => github.com/dgraph-io/ristretto v0.1.1-0.20211108053508-297c39e6640f + +replace github.com/ssvlabs/eth2-key-manager => github.com/ssvlabs/eth2-key-manager v1.5.4-0.20250321004656-079eb6f1f94f diff --git a/go.sum b/go.sum index 892d99847a..6092466ce2 100644 --- a/go.sum +++ b/go.sum @@ -742,8 +742,8 @@ github.com/spf13/pflag v1.0.1-0.20170901120850-7aff26db30c1/go.mod h1:DYY7MBk1bd github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= -github.com/ssvlabs/eth2-key-manager v1.5.2 h1:gF+8FJkoV1VXpVCPspyVW/Jdky0kt9Pndk88W8ePqx8= -github.com/ssvlabs/eth2-key-manager v1.5.2/go.mod h1:yeUzAP+SBJXgeXPiGBrLeLuHIQCpeJZV7Jz3Fwzm/zk= +github.com/ssvlabs/eth2-key-manager v1.5.4-0.20250321004656-079eb6f1f94f h1:b1+GWbY6rNsg1Yl5yzunIfrtMkkyqt4cRbBn+mdf484= +github.com/ssvlabs/eth2-key-manager v1.5.4-0.20250321004656-079eb6f1f94f/go.mod h1:yeUzAP+SBJXgeXPiGBrLeLuHIQCpeJZV7Jz3Fwzm/zk= github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo8= github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= diff --git a/message/validation/common_checks.go b/message/validation/common_checks.go index 1b8c5227e7..b355d531c0 100644 --- a/message/validation/common_checks.go +++ b/message/validation/common_checks.go @@ -40,7 +40,7 @@ func (mv *messageValidator) messageLateness(slot phase0.Slot, role spectypes.Run case spectypes.RoleProposer, spectypes.RoleSyncCommitteeContribution: ttl = 1 + LateSlotAllowance case spectypes.RoleCommittee, spectypes.RoleAggregator: - ttl = mv.netCfg.SlotsPerEpoch + LateSlotAllowance + ttl = mv.netCfg.GetSlotsPerEpoch() + LateSlotAllowance case spectypes.RoleValidatorRegistration, spectypes.RoleVoluntaryExit: return 0 } @@ -90,7 +90,7 @@ func (mv *messageValidator) dutyLimit(msgID spectypes.MessageID, slot phase0.Slo case spectypes.RoleCommittee: validatorIndexCount := uint64(len(validatorIndices)) - slotsPerEpoch := mv.netCfg.SlotsPerEpoch + slotsPerEpoch := mv.netCfg.GetSlotsPerEpoch() // Skip duty search if validators * 2 exceeds slots per epoch, // as the maximum duties per epoch is capped at the number of slots. diff --git a/message/validation/signed_ssv_message.go b/message/validation/signed_ssv_message.go index 1a18e200f9..f186d70fc0 100644 --- a/message/validation/signed_ssv_message.go +++ b/message/validation/signed_ssv_message.go @@ -113,7 +113,7 @@ func (mv *messageValidator) validateSSVMessage(ssvMessage *spectypes.SSVMessage) } // Rule: If domain is different then self domain - domain := mv.netCfg.DomainType + domain := mv.netCfg.GetDomainType() if !bytes.Equal(ssvMessage.GetID().GetDomain(), domain[:]) { err := ErrWrongDomain err.got = hex.EncodeToString(ssvMessage.MsgID.GetDomain()) diff --git a/message/validation/validation.go b/message/validation/validation.go index c59c245f91..ee69de8171 100644 --- a/message/validation/validation.go +++ b/message/validation/validation.go @@ -35,7 +35,7 @@ type MessageValidator interface { type messageValidator struct { logger *zap.Logger - netCfg networkconfig.NetworkConfig + netCfg networkconfig.Network pectraForkEpoch phase0.Epoch consensusStateIndex map[consensusID]*consensusState @@ -62,7 +62,7 @@ type messageValidator struct { // New returns a new MessageValidator with the given network configuration and options. func New( - netCfg networkconfig.NetworkConfig, + netCfg networkconfig.Network, validatorStore storage.ValidatorStore, dutyStore *dutystore.Store, signatureVerifier signatureverifier.SignatureVerifier, @@ -211,7 +211,7 @@ func (mv *messageValidator) getValidationLock(messageID spectypes.MessageID) *sy lock := &sync.Mutex{} - epochDuration := time.Duration(mv.netCfg.SlotsPerEpoch) * mv.netCfg.SlotDuration // #nosec G115 - slots per epoch never exceeds math.MaxInt64 + epochDuration := time.Duration(mv.netCfg.GetSlotsPerEpoch()) * mv.netCfg.GetSlotDuration() // #nosec G115 - slots per epoch never exceeds math.MaxInt64 // validationLockTTL specifies how much time a particular validation lock is meant to // live. It must be large enough for validation lock to never expire while we still are // expecting to process messages targeting that same validation lock. For a message @@ -305,7 +305,7 @@ func (mv *messageValidator) consensusState(messageID spectypes.MessageID) *conse if _, ok := mv.consensusStateIndex[id]; !ok { cs := &consensusState{ state: make(map[spectypes.OperatorID]*OperatorState), - storedSlotCount: mv.netCfg.SlotsPerEpoch * 2, // store last two epochs to calculate duty count + storedSlotCount: mv.netCfg.GetSlotsPerEpoch() * 2, // store last two epochs to calculate duty count } mv.consensusStateIndex[id] = cs } diff --git a/message/validation/validation_test.go b/message/validation/validation_test.go index 90a94e9264..028f906afb 100644 --- a/message/validation/validation_test.go +++ b/message/validation/validation_test.go @@ -628,8 +628,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("accept pre-consensus randao message when epoch duties are not set", func(t *testing.T) { currentSlot := &utils.SlotValue{} - mockNetworkConfig := networkconfig.NetworkConfig{} - mockNetworkConfig.Beacon = utils.SetupMockBeaconNetwork(t, currentSlot) + mockNetworkConfig := utils.SetupMockNetworkConfig(t, networkconfig.TestNetwork.DomainType, currentSlot) const epoch = 1 currentSlot.SetSlot(netCfg.FirstSlotAtEpoch(epoch)) @@ -645,7 +644,7 @@ func Test_ValidateSSVMessage(t *testing.T) { dutyExecutorID := shares.active.ValidatorPubKey[:] ssvMessage := &spectypes.SSVMessage{ MsgType: spectypes.SSVPartialSignatureMsgType, - MsgID: spectypes.NewMsgID(mockNetworkConfig.DomainType, dutyExecutorID, spectypes.RoleProposer), + MsgID: spectypes.NewMsgID(mockNetworkConfig.GetDomainType(), dutyExecutorID, spectypes.RoleProposer), Data: encodedMessages, } @@ -662,8 +661,7 @@ func Test_ValidateSSVMessage(t *testing.T) { t.Run("reject pre-consensus randao message when epoch duties are set", func(t *testing.T) { currentSlot := &utils.SlotValue{} - mockNetworkConfig := networkconfig.NetworkConfig{} - mockNetworkConfig.Beacon = utils.SetupMockBeaconNetwork(t, currentSlot) + mockNetworkConfig := utils.SetupMockNetworkConfig(t, networkconfig.TestNetwork.DomainType, currentSlot) const epoch = 1 currentSlot.SetSlot(mockNetworkConfig.FirstSlotAtEpoch(epoch)) @@ -680,7 +678,7 @@ func Test_ValidateSSVMessage(t *testing.T) { dutyExecutorID := shares.active.ValidatorPubKey[:] ssvMessage := &spectypes.SSVMessage{ MsgType: spectypes.SSVPartialSignatureMsgType, - MsgID: spectypes.NewMsgID(mockNetworkConfig.DomainType, dutyExecutorID, spectypes.RoleProposer), + MsgID: spectypes.NewMsgID(mockNetworkConfig.GetDomainType(), dutyExecutorID, spectypes.RoleProposer), Data: encodedMessages, } diff --git a/migrations/migrations.go b/migrations/migrations.go index abb0461fca..7b3a177572 100644 --- a/migrations/migrations.go +++ b/migrations/migrations.go @@ -10,8 +10,8 @@ import ( "github.com/ssvlabs/ssv/ekm" "github.com/ssvlabs/ssv/logging/fields" + "github.com/ssvlabs/ssv/networkconfig" operatorstorage "github.com/ssvlabs/ssv/operator/storage" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" "github.com/ssvlabs/ssv/storage/basedb" ) @@ -53,10 +53,10 @@ type Migrations []Migration // Options is the options for running migrations. type Options struct { - Db basedb.Database - NodeStorage operatorstorage.Storage - DbPath string - Network beacon.Network + Db basedb.Database + NodeStorage operatorstorage.Storage + DbPath string + BeaconConfig networkconfig.Beacon } // nolint @@ -66,7 +66,7 @@ func (o Options) nodeStorage(logger *zap.Logger) (operatorstorage.Storage, error // nolint func (o Options) signerStorage(logger *zap.Logger) ekm.Storage { - return ekm.NewSignerStorage(o.Db, o.Network, logger) + return ekm.NewSignerStorage(o.Db, o.BeaconConfig, logger) } // Run executes the migrations. diff --git a/network/discovery/dv5_service_test.go b/network/discovery/dv5_service_test.go index 2c4c0622be..a6ce738826 100644 --- a/network/discovery/dv5_service_test.go +++ b/network/discovery/dv5_service_test.go @@ -19,15 +19,12 @@ import ( "github.com/ssvlabs/ssv/network/peers/connections/mock" "github.com/ssvlabs/ssv/network/records" "github.com/ssvlabs/ssv/networkconfig" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" "github.com/ssvlabs/ssv/utils" "github.com/ssvlabs/ssv/utils/ttl" ) var TestNetwork = networkconfig.NetworkConfig{ - BeaconConfig: networkconfig.BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.BeaconTestNetwork), - }, + BeaconConfig: networkconfig.TestNetwork.BeaconConfig, SSVConfig: networkconfig.SSVConfig{ DomainType: spectypes.DomainType{0x1, 0x2, 0x3, 0x4}, }, diff --git a/network/discovery/util_test.go b/network/discovery/util_test.go index f19b4cd163..aea6d9600f 100644 --- a/network/discovery/util_test.go +++ b/network/discovery/util_test.go @@ -95,11 +95,8 @@ func testingDiscovery(t *testing.T) *DiscV5Service { func testingNetConfigWithForkEpoch(forkEpoch phase0.Epoch) networkconfig.NetworkConfig { n := networkconfig.HoleskyStage return networkconfig.NetworkConfig{ - Name: n.Name, - BeaconConfig: networkconfig.BeaconConfig{ - Beacon: n.Beacon, - GenesisEpoch: n.GenesisEpoch, - }, + Name: n.Name, + BeaconConfig: n.BeaconConfig, SSVConfig: networkconfig.SSVConfig{ DomainType: n.DomainType, RegistrySyncOffset: n.RegistrySyncOffset, diff --git a/network/topics/msg_validator_test.go b/network/topics/msg_validator_test.go index 2a32000dde..fc8621c0cb 100644 --- a/network/topics/msg_validator_test.go +++ b/network/topics/msg_validator_test.go @@ -52,7 +52,7 @@ func TestMsgValidator(t *testing.T) { mv := validation.New(networkconfig.TestNetwork, ns.ValidatorStore(), dutystore.New(), signatureVerifier, phase0.Epoch(0), validation.WithLogger(logger)) require.NotNil(t, mv) - slot := networkconfig.TestNetwork.Beacon.GetBeaconNetwork().EstimatedCurrentSlot() + slot := networkconfig.TestNetwork.EstimatedCurrentSlot() operatorID := uint64(1) operatorPrivateKey := ks.OperatorKeys[operatorID] diff --git a/networkconfig/beacon.go b/networkconfig/beacon.go index 3edac5f76d..dc6270fcca 100644 --- a/networkconfig/beacon.go +++ b/networkconfig/beacon.go @@ -5,12 +5,33 @@ import ( "time" "github.com/attestantio/go-eth2-client/spec/phase0" - - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) +//go:generate go tool -modfile=../tool.mod mockgen -package=networkconfig -destination=./beacon_mock.go -source=./beacon.go + +type Beacon interface { + GetSlotStartTime(slot phase0.Slot) time.Time + GetSlotEndTime(slot phase0.Slot) time.Time + EstimatedCurrentSlot() phase0.Slot + EstimatedSlotAtTime(time time.Time) phase0.Slot + EstimatedCurrentEpoch() phase0.Epoch + EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch + IsFirstSlotOfEpoch(slot phase0.Slot) bool + GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot + EpochsPerSyncCommitteePeriod() phase0.Epoch + EstimatedSyncCommitteePeriodAtEpoch(epoch phase0.Epoch) uint64 + FirstEpochOfSyncPeriod(period uint64) phase0.Epoch + LastSlotOfSyncPeriod(period uint64) phase0.Slot + FirstSlotAtEpoch(epoch phase0.Epoch) phase0.Slot + EpochStartTime(epoch phase0.Epoch) time.Time + EstimatedTimeAtSlot(slot phase0.Slot) time.Time + GetSlotDuration() time.Duration + GetSlotsPerEpoch() phase0.Slot + GetBeaconName() string +} + type BeaconConfig struct { - Beacon beacon.BeaconNetwork + BeaconName string GenesisEpoch phase0.Epoch SlotDuration time.Duration SlotsPerEpoch phase0.Slot @@ -109,3 +130,15 @@ func (b BeaconConfig) EstimatedTimeAtSlot(slot phase0.Slot) time.Time { d := time.Duration(slot) * b.SlotDuration // #nosec G115: slot cannot exceed math.MaxInt64 return b.GenesisTime.Add(d) } + +func (b BeaconConfig) GetSlotDuration() time.Duration { + return b.SlotDuration +} + +func (b BeaconConfig) GetSlotsPerEpoch() phase0.Slot { + return b.SlotsPerEpoch +} + +func (b BeaconConfig) GetBeaconName() string { + return b.BeaconName +} diff --git a/networkconfig/beacon_mock.go b/networkconfig/beacon_mock.go new file mode 100644 index 0000000000..ec5fce2d2b --- /dev/null +++ b/networkconfig/beacon_mock.go @@ -0,0 +1,294 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./beacon.go +// +// Generated by this command: +// +// mockgen -package=networkconfig -destination=./beacon_mock.go -source=./beacon.go +// + +// Package networkconfig is a generated GoMock package. +package networkconfig + +import ( + reflect "reflect" + time "time" + + phase0 "github.com/attestantio/go-eth2-client/spec/phase0" + gomock "go.uber.org/mock/gomock" +) + +// MockBeacon is a mock of Beacon interface. +type MockBeacon struct { + ctrl *gomock.Controller + recorder *MockBeaconMockRecorder + isgomock struct{} +} + +// MockBeaconMockRecorder is the mock recorder for MockBeacon. +type MockBeaconMockRecorder struct { + mock *MockBeacon +} + +// NewMockBeacon creates a new mock instance. +func NewMockBeacon(ctrl *gomock.Controller) *MockBeacon { + mock := &MockBeacon{ctrl: ctrl} + mock.recorder = &MockBeaconMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBeacon) EXPECT() *MockBeaconMockRecorder { + return m.recorder +} + +// EpochStartTime mocks base method. +func (m *MockBeacon) EpochStartTime(epoch phase0.Epoch) time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EpochStartTime", epoch) + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// EpochStartTime indicates an expected call of EpochStartTime. +func (mr *MockBeaconMockRecorder) EpochStartTime(epoch any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochStartTime", reflect.TypeOf((*MockBeacon)(nil).EpochStartTime), epoch) +} + +// EpochsPerSyncCommitteePeriod mocks base method. +func (m *MockBeacon) EpochsPerSyncCommitteePeriod() phase0.Epoch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EpochsPerSyncCommitteePeriod") + ret0, _ := ret[0].(phase0.Epoch) + return ret0 +} + +// EpochsPerSyncCommitteePeriod indicates an expected call of EpochsPerSyncCommitteePeriod. +func (mr *MockBeaconMockRecorder) EpochsPerSyncCommitteePeriod() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochsPerSyncCommitteePeriod", reflect.TypeOf((*MockBeacon)(nil).EpochsPerSyncCommitteePeriod)) +} + +// EstimatedCurrentEpoch mocks base method. +func (m *MockBeacon) EstimatedCurrentEpoch() phase0.Epoch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedCurrentEpoch") + ret0, _ := ret[0].(phase0.Epoch) + return ret0 +} + +// EstimatedCurrentEpoch indicates an expected call of EstimatedCurrentEpoch. +func (mr *MockBeaconMockRecorder) EstimatedCurrentEpoch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedCurrentEpoch", reflect.TypeOf((*MockBeacon)(nil).EstimatedCurrentEpoch)) +} + +// EstimatedCurrentSlot mocks base method. +func (m *MockBeacon) EstimatedCurrentSlot() phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedCurrentSlot") + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// EstimatedCurrentSlot indicates an expected call of EstimatedCurrentSlot. +func (mr *MockBeaconMockRecorder) EstimatedCurrentSlot() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedCurrentSlot", reflect.TypeOf((*MockBeacon)(nil).EstimatedCurrentSlot)) +} + +// EstimatedEpochAtSlot mocks base method. +func (m *MockBeacon) EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedEpochAtSlot", slot) + ret0, _ := ret[0].(phase0.Epoch) + return ret0 +} + +// EstimatedEpochAtSlot indicates an expected call of EstimatedEpochAtSlot. +func (mr *MockBeaconMockRecorder) EstimatedEpochAtSlot(slot any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedEpochAtSlot", reflect.TypeOf((*MockBeacon)(nil).EstimatedEpochAtSlot), slot) +} + +// EstimatedSlotAtTime mocks base method. +func (m *MockBeacon) EstimatedSlotAtTime(arg0 time.Time) phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedSlotAtTime", arg0) + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// EstimatedSlotAtTime indicates an expected call of EstimatedSlotAtTime. +func (mr *MockBeaconMockRecorder) EstimatedSlotAtTime(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedSlotAtTime", reflect.TypeOf((*MockBeacon)(nil).EstimatedSlotAtTime), arg0) +} + +// EstimatedSyncCommitteePeriodAtEpoch mocks base method. +func (m *MockBeacon) EstimatedSyncCommitteePeriodAtEpoch(epoch phase0.Epoch) uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedSyncCommitteePeriodAtEpoch", epoch) + ret0, _ := ret[0].(uint64) + return ret0 +} + +// EstimatedSyncCommitteePeriodAtEpoch indicates an expected call of EstimatedSyncCommitteePeriodAtEpoch. +func (mr *MockBeaconMockRecorder) EstimatedSyncCommitteePeriodAtEpoch(epoch any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedSyncCommitteePeriodAtEpoch", reflect.TypeOf((*MockBeacon)(nil).EstimatedSyncCommitteePeriodAtEpoch), epoch) +} + +// EstimatedTimeAtSlot mocks base method. +func (m *MockBeacon) EstimatedTimeAtSlot(slot phase0.Slot) time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedTimeAtSlot", slot) + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// EstimatedTimeAtSlot indicates an expected call of EstimatedTimeAtSlot. +func (mr *MockBeaconMockRecorder) EstimatedTimeAtSlot(slot any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedTimeAtSlot", reflect.TypeOf((*MockBeacon)(nil).EstimatedTimeAtSlot), slot) +} + +// FirstEpochOfSyncPeriod mocks base method. +func (m *MockBeacon) FirstEpochOfSyncPeriod(period uint64) phase0.Epoch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FirstEpochOfSyncPeriod", period) + ret0, _ := ret[0].(phase0.Epoch) + return ret0 +} + +// FirstEpochOfSyncPeriod indicates an expected call of FirstEpochOfSyncPeriod. +func (mr *MockBeaconMockRecorder) FirstEpochOfSyncPeriod(period any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FirstEpochOfSyncPeriod", reflect.TypeOf((*MockBeacon)(nil).FirstEpochOfSyncPeriod), period) +} + +// FirstSlotAtEpoch mocks base method. +func (m *MockBeacon) FirstSlotAtEpoch(epoch phase0.Epoch) phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FirstSlotAtEpoch", epoch) + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// FirstSlotAtEpoch indicates an expected call of FirstSlotAtEpoch. +func (mr *MockBeaconMockRecorder) FirstSlotAtEpoch(epoch any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FirstSlotAtEpoch", reflect.TypeOf((*MockBeacon)(nil).FirstSlotAtEpoch), epoch) +} + +// GetBeaconName mocks base method. +func (m *MockBeacon) GetBeaconName() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBeaconName") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetBeaconName indicates an expected call of GetBeaconName. +func (mr *MockBeaconMockRecorder) GetBeaconName() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBeaconName", reflect.TypeOf((*MockBeacon)(nil).GetBeaconName)) +} + +// GetEpochFirstSlot mocks base method. +func (m *MockBeacon) GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEpochFirstSlot", epoch) + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// GetEpochFirstSlot indicates an expected call of GetEpochFirstSlot. +func (mr *MockBeaconMockRecorder) GetEpochFirstSlot(epoch any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEpochFirstSlot", reflect.TypeOf((*MockBeacon)(nil).GetEpochFirstSlot), epoch) +} + +// GetSlotDuration mocks base method. +func (m *MockBeacon) GetSlotDuration() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSlotDuration") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// GetSlotDuration indicates an expected call of GetSlotDuration. +func (mr *MockBeaconMockRecorder) GetSlotDuration() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotDuration", reflect.TypeOf((*MockBeacon)(nil).GetSlotDuration)) +} + +// GetSlotEndTime mocks base method. +func (m *MockBeacon) GetSlotEndTime(slot phase0.Slot) time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSlotEndTime", slot) + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// GetSlotEndTime indicates an expected call of GetSlotEndTime. +func (mr *MockBeaconMockRecorder) GetSlotEndTime(slot any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotEndTime", reflect.TypeOf((*MockBeacon)(nil).GetSlotEndTime), slot) +} + +// GetSlotStartTime mocks base method. +func (m *MockBeacon) GetSlotStartTime(slot phase0.Slot) time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSlotStartTime", slot) + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// GetSlotStartTime indicates an expected call of GetSlotStartTime. +func (mr *MockBeaconMockRecorder) GetSlotStartTime(slot any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotStartTime", reflect.TypeOf((*MockBeacon)(nil).GetSlotStartTime), slot) +} + +// GetSlotsPerEpoch mocks base method. +func (m *MockBeacon) GetSlotsPerEpoch() phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSlotsPerEpoch") + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// GetSlotsPerEpoch indicates an expected call of GetSlotsPerEpoch. +func (mr *MockBeaconMockRecorder) GetSlotsPerEpoch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotsPerEpoch", reflect.TypeOf((*MockBeacon)(nil).GetSlotsPerEpoch)) +} + +// IsFirstSlotOfEpoch mocks base method. +func (m *MockBeacon) IsFirstSlotOfEpoch(slot phase0.Slot) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsFirstSlotOfEpoch", slot) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsFirstSlotOfEpoch indicates an expected call of IsFirstSlotOfEpoch. +func (mr *MockBeaconMockRecorder) IsFirstSlotOfEpoch(slot any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsFirstSlotOfEpoch", reflect.TypeOf((*MockBeacon)(nil).IsFirstSlotOfEpoch), slot) +} + +// LastSlotOfSyncPeriod mocks base method. +func (m *MockBeacon) LastSlotOfSyncPeriod(period uint64) phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LastSlotOfSyncPeriod", period) + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// LastSlotOfSyncPeriod indicates an expected call of LastSlotOfSyncPeriod. +func (mr *MockBeaconMockRecorder) LastSlotOfSyncPeriod(period any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastSlotOfSyncPeriod", reflect.TypeOf((*MockBeacon)(nil).LastSlotOfSyncPeriod), period) +} diff --git a/networkconfig/config.go b/networkconfig/config.go index c208a2469b..55f96360c4 100644 --- a/networkconfig/config.go +++ b/networkconfig/config.go @@ -5,6 +5,8 @@ import ( "fmt" ) +//go:generate go tool -modfile=../tool.mod mockgen -package=networkconfig -destination=./config_mock.go -source=./config.go + var SupportedConfigs = map[string]NetworkConfig{ Mainnet.Name: Mainnet, Holesky.Name: Holesky, @@ -26,6 +28,12 @@ func GetNetworkConfigByName(name string) (NetworkConfig, error) { return NetworkConfig{}, fmt.Errorf("network not supported: %v", name) } +type Network interface { + NetworkName() string + Beacon + SSV +} + type NetworkConfig struct { Name string BeaconConfig diff --git a/networkconfig/config_mock.go b/networkconfig/config_mock.go new file mode 100644 index 0000000000..3945cbd1c5 --- /dev/null +++ b/networkconfig/config_mock.go @@ -0,0 +1,323 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./config.go +// +// Generated by this command: +// +// mockgen -package=networkconfig -destination=./config_mock.go -source=./config.go +// + +// Package networkconfig is a generated GoMock package. +package networkconfig + +import ( + reflect "reflect" + time "time" + + phase0 "github.com/attestantio/go-eth2-client/spec/phase0" + types "github.com/ssvlabs/ssv-spec/types" + gomock "go.uber.org/mock/gomock" +) + +// MockNetwork is a mock of Network interface. +type MockNetwork struct { + ctrl *gomock.Controller + recorder *MockNetworkMockRecorder + isgomock struct{} +} + +// MockNetworkMockRecorder is the mock recorder for MockNetwork. +type MockNetworkMockRecorder struct { + mock *MockNetwork +} + +// NewMockNetwork creates a new mock instance. +func NewMockNetwork(ctrl *gomock.Controller) *MockNetwork { + mock := &MockNetwork{ctrl: ctrl} + mock.recorder = &MockNetworkMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockNetwork) EXPECT() *MockNetworkMockRecorder { + return m.recorder +} + +// EpochStartTime mocks base method. +func (m *MockNetwork) EpochStartTime(epoch phase0.Epoch) time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EpochStartTime", epoch) + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// EpochStartTime indicates an expected call of EpochStartTime. +func (mr *MockNetworkMockRecorder) EpochStartTime(epoch any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochStartTime", reflect.TypeOf((*MockNetwork)(nil).EpochStartTime), epoch) +} + +// EpochsPerSyncCommitteePeriod mocks base method. +func (m *MockNetwork) EpochsPerSyncCommitteePeriod() phase0.Epoch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EpochsPerSyncCommitteePeriod") + ret0, _ := ret[0].(phase0.Epoch) + return ret0 +} + +// EpochsPerSyncCommitteePeriod indicates an expected call of EpochsPerSyncCommitteePeriod. +func (mr *MockNetworkMockRecorder) EpochsPerSyncCommitteePeriod() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochsPerSyncCommitteePeriod", reflect.TypeOf((*MockNetwork)(nil).EpochsPerSyncCommitteePeriod)) +} + +// EstimatedCurrentEpoch mocks base method. +func (m *MockNetwork) EstimatedCurrentEpoch() phase0.Epoch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedCurrentEpoch") + ret0, _ := ret[0].(phase0.Epoch) + return ret0 +} + +// EstimatedCurrentEpoch indicates an expected call of EstimatedCurrentEpoch. +func (mr *MockNetworkMockRecorder) EstimatedCurrentEpoch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedCurrentEpoch", reflect.TypeOf((*MockNetwork)(nil).EstimatedCurrentEpoch)) +} + +// EstimatedCurrentSlot mocks base method. +func (m *MockNetwork) EstimatedCurrentSlot() phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedCurrentSlot") + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// EstimatedCurrentSlot indicates an expected call of EstimatedCurrentSlot. +func (mr *MockNetworkMockRecorder) EstimatedCurrentSlot() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedCurrentSlot", reflect.TypeOf((*MockNetwork)(nil).EstimatedCurrentSlot)) +} + +// EstimatedEpochAtSlot mocks base method. +func (m *MockNetwork) EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedEpochAtSlot", slot) + ret0, _ := ret[0].(phase0.Epoch) + return ret0 +} + +// EstimatedEpochAtSlot indicates an expected call of EstimatedEpochAtSlot. +func (mr *MockNetworkMockRecorder) EstimatedEpochAtSlot(slot any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedEpochAtSlot", reflect.TypeOf((*MockNetwork)(nil).EstimatedEpochAtSlot), slot) +} + +// EstimatedSlotAtTime mocks base method. +func (m *MockNetwork) EstimatedSlotAtTime(arg0 time.Time) phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedSlotAtTime", arg0) + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// EstimatedSlotAtTime indicates an expected call of EstimatedSlotAtTime. +func (mr *MockNetworkMockRecorder) EstimatedSlotAtTime(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedSlotAtTime", reflect.TypeOf((*MockNetwork)(nil).EstimatedSlotAtTime), arg0) +} + +// EstimatedSyncCommitteePeriodAtEpoch mocks base method. +func (m *MockNetwork) EstimatedSyncCommitteePeriodAtEpoch(epoch phase0.Epoch) uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedSyncCommitteePeriodAtEpoch", epoch) + ret0, _ := ret[0].(uint64) + return ret0 +} + +// EstimatedSyncCommitteePeriodAtEpoch indicates an expected call of EstimatedSyncCommitteePeriodAtEpoch. +func (mr *MockNetworkMockRecorder) EstimatedSyncCommitteePeriodAtEpoch(epoch any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedSyncCommitteePeriodAtEpoch", reflect.TypeOf((*MockNetwork)(nil).EstimatedSyncCommitteePeriodAtEpoch), epoch) +} + +// EstimatedTimeAtSlot mocks base method. +func (m *MockNetwork) EstimatedTimeAtSlot(slot phase0.Slot) time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EstimatedTimeAtSlot", slot) + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// EstimatedTimeAtSlot indicates an expected call of EstimatedTimeAtSlot. +func (mr *MockNetworkMockRecorder) EstimatedTimeAtSlot(slot any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedTimeAtSlot", reflect.TypeOf((*MockNetwork)(nil).EstimatedTimeAtSlot), slot) +} + +// FirstEpochOfSyncPeriod mocks base method. +func (m *MockNetwork) FirstEpochOfSyncPeriod(period uint64) phase0.Epoch { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FirstEpochOfSyncPeriod", period) + ret0, _ := ret[0].(phase0.Epoch) + return ret0 +} + +// FirstEpochOfSyncPeriod indicates an expected call of FirstEpochOfSyncPeriod. +func (mr *MockNetworkMockRecorder) FirstEpochOfSyncPeriod(period any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FirstEpochOfSyncPeriod", reflect.TypeOf((*MockNetwork)(nil).FirstEpochOfSyncPeriod), period) +} + +// FirstSlotAtEpoch mocks base method. +func (m *MockNetwork) FirstSlotAtEpoch(epoch phase0.Epoch) phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FirstSlotAtEpoch", epoch) + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// FirstSlotAtEpoch indicates an expected call of FirstSlotAtEpoch. +func (mr *MockNetworkMockRecorder) FirstSlotAtEpoch(epoch any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FirstSlotAtEpoch", reflect.TypeOf((*MockNetwork)(nil).FirstSlotAtEpoch), epoch) +} + +// GetBeaconName mocks base method. +func (m *MockNetwork) GetBeaconName() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBeaconName") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetBeaconName indicates an expected call of GetBeaconName. +func (mr *MockNetworkMockRecorder) GetBeaconName() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBeaconName", reflect.TypeOf((*MockNetwork)(nil).GetBeaconName)) +} + +// GetDomainType mocks base method. +func (m *MockNetwork) GetDomainType() types.DomainType { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDomainType") + ret0, _ := ret[0].(types.DomainType) + return ret0 +} + +// GetDomainType indicates an expected call of GetDomainType. +func (mr *MockNetworkMockRecorder) GetDomainType() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDomainType", reflect.TypeOf((*MockNetwork)(nil).GetDomainType)) +} + +// GetEpochFirstSlot mocks base method. +func (m *MockNetwork) GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEpochFirstSlot", epoch) + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// GetEpochFirstSlot indicates an expected call of GetEpochFirstSlot. +func (mr *MockNetworkMockRecorder) GetEpochFirstSlot(epoch any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEpochFirstSlot", reflect.TypeOf((*MockNetwork)(nil).GetEpochFirstSlot), epoch) +} + +// GetSlotDuration mocks base method. +func (m *MockNetwork) GetSlotDuration() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSlotDuration") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// GetSlotDuration indicates an expected call of GetSlotDuration. +func (mr *MockNetworkMockRecorder) GetSlotDuration() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotDuration", reflect.TypeOf((*MockNetwork)(nil).GetSlotDuration)) +} + +// GetSlotEndTime mocks base method. +func (m *MockNetwork) GetSlotEndTime(slot phase0.Slot) time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSlotEndTime", slot) + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// GetSlotEndTime indicates an expected call of GetSlotEndTime. +func (mr *MockNetworkMockRecorder) GetSlotEndTime(slot any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotEndTime", reflect.TypeOf((*MockNetwork)(nil).GetSlotEndTime), slot) +} + +// GetSlotStartTime mocks base method. +func (m *MockNetwork) GetSlotStartTime(slot phase0.Slot) time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSlotStartTime", slot) + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// GetSlotStartTime indicates an expected call of GetSlotStartTime. +func (mr *MockNetworkMockRecorder) GetSlotStartTime(slot any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotStartTime", reflect.TypeOf((*MockNetwork)(nil).GetSlotStartTime), slot) +} + +// GetSlotsPerEpoch mocks base method. +func (m *MockNetwork) GetSlotsPerEpoch() phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSlotsPerEpoch") + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// GetSlotsPerEpoch indicates an expected call of GetSlotsPerEpoch. +func (mr *MockNetworkMockRecorder) GetSlotsPerEpoch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotsPerEpoch", reflect.TypeOf((*MockNetwork)(nil).GetSlotsPerEpoch)) +} + +// IsFirstSlotOfEpoch mocks base method. +func (m *MockNetwork) IsFirstSlotOfEpoch(slot phase0.Slot) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsFirstSlotOfEpoch", slot) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsFirstSlotOfEpoch indicates an expected call of IsFirstSlotOfEpoch. +func (mr *MockNetworkMockRecorder) IsFirstSlotOfEpoch(slot any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsFirstSlotOfEpoch", reflect.TypeOf((*MockNetwork)(nil).IsFirstSlotOfEpoch), slot) +} + +// LastSlotOfSyncPeriod mocks base method. +func (m *MockNetwork) LastSlotOfSyncPeriod(period uint64) phase0.Slot { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LastSlotOfSyncPeriod", period) + ret0, _ := ret[0].(phase0.Slot) + return ret0 +} + +// LastSlotOfSyncPeriod indicates an expected call of LastSlotOfSyncPeriod. +func (mr *MockNetworkMockRecorder) LastSlotOfSyncPeriod(period any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastSlotOfSyncPeriod", reflect.TypeOf((*MockNetwork)(nil).LastSlotOfSyncPeriod), period) +} + +// NetworkName mocks base method. +func (m *MockNetwork) NetworkName() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NetworkName") + ret0, _ := ret[0].(string) + return ret0 +} + +// NetworkName indicates an expected call of NetworkName. +func (mr *MockNetworkMockRecorder) NetworkName() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkName", reflect.TypeOf((*MockNetwork)(nil).NetworkName)) +} diff --git a/networkconfig/holesky-e2e.go b/networkconfig/holesky-e2e.go index 344a3d1d88..852b3c94b5 100644 --- a/networkconfig/holesky-e2e.go +++ b/networkconfig/holesky-e2e.go @@ -6,14 +6,12 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" - - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) var HoleskyE2E = NetworkConfig{ Name: "holesky-e2e", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + BeaconName: string(spectypes.HoleskyNetwork), GenesisEpoch: 1, SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), SlotsPerEpoch: phase0.Slot(spectypes.HoleskyNetwork.SlotsPerEpoch()), diff --git a/networkconfig/holesky-stage.go b/networkconfig/holesky-stage.go index e8b1f5841b..87c904a013 100644 --- a/networkconfig/holesky-stage.go +++ b/networkconfig/holesky-stage.go @@ -6,14 +6,12 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" - - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) var HoleskyStage = NetworkConfig{ Name: "holesky-stage", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + BeaconName: string(spectypes.HoleskyNetwork), GenesisEpoch: 1, SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), SlotsPerEpoch: phase0.Slot(spectypes.HoleskyNetwork.SlotsPerEpoch()), diff --git a/networkconfig/holesky.go b/networkconfig/holesky.go index a0037109b0..d1974200d6 100644 --- a/networkconfig/holesky.go +++ b/networkconfig/holesky.go @@ -6,14 +6,12 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" - - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) var Holesky = NetworkConfig{ Name: "holesky", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + BeaconName: string(spectypes.HoleskyNetwork), GenesisEpoch: 1, SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), SlotsPerEpoch: phase0.Slot(spectypes.HoleskyNetwork.SlotsPerEpoch()), diff --git a/networkconfig/hoodi-stage.go b/networkconfig/hoodi-stage.go index 4cf52822f6..12a013aeff 100644 --- a/networkconfig/hoodi-stage.go +++ b/networkconfig/hoodi-stage.go @@ -6,14 +6,12 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" - - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) var HoodiStage = NetworkConfig{ Name: "hoodi-stage", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), + BeaconName: string(spectypes.HoleskyNetwork), GenesisEpoch: 1, SlotDuration: spectypes.HoodiNetwork.SlotDurationSec(), SlotsPerEpoch: phase0.Slot(spectypes.HoodiNetwork.SlotsPerEpoch()), diff --git a/networkconfig/hoodi.go b/networkconfig/hoodi.go index 83fb673985..e3a1987c83 100644 --- a/networkconfig/hoodi.go +++ b/networkconfig/hoodi.go @@ -6,14 +6,12 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" - - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) var Hoodi = NetworkConfig{ Name: "hoodi", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), + BeaconName: string(spectypes.HoodiNetwork), GenesisEpoch: 1, SlotDuration: spectypes.HoodiNetwork.SlotDurationSec(), SlotsPerEpoch: phase0.Slot(spectypes.HoodiNetwork.SlotsPerEpoch()), diff --git a/networkconfig/local-testnet.go b/networkconfig/local-testnet.go index d7001d638e..868151da9b 100644 --- a/networkconfig/local-testnet.go +++ b/networkconfig/local-testnet.go @@ -5,14 +5,12 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" - - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) var LocalTestnet = NetworkConfig{ Name: "local-testnet", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewLocalTestNetwork(spectypes.PraterNetwork), + BeaconName: string(spectypes.PraterNetwork), GenesisEpoch: 1, SlotDuration: spectypes.PraterNetwork.SlotDurationSec(), SlotsPerEpoch: phase0.Slot(spectypes.PraterNetwork.SlotsPerEpoch()), diff --git a/networkconfig/mainnet.go b/networkconfig/mainnet.go index 3dd994ba05..05f0432a59 100644 --- a/networkconfig/mainnet.go +++ b/networkconfig/mainnet.go @@ -6,14 +6,12 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" - - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) var Mainnet = NetworkConfig{ Name: "mainnet", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.MainNetwork), + BeaconName: string(spectypes.MainNetwork), GenesisEpoch: 218450, SlotDuration: spectypes.MainNetwork.SlotDurationSec(), SlotsPerEpoch: phase0.Slot(spectypes.MainNetwork.SlotsPerEpoch()), diff --git a/networkconfig/sepolia.go b/networkconfig/sepolia.go index da0be0866c..7eb7133b65 100644 --- a/networkconfig/sepolia.go +++ b/networkconfig/sepolia.go @@ -6,14 +6,12 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" - - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) var Sepolia = NetworkConfig{ Name: "sepolia", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.SepoliaNetwork), + BeaconName: string(spectypes.SepoliaNetwork), GenesisEpoch: 1, SlotDuration: spectypes.SepoliaNetwork.SlotDurationSec(), SlotsPerEpoch: phase0.Slot(spectypes.SepoliaNetwork.SlotsPerEpoch()), diff --git a/networkconfig/ssv.go b/networkconfig/ssv.go index 6ae33b78e9..fd47b58391 100644 --- a/networkconfig/ssv.go +++ b/networkconfig/ssv.go @@ -3,13 +3,23 @@ package networkconfig import ( "math/big" - spectypes "github.com/ssvlabs/ssv-spec/types" + "github.com/ssvlabs/ssv-spec/types" ) +//go:generate go tool -modfile=../tool.mod mockgen -package=networkconfig -destination=./ssv_mock.go -source=./ssv.go + +type SSV interface { + GetDomainType() types.DomainType // using spectypes.DomainType breaks mock generation +} + type SSVConfig struct { - DomainType spectypes.DomainType + DomainType types.DomainType RegistrySyncOffset *big.Int RegistryContractAddr string // TODO: ethcommon.Address Bootnodes []string DiscoveryProtocolID [6]byte } + +func (ssv SSVConfig) GetDomainType() types.DomainType { + return ssv.DomainType +} diff --git a/networkconfig/ssv_mock.go b/networkconfig/ssv_mock.go new file mode 100644 index 0000000000..8bccd1f876 --- /dev/null +++ b/networkconfig/ssv_mock.go @@ -0,0 +1,55 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./ssv.go +// +// Generated by this command: +// +// mockgen -package=networkconfig -destination=./ssv_mock.go -source=./ssv.go +// + +// Package networkconfig is a generated GoMock package. +package networkconfig + +import ( + reflect "reflect" + + types "github.com/ssvlabs/ssv-spec/types" + gomock "go.uber.org/mock/gomock" +) + +// MockSSV is a mock of SSV interface. +type MockSSV struct { + ctrl *gomock.Controller + recorder *MockSSVMockRecorder + isgomock struct{} +} + +// MockSSVMockRecorder is the mock recorder for MockSSV. +type MockSSVMockRecorder struct { + mock *MockSSV +} + +// NewMockSSV creates a new mock instance. +func NewMockSSV(ctrl *gomock.Controller) *MockSSV { + mock := &MockSSV{ctrl: ctrl} + mock.recorder = &MockSSVMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSSV) EXPECT() *MockSSVMockRecorder { + return m.recorder +} + +// GetDomainType mocks base method. +func (m *MockSSV) GetDomainType() types.DomainType { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDomainType") + ret0, _ := ret[0].(types.DomainType) + return ret0 +} + +// GetDomainType indicates an expected call of GetDomainType. +func (mr *MockSSVMockRecorder) GetDomainType() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDomainType", reflect.TypeOf((*MockSSV)(nil).GetDomainType)) +} diff --git a/networkconfig/test-network.go b/networkconfig/test-network.go index dee9cb1d77..19659cec16 100644 --- a/networkconfig/test-network.go +++ b/networkconfig/test-network.go @@ -6,14 +6,12 @@ import ( "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" - - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) var TestNetwork = NetworkConfig{ Name: "testnet", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.BeaconTestNetwork), + BeaconName: string(spectypes.BeaconTestNetwork), GenesisEpoch: 152834, SlotDuration: spectypes.BeaconTestNetwork.SlotDurationSec(), SlotsPerEpoch: phase0.Slot(spectypes.BeaconTestNetwork.SlotsPerEpoch()), diff --git a/operator/duties/attester.go b/operator/duties/attester.go index 547af7ab68..ec6c7bdfac 100644 --- a/operator/duties/attester.go +++ b/operator/duties/attester.go @@ -74,14 +74,14 @@ func (h *AttesterHandler) HandleDuties(ctx context.Context) { case <-next: slot := h.ticker.Slot() next = h.ticker.Next() - currentEpoch := h.network.EstimatedEpochAtSlot(slot) + currentEpoch := h.beaconConfig.EstimatedEpochAtSlot(slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, slot, slot%32+1) h.logger.Debug("🛠 ticker event", zap.String("epoch_slot_pos", buildStr)) h.processExecution(ctx, currentEpoch, slot) h.processFetching(ctx, currentEpoch, slot) - slotsPerEpoch := h.network.SlotsPerEpoch + slotsPerEpoch := h.beaconConfig.GetSlotsPerEpoch() // If we have reached the mid-point of the epoch, fetch the duties for the next epoch in the next slot. // This allows us to set them up at a time when the beacon node should be less busy. @@ -95,7 +95,7 @@ func (h *AttesterHandler) HandleDuties(ctx context.Context) { } case reorgEvent := <-h.reorg: - currentEpoch := h.network.EstimatedEpochAtSlot(reorgEvent.Slot) + currentEpoch := h.beaconConfig.EstimatedEpochAtSlot(reorgEvent.Slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, reorgEvent.Slot, reorgEvent.Slot%32+1) h.logger.Info("🔀 reorg event received", zap.String("epoch_slot_pos", buildStr), zap.Any("event", reorgEvent)) @@ -119,8 +119,8 @@ func (h *AttesterHandler) HandleDuties(ctx context.Context) { } case <-h.indicesChange: - slot := h.network.EstimatedCurrentSlot() - currentEpoch := h.network.EstimatedEpochAtSlot(slot) + slot := h.beaconConfig.EstimatedCurrentSlot() + currentEpoch := h.beaconConfig.EstimatedEpochAtSlot(slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, slot, slot%32+1) h.logger.Info("🔁 indices change received", zap.String("epoch_slot_pos", buildStr)) @@ -135,16 +135,16 @@ func (h *AttesterHandler) HandleDuties(ctx context.Context) { } func (h *AttesterHandler) HandleInitialDuties(ctx context.Context) { - ctx, cancel := context.WithTimeout(ctx, h.network.SlotDuration/2) + ctx, cancel := context.WithTimeout(ctx, h.beaconConfig.GetSlotDuration()/2) defer cancel() - slot := h.network.EstimatedCurrentSlot() - epoch := h.network.EstimatedEpochAtSlot(slot) + slot := h.beaconConfig.EstimatedCurrentSlot() + epoch := h.beaconConfig.EstimatedEpochAtSlot(slot) h.processFetching(ctx, epoch, slot) } func (h *AttesterHandler) processFetching(ctx context.Context, epoch phase0.Epoch, slot phase0.Slot) { - ctx, cancel := context.WithDeadline(ctx, h.network.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) + ctx, cancel := context.WithDeadline(ctx, h.beaconConfig.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) defer cancel() if h.fetchCurrentEpoch { @@ -248,8 +248,8 @@ func (h *AttesterHandler) toSpecDuty(duty *eth2apiv1.AttesterDuty, role spectype } func (h *AttesterHandler) shouldExecute(duty *eth2apiv1.AttesterDuty) bool { - currentSlot := h.network.EstimatedCurrentSlot() - currentEpoch := h.network.EstimatedEpochAtSlot(currentSlot) + currentSlot := h.beaconConfig.EstimatedCurrentSlot() + currentEpoch := h.beaconConfig.EstimatedEpochAtSlot(currentSlot) v, exists := h.validatorProvider.Validator(duty.PubKey[:]) if !exists { @@ -267,7 +267,7 @@ func (h *AttesterHandler) shouldExecute(duty *eth2apiv1.AttesterDuty) bool { } // execute task if slot already began and not pass 1 epoch - var attestationPropagationSlotRange = h.network.SlotsPerEpoch + var attestationPropagationSlotRange = h.beaconConfig.GetSlotsPerEpoch() if currentSlot >= duty.Slot && currentSlot-duty.Slot <= attestationPropagationSlotRange { return true } @@ -304,5 +304,6 @@ func toBeaconCommitteeSubscription(duty *eth2apiv1.AttesterDuty, role spectypes. } func (h *AttesterHandler) shouldFetchNexEpoch(slot phase0.Slot) bool { - return slot%h.network.SlotsPerEpoch > h.network.SlotsPerEpoch/2-2 + slotsPerEpoch := h.beaconConfig.GetSlotsPerEpoch() + return slot%slotsPerEpoch > slotsPerEpoch/2-2 } diff --git a/operator/duties/attester_test.go b/operator/duties/attester_test.go index b502dd02df..a3f731b0ec 100644 --- a/operator/duties/attester_test.go +++ b/operator/duties/attester_test.go @@ -888,7 +888,7 @@ func TestScheduler_Attester_Early_Block(t *testing.T) { } scheduler.HandleHeadEvent(logger)(e.Data.(*eth2apiv1.HeadEvent)) waitForDutiesExecution(t, logger, fetchDutiesCall, executeDutiesCall, timeout, expected) - require.Less(t, time.Since(startTime), scheduler.network.SlotDuration/3) + require.Less(t, time.Since(startTime), scheduler.beaconConfig.GetSlotDuration()/3) // Stop scheduler & wait for graceful exit. cancel() diff --git a/operator/duties/base_handler.go b/operator/duties/base_handler.go index bde0f436ac..bfbee074b6 100644 --- a/operator/duties/base_handler.go +++ b/operator/duties/base_handler.go @@ -17,7 +17,7 @@ type dutyHandler interface { logger *zap.Logger, beaconNode BeaconNode, executionClient ExecutionClient, - network networkconfig.NetworkConfig, + beaconConfig networkconfig.Beacon, validatorProvider ValidatorProvider, validatorController ValidatorController, dutiesExecutor DutiesExecutor, @@ -34,7 +34,7 @@ type baseHandler struct { logger *zap.Logger beaconNode BeaconNode executionClient ExecutionClient - network networkconfig.NetworkConfig + beaconConfig networkconfig.Beacon validatorProvider ValidatorProvider validatorController ValidatorController dutiesExecutor DutiesExecutor @@ -51,7 +51,7 @@ func (h *baseHandler) Setup( logger *zap.Logger, beaconNode BeaconNode, executionClient ExecutionClient, - network networkconfig.NetworkConfig, + beaconConfig networkconfig.Beacon, validatorProvider ValidatorProvider, validatorController ValidatorController, dutiesExecutor DutiesExecutor, @@ -62,7 +62,7 @@ func (h *baseHandler) Setup( h.logger = logger.With(zap.String("handler", name)) h.beaconNode = beaconNode h.executionClient = executionClient - h.network = network + h.beaconConfig = beaconConfig h.validatorProvider = validatorProvider h.validatorController = validatorController h.dutiesExecutor = dutiesExecutor diff --git a/operator/duties/base_handler_mock.go b/operator/duties/base_handler_mock.go index 512df18ddb..56b9037bab 100644 --- a/operator/duties/base_handler_mock.go +++ b/operator/duties/base_handler_mock.go @@ -23,6 +23,7 @@ import ( type MockdutyHandler struct { ctrl *gomock.Controller recorder *MockdutyHandlerMockRecorder + isgomock struct{} } // MockdutyHandlerMockRecorder is the mock recorder for MockdutyHandler. @@ -81,13 +82,13 @@ func (mr *MockdutyHandlerMockRecorder) Name() *gomock.Call { } // Setup mocks base method. -func (m *MockdutyHandler) Setup(name string, logger *zap.Logger, beaconNode BeaconNode, executionClient ExecutionClient, network networkconfig.NetworkConfig, validatorProvider ValidatorProvider, validatorController ValidatorController, dutiesExecutor DutiesExecutor, slotTickerProvider slotticker.Provider, reorgEvents chan ReorgEvent, indicesChange chan struct{}) { +func (m *MockdutyHandler) Setup(name string, logger *zap.Logger, beaconNode BeaconNode, executionClient ExecutionClient, beaconConfig networkconfig.Beacon, validatorProvider ValidatorProvider, validatorController ValidatorController, dutiesExecutor DutiesExecutor, slotTickerProvider slotticker.Provider, reorgEvents chan ReorgEvent, indicesChange chan struct{}) { m.ctrl.T.Helper() - m.ctrl.Call(m, "Setup", name, logger, beaconNode, executionClient, network, validatorProvider, validatorController, dutiesExecutor, slotTickerProvider, reorgEvents, indicesChange) + m.ctrl.Call(m, "Setup", name, logger, beaconNode, executionClient, beaconConfig, validatorProvider, validatorController, dutiesExecutor, slotTickerProvider, reorgEvents, indicesChange) } // Setup indicates an expected call of Setup. -func (mr *MockdutyHandlerMockRecorder) Setup(name, logger, beaconNode, executionClient, network, validatorProvider, validatorController, dutiesExecutor, slotTickerProvider, reorgEvents, indicesChange any) *gomock.Call { +func (mr *MockdutyHandlerMockRecorder) Setup(name, logger, beaconNode, executionClient, beaconConfig, validatorProvider, validatorController, dutiesExecutor, slotTickerProvider, reorgEvents, indicesChange any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Setup", reflect.TypeOf((*MockdutyHandler)(nil).Setup), name, logger, beaconNode, executionClient, network, validatorProvider, validatorController, dutiesExecutor, slotTickerProvider, reorgEvents, indicesChange) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Setup", reflect.TypeOf((*MockdutyHandler)(nil).Setup), name, logger, beaconNode, executionClient, beaconConfig, validatorProvider, validatorController, dutiesExecutor, slotTickerProvider, reorgEvents, indicesChange) } diff --git a/operator/duties/committee.go b/operator/duties/committee.go index 1bfab29c5f..6813f44f85 100644 --- a/operator/duties/committee.go +++ b/operator/duties/committee.go @@ -55,8 +55,8 @@ func (h *CommitteeHandler) HandleDuties(ctx context.Context) { case <-next: slot := h.ticker.Slot() next = h.ticker.Next() - epoch := h.network.EstimatedEpochAtSlot(slot) - period := h.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) + epoch := h.beaconConfig.EstimatedEpochAtSlot(slot) + period := h.beaconConfig.EstimatedSyncCommitteePeriodAtEpoch(epoch) buildStr := fmt.Sprintf("p%v-e%v-s%v-#%v", period, epoch, slot, slot%32+1) h.logger.Debug("🛠 ticker event", zap.String("period_epoch_slot_pos", buildStr)) @@ -168,14 +168,14 @@ func (h *CommitteeHandler) toSpecSyncDuty(duty *eth2apiv1.SyncCommitteeDuty, slo } func (h *CommitteeHandler) shouldExecuteAtt(duty *eth2apiv1.AttesterDuty) bool { - currentSlot := h.network.EstimatedCurrentSlot() + currentSlot := h.beaconConfig.EstimatedCurrentSlot() if participates := h.canParticipate(duty.PubKey[:], currentSlot); !participates { return false } // execute task if slot already began and not pass 1 epoch - var attestationPropagationSlotRange = h.network.SlotsPerEpoch + var attestationPropagationSlotRange = h.beaconConfig.GetSlotsPerEpoch() if currentSlot >= duty.Slot && currentSlot-duty.Slot <= attestationPropagationSlotRange { return true } @@ -187,7 +187,7 @@ func (h *CommitteeHandler) shouldExecuteAtt(duty *eth2apiv1.AttesterDuty) bool { } func (h *CommitteeHandler) shouldExecuteSync(duty *eth2apiv1.SyncCommitteeDuty, slot phase0.Slot) bool { - currentSlot := h.network.EstimatedCurrentSlot() + currentSlot := h.beaconConfig.EstimatedCurrentSlot() if participates := h.canParticipate(duty.PubKey[:], currentSlot); !participates { return false @@ -205,7 +205,7 @@ func (h *CommitteeHandler) shouldExecuteSync(duty *eth2apiv1.SyncCommitteeDuty, } func (h *CommitteeHandler) canParticipate(pubKey []byte, currentSlot phase0.Slot) bool { - currentEpoch := h.network.EstimatedEpochAtSlot(currentSlot) + currentEpoch := h.beaconConfig.EstimatedEpochAtSlot(currentSlot) v, exists := h.validatorProvider.Validator(pubKey) if !exists { diff --git a/operator/duties/committee_test.go b/operator/duties/committee_test.go index 8b9422aca9..eca85e4787 100644 --- a/operator/duties/committee_test.go +++ b/operator/duties/committee_test.go @@ -12,8 +12,8 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/operator/duties/dutystore" - mocknetwork "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon/mocks" ssvtypes "github.com/ssvlabs/ssv/protocol/v2/types" "github.com/ssvlabs/ssv/utils/hashmap" ) @@ -28,30 +28,30 @@ func setupCommitteeDutiesMock( fetchDutiesCall := make(chan struct{}) executeDutiesCall := make(chan committeeDutiesMap) - s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().EstimatedSyncCommitteePeriodAtEpoch(gomock.Any()).DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedSyncCommitteePeriodAtEpoch(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) uint64 { - return uint64(epoch / s.network.EpochsPerSyncCommitteePeriod()) + return uint64(epoch / s.beaconConfig.EpochsPerSyncCommitteePeriod()) }, ).AnyTimes() - s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().FirstEpochOfSyncPeriod(gomock.Any()).DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().FirstEpochOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Epoch { - return phase0.Epoch(period) * s.network.EpochsPerSyncCommitteePeriod() + return phase0.Epoch(period) * s.beaconConfig.EpochsPerSyncCommitteePeriod() }, ).AnyTimes() - s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().GetEpochFirstSlot(gomock.Any()).DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetEpochFirstSlot(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) phase0.Slot { - return phase0.Slot(epoch) * s.network.SlotsPerEpoch + return phase0.Slot(epoch) * s.beaconConfig.GetSlotsPerEpoch() }, ).AnyTimes() - s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().LastSlotOfSyncPeriod(gomock.Any()).DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().LastSlotOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Slot { - lastEpoch := s.network.FirstEpochOfSyncPeriod(period+1) - 1 + lastEpoch := s.beaconConfig.FirstEpochOfSyncPeriod(period+1) - 1 // If we are in the sync committee that ends at slot x we do not generate a message during slot x-1 // as it will never be included, hence -1. - return s.network.GetEpochFirstSlot(lastEpoch+1) - 2 + return s.beaconConfig.GetEpochFirstSlot(lastEpoch+1) - 2 }, ).AnyTimes() @@ -69,7 +69,7 @@ func setupCommitteeDutiesMock( if waitForDuties.Get() { fetchDutiesCall <- struct{}{} } - period := s.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) + period := s.beaconConfig.EstimatedSyncCommitteePeriodAtEpoch(epoch) duties, _ := syncDuties.Get(period) return duties, nil }).AnyTimes() @@ -108,7 +108,7 @@ func setupCommitteeDutiesMock( ValidatorIndex: duty.ValidatorIndex, }, } - firstEpoch := s.network.FirstEpochOfSyncPeriod(period) + firstEpoch := s.beaconConfig.FirstEpochOfSyncPeriod(period) if firstEpoch < minEpoch { minEpoch = firstEpoch ssvShare.SetMinParticipationEpoch(firstEpoch) @@ -183,7 +183,7 @@ func TestScheduler_Committee_Same_Slot_Attester_Only(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) + require.Less(t, scheduler.beaconConfig.GetSlotDuration()/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -233,7 +233,7 @@ func TestScheduler_Committee_Same_Slot_SyncCommittee_Only(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) + require.Less(t, scheduler.beaconConfig.GetSlotDuration()/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -291,7 +291,7 @@ func TestScheduler_Committee_Same_Slot(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) + require.Less(t, scheduler.beaconConfig.GetSlotDuration()/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -347,7 +347,7 @@ func TestScheduler_Committee_Diff_Slot_Attester_Only(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) + require.Less(t, scheduler.beaconConfig.GetSlotDuration()/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -449,7 +449,7 @@ func TestScheduler_Committee_Indices_Changed_Attester_Only(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) + require.Less(t, scheduler.beaconConfig.GetSlotDuration()/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -551,7 +551,7 @@ func TestScheduler_Committee_Indices_Changed_Attester_Only_2(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) + require.Less(t, scheduler.beaconConfig.GetSlotDuration()/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -643,7 +643,7 @@ func TestScheduler_Committee_Indices_Changed_Attester_Only_3(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) + require.Less(t, scheduler.beaconConfig.GetSlotDuration()/3, time.Since(startTime)) // Stop scheduler & wait for graceful exit. cancel() @@ -1020,7 +1020,7 @@ func TestScheduler_Committee_Early_Block_Attester_Only(t *testing.T) { } scheduler.HandleHeadEvent(logger)(e.Data.(*eth2apiv1.HeadEvent)) waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) - require.Less(t, time.Since(startTime), scheduler.network.SlotDuration/3) + require.Less(t, time.Since(startTime), scheduler.beaconConfig.GetSlotDuration()/3) // Stop scheduler & wait for graceful exit. cancel() @@ -1076,7 +1076,7 @@ func TestScheduler_Committee_Early_Block(t *testing.T) { waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) // validate the 1/3 of the slot waiting time - require.Less(t, scheduler.network.SlotDuration/3, time.Since(startTime)) + require.Less(t, scheduler.beaconConfig.GetSlotDuration()/3, time.Since(startTime)) // STEP 3: wait for attester duties to be executed faster than 1/3 of the slot duration when // Beacon head event is observed (block arrival) @@ -1094,7 +1094,7 @@ func TestScheduler_Committee_Early_Block(t *testing.T) { } scheduler.HandleHeadEvent(logger)(e.Data.(*eth2apiv1.HeadEvent)) waitForDutiesExecutionCommittee(t, logger, fetchDutiesCall, executeDutiesCall, timeout, committeeMap) - require.Less(t, time.Since(startTime), scheduler.network.SlotDuration/3) + require.Less(t, time.Since(startTime), scheduler.beaconConfig.GetSlotDuration()/3) // Stop scheduler & wait for graceful exit. cancel() diff --git a/operator/duties/proposer.go b/operator/duties/proposer.go index 8716daec4a..88902cd02f 100644 --- a/operator/duties/proposer.go +++ b/operator/duties/proposer.go @@ -63,11 +63,11 @@ func (h *ProposerHandler) HandleDuties(ctx context.Context) { case <-next: slot := h.ticker.Slot() next = h.ticker.Next() - currentEpoch := h.network.EstimatedEpochAtSlot(slot) + currentEpoch := h.beaconConfig.EstimatedEpochAtSlot(slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, slot, slot%32+1) h.logger.Debug("🛠 ticker event", zap.String("epoch_slot_pos", buildStr)) - ctx, cancel := context.WithDeadline(ctx, h.network.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) + ctx, cancel := context.WithDeadline(ctx, h.beaconConfig.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) if h.fetchFirst { h.fetchFirst = false h.indicesChanged = false @@ -83,13 +83,13 @@ func (h *ProposerHandler) HandleDuties(ctx context.Context) { cancel() // last slot of epoch - if slot%h.network.SlotsPerEpoch == h.network.SlotsPerEpoch-1 { + if slot%h.beaconConfig.GetSlotsPerEpoch() == h.beaconConfig.GetSlotsPerEpoch()-1 { h.duties.ResetEpoch(currentEpoch - 1) h.fetchFirst = true } case reorgEvent := <-h.reorg: - currentEpoch := h.network.EstimatedEpochAtSlot(reorgEvent.Slot) + currentEpoch := h.beaconConfig.EstimatedEpochAtSlot(reorgEvent.Slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, reorgEvent.Slot, reorgEvent.Slot%32+1) h.logger.Info("🔀 reorg event received", zap.String("epoch_slot_pos", buildStr), zap.Any("event", reorgEvent)) @@ -100,8 +100,8 @@ func (h *ProposerHandler) HandleDuties(ctx context.Context) { } case <-h.indicesChange: - slot := h.network.EstimatedCurrentSlot() - currentEpoch := h.network.EstimatedEpochAtSlot(slot) + slot := h.beaconConfig.EstimatedCurrentSlot() + currentEpoch := h.beaconConfig.EstimatedEpochAtSlot(slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, slot, slot%32+1) h.logger.Info("🔁 indices change received", zap.String("epoch_slot_pos", buildStr)) @@ -111,10 +111,10 @@ func (h *ProposerHandler) HandleDuties(ctx context.Context) { } func (h *ProposerHandler) HandleInitialDuties(ctx context.Context) { - ctx, cancel := context.WithTimeout(ctx, h.network.SlotDuration/2) + ctx, cancel := context.WithTimeout(ctx, h.beaconConfig.GetSlotDuration()/2) defer cancel() - epoch := h.network.EstimatedCurrentEpoch() + epoch := h.beaconConfig.EstimatedCurrentEpoch() h.processFetching(ctx, epoch) } @@ -200,7 +200,7 @@ func (h *ProposerHandler) toSpecDuty(duty *eth2apiv1.ProposerDuty, role spectype } func (h *ProposerHandler) shouldExecute(duty *eth2apiv1.ProposerDuty) bool { - currentSlot := h.network.EstimatedCurrentSlot() + currentSlot := h.beaconConfig.EstimatedCurrentSlot() // execute task if slot already began and not pass 1 slot if currentSlot == duty.Slot { return true diff --git a/operator/duties/scheduler.go b/operator/duties/scheduler.go index 34a834794e..0a0fb0f50a 100644 --- a/operator/duties/scheduler.go +++ b/operator/duties/scheduler.go @@ -76,7 +76,7 @@ type SchedulerOptions struct { Ctx context.Context BeaconNode BeaconNode ExecutionClient ExecutionClient - Network networkconfig.NetworkConfig + BeaconConfig networkconfig.Beacon ValidatorProvider ValidatorProvider ValidatorController ValidatorController DutyExecutor DutyExecutor @@ -90,7 +90,7 @@ type SchedulerOptions struct { type Scheduler struct { beaconNode BeaconNode executionClient ExecutionClient - network networkconfig.NetworkConfig + beaconConfig networkconfig.Beacon validatorProvider ValidatorProvider validatorController ValidatorController slotTickerProvider slotticker.Provider @@ -120,7 +120,7 @@ func NewScheduler(opts *SchedulerOptions) *Scheduler { s := &Scheduler{ beaconNode: opts.BeaconNode, executionClient: opts.ExecutionClient, - network: opts.Network, + beaconConfig: opts.BeaconConfig, slotTickerProvider: opts.SlotTickerProvider, dutyExecutor: opts.DutyExecutor, validatorProvider: opts.ValidatorProvider, @@ -179,7 +179,7 @@ func (s *Scheduler) Start(ctx context.Context, logger *zap.Logger) error { logger, s.beaconNode, s.executionClient, - s.network, + s.beaconConfig, s.validatorProvider, s.validatorController, s, @@ -287,8 +287,8 @@ func (s *Scheduler) SlotTicker(ctx context.Context) { case <-s.ticker.Next(): slot := s.ticker.Slot() - delay := s.network.SlotDuration / casts.DurationFromUint64(goclient.IntervalsPerSlot) /* a third of the slot duration */ - finalTime := s.network.GetSlotStartTime(slot).Add(delay) + delay := s.beaconConfig.GetSlotDuration() / casts.DurationFromUint64(goclient.IntervalsPerSlot) /* a third of the slot duration */ + finalTime := s.beaconConfig.GetSlotStartTime(slot).Add(delay) waitDuration := time.Until(finalTime) if waitDuration > 0 { @@ -308,12 +308,12 @@ func (s *Scheduler) SlotTicker(ctx context.Context) { func (s *Scheduler) HandleHeadEvent(logger *zap.Logger) func(event *eth2apiv1.HeadEvent) { return func(event *eth2apiv1.HeadEvent) { var zeroRoot phase0.Root - if event.Slot != s.network.EstimatedCurrentSlot() { + if event.Slot != s.beaconConfig.EstimatedCurrentSlot() { return } // check for reorg - epoch := s.network.EstimatedEpochAtSlot(event.Slot) + epoch := s.beaconConfig.EstimatedEpochAtSlot(event.Slot) buildStr := fmt.Sprintf("e%v-s%v-#%v", epoch, event.Slot, event.Slot%32+1) logger := logger.With(zap.String("epoch_slot_pos", buildStr)) if s.lastBlockEpoch != 0 { @@ -366,8 +366,8 @@ func (s *Scheduler) HandleHeadEvent(logger *zap.Logger) func(event *eth2apiv1.He s.currentDutyDependentRoot = event.CurrentDutyDependentRoot currentTime := time.Now() - delay := s.network.SlotDuration / casts.DurationFromUint64(goclient.IntervalsPerSlot) /* a third of the slot duration */ - slotStartTimeWithDelay := s.network.GetSlotStartTime(event.Slot).Add(delay) + delay := s.beaconConfig.GetSlotDuration() / casts.DurationFromUint64(goclient.IntervalsPerSlot) /* a third of the slot duration */ + slotStartTimeWithDelay := s.beaconConfig.GetSlotStartTime(event.Slot).Add(delay) if currentTime.Before(slotStartTimeWithDelay) { logger.Debug("🏁 Head event: Block arrived before 1/3 slot", zap.Duration("time_saved", slotStartTimeWithDelay.Sub(currentTime))) @@ -388,7 +388,7 @@ func (s *Scheduler) ExecuteDuties(ctx context.Context, logger *zap.Logger, dutie for _, duty := range duties { duty := duty logger := s.loggerWithDutyContext(logger, duty) - slotDelay := time.Since(s.network.GetSlotStartTime(duty.Slot)) + slotDelay := time.Since(s.beaconConfig.GetSlotStartTime(duty.Slot)) if slotDelay >= 100*time.Millisecond { logger.Debug("⚠️ late duty execution", zap.Int64("slot_delay", slotDelay.Milliseconds())) } @@ -408,10 +408,10 @@ func (s *Scheduler) ExecuteCommitteeDuties(ctx context.Context, logger *zap.Logg for _, committee := range duties { duty := committee.duty logger := s.loggerWithCommitteeDutyContext(logger, committee) - dutyEpoch := s.network.EstimatedEpochAtSlot(duty.Slot) + dutyEpoch := s.beaconConfig.EstimatedEpochAtSlot(duty.Slot) logger.Debug("🔧 executing committee duty", fields.Duties(dutyEpoch, duty.ValidatorDuties)) - slotDelay := time.Since(s.network.GetSlotStartTime(duty.Slot)) + slotDelay := time.Since(s.beaconConfig.GetSlotStartTime(duty.Slot)) if slotDelay >= 100*time.Millisecond { logger.Debug("⚠️ late duty execution", zap.Int64("slot_delay", slotDelay.Milliseconds())) } @@ -429,27 +429,27 @@ func (s *Scheduler) loggerWithDutyContext(logger *zap.Logger, duty *spectypes.Va return logger. With(fields.BeaconRole(duty.Type)). With(zap.Uint64("committee_index", uint64(duty.CommitteeIndex))). - With(fields.CurrentSlot(s.network.EstimatedCurrentSlot())). + With(fields.CurrentSlot(s.beaconConfig.EstimatedCurrentSlot())). With(fields.Slot(duty.Slot)). - With(fields.Epoch(s.network.EstimatedEpochAtSlot(duty.Slot))). + With(fields.Epoch(s.beaconConfig.EstimatedEpochAtSlot(duty.Slot))). With(fields.PubKey(duty.PubKey[:])). - With(fields.StartTimeUnixMilli(s.network.GetSlotStartTime(duty.Slot))) + With(fields.StartTimeUnixMilli(s.beaconConfig.GetSlotStartTime(duty.Slot))) } // loggerWithCommitteeDutyContext returns an instance of logger with the given committee duty's information func (s *Scheduler) loggerWithCommitteeDutyContext(logger *zap.Logger, committeeDuty *committeeDuty) *zap.Logger { duty := committeeDuty.duty - dutyEpoch := s.network.EstimatedEpochAtSlot(duty.Slot) + dutyEpoch := s.beaconConfig.EstimatedEpochAtSlot(duty.Slot) committeeDutyID := fields.FormatCommitteeDutyID(committeeDuty.operatorIDs, dutyEpoch, duty.Slot) return logger. With(fields.CommitteeID(committeeDuty.id)). With(fields.DutyID(committeeDutyID)). With(fields.Role(duty.RunnerRole())). - With(fields.CurrentSlot(s.network.EstimatedCurrentSlot())). + With(fields.CurrentSlot(s.beaconConfig.EstimatedCurrentSlot())). With(fields.Slot(duty.Slot)). With(fields.Epoch(dutyEpoch)). - With(fields.StartTimeUnixMilli(s.network.GetSlotStartTime(duty.Slot))) + With(fields.StartTimeUnixMilli(s.beaconConfig.GetSlotStartTime(duty.Slot))) } // waitOneThirdOrValidBlock waits until one-third of the slot has transpired (SECONDS_PER_SLOT / 3 seconds after the start of slot) diff --git a/operator/duties/scheduler_test.go b/operator/duties/scheduler_test.go index 27554242c6..c7f61affca 100644 --- a/operator/duties/scheduler_test.go +++ b/operator/duties/scheduler_test.go @@ -18,7 +18,6 @@ import ( "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/operator/slotticker" mockslotticker "github.com/ssvlabs/ssv/operator/slotticker/mocks" - mocknetwork "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon/mocks" ) type MockSlotTicker interface { @@ -86,14 +85,13 @@ func setupSchedulerAndMocks(t *testing.T, handlers []dutyHandler, currentSlot *S mockValidatorController := NewMockValidatorController(ctrl) mockDutyExecutor := NewMockDutyExecutor(ctrl) mockSlotService := &mockSlotTickerService{} - mockNetworkConfig := networkconfig.NetworkConfig{} - mockNetworkConfig.Beacon = mocknetwork.NewMockBeaconNetwork(ctrl) + mockBeaconConfig := networkconfig.NewMockBeacon(ctrl) opts := &SchedulerOptions{ Ctx: ctx, BeaconNode: mockBeaconNode, ExecutionClient: mockExecutionClient, - Network: mockNetworkConfig, + BeaconConfig: mockBeaconConfig, ValidatorProvider: mockValidatorProvider, ValidatorController: mockValidatorController, DutyExecutor: mockDutyExecutor, @@ -111,33 +109,32 @@ func setupSchedulerAndMocks(t *testing.T, handlers []dutyHandler, currentSlot *S mockBeaconNode.EXPECT().SubscribeToHeadEvents(ctx, "duty_scheduler", gomock.Any()).Return(nil) - mockNetworkConfig.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().MinGenesisTime().Return(int64(0)).AnyTimes() - mockNetworkConfig.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().SlotDurationSec().Return(150 * time.Millisecond).AnyTimes() - mockNetworkConfig.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().SlotsPerEpoch().Return(uint64(32)).AnyTimes() - mockNetworkConfig.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().GetSlotStartTime(gomock.Any()).DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetSlotDuration().Return(150 * time.Millisecond).AnyTimes() + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetSlotsPerEpoch().Return(phase0.Slot(32)).AnyTimes() + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetSlotStartTime(gomock.Any()).DoAndReturn( func(slot phase0.Slot) time.Time { return time.Now() }, ).AnyTimes() - mockNetworkConfig.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().EstimatedEpochAtSlot(gomock.Any()).DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedEpochAtSlot(gomock.Any()).DoAndReturn( func(slot phase0.Slot) phase0.Epoch { - return phase0.Epoch(slot / s.network.SlotsPerEpoch) + return phase0.Epoch(slot / s.beaconConfig.GetSlotsPerEpoch()) }, ).AnyTimes() - s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().EstimatedCurrentSlot().DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedCurrentSlot().DoAndReturn( func() phase0.Slot { return currentSlot.Get() }, ).AnyTimes() - s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().EstimatedCurrentEpoch().DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedCurrentEpoch().DoAndReturn( func() phase0.Epoch { - return phase0.Epoch(currentSlot.Get() / s.network.SlotsPerEpoch) + return phase0.Epoch(currentSlot.Get() / s.beaconConfig.GetSlotsPerEpoch()) }, ).AnyTimes() - s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().EpochsPerSyncCommitteePeriod().Return(uint64(256)).AnyTimes() + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EpochsPerSyncCommitteePeriod().Return(phase0.Epoch(256)).AnyTimes() // Create a pool to wait for the scheduler to finish. schedulerPool := pool.New().WithErrors().WithContext(ctx) @@ -351,7 +348,7 @@ func TestScheduler_Run(t *testing.T) { opts := &SchedulerOptions{ Ctx: ctx, BeaconNode: mockBeaconNode, - Network: networkconfig.TestNetwork, + BeaconConfig: networkconfig.TestNetwork.BeaconConfig, ValidatorProvider: mockValidatorProvider, SlotTickerProvider: func() slotticker.SlotTicker { return mockTicker @@ -399,7 +396,7 @@ func TestScheduler_Regression_IndicesChangeStuck(t *testing.T) { opts := &SchedulerOptions{ Ctx: ctx, BeaconNode: mockBeaconNode, - Network: networkconfig.TestNetwork, + BeaconConfig: networkconfig.TestNetwork.BeaconConfig, ValidatorProvider: mockValidatorProvider, SlotTickerProvider: func() slotticker.SlotTicker { return mockTicker diff --git a/operator/duties/sync_committee.go b/operator/duties/sync_committee.go index 391c56c050..052175b80a 100644 --- a/operator/duties/sync_committee.go +++ b/operator/duties/sync_committee.go @@ -65,9 +65,9 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { // Prepare relevant duties 1.5 epochs (48 slots) ahead of the sync committee period change. // The 1.5 epochs timing helps ensure setup occurs when the beacon node is likely less busy. - h.preparationSlots = h.network.SlotsPerEpoch * 3 / 2 + h.preparationSlots = h.beaconConfig.GetSlotsPerEpoch() * 3 / 2 - if h.shouldFetchNextPeriod(h.network.EstimatedCurrentSlot()) { + if h.shouldFetchNextPeriod(h.beaconConfig.EstimatedCurrentSlot()) { h.fetchNextPeriod = true } @@ -80,12 +80,12 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { case <-next: slot := h.ticker.Slot() next = h.ticker.Next() - epoch := h.network.EstimatedEpochAtSlot(slot) - period := h.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) + epoch := h.beaconConfig.EstimatedEpochAtSlot(slot) + period := h.beaconConfig.EstimatedSyncCommitteePeriodAtEpoch(epoch) buildStr := fmt.Sprintf("p%v-e%v-s%v-#%v", period, epoch, slot, slot%32+1) h.logger.Debug("🛠 ticker event", zap.String("period_epoch_slot_pos", buildStr)) - ctx, cancel := context.WithDeadline(ctx, h.network.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) + ctx, cancel := context.WithDeadline(ctx, h.beaconConfig.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) h.processExecution(ctx, period, slot) h.processFetching(ctx, period, true) cancel() @@ -97,13 +97,13 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { } // last slot of period - if slot == h.network.LastSlotOfSyncPeriod(period) { + if slot == h.beaconConfig.LastSlotOfSyncPeriod(period) { h.duties.Reset(period - 1) } case reorgEvent := <-h.reorg: - epoch := h.network.EstimatedEpochAtSlot(reorgEvent.Slot) - period := h.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) + epoch := h.beaconConfig.EstimatedEpochAtSlot(reorgEvent.Slot) + period := h.beaconConfig.EstimatedSyncCommitteePeriodAtEpoch(epoch) buildStr := fmt.Sprintf("p%v-e%v-s%v-#%v", period, epoch, reorgEvent.Slot, reorgEvent.Slot%32+1) h.logger.Info("🔀 reorg event received", zap.String("period_epoch_slot_pos", buildStr), zap.Any("event", reorgEvent)) @@ -115,9 +115,9 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { } case <-h.indicesChange: - slot := h.network.EstimatedCurrentSlot() - epoch := h.network.EstimatedEpochAtSlot(slot) - period := h.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) + slot := h.beaconConfig.EstimatedCurrentSlot() + epoch := h.beaconConfig.EstimatedEpochAtSlot(slot) + period := h.beaconConfig.EstimatedSyncCommitteePeriodAtEpoch(epoch) buildStr := fmt.Sprintf("p%v-e%v-s%v-#%v", period, epoch, slot, slot%32+1) h.logger.Info("🔁 indices change received", zap.String("period_epoch_slot_pos", buildStr)) @@ -132,11 +132,11 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { } func (h *SyncCommitteeHandler) HandleInitialDuties(ctx context.Context) { - ctx, cancel := context.WithTimeout(ctx, h.network.SlotDuration/2) + ctx, cancel := context.WithTimeout(ctx, h.beaconConfig.GetSlotDuration()/2) defer cancel() - epoch := h.network.EstimatedCurrentEpoch() - period := h.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) + epoch := h.beaconConfig.EstimatedCurrentEpoch() + period := h.beaconConfig.EstimatedSyncCommitteePeriodAtEpoch(epoch) h.processFetching(ctx, period, false) } @@ -180,12 +180,12 @@ func (h *SyncCommitteeHandler) processExecution(ctx context.Context, period uint func (h *SyncCommitteeHandler) fetchAndProcessDuties(ctx context.Context, period uint64, waitForInitial bool) error { start := time.Now() - firstEpoch := h.network.FirstEpochOfSyncPeriod(period) - currentEpoch := h.network.EstimatedCurrentEpoch() + firstEpoch := h.beaconConfig.FirstEpochOfSyncPeriod(period) + currentEpoch := h.beaconConfig.EstimatedCurrentEpoch() if firstEpoch < currentEpoch { firstEpoch = currentEpoch } - lastEpoch := h.network.FirstEpochOfSyncPeriod(period+1) - 1 + lastEpoch := h.beaconConfig.FirstEpochOfSyncPeriod(period+1) - 1 allActiveIndices := h.validatorController.AllActiveIndices(firstEpoch, waitForInitial) if len(allActiveIndices) == 0 { @@ -268,8 +268,8 @@ func (h *SyncCommitteeHandler) toSpecDuty(duty *eth2apiv1.SyncCommitteeDuty, slo } func (h *SyncCommitteeHandler) shouldExecute(duty *eth2apiv1.SyncCommitteeDuty, slot phase0.Slot) bool { - currentSlot := h.network.EstimatedCurrentSlot() - currentEpoch := h.network.EstimatedEpochAtSlot(currentSlot) + currentSlot := h.beaconConfig.EstimatedCurrentSlot() + currentEpoch := h.beaconConfig.EstimatedEpochAtSlot(currentSlot) v, exists := h.validatorProvider.Validator(duty.PubKey[:]) if !exists { @@ -317,5 +317,5 @@ func (h *SyncCommitteeHandler) shouldFetchNextPeriod(slot phase0.Slot) bool { } func (h *SyncCommitteeHandler) slotsPerPeriod() phase0.Slot { - return phase0.Slot(h.network.EpochsPerSyncCommitteePeriod()) * h.network.SlotsPerEpoch + return phase0.Slot(h.beaconConfig.EpochsPerSyncCommitteePeriod()) * h.beaconConfig.GetSlotsPerEpoch() } diff --git a/operator/duties/sync_committee_test.go b/operator/duties/sync_committee_test.go index 98d94f2c6a..5441bda844 100644 --- a/operator/duties/sync_committee_test.go +++ b/operator/duties/sync_committee_test.go @@ -12,8 +12,8 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/operator/duties/dutystore" - mocknetwork "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon/mocks" ssvtypes "github.com/ssvlabs/ssv/protocol/v2/types" "github.com/ssvlabs/ssv/utils/hashmap" ) @@ -27,30 +27,30 @@ func setupSyncCommitteeDutiesMock( fetchDutiesCall := make(chan struct{}) executeDutiesCall := make(chan []*spectypes.ValidatorDuty) - s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().EstimatedSyncCommitteePeriodAtEpoch(gomock.Any()).DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedSyncCommitteePeriodAtEpoch(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) uint64 { - return uint64(epoch / s.network.EpochsPerSyncCommitteePeriod()) + return uint64(epoch / s.beaconConfig.EpochsPerSyncCommitteePeriod()) }, ).AnyTimes() - s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().FirstEpochOfSyncPeriod(gomock.Any()).DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().FirstEpochOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Epoch { - return phase0.Epoch(period) * s.network.EpochsPerSyncCommitteePeriod() + return phase0.Epoch(period) * s.beaconConfig.EpochsPerSyncCommitteePeriod() }, ).AnyTimes() - s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().LastSlotOfSyncPeriod(gomock.Any()).DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().LastSlotOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Slot { - lastEpoch := s.network.FirstEpochOfSyncPeriod(period+1) - 1 + lastEpoch := s.beaconConfig.FirstEpochOfSyncPeriod(period+1) - 1 // If we are in the sync committee that ends at slot x we do not generate a message during slot x-1 // as it will never be included, hence -1. - return s.network.GetEpochFirstSlot(lastEpoch+1) - 2 + return s.beaconConfig.GetEpochFirstSlot(lastEpoch+1) - 2 }, ).AnyTimes() - s.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().GetEpochFirstSlot(gomock.Any()).DoAndReturn( + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetEpochFirstSlot(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) phase0.Slot { - return phase0.Slot(epoch) * s.network.SlotsPerEpoch + return phase0.Slot(epoch) * s.beaconConfig.GetSlotsPerEpoch() }, ).AnyTimes() @@ -59,7 +59,7 @@ func setupSyncCommitteeDutiesMock( if waitForDuties.Get() { fetchDutiesCall <- struct{}{} } - period := s.network.EstimatedSyncCommitteePeriodAtEpoch(epoch) + period := s.beaconConfig.EstimatedSyncCommitteePeriodAtEpoch(epoch) duties, _ := dutiesMap.Get(period) return duties, nil }).AnyTimes() @@ -78,7 +78,7 @@ func setupSyncCommitteeDutiesMock( ValidatorIndex: duty.ValidatorIndex, }, } - firstEpoch := s.network.FirstEpochOfSyncPeriod(period) + firstEpoch := s.beaconConfig.FirstEpochOfSyncPeriod(period) if firstEpoch < minEpoch { minEpoch = firstEpoch ssvShare.SetMinParticipationEpoch(firstEpoch) @@ -161,7 +161,7 @@ func TestScheduler_SyncCommittee_Same_Period(t *testing.T) { waitForDutiesExecution(t, logger, fetchDutiesCall, executeDutiesCall, timeout, expected) // STEP 3: expect sync committee duties to be executed at the last slot of the period - currentSlot.Set(scheduler.network.LastSlotOfSyncPeriod(0)) + currentSlot.Set(scheduler.beaconConfig.LastSlotOfSyncPeriod(0)) duties, _ = dutiesMap.Get(0) expected = expectedExecutedSyncCommitteeDuties(handler, duties, currentSlot.Get()) setExecuteDutyFunc(scheduler, executeDutiesCall, len(expected)) @@ -170,7 +170,7 @@ func TestScheduler_SyncCommittee_Same_Period(t *testing.T) { waitForDutiesExecution(t, logger, fetchDutiesCall, executeDutiesCall, timeout, expected) // STEP 4: expect no action to be taken as we are in the next period - firstSlotOfNextPeriod := scheduler.network.GetEpochFirstSlot(scheduler.network.FirstEpochOfSyncPeriod(1)) + firstSlotOfNextPeriod := scheduler.beaconConfig.GetEpochFirstSlot(scheduler.beaconConfig.FirstEpochOfSyncPeriod(1)) currentSlot.Set(firstSlotOfNextPeriod) ticker.Send(currentSlot.Get()) waitForNoAction(t, logger, fetchDutiesCall, executeDutiesCall, timeout) @@ -685,7 +685,7 @@ func TestScheduler_SyncCommittee_Early_Block(t *testing.T) { } scheduler.HandleHeadEvent(logger)(e.Data.(*v1.HeadEvent)) waitForDutiesExecution(t, logger, fetchDutiesCall, executeDutiesCall, timeout, expected) - require.Greater(t, time.Since(startTime), time.Duration(float64(scheduler.network.SlotDuration/3)*0.90)) // 10% margin due to flakiness of the test + require.Greater(t, time.Since(startTime), time.Duration(float64(scheduler.beaconConfig.GetSlotDuration()/3)*0.90)) // 10% margin due to flakiness of the test // Stop scheduler & wait for graceful exit. cancel() diff --git a/operator/duties/validatorregistration.go b/operator/duties/validatorregistration.go index ec5a90b93f..40d6fb3c7f 100644 --- a/operator/duties/validatorregistration.go +++ b/operator/duties/validatorregistration.go @@ -38,7 +38,7 @@ func (h *ValidatorRegistrationHandler) HandleDuties(ctx context.Context) { defer h.logger.Info("duty handler exited") // validator should be registered within frequencyEpochs epochs time in a corresponding slot - registrationSlots := h.network.SlotsPerEpoch * phase0.Slot(frequencyEpochs) + registrationSlots := h.beaconConfig.GetSlotsPerEpoch() * phase0.Slot(frequencyEpochs) next := h.ticker.Next() for { @@ -49,7 +49,7 @@ func (h *ValidatorRegistrationHandler) HandleDuties(ctx context.Context) { case <-next: slot := h.ticker.Slot() next = h.ticker.Next() - epoch := h.network.EstimatedEpochAtSlot(slot) + epoch := h.beaconConfig.EstimatedEpochAtSlot(slot) shares := h.validatorProvider.SelfParticipatingValidators(epoch + frequencyEpochs) var vrs []ValidatorRegistration diff --git a/operator/duties/voluntary_exit.go b/operator/duties/voluntary_exit.go index 863e5b387f..7f1abbe585 100644 --- a/operator/duties/voluntary_exit.go +++ b/operator/duties/voluntary_exit.go @@ -115,7 +115,7 @@ func (h *VoluntaryExitHandler) processExecution(ctx context.Context, slot phase0 } h.dutyQueue = pendingDuties - h.duties.RemoveSlot(slot - h.network.SlotsPerEpoch) + h.duties.RemoveSlot(slot - h.beaconConfig.GetSlotsPerEpoch()) if dutyCount := len(dutiesForExecution); dutyCount != 0 { h.dutiesExecutor.ExecuteDuties(ctx, h.logger, dutiesForExecution) @@ -138,7 +138,7 @@ func (h *VoluntaryExitHandler) blockSlot(ctx context.Context, blockNumber uint64 return 0, err } - blockSlot = h.network.EstimatedSlotAtTime(time.Unix(int64(block.Time()), 0)) // #nosec G115 + blockSlot = h.beaconConfig.EstimatedSlotAtTime(time.Unix(int64(block.Time()), 0)) // #nosec G115 h.blockSlots[blockNumber] = blockSlot for k, v := range h.blockSlots { diff --git a/operator/duties/voluntary_exit_test.go b/operator/duties/voluntary_exit_test.go index 167e813721..5420c4b517 100644 --- a/operator/duties/voluntary_exit_test.go +++ b/operator/duties/voluntary_exit_test.go @@ -14,8 +14,8 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/operator/duties/dutystore" - mocknetwork "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon/mocks" ) func TestVoluntaryExitHandler_HandleDuties(t *testing.T) { @@ -151,9 +151,9 @@ func create1to1BlockSlotMapping(scheduler *Scheduler) *atomic.Uint64 { return expectedBlock, nil }, ).AnyTimes() - scheduler.network.Beacon.(*mocknetwork.MockBeaconNetwork).EXPECT().EstimatedSlotAtTime(gomock.Any()).DoAndReturn( - func(time int64) phase0.Slot { - return phase0.Slot(time) + scheduler.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedSlotAtTime(gomock.Any()).DoAndReturn( + func(time time.Time) phase0.Slot { + return phase0.Slot(time.Unix()) }, ).AnyTimes() @@ -167,7 +167,7 @@ func assert1to1BlockSlotMapping(t *testing.T, scheduler *Scheduler) { require.NoError(t, err) require.NotNil(t, block) - slot := scheduler.network.EstimatedSlotAtTime(time.Unix(int64(block.Time()), 0)) + slot := scheduler.beaconConfig.EstimatedSlotAtTime(time.Unix(int64(block.Time()), 0)) require.EqualValues(t, blockNumber, slot) } diff --git a/operator/fee_recipient/controller.go b/operator/fee_recipient/controller.go index d37b919bdf..c1bb6d4a04 100644 --- a/operator/fee_recipient/controller.go +++ b/operator/fee_recipient/controller.go @@ -28,7 +28,7 @@ type RecipientController interface { type ControllerOptions struct { Ctx context.Context BeaconClient beaconprotocol.BeaconNode - Network networkconfig.NetworkConfig + BeaconConfig networkconfig.BeaconConfig ShareStorage storage.Shares RecipientStorage storage.Recipients SlotTickerProvider slotticker.Provider @@ -39,7 +39,7 @@ type ControllerOptions struct { type recipientController struct { ctx context.Context beaconClient beaconprotocol.BeaconNode - network networkconfig.NetworkConfig + beaconConfig networkconfig.BeaconConfig shareStorage storage.Shares recipientStorage storage.Recipients slotTickerProvider slotticker.Provider @@ -50,7 +50,7 @@ func NewController(opts *ControllerOptions) *recipientController { return &recipientController{ ctx: opts.Ctx, beaconClient: opts.BeaconClient, - network: opts.Network, + beaconConfig: opts.BeaconConfig, shareStorage: opts.ShareStorage, recipientStorage: opts.RecipientStorage, slotTickerProvider: opts.SlotTickerProvider, @@ -74,7 +74,7 @@ func (rc *recipientController) listenToTicker(logger *zap.Logger) { <-ticker.Next() slot := ticker.Slot() // submit if first time or if first slot in epoch - if firstTimeSubmitted && slot%rc.network.SlotsPerEpoch != (rc.network.SlotsPerEpoch/2) { + if firstTimeSubmitted && slot%rc.beaconConfig.SlotsPerEpoch != (rc.beaconConfig.SlotsPerEpoch/2) { continue } firstTimeSubmitted = true diff --git a/operator/fee_recipient/controller_test.go b/operator/fee_recipient/controller_test.go index a467371338..2cf65057b3 100644 --- a/operator/fee_recipient/controller_test.go +++ b/operator/fee_recipient/controller_test.go @@ -42,12 +42,13 @@ func TestSubmitProposal(t *testing.T) { db, shareStorage, recipientStorage := createStorage(t) defer db.Close() - network := networkconfig.TestNetwork + + beaconConfig := networkconfig.TestNetwork.BeaconConfig populateStorage(t, logger, shareStorage, operatorData) frCtrl := NewController(&ControllerOptions{ Ctx: context.TODO(), - Network: network, + BeaconConfig: beaconConfig, ShareStorage: shareStorage, RecipientStorage: recipientStorage, OperatorDataStore: operatorDataStore, @@ -80,11 +81,11 @@ func TestSubmitProposal(t *testing.T) { go frCtrl.Start(logger) slots := []phase0.Slot{ - 1, // first time - 2, // should not call submit - 20, // should not call submit - network.SlotsPerEpoch / 2, // halfway through epoch - 63, // should not call submit + 1, // first time + 2, // should not call submit + 20, // should not call submit + beaconConfig.SlotsPerEpoch / 2, // halfway through epoch + 63, // should not call submit } for _, s := range slots { diff --git a/operator/node.go b/operator/node.go index 5797eb7e1c..b58d5b02ad 100644 --- a/operator/node.go +++ b/operator/node.go @@ -29,7 +29,7 @@ type Options struct { // NetworkName is the network name of this node NetworkName string `yaml:"Network" env:"NETWORK" env-default:"mainnet" env-description:"Ethereum network to connect to (mainnet, holesky, sepolia, etc.)"` CustomDomainType string `yaml:"CustomDomainType" env:"CUSTOM_DOMAIN_TYPE" env-default:"" env-description:"Override SSV domain type for network isolation. Warning: Please modify only if you are certain of the implications. This would be incremented by 1 after Alan fork (e.g., 0x01020304 → 0x01020305 post-fork)"` - Network networkconfig.NetworkConfig + NetworkConfig networkconfig.NetworkConfig BeaconNode beaconprotocol.BeaconNode // TODO: consider renaming to ConsensusClient ExecutionClient executionclient.Provider P2PNetwork network.P2PNetwork @@ -66,7 +66,7 @@ func New(logger *zap.Logger, opts Options, slotTickerProvider slotticker.Provide context: opts.Context, validatorsCtrl: opts.ValidatorController, validatorOptions: opts.ValidatorOptions, - network: opts.Network, + network: opts.NetworkConfig, consensusClient: opts.BeaconNode, executionClient: opts.ExecutionClient, net: opts.P2PNetwork, @@ -76,7 +76,7 @@ func New(logger *zap.Logger, opts Options, slotTickerProvider slotticker.Provide Ctx: opts.Context, BeaconNode: opts.BeaconNode, ExecutionClient: opts.ExecutionClient, - Network: opts.Network, + BeaconConfig: opts.NetworkConfig, ValidatorProvider: opts.ValidatorStore.WithOperatorID(opts.ValidatorOptions.OperatorDataStore.GetOperatorID), ValidatorController: opts.ValidatorController, DutyExecutor: opts.ValidatorController, @@ -89,7 +89,7 @@ func New(logger *zap.Logger, opts Options, slotTickerProvider slotticker.Provide feeRecipientCtrl: fee_recipient.NewController(&fee_recipient.ControllerOptions{ Ctx: opts.Context, BeaconClient: opts.BeaconNode, - Network: opts.Network, + BeaconConfig: opts.NetworkConfig.BeaconConfig, ShareStorage: opts.ValidatorOptions.RegistryStorage.Shares(), RecipientStorage: opts.ValidatorOptions.RegistryStorage, OperatorDataStore: opts.ValidatorOptions.OperatorDataStore, diff --git a/operator/validator/controller.go b/operator/validator/controller.go index 7ea3bf50a1..a6289f4598 100644 --- a/operator/validator/controller.go +++ b/operator/validator/controller.go @@ -83,7 +83,7 @@ type ControllerOptions struct { MessageValidator validation.MessageValidator ValidatorsMap *validators.ValidatorsMap DoppelgangerHandler doppelganger.Provider - NetworkConfig networkconfig.NetworkConfig + NetworkConfig networkconfig.Network ValidatorSyncer *metadata.Syncer Graffiti []byte @@ -149,7 +149,7 @@ type controller struct { logger *zap.Logger - networkConfig networkconfig.NetworkConfig + networkConfig networkconfig.Network sharesStorage SharesStorage operatorsStorage registrystorage.Operators recipientsStorage Recipients @@ -229,7 +229,7 @@ func NewController(logger *zap.Logger, options ControllerOptions) Controller { } } - cacheTTL := options.NetworkConfig.SlotDuration * time.Duration(options.NetworkConfig.SlotsPerEpoch*2) // #nosec G115 + cacheTTL := options.NetworkConfig.GetSlotDuration() * time.Duration(options.NetworkConfig.GetSlotsPerEpoch()*2) // #nosec G115 ctrl := controller{ logger: logger.Named(logging.NameController), @@ -302,7 +302,7 @@ func (c *controller) GetValidatorStats() (uint64, uint64, uint64, error) { if ok := s.BelongsToOperator(c.operatorDataStore.GetOperatorID()); ok { operatorShares++ } - if s.IsParticipating(c.beacon.GetBeaconNetwork().EstimatedCurrentEpoch()) { + if s.IsParticipating(c.networkConfig.EstimatedCurrentEpoch()) { active++ } } @@ -368,7 +368,7 @@ func (c *controller) handleWorkerMessages(msg network.DecodedSSVMessage) error { if item == nil { committeeObserverOptions := validator.CommitteeObserverOptions{ Logger: c.logger, - NetworkConfig: c.networkConfig, + BeaconConfig: c.networkConfig, ValidatorStore: c.validatorStore, Network: c.validatorOptions.Network, Storage: c.validatorOptions.Storage, @@ -387,7 +387,7 @@ func (c *controller) handleWorkerMessages(msg network.DecodedSSVMessage) error { c.committeesObservers.Set( ssvMsg.GetID(), ncv, - time.Duration(ttlSlots)*c.beacon.GetBeaconNetwork().SlotDurationSec(), + time.Duration(ttlSlots)*c.networkConfig.GetSlotDuration(), ) } else { ncv = item @@ -601,7 +601,7 @@ func (c *controller) ExecuteDuty(ctx context.Context, logger *zap.Logger, duty * copy(pk, duty.PubKey[:]) if v, ok := c.GetValidator(spectypes.ValidatorPK(pk)); ok { - ssvMsg, err := CreateDutyExecuteMsg(duty, pk, c.networkConfig.DomainType) + ssvMsg, err := CreateDutyExecuteMsg(duty, pk, c.networkConfig.GetDomainType()) if err != nil { logger.Error("could not create duty execute msg", zap.Error(err)) return @@ -622,7 +622,7 @@ func (c *controller) ExecuteDuty(ctx context.Context, logger *zap.Logger, duty * func (c *controller) ExecuteCommitteeDuty(ctx context.Context, logger *zap.Logger, committeeID spectypes.CommitteeID, duty *spectypes.CommitteeDuty) { if cm, ok := c.validatorsMap.GetCommittee(committeeID); ok { - ssvMsg, err := CreateCommitteeDutyExecuteMsg(duty, committeeID, c.networkConfig.DomainType) + ssvMsg, err := CreateCommitteeDutyExecuteMsg(duty, committeeID, c.networkConfig.GetDomainType()) if err != nil { logger.Error("could not create duty execute msg", zap.Error(err)) return @@ -791,7 +791,7 @@ func (c *controller) onShareInit(share *ssvtypes.SSVShare) (*validator.Validator ctx, cancel, logger, - c.beacon.GetBeaconNetwork(), + c.networkConfig, operator, committeeRunnerFunc, nil, @@ -944,7 +944,7 @@ func (c *controller) handleMetadataUpdate(ctx context.Context, syncBatch metadat zap.Int("started_validators", startedValidators), ) // Refresh duties if there are any new active validators. - if !c.reportIndicesChange(ctx, 2*c.beacon.GetBeaconNetwork().SlotDurationSec()) { + if !c.reportIndicesChange(ctx, 2*c.networkConfig.GetSlotDuration()) { c.logger.Warn("timed out while notifying DutyScheduler of new validators") } } @@ -979,7 +979,7 @@ func (c *controller) ReportValidatorStatuses(ctx context.Context) { validatorsPerStatus := make(map[validatorStatus]uint32) for _, share := range c.validatorStore.OperatorValidators(c.operatorDataStore.GetOperatorID()) { - if share.IsParticipating(c.beacon.GetBeaconNetwork().EstimatedCurrentEpoch()) { + if share.IsParticipating(c.networkConfig.EstimatedCurrentEpoch()) { validatorsPerStatus[statusParticipating]++ } if !share.HasBeaconMetadata() { @@ -1036,25 +1036,25 @@ func SetupCommitteeRunners( buildController := func(role spectypes.RunnerRole, valueCheckF specqbft.ProposedValueCheckF) *qbftcontroller.Controller { config := &qbft.Config{ BeaconSigner: options.Signer, - Domain: options.NetworkConfig.DomainType, + Domain: options.NetworkConfig.GetDomainType(), ValueCheckF: valueCheckF, ProposerF: func(state *specqbft.State, round specqbft.Round) spectypes.OperatorID { leader := qbft.RoundRobinProposer(state, round) return leader }, Network: options.Network, - Timer: roundtimer.New(ctx, options.NetworkConfig.Beacon, role, nil), + Timer: roundtimer.New(ctx, options.NetworkConfig, role, nil), CutOffRound: roundtimer.CutOffRound, } - identifier := spectypes.NewMsgID(options.NetworkConfig.DomainType, options.Operator.CommitteeID[:], role) + identifier := spectypes.NewMsgID(options.NetworkConfig.GetDomainType(), options.Operator.CommitteeID[:], role) qbftCtrl := qbftcontroller.NewController(identifier[:], options.Operator, config, options.OperatorSigner, options.FullNode) return qbftCtrl } return func(slot phase0.Slot, shares map[phase0.ValidatorIndex]*spectypes.Share, attestingValidators []spectypes.ShareValidatorPK, dutyGuard runner.CommitteeDutyGuard) (*runner.CommitteeRunner, error) { // Create a committee runner. - epoch := options.NetworkConfig.Beacon.GetBeaconNetwork().EstimatedEpochAtSlot(slot) + epoch := options.NetworkConfig.EstimatedEpochAtSlot(slot) valCheck := ssv.BeaconVoteValueCheckF(options.Signer, slot, attestingValidators, epoch) crunner, err := runner.NewCommitteeRunner( options.NetworkConfig, @@ -1099,7 +1099,7 @@ func SetupRunners( buildController := func(role spectypes.RunnerRole, valueCheckF specqbft.ProposedValueCheckF) *qbftcontroller.Controller { config := &qbft.Config{ BeaconSigner: options.Signer, - Domain: options.NetworkConfig.DomainType, + Domain: options.NetworkConfig.GetDomainType(), ValueCheckF: nil, // sets per role type ProposerF: func(state *specqbft.State, round specqbft.Round) spectypes.OperatorID { leader := qbft.RoundRobinProposer(state, round) @@ -1107,12 +1107,12 @@ func SetupRunners( return leader }, Network: options.Network, - Timer: roundtimer.New(ctx, options.NetworkConfig.Beacon, role, nil), + Timer: roundtimer.New(ctx, options.NetworkConfig, role, nil), CutOffRound: roundtimer.CutOffRound, } config.ValueCheckF = valueCheckF - identifier := spectypes.NewMsgID(options.NetworkConfig.DomainType, options.SSVShare.ValidatorPubKey[:], role) + identifier := spectypes.NewMsgID(options.NetworkConfig.GetDomainType(), options.SSVShare.ValidatorPubKey[:], role) qbftCtrl := qbftcontroller.NewController(identifier[:], options.Operator, config, options.OperatorSigner, options.FullNode) return qbftCtrl } @@ -1121,26 +1121,25 @@ func SetupRunners( shareMap[options.SSVShare.ValidatorIndex] = &options.SSVShare.Share runners := runner.ValidatorDutyRunners{} - domainType := options.NetworkConfig.DomainType var err error for _, role := range runnersType { switch role { case spectypes.RoleProposer: - proposedValueCheck := ssv.ProposerValueCheckF(options.Signer, options.NetworkConfig.Beacon.GetBeaconNetwork(), options.SSVShare.ValidatorPubKey, options.SSVShare.ValidatorIndex, options.SSVShare.SharePubKey) + proposedValueCheck := ssv.ProposerValueCheckF(options.Signer, options.NetworkConfig, options.SSVShare.ValidatorPubKey, options.SSVShare.ValidatorIndex, options.SSVShare.SharePubKey) qbftCtrl := buildController(spectypes.RoleProposer, proposedValueCheck) - runners[role], err = runner.NewProposerRunner(domainType, options.NetworkConfig.Beacon.GetBeaconNetwork(), shareMap, qbftCtrl, options.Beacon, options.Network, options.Signer, options.OperatorSigner, options.DoppelgangerHandler, proposedValueCheck, 0, options.Graffiti) + runners[role], err = runner.NewProposerRunner(options.NetworkConfig, shareMap, qbftCtrl, options.Beacon, options.Network, options.Signer, options.OperatorSigner, options.DoppelgangerHandler, proposedValueCheck, 0, options.Graffiti) case spectypes.RoleAggregator: - aggregatorValueCheckF := ssv.AggregatorValueCheckF(options.Signer, options.NetworkConfig.Beacon.GetBeaconNetwork(), options.SSVShare.ValidatorPubKey, options.SSVShare.ValidatorIndex) + aggregatorValueCheckF := ssv.AggregatorValueCheckF(options.Signer, options.NetworkConfig, options.SSVShare.ValidatorPubKey, options.SSVShare.ValidatorIndex) qbftCtrl := buildController(spectypes.RoleAggregator, aggregatorValueCheckF) - runners[role], err = runner.NewAggregatorRunner(domainType, options.NetworkConfig.Beacon.GetBeaconNetwork(), shareMap, qbftCtrl, options.Beacon, options.Network, options.Signer, options.OperatorSigner, aggregatorValueCheckF, 0) + runners[role], err = runner.NewAggregatorRunner(options.NetworkConfig, shareMap, qbftCtrl, options.Beacon, options.Network, options.Signer, options.OperatorSigner, aggregatorValueCheckF, 0) case spectypes.RoleSyncCommitteeContribution: - syncCommitteeContributionValueCheckF := ssv.SyncCommitteeContributionValueCheckF(options.Signer, options.NetworkConfig.Beacon.GetBeaconNetwork(), options.SSVShare.ValidatorPubKey, options.SSVShare.ValidatorIndex) + syncCommitteeContributionValueCheckF := ssv.SyncCommitteeContributionValueCheckF(options.Signer, options.NetworkConfig, options.SSVShare.ValidatorPubKey, options.SSVShare.ValidatorIndex) qbftCtrl := buildController(spectypes.RoleSyncCommitteeContribution, syncCommitteeContributionValueCheckF) - runners[role], err = runner.NewSyncCommitteeAggregatorRunner(domainType, options.NetworkConfig.Beacon.GetBeaconNetwork(), shareMap, qbftCtrl, options.Beacon, options.Network, options.Signer, options.OperatorSigner, syncCommitteeContributionValueCheckF, 0) + runners[role], err = runner.NewSyncCommitteeAggregatorRunner(options.NetworkConfig, shareMap, qbftCtrl, options.Beacon, options.Network, options.Signer, options.OperatorSigner, syncCommitteeContributionValueCheckF, 0) case spectypes.RoleValidatorRegistration: - runners[role], err = runner.NewValidatorRegistrationRunner(domainType, options.NetworkConfig.Beacon.GetBeaconNetwork(), shareMap, options.Beacon, options.Network, options.Signer, options.OperatorSigner, options.GasLimit) + runners[role], err = runner.NewValidatorRegistrationRunner(options.NetworkConfig, shareMap, options.Beacon, options.Network, options.Signer, options.OperatorSigner, options.GasLimit) case spectypes.RoleVoluntaryExit: - runners[role], err = runner.NewVoluntaryExitRunner(domainType, options.NetworkConfig.Beacon.GetBeaconNetwork(), shareMap, options.Beacon, options.Network, options.Signer, options.OperatorSigner) + runners[role], err = runner.NewVoluntaryExitRunner(options.NetworkConfig, shareMap, options.Beacon, options.Network, options.Signer, options.OperatorSigner) } if err != nil { return nil, errors.Wrap(err, "could not create duty runner") diff --git a/operator/validator/controller_test.go b/operator/validator/controller_test.go index 0d203af257..26de242db1 100644 --- a/operator/validator/controller_test.go +++ b/operator/validator/controller_test.go @@ -513,8 +513,6 @@ func TestSetupValidators(t *testing.T) { committeeMap := make(map[spectypes.CommitteeID]*validator.Committee) mockValidatorsMap := validators.New(context.TODO(), validators.WithInitialState(testValidatorsMap, committeeMap)) - bc.EXPECT().GetBeaconNetwork().Return(networkconfig.TestNetwork.Beacon.GetBeaconNetwork()).AnyTimes() - // Set up the controller with mock data controllerOptions := MockControllerOptions{ beacon: bc, @@ -579,9 +577,6 @@ func TestGetValidatorStats(t *testing.T) { bc := beacon.NewMockBeaconNode(ctrl) activationEpoch, exitEpoch := phase0.Epoch(1), goclient.FarFutureEpoch - netCfg := networkconfig.TestNetwork - bc.EXPECT().GetBeaconNetwork().Return(netCfg.Beacon.GetBeaconNetwork()).AnyTimes() - t.Run("Test with multiple operators", func(t *testing.T) { // Setup for this subtest operatorIds := []uint64{1, 2, 3} diff --git a/operator/validator/metadata/syncer.go b/operator/validator/metadata/syncer.go index 633855d0c0..c1186a3638 100644 --- a/operator/validator/metadata/syncer.go +++ b/operator/validator/metadata/syncer.go @@ -12,6 +12,7 @@ import ( "github.com/ssvlabs/ssv/logging/fields" networkcommons "github.com/ssvlabs/ssv/network/commons" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ssvtypes "github.com/ssvlabs/ssv/protocol/v2/types" registrystorage "github.com/ssvlabs/ssv/registry/storage" @@ -31,7 +32,7 @@ type Syncer struct { logger *zap.Logger shareStorage shareStorage validatorStore selfValidatorStore - beaconNetwork beacon.BeaconNetwork + beaconConfig networkconfig.BeaconConfig beaconNode beacon.BeaconNode fixedSubnets networkcommons.Subnets syncInterval time.Duration @@ -53,7 +54,7 @@ func NewSyncer( logger *zap.Logger, shareStorage shareStorage, validatorStore selfValidatorStore, - beaconNetwork beacon.BeaconNetwork, + beaconNetwork networkconfig.BeaconConfig, beaconNode beacon.BeaconNode, fixedSubnets networkcommons.Subnets, opts ...Option, @@ -62,7 +63,7 @@ func NewSyncer( logger: logger, shareStorage: shareStorage, validatorStore: validatorStore, - beaconNetwork: beaconNetwork, + beaconConfig: beaconNetwork, beaconNode: beaconNode, fixedSubnets: fixedSubnets, syncInterval: defaultSyncInterval, @@ -253,14 +254,14 @@ func (s *Syncer) syncNextBatch(ctx context.Context, subnetsBuf *big.Int) (SyncBa pubKeys[i] = share.ValidatorPubKey } - indicesBefore := s.allActiveIndices(ctx, s.beaconNetwork.GetBeaconNetwork().EstimatedCurrentEpoch()) + indicesBefore := s.allActiveIndices(ctx, s.beaconConfig.EstimatedCurrentEpoch()) validators, err := s.Sync(ctx, pubKeys) if err != nil { return SyncBatch{}, false, fmt.Errorf("sync: %w", err) } - indicesAfter := s.allActiveIndices(ctx, s.beaconNetwork.GetBeaconNetwork().EstimatedCurrentEpoch()) + indicesAfter := s.allActiveIndices(ctx, s.beaconConfig.EstimatedCurrentEpoch()) update := SyncBatch{ IndicesBefore: indicesBefore, diff --git a/operator/validator/metadata/syncer_test.go b/operator/validator/metadata/syncer_test.go index ceba8dbc94..a77c512cca 100644 --- a/operator/validator/metadata/syncer_test.go +++ b/operator/validator/metadata/syncer_test.go @@ -12,7 +12,7 @@ import ( spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - gomock "go.uber.org/mock/gomock" + "go.uber.org/mock/gomock" "go.uber.org/zap" "github.com/ssvlabs/ssv/beacon/goclient" @@ -98,7 +98,7 @@ func TestUpdateValidatorMetadata(t *testing.T) { noSubnets, err := commons.FromString("0x00000000000000000000000000000000") require.NoError(t, err) - syncer := NewSyncer(logger, sharesStorage, validatorStore, networkconfig.TestNetwork.Beacon, beaconNode, noSubnets) + syncer := NewSyncer(logger, sharesStorage, validatorStore, networkconfig.TestNetwork.BeaconConfig, beaconNode, noSubnets) _, err = syncer.Sync(context.TODO(), []spectypes.ValidatorPK{tc.testPublicKey}) if tc.sharesStorageErr != nil { require.ErrorIs(t, err, tc.sharesStorageErr) @@ -425,7 +425,7 @@ func TestSyncer_Stream(t *testing.T) { shareStorage: mockShareStorage, validatorStore: mockValidatorStore, beaconNode: defaultMockBeaconNode, - beaconNetwork: networkconfig.TestNetwork.Beacon, + beaconConfig: networkconfig.TestNetwork.BeaconConfig, syncInterval: testSyncInterval, streamInterval: testStreamInterval, updateSendTimeout: testUpdateSendTimeout, @@ -524,7 +524,7 @@ func TestSyncer_Stream(t *testing.T) { shareStorage: mockShareStorage, validatorStore: mockValidatorStore, beaconNode: errMockBeaconNode, - beaconNetwork: networkconfig.TestNetwork.Beacon, + beaconConfig: networkconfig.TestNetwork.BeaconConfig, syncInterval: testSyncInterval, streamInterval: testStreamInterval, updateSendTimeout: testUpdateSendTimeout, @@ -598,7 +598,7 @@ func TestSyncer_Stream(t *testing.T) { shareStorage: mockShareStorage, validatorStore: mockValidatorStore, beaconNode: defaultMockBeaconNode, - beaconNetwork: networkconfig.TestNetwork.Beacon, + beaconConfig: networkconfig.TestNetwork.BeaconConfig, syncInterval: testSyncInterval, streamInterval: testStreamInterval, updateSendTimeout: testUpdateSendTimeout, @@ -673,7 +673,7 @@ func TestWithUpdateInterval(t *testing.T) { logger, mockShareStorage, mockValidatorStore, - networkconfig.TestNetwork.Beacon, + networkconfig.TestNetwork.BeaconConfig, mockBeaconNode, noSubnets, WithSyncInterval(interval), diff --git a/operator/validator/task_executor.go b/operator/validator/task_executor.go index 2ab9d52567..9b18db7e4c 100644 --- a/operator/validator/task_executor.go +++ b/operator/validator/task_executor.go @@ -62,7 +62,7 @@ func (c *controller) ReactivateCluster(owner common.Address, operatorIDs []spect // Notify DutyScheduler about the changes in validator indices without blocking. go func() { ctx := context.Background() // TODO: pass context - if !c.reportIndicesChange(ctx, 2*c.beacon.GetBeaconNetwork().SlotDurationSec()) { + if !c.reportIndicesChange(ctx, 2*c.networkConfig.GetSlotDuration()) { logger.Error("failed to notify indices change") } }() @@ -109,7 +109,7 @@ func (c *controller) ExitValidator(pubKey phase0.BLSPubKey, blockNumber uint64, select { case c.validatorExitCh <- exitDesc: logger.Debug("added voluntary exit task to pipeline") - case <-time.After(2 * c.beacon.GetBeaconNetwork().SlotDurationSec()): + case <-time.After(2 * c.networkConfig.GetSlotDuration()): logger.Error("failed to schedule ExitValidator duty!") } }() diff --git a/operator/validator/task_executor_test.go b/operator/validator/task_executor_test.go index 857fe5dc33..dbabcd841b 100644 --- a/operator/validator/task_executor_test.go +++ b/operator/validator/task_executor_test.go @@ -215,8 +215,6 @@ func TestController_ReactivateCluster(t *testing.T) { recipientData := buildFeeRecipient("67Ce5c69260bd819B4e0AD13f4b873074D479811", "45E668aba4b7fc8761331EC3CE77584B7A99A51A") recipientStorage.EXPECT().GetRecipientData(gomock.Any(), gomock.Any()).AnyTimes().Return(recipientData, true, nil) - bc.EXPECT().GetBeaconNetwork().AnyTimes().Return(testingBC.GetBeaconNetwork()) - indiciesUpdate := make(chan struct{}) go func() { <-ctr.indicesChange diff --git a/protocol/v2/blockchain/beacon/client.go b/protocol/v2/blockchain/beacon/client.go index 0ab727fdc7..b228cc52e6 100644 --- a/protocol/v2/blockchain/beacon/client.go +++ b/protocol/v2/blockchain/beacon/client.go @@ -8,6 +8,8 @@ import ( "github.com/attestantio/go-eth2-client/spec/bellatrix" "github.com/attestantio/go-eth2-client/spec/phase0" specssv "github.com/ssvlabs/ssv-spec/ssv" + + "github.com/ssvlabs/ssv/networkconfig" ) // TODO: add missing tests @@ -49,7 +51,15 @@ type signer interface { // BeaconNode interface for all beacon duty calls type BeaconNode interface { - specssv.BeaconNode // spec beacon interface + specssv.AttesterCalls + specssv.ProposerCalls + specssv.AggregatorCalls + specssv.SyncCommitteeCalls + specssv.SyncCommitteeContributionCalls + specssv.ValidatorRegistrationCalls + specssv.VoluntaryExitCalls + specssv.DomainCalls + specssv.VersionCalls beaconDuties beaconSubscriber beaconValidator @@ -60,7 +70,7 @@ type BeaconNode interface { // Options for controller struct creation type Options struct { Context context.Context - Network Network + BeaconConfig networkconfig.BeaconConfig BeaconNodeAddr string `yaml:"BeaconNodeAddr" env:"BEACON_NODE_ADDR" env-required:"true" env-description:"Beacon node URL(s). Multiple nodes are supported via semicolon-separated URLs (e.g. 'http://localhost:5052;http://localhost:5053')"` SyncDistanceTolerance uint64 `yaml:"SyncDistanceTolerance" env:"BEACON_SYNC_DISTANCE_TOLERANCE" env-default:"4" env-description:"Maximum number of slots behind head considered in-sync"` WithWeightedAttestationData bool `yaml:"WithWeightedAttestationData" env:"WITH_WEIGHTED_ATTESTATION_DATA" env-default:"false" env-description:"Enable attestation data scoring across multiple beacon nodes"` diff --git a/protocol/v2/blockchain/beacon/mock_client.go b/protocol/v2/blockchain/beacon/mock_client.go index b1658013aa..b649abfa90 100644 --- a/protocol/v2/blockchain/beacon/mock_client.go +++ b/protocol/v2/blockchain/beacon/mock_client.go @@ -20,7 +20,6 @@ import ( bellatrix "github.com/attestantio/go-eth2-client/spec/bellatrix" phase0 "github.com/attestantio/go-eth2-client/spec/phase0" ssz "github.com/ferranbt/fastssz" - types "github.com/ssvlabs/ssv-spec/types" gomock "go.uber.org/mock/gomock" ) @@ -28,6 +27,7 @@ import ( type MockbeaconDuties struct { ctrl *gomock.Controller recorder *MockbeaconDutiesMockRecorder + isgomock struct{} } // MockbeaconDutiesMockRecorder is the mock recorder for MockbeaconDuties. @@ -110,6 +110,7 @@ func (mr *MockbeaconDutiesMockRecorder) SyncCommitteeDuties(ctx, epoch, indices type MockbeaconSubscriber struct { ctrl *gomock.Controller recorder *MockbeaconSubscriberMockRecorder + isgomock struct{} } // MockbeaconSubscriberMockRecorder is the mock recorder for MockbeaconSubscriber. @@ -161,6 +162,7 @@ func (mr *MockbeaconSubscriberMockRecorder) SubmitSyncCommitteeSubscriptions(ctx type MockbeaconValidator struct { ctrl *gomock.Controller recorder *MockbeaconValidatorMockRecorder + isgomock struct{} } // MockbeaconValidatorMockRecorder is the mock recorder for MockbeaconValidator. @@ -199,6 +201,7 @@ func (mr *MockbeaconValidatorMockRecorder) GetValidatorData(validatorPubKeys any type Mockproposer struct { ctrl *gomock.Controller recorder *MockproposerMockRecorder + isgomock struct{} } // MockproposerMockRecorder is the mock recorder for Mockproposer. @@ -236,6 +239,7 @@ func (mr *MockproposerMockRecorder) SubmitProposalPreparation(feeRecipients any) type Mocksigner struct { ctrl *gomock.Controller recorder *MocksignerMockRecorder + isgomock struct{} } // MocksignerMockRecorder is the mock recorder for Mocksigner. @@ -274,6 +278,7 @@ func (mr *MocksignerMockRecorder) ComputeSigningRoot(object, domain any) *gomock type MockBeaconNode struct { ctrl *gomock.Controller recorder *MockBeaconNodeMockRecorder + isgomock struct{} } // MockBeaconNodeMockRecorder is the mock recorder for MockBeaconNode. @@ -384,20 +389,6 @@ func (mr *MockBeaconNodeMockRecorder) GetBeaconBlock(slot, graffiti, randao any) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBeaconBlock", reflect.TypeOf((*MockBeaconNode)(nil).GetBeaconBlock), slot, graffiti, randao) } -// GetBeaconNetwork mocks base method. -func (m *MockBeaconNode) GetBeaconNetwork() types.BeaconNetwork { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBeaconNetwork") - ret0, _ := ret[0].(types.BeaconNetwork) - return ret0 -} - -// GetBeaconNetwork indicates an expected call of GetBeaconNetwork. -func (mr *MockBeaconNodeMockRecorder) GetBeaconNetwork() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBeaconNetwork", reflect.TypeOf((*MockBeaconNode)(nil).GetBeaconNetwork)) -} - // GetSyncCommitteeContribution mocks base method. func (m *MockBeaconNode) GetSyncCommitteeContribution(slot phase0.Slot, selectionProofs []phase0.BLSSignature, subnetIDs []uint64) (ssz.Marshaler, spec.DataVersion, error) { m.ctrl.T.Helper() diff --git a/protocol/v2/blockchain/beacon/mocks/network.go b/protocol/v2/blockchain/beacon/mocks/network.go deleted file mode 100644 index 7fdaea7afb..0000000000 --- a/protocol/v2/blockchain/beacon/mocks/network.go +++ /dev/null @@ -1,337 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: ./network.go -// -// Generated by this command: -// -// mockgen -package=mocks -destination=./mocks/network.go -source=./network.go -// - -// Package mocks is a generated GoMock package. -package mocks - -import ( - reflect "reflect" - time "time" - - phase0 "github.com/attestantio/go-eth2-client/spec/phase0" - types "github.com/ssvlabs/ssv-spec/types" - beacon "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" - gomock "go.uber.org/mock/gomock" -) - -// MockBeaconNetwork is a mock of BeaconNetwork interface. -type MockBeaconNetwork struct { - ctrl *gomock.Controller - recorder *MockBeaconNetworkMockRecorder -} - -// MockBeaconNetworkMockRecorder is the mock recorder for MockBeaconNetwork. -type MockBeaconNetworkMockRecorder struct { - mock *MockBeaconNetwork -} - -// NewMockBeaconNetwork creates a new mock instance. -func NewMockBeaconNetwork(ctrl *gomock.Controller) *MockBeaconNetwork { - mock := &MockBeaconNetwork{ctrl: ctrl} - mock.recorder = &MockBeaconNetworkMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockBeaconNetwork) EXPECT() *MockBeaconNetworkMockRecorder { - return m.recorder -} - -// EpochStartTime mocks base method. -func (m *MockBeaconNetwork) EpochStartTime(epoch phase0.Epoch) time.Time { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EpochStartTime", epoch) - ret0, _ := ret[0].(time.Time) - return ret0 -} - -// EpochStartTime indicates an expected call of EpochStartTime. -func (mr *MockBeaconNetworkMockRecorder) EpochStartTime(epoch any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochStartTime", reflect.TypeOf((*MockBeaconNetwork)(nil).EpochStartTime), epoch) -} - -// EpochsPerSyncCommitteePeriod mocks base method. -func (m *MockBeaconNetwork) EpochsPerSyncCommitteePeriod() uint64 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EpochsPerSyncCommitteePeriod") - ret0, _ := ret[0].(uint64) - return ret0 -} - -// EpochsPerSyncCommitteePeriod indicates an expected call of EpochsPerSyncCommitteePeriod. -func (mr *MockBeaconNetworkMockRecorder) EpochsPerSyncCommitteePeriod() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochsPerSyncCommitteePeriod", reflect.TypeOf((*MockBeaconNetwork)(nil).EpochsPerSyncCommitteePeriod)) -} - -// EstimatedCurrentEpoch mocks base method. -func (m *MockBeaconNetwork) EstimatedCurrentEpoch() phase0.Epoch { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EstimatedCurrentEpoch") - ret0, _ := ret[0].(phase0.Epoch) - return ret0 -} - -// EstimatedCurrentEpoch indicates an expected call of EstimatedCurrentEpoch. -func (mr *MockBeaconNetworkMockRecorder) EstimatedCurrentEpoch() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedCurrentEpoch", reflect.TypeOf((*MockBeaconNetwork)(nil).EstimatedCurrentEpoch)) -} - -// EstimatedCurrentSlot mocks base method. -func (m *MockBeaconNetwork) EstimatedCurrentSlot() phase0.Slot { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EstimatedCurrentSlot") - ret0, _ := ret[0].(phase0.Slot) - return ret0 -} - -// EstimatedCurrentSlot indicates an expected call of EstimatedCurrentSlot. -func (mr *MockBeaconNetworkMockRecorder) EstimatedCurrentSlot() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedCurrentSlot", reflect.TypeOf((*MockBeaconNetwork)(nil).EstimatedCurrentSlot)) -} - -// EstimatedEpochAtSlot mocks base method. -func (m *MockBeaconNetwork) EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EstimatedEpochAtSlot", slot) - ret0, _ := ret[0].(phase0.Epoch) - return ret0 -} - -// EstimatedEpochAtSlot indicates an expected call of EstimatedEpochAtSlot. -func (mr *MockBeaconNetworkMockRecorder) EstimatedEpochAtSlot(slot any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedEpochAtSlot", reflect.TypeOf((*MockBeaconNetwork)(nil).EstimatedEpochAtSlot), slot) -} - -// EstimatedSlotAtTime mocks base method. -func (m *MockBeaconNetwork) EstimatedSlotAtTime(time int64) phase0.Slot { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EstimatedSlotAtTime", time) - ret0, _ := ret[0].(phase0.Slot) - return ret0 -} - -// EstimatedSlotAtTime indicates an expected call of EstimatedSlotAtTime. -func (mr *MockBeaconNetworkMockRecorder) EstimatedSlotAtTime(time any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedSlotAtTime", reflect.TypeOf((*MockBeaconNetwork)(nil).EstimatedSlotAtTime), time) -} - -// EstimatedSyncCommitteePeriodAtEpoch mocks base method. -func (m *MockBeaconNetwork) EstimatedSyncCommitteePeriodAtEpoch(epoch phase0.Epoch) uint64 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EstimatedSyncCommitteePeriodAtEpoch", epoch) - ret0, _ := ret[0].(uint64) - return ret0 -} - -// EstimatedSyncCommitteePeriodAtEpoch indicates an expected call of EstimatedSyncCommitteePeriodAtEpoch. -func (mr *MockBeaconNetworkMockRecorder) EstimatedSyncCommitteePeriodAtEpoch(epoch any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedSyncCommitteePeriodAtEpoch", reflect.TypeOf((*MockBeaconNetwork)(nil).EstimatedSyncCommitteePeriodAtEpoch), epoch) -} - -// EstimatedTimeAtSlot mocks base method. -func (m *MockBeaconNetwork) EstimatedTimeAtSlot(slot phase0.Slot) int64 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EstimatedTimeAtSlot", slot) - ret0, _ := ret[0].(int64) - return ret0 -} - -// EstimatedTimeAtSlot indicates an expected call of EstimatedTimeAtSlot. -func (mr *MockBeaconNetworkMockRecorder) EstimatedTimeAtSlot(slot any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimatedTimeAtSlot", reflect.TypeOf((*MockBeaconNetwork)(nil).EstimatedTimeAtSlot), slot) -} - -// FirstEpochOfSyncPeriod mocks base method. -func (m *MockBeaconNetwork) FirstEpochOfSyncPeriod(period uint64) phase0.Epoch { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FirstEpochOfSyncPeriod", period) - ret0, _ := ret[0].(phase0.Epoch) - return ret0 -} - -// FirstEpochOfSyncPeriod indicates an expected call of FirstEpochOfSyncPeriod. -func (mr *MockBeaconNetworkMockRecorder) FirstEpochOfSyncPeriod(period any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FirstEpochOfSyncPeriod", reflect.TypeOf((*MockBeaconNetwork)(nil).FirstEpochOfSyncPeriod), period) -} - -// FirstSlotAtEpoch mocks base method. -func (m *MockBeaconNetwork) FirstSlotAtEpoch(epoch phase0.Epoch) phase0.Slot { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FirstSlotAtEpoch", epoch) - ret0, _ := ret[0].(phase0.Slot) - return ret0 -} - -// FirstSlotAtEpoch indicates an expected call of FirstSlotAtEpoch. -func (mr *MockBeaconNetworkMockRecorder) FirstSlotAtEpoch(epoch any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FirstSlotAtEpoch", reflect.TypeOf((*MockBeaconNetwork)(nil).FirstSlotAtEpoch), epoch) -} - -// ForkVersion mocks base method. -func (m *MockBeaconNetwork) ForkVersion() [4]byte { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ForkVersion") - ret0, _ := ret[0].([4]byte) - return ret0 -} - -// ForkVersion indicates an expected call of ForkVersion. -func (mr *MockBeaconNetworkMockRecorder) ForkVersion() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForkVersion", reflect.TypeOf((*MockBeaconNetwork)(nil).ForkVersion)) -} - -// GetBeaconNetwork mocks base method. -func (m *MockBeaconNetwork) GetBeaconNetwork() types.BeaconNetwork { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBeaconNetwork") - ret0, _ := ret[0].(types.BeaconNetwork) - return ret0 -} - -// GetBeaconNetwork indicates an expected call of GetBeaconNetwork. -func (mr *MockBeaconNetworkMockRecorder) GetBeaconNetwork() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBeaconNetwork", reflect.TypeOf((*MockBeaconNetwork)(nil).GetBeaconNetwork)) -} - -// GetEpochFirstSlot mocks base method. -func (m *MockBeaconNetwork) GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEpochFirstSlot", epoch) - ret0, _ := ret[0].(phase0.Slot) - return ret0 -} - -// GetEpochFirstSlot indicates an expected call of GetEpochFirstSlot. -func (mr *MockBeaconNetworkMockRecorder) GetEpochFirstSlot(epoch any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEpochFirstSlot", reflect.TypeOf((*MockBeaconNetwork)(nil).GetEpochFirstSlot), epoch) -} - -// GetNetwork mocks base method. -func (m *MockBeaconNetwork) GetNetwork() beacon.Network { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetNetwork") - ret0, _ := ret[0].(beacon.Network) - return ret0 -} - -// GetNetwork indicates an expected call of GetNetwork. -func (mr *MockBeaconNetworkMockRecorder) GetNetwork() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNetwork", reflect.TypeOf((*MockBeaconNetwork)(nil).GetNetwork)) -} - -// GetSlotEndTime mocks base method. -func (m *MockBeaconNetwork) GetSlotEndTime(slot phase0.Slot) time.Time { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSlotEndTime", slot) - ret0, _ := ret[0].(time.Time) - return ret0 -} - -// GetSlotEndTime indicates an expected call of GetSlotEndTime. -func (mr *MockBeaconNetworkMockRecorder) GetSlotEndTime(slot any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotEndTime", reflect.TypeOf((*MockBeaconNetwork)(nil).GetSlotEndTime), slot) -} - -// GetSlotStartTime mocks base method. -func (m *MockBeaconNetwork) GetSlotStartTime(slot phase0.Slot) time.Time { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSlotStartTime", slot) - ret0, _ := ret[0].(time.Time) - return ret0 -} - -// GetSlotStartTime indicates an expected call of GetSlotStartTime. -func (mr *MockBeaconNetworkMockRecorder) GetSlotStartTime(slot any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotStartTime", reflect.TypeOf((*MockBeaconNetwork)(nil).GetSlotStartTime), slot) -} - -// IsFirstSlotOfEpoch mocks base method. -func (m *MockBeaconNetwork) IsFirstSlotOfEpoch(slot phase0.Slot) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsFirstSlotOfEpoch", slot) - ret0, _ := ret[0].(bool) - return ret0 -} - -// IsFirstSlotOfEpoch indicates an expected call of IsFirstSlotOfEpoch. -func (mr *MockBeaconNetworkMockRecorder) IsFirstSlotOfEpoch(slot any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsFirstSlotOfEpoch", reflect.TypeOf((*MockBeaconNetwork)(nil).IsFirstSlotOfEpoch), slot) -} - -// LastSlotOfSyncPeriod mocks base method. -func (m *MockBeaconNetwork) LastSlotOfSyncPeriod(period uint64) phase0.Slot { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LastSlotOfSyncPeriod", period) - ret0, _ := ret[0].(phase0.Slot) - return ret0 -} - -// LastSlotOfSyncPeriod indicates an expected call of LastSlotOfSyncPeriod. -func (mr *MockBeaconNetworkMockRecorder) LastSlotOfSyncPeriod(period any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LastSlotOfSyncPeriod", reflect.TypeOf((*MockBeaconNetwork)(nil).LastSlotOfSyncPeriod), period) -} - -// MinGenesisTime mocks base method. -func (m *MockBeaconNetwork) MinGenesisTime() int64 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MinGenesisTime") - ret0, _ := ret[0].(int64) - return ret0 -} - -// MinGenesisTime indicates an expected call of MinGenesisTime. -func (mr *MockBeaconNetworkMockRecorder) MinGenesisTime() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MinGenesisTime", reflect.TypeOf((*MockBeaconNetwork)(nil).MinGenesisTime)) -} - -// SlotDurationSec mocks base method. -func (m *MockBeaconNetwork) SlotDurationSec() time.Duration { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SlotDurationSec") - ret0, _ := ret[0].(time.Duration) - return ret0 -} - -// SlotDurationSec indicates an expected call of SlotDurationSec. -func (mr *MockBeaconNetworkMockRecorder) SlotDurationSec() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SlotDurationSec", reflect.TypeOf((*MockBeaconNetwork)(nil).SlotDurationSec)) -} - -// SlotsPerEpoch mocks base method. -func (m *MockBeaconNetwork) SlotsPerEpoch() uint64 { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SlotsPerEpoch") - ret0, _ := ret[0].(uint64) - return ret0 -} - -// SlotsPerEpoch indicates an expected call of SlotsPerEpoch. -func (mr *MockBeaconNetworkMockRecorder) SlotsPerEpoch() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SlotsPerEpoch", reflect.TypeOf((*MockBeaconNetwork)(nil).SlotsPerEpoch)) -} diff --git a/protocol/v2/blockchain/beacon/network.go b/protocol/v2/blockchain/beacon/network.go deleted file mode 100644 index 30c87cfefb..0000000000 --- a/protocol/v2/blockchain/beacon/network.go +++ /dev/null @@ -1,163 +0,0 @@ -package beacon - -import ( - "time" - - "github.com/attestantio/go-eth2-client/spec/phase0" - spectypes "github.com/ssvlabs/ssv-spec/types" -) - -//go:generate go tool -modfile=../../../../tool.mod mockgen -package=mocks -destination=./mocks/network.go -source=./network.go - -// Network is a beacon chain network. -type Network struct { - spectypes.BeaconNetwork - LocalTestNet bool -} - -type BeaconNetwork interface { - ForkVersion() [4]byte - MinGenesisTime() int64 - SlotDurationSec() time.Duration - SlotsPerEpoch() uint64 - EstimatedCurrentSlot() phase0.Slot // TODO: use networkconfig's method instead - EstimatedSlotAtTime(time int64) phase0.Slot - EstimatedTimeAtSlot(slot phase0.Slot) int64 - EstimatedCurrentEpoch() phase0.Epoch - EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch // TODO: use networkconfig's method instead - FirstSlotAtEpoch(epoch phase0.Epoch) phase0.Slot - EpochStartTime(epoch phase0.Epoch) time.Time - - GetSlotStartTime(slot phase0.Slot) time.Time - GetSlotEndTime(slot phase0.Slot) time.Time - IsFirstSlotOfEpoch(slot phase0.Slot) bool - GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot - - EpochsPerSyncCommitteePeriod() uint64 - EstimatedSyncCommitteePeriodAtEpoch(epoch phase0.Epoch) uint64 - FirstEpochOfSyncPeriod(period uint64) phase0.Epoch - LastSlotOfSyncPeriod(period uint64) phase0.Slot - - GetNetwork() Network - GetBeaconNetwork() spectypes.BeaconNetwork -} - -// NewNetwork creates a new beacon chain network. -func NewNetwork(network spectypes.BeaconNetwork) Network { - return Network{ - BeaconNetwork: network, - LocalTestNet: false, - } -} - -// NewLocalTestNetwork creates a new local beacon chain network. -func NewLocalTestNetwork(network spectypes.BeaconNetwork) Network { - return Network{ - BeaconNetwork: network, - LocalTestNet: true, - } -} - -// MinGenesisTime returns min genesis time value -func (n Network) MinGenesisTime() int64 { - if n.LocalTestNet { - return 1689072978 - } - return int64(n.BeaconNetwork.MinGenesisTime()) // #nosec G115 -} - -// GetNetwork returns the network -func (n Network) GetNetwork() Network { - return n -} - -// GetBeaconNetwork returns the beacon network the node is on -func (n Network) GetBeaconNetwork() spectypes.BeaconNetwork { - return n.BeaconNetwork -} - -// GetSlotStartTime returns the start time for the given slot -func (n Network) GetSlotStartTime(slot phase0.Slot) time.Time { - timeSinceGenesisStart := int64(uint64(slot) * uint64(n.SlotDurationSec().Seconds())) // #nosec G115 - start := time.Unix(n.MinGenesisTime()+timeSinceGenesisStart, 0) - return start -} - -// GetSlotEndTime returns the end time for the given slot -func (n Network) GetSlotEndTime(slot phase0.Slot) time.Time { - return n.GetSlotStartTime(slot + 1) -} - -// EstimatedCurrentSlot returns the estimation of the current slot -func (n Network) EstimatedCurrentSlot() phase0.Slot { - return n.EstimatedSlotAtTime(time.Now().Unix()) -} - -// EstimatedSlotAtTime estimates slot at the given time -func (n Network) EstimatedSlotAtTime(time int64) phase0.Slot { - genesis := n.MinGenesisTime() - if time < genesis { - return 0 - } - return phase0.Slot(uint64(time-genesis) / uint64(n.SlotDurationSec().Seconds())) //#nosec G115 -} - -// EstimatedCurrentEpoch estimates the current epoch -// https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#compute_start_slot_at_epoch -func (n Network) EstimatedCurrentEpoch() phase0.Epoch { - return n.EstimatedEpochAtSlot(n.EstimatedCurrentSlot()) -} - -// EstimatedEpochAtSlot estimates epoch at the given slot -func (n Network) EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch { - return phase0.Epoch(slot / phase0.Slot(n.SlotsPerEpoch())) -} - -// IsFirstSlotOfEpoch estimates epoch at the given slot -func (n Network) IsFirstSlotOfEpoch(slot phase0.Slot) bool { - return uint64(slot)%n.SlotsPerEpoch() == 0 -} - -// GetEpochFirstSlot returns the beacon node first slot in epoch -func (n Network) GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot { - return phase0.Slot(uint64(epoch) * n.SlotsPerEpoch()) -} - -// EpochsPerSyncCommitteePeriod returns the number of epochs per sync committee period. -func (n Network) EpochsPerSyncCommitteePeriod() uint64 { - return 256 -} - -// EstimatedSyncCommitteePeriodAtEpoch estimates the current sync committee period at the given Epoch -func (n Network) EstimatedSyncCommitteePeriodAtEpoch(epoch phase0.Epoch) uint64 { - return uint64(epoch) / n.EpochsPerSyncCommitteePeriod() -} - -// FirstEpochOfSyncPeriod calculates the first epoch of the given sync period. -func (n Network) FirstEpochOfSyncPeriod(period uint64) phase0.Epoch { - return phase0.Epoch(period * n.EpochsPerSyncCommitteePeriod()) -} - -// LastSlotOfSyncPeriod calculates the first epoch of the given sync period. -func (n Network) LastSlotOfSyncPeriod(period uint64) phase0.Slot { - lastEpoch := n.FirstEpochOfSyncPeriod(period+1) - 1 - // If we are in the sync committee that ends at slot x we do not generate a message during slot x-1 - // as it will never be included, hence -1. - return n.GetEpochFirstSlot(lastEpoch+1) - 2 -} - -func (n Network) String() string { - return string(n.BeaconNetwork) -} - -func (n Network) MarshalJSON() ([]byte, error) { - return []byte(`"` + n.BeaconNetwork + `"`), nil -} - -func (n *Network) UnmarshalJSON(b []byte) error { - if len(b) < 2 { - return nil - } - *n = NewNetwork(spectypes.BeaconNetwork(b[1 : len(b)-1])) - return nil -} diff --git a/protocol/v2/blockchain/beacon/network_test.go b/protocol/v2/blockchain/beacon/network_test.go deleted file mode 100644 index 6145dd7667..0000000000 --- a/protocol/v2/blockchain/beacon/network_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package beacon - -import ( - "testing" - - "github.com/attestantio/go-eth2-client/spec/phase0" - spectypes "github.com/ssvlabs/ssv-spec/types" - "github.com/stretchr/testify/require" -) - -func TestNetwork_GetSlotEndTime(t *testing.T) { - slot := phase0.Slot(1) - - n := NewNetwork(spectypes.PraterNetwork) - slotStart := n.GetSlotStartTime(slot) - slotEnd := n.GetSlotEndTime(slot) - - require.Equal(t, n.SlotDurationSec(), slotEnd.Sub(slotStart)) -} diff --git a/protocol/v2/qbft/roundtimer/timer.go b/protocol/v2/qbft/roundtimer/timer.go index 5f8ee3347e..87bc7d509b 100644 --- a/protocol/v2/qbft/roundtimer/timer.go +++ b/protocol/v2/qbft/roundtimer/timer.go @@ -10,6 +10,7 @@ import ( specqbft "github.com/ssvlabs/ssv-spec/qbft" spectypes "github.com/ssvlabs/ssv-spec/types" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/utils/casts" ) @@ -58,21 +59,21 @@ type RoundTimer struct { timeoutOptions TimeoutOptions // role is the role of the instance role spectypes.RunnerRole - // beaconNetwork is the beacon network - beaconNetwork BeaconNetwork + // netCfg is the network network + netCfg networkconfig.Beacon } // New creates a new instance of RoundTimer. -func New(pctx context.Context, beaconNetwork BeaconNetwork, role spectypes.RunnerRole, done OnRoundTimeoutF) *RoundTimer { +func New(pctx context.Context, beaconConfig networkconfig.Beacon, role spectypes.RunnerRole, done OnRoundTimeoutF) *RoundTimer { ctx, cancelCtx := context.WithCancel(pctx) return &RoundTimer{ - mtx: &sync.RWMutex{}, - ctx: ctx, - cancelCtx: cancelCtx, - timer: nil, - done: done, - role: role, - beaconNetwork: beaconNetwork, + mtx: &sync.RWMutex{}, + ctx: ctx, + cancelCtx: cancelCtx, + timer: nil, + done: done, + role: role, + netCfg: beaconConfig, timeoutOptions: TimeoutOptions{ quickThreshold: QuickTimeoutThreshold, quick: QuickTimeout, @@ -110,10 +111,10 @@ func (t *RoundTimer) RoundTimeout(height specqbft.Height, round specqbft.Round) switch t.role { case spectypes.RoleCommittee: // third of the slot time - baseDuration = t.beaconNetwork.SlotDurationSec() / 3 + baseDuration = t.netCfg.GetSlotDuration() / 3 case spectypes.RoleAggregator, spectypes.RoleSyncCommitteeContribution: // two-third of the slot time - baseDuration = t.beaconNetwork.SlotDurationSec() / 3 * 2 + baseDuration = t.netCfg.GetSlotDuration() / 3 * 2 default: if round <= t.timeoutOptions.quickThreshold { return t.timeoutOptions.quick @@ -135,7 +136,7 @@ func (t *RoundTimer) RoundTimeout(height specqbft.Height, round specqbft.Round) timeoutDuration := baseDuration + additionalTimeout // Get the start time of the duty - dutyStartTime := t.beaconNetwork.GetSlotStartTime(phase0.Slot(height)) + dutyStartTime := t.netCfg.GetSlotStartTime(phase0.Slot(height)) // Calculate the time until the duty should start plus the timeout duration return time.Until(dutyStartTime.Add(timeoutDuration)) diff --git a/protocol/v2/qbft/roundtimer/timer_test.go b/protocol/v2/qbft/roundtimer/timer_test.go index 207a8d44ef..4b383f2fe1 100644 --- a/protocol/v2/qbft/roundtimer/timer_test.go +++ b/protocol/v2/qbft/roundtimer/timer_test.go @@ -8,13 +8,11 @@ import ( "testing" "time" - "github.com/attestantio/go-eth2-client/spec/phase0" specqbft "github.com/ssvlabs/ssv-spec/qbft" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/stretchr/testify/require" - gomock "go.uber.org/mock/gomock" - "github.com/ssvlabs/ssv/protocol/v2/qbft/roundtimer/mocks" + "github.com/ssvlabs/ssv/networkconfig" ) func TestTimeoutForRound(t *testing.T) { @@ -50,21 +48,16 @@ func TestTimeoutForRound(t *testing.T) { } } -func setupMockBeaconNetwork(t *testing.T) *mocks.MockBeaconNetwork { - ctrl := gomock.NewController(t) - mockBeaconNetwork := mocks.NewMockBeaconNetwork(ctrl) - - mockBeaconNetwork.EXPECT().SlotDurationSec().Return(120 * time.Millisecond).AnyTimes() - mockBeaconNetwork.EXPECT().GetSlotStartTime(gomock.Any()).DoAndReturn( - func(slot phase0.Slot) time.Time { - return time.Now() - }, - ).AnyTimes() - return mockBeaconNetwork +func setupMockBeaconConfig() networkconfig.BeaconConfig { + config := networkconfig.TestNetwork.BeaconConfig + config.SlotDuration = 120 * time.Millisecond + config.GenesisTime = time.Now() + + return config } -func setupTimer(mockBeaconNetwork *mocks.MockBeaconNetwork, onTimeout OnRoundTimeoutF, role spectypes.RunnerRole, round specqbft.Round) *RoundTimer { - timer := New(context.Background(), mockBeaconNetwork, role, onTimeout) +func setupTimer(beaconConfig networkconfig.BeaconConfig, onTimeout OnRoundTimeoutF, role spectypes.RunnerRole, round specqbft.Round) *RoundTimer { + timer := New(context.Background(), beaconConfig, role, onTimeout) timer.timeoutOptions = TimeoutOptions{ quickThreshold: round, quick: 100 * time.Millisecond, @@ -75,7 +68,7 @@ func setupTimer(mockBeaconNetwork *mocks.MockBeaconNetwork, onTimeout OnRoundTim } func testTimeoutForRound(t *testing.T, role spectypes.RunnerRole, threshold specqbft.Round) { - mockBeaconNetwork := setupMockBeaconNetwork(t) + mockBeaconNetwork := setupMockBeaconConfig() count := int32(0) onTimeout := func(round specqbft.Round) { @@ -91,7 +84,7 @@ func testTimeoutForRound(t *testing.T, role spectypes.RunnerRole, threshold spec } func testTimeoutForRoundElapsed(t *testing.T, role spectypes.RunnerRole, threshold specqbft.Round) { - mockBeaconNetwork := setupMockBeaconNetwork(t) + mockBeaconNetwork := setupMockBeaconConfig() count := int32(0) onTimeout := func(round specqbft.Round) { @@ -109,8 +102,7 @@ func testTimeoutForRoundElapsed(t *testing.T, role spectypes.RunnerRole, thresho } func testTimeoutForRoundMulti(t *testing.T, role spectypes.RunnerRole, threshold specqbft.Round) { - ctrl := gomock.NewController(t) - mockBeaconNetwork := mocks.NewMockBeaconNetwork(ctrl) + mockBeaconConfig := setupMockBeaconConfig() var count int32 var timestamps = make([]int64, 4) @@ -123,19 +115,11 @@ func testTimeoutForRoundMulti(t *testing.T, role spectypes.RunnerRole, threshold mu.Unlock() } - timeNow := time.Now() - mockBeaconNetwork.EXPECT().SlotDurationSec().Return(100 * time.Millisecond).AnyTimes() - mockBeaconNetwork.EXPECT().GetSlotStartTime(gomock.Any()).DoAndReturn( - func(slot phase0.Slot) time.Time { - return timeNow - }, - ).AnyTimes() - var wg sync.WaitGroup for i := 0; i < 4; i++ { wg.Add(1) go func(index int) { - timer := New(context.Background(), mockBeaconNetwork, role, func(round specqbft.Round) { onTimeout(index) }) + timer := New(context.Background(), mockBeaconConfig, role, func(round specqbft.Round) { onTimeout(index) }) timer.timeoutOptions = TimeoutOptions{ quickThreshold: threshold, quick: 100 * time.Millisecond, @@ -148,7 +132,7 @@ func testTimeoutForRoundMulti(t *testing.T, role spectypes.RunnerRole, threshold wg.Wait() // Wait for all go-routines to finish - timer := New(context.Background(), mockBeaconNetwork, role, nil) + timer := New(context.Background(), mockBeaconConfig, role, nil) timer.timeoutOptions = TimeoutOptions{ quickThreshold: specqbft.Round(1), quick: 100 * time.Millisecond, diff --git a/protocol/v2/ssv/runner/aggregator.go b/protocol/v2/ssv/runner/aggregator.go index 27e5781beb..ead21e34cd 100644 --- a/protocol/v2/ssv/runner/aggregator.go +++ b/protocol/v2/ssv/runner/aggregator.go @@ -16,6 +16,7 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/logging/fields" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" "github.com/ssvlabs/ssv/protocol/v2/qbft/controller" ssvtypes "github.com/ssvlabs/ssv/protocol/v2/types" @@ -35,8 +36,7 @@ type AggregatorRunner struct { var _ Runner = &AggregatorRunner{} func NewAggregatorRunner( - domainType spectypes.DomainType, - beaconNetwork spectypes.BeaconNetwork, + networkConfig networkconfig.Network, share map[phase0.ValidatorIndex]*spectypes.Share, qbftController *controller.Controller, beacon beacon.BeaconNode, @@ -53,8 +53,7 @@ func NewAggregatorRunner( return &AggregatorRunner{ BaseRunner: &BaseRunner{ RunnerRoleType: spectypes.RoleAggregator, - DomainType: domainType, - BeaconNetwork: beaconNetwork, + NetworkConfig: networkConfig, Share: share, QBFTController: qbftController, highestDecidedSlot: highestDecidedSlot, @@ -168,7 +167,7 @@ func (r *AggregatorRunner) ProcessConsensus(ctx context.Context, logger *zap.Log Messages: []*spectypes.PartialSignatureMessage{msg}, } - msgID := spectypes.NewMsgID(r.BaseRunner.DomainType, r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) + msgID := spectypes.NewMsgID(r.BaseRunner.NetworkConfig.GetDomainType(), r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) encodedMsg, err := postConsensusMsg.Encode() if err != nil { @@ -262,7 +261,7 @@ func (r *AggregatorRunner) ProcessPostConsensus(ctx context.Context, logger *zap recordDutyDuration(ctx, r.measurements.DutyDurationTime(), spectypes.BNRoleAggregator, r.GetState().RunningInstance.State.Round) recordSuccessfulSubmission(ctx, successfullySubmittedAggregates, - r.GetBeaconNode().GetBeaconNetwork().EstimatedEpochAtSlot(r.GetState().StartingDuty.DutySlot()), + r.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(r.GetState().StartingDuty.DutySlot()), spectypes.BNRoleAggregator) return nil @@ -308,7 +307,7 @@ func (r *AggregatorRunner) executeDuty(ctx context.Context, logger *zap.Logger, Messages: []*spectypes.PartialSignatureMessage{msg}, } - msgID := spectypes.NewMsgID(r.BaseRunner.DomainType, r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) + msgID := spectypes.NewMsgID(r.BaseRunner.NetworkConfig.GetDomainType(), r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) encodedMsg, err := msgs.Encode() if err != nil { return err diff --git a/protocol/v2/ssv/runner/committee.go b/protocol/v2/ssv/runner/committee.go index 775dcd8eb8..8506a1d211 100644 --- a/protocol/v2/ssv/runner/committee.go +++ b/protocol/v2/ssv/runner/committee.go @@ -50,7 +50,7 @@ type CommitteeRunner struct { } func NewCommitteeRunner( - networkConfig networkconfig.NetworkConfig, + networkConfig networkconfig.Network, share map[phase0.ValidatorIndex]*spectypes.Share, qbftController *controller.Controller, beacon beacon.BeaconNode, @@ -67,8 +67,7 @@ func NewCommitteeRunner( return &CommitteeRunner{ BaseRunner: &BaseRunner{ RunnerRoleType: spectypes.RoleCommittee, - DomainType: networkConfig.DomainType, - BeaconNetwork: networkConfig.Beacon.GetBeaconNetwork(), + NetworkConfig: networkConfig, Share: share, QBFTController: qbftController, }, @@ -230,7 +229,7 @@ func (cr *CommitteeRunner) ProcessConsensus(ctx context.Context, logger *zap.Log totalSyncCommitteeDuties := 0 blockedAttesterDuties := 0 - epoch := cr.beacon.GetBeaconNetwork().EstimatedEpochAtSlot(duty.DutySlot()) + epoch := cr.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(duty.DutySlot()) version := cr.beacon.DataVersion(epoch) for _, validatorDuty := range duty.(*spectypes.CommitteeDuty).ValidatorDuties { @@ -307,7 +306,7 @@ func (cr *CommitteeRunner) ProcessConsensus(ctx context.Context, logger *zap.Log ssvMsg := &spectypes.SSVMessage{ MsgType: spectypes.SSVPartialSignatureMsgType, MsgID: spectypes.NewMsgID( - cr.BaseRunner.DomainType, + cr.BaseRunner.NetworkConfig.GetDomainType(), cr.GetBaseRunner().QBFTController.CommitteeMember.CommitteeID[:], cr.BaseRunner.RunnerRoleType, ), @@ -504,7 +503,7 @@ func (cr *CommitteeRunner) ProcessPostConsensus(ctx context.Context, logger *zap if attestationsCount <= math.MaxUint32 { recordSuccessfulSubmission(ctx, uint32(attestationsCount), - cr.GetBeaconNode().GetBeaconNetwork().EstimatedEpochAtSlot(cr.GetBaseRunner().State.StartingDuty.DutySlot()), + cr.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(cr.GetBaseRunner().State.StartingDuty.DutySlot()), spectypes.BNRoleAttester) } @@ -514,7 +513,7 @@ func (cr *CommitteeRunner) ProcessPostConsensus(ctx context.Context, logger *zap // TODO return error? } logger.Info("✅ successfully submitted attestations", - fields.Epoch(cr.GetBeaconNode().GetBeaconNetwork().EstimatedEpochAtSlot(cr.GetBaseRunner().State.StartingDuty.DutySlot())), + fields.Epoch(cr.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(cr.GetBaseRunner().State.StartingDuty.DutySlot())), fields.Height(cr.BaseRunner.QBFTController.Height), fields.Round(cr.BaseRunner.State.RunningInstance.State.Round), fields.BlockRoot(attData.BeaconBlockRoot), @@ -547,7 +546,7 @@ func (cr *CommitteeRunner) ProcessPostConsensus(ctx context.Context, logger *zap if syncMsgsCount <= math.MaxUint32 { recordSuccessfulSubmission(ctx, uint32(syncMsgsCount), - cr.GetBeaconNode().GetBeaconNetwork().EstimatedEpochAtSlot(cr.GetBaseRunner().State.StartingDuty.DutySlot()), + cr.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(cr.GetBaseRunner().State.StartingDuty.DutySlot()), spectypes.BNRoleSyncCommittee) } @@ -669,7 +668,7 @@ func (cr *CommitteeRunner) expectedPostConsensusRootsAndBeaconObjects(logger *za } slot := duty.DutySlot() - epoch := cr.GetBaseRunner().BeaconNetwork.EstimatedEpochAtSlot(slot) + epoch := cr.GetBaseRunner().NetworkConfig.EstimatedEpochAtSlot(slot) dataVersion := cr.beacon.DataVersion(epoch) @@ -683,7 +682,7 @@ func (cr *CommitteeRunner) expectedPostConsensusRootsAndBeaconObjects(logger *za } logger := logger.With(fields.Validator(validatorDuty.PubKey[:])) slot := validatorDuty.DutySlot() - epoch := cr.GetBaseRunner().BeaconNetwork.EstimatedEpochAtSlot(slot) + epoch := cr.GetBaseRunner().NetworkConfig.EstimatedEpochAtSlot(slot) switch validatorDuty.Type { case spectypes.BNRoleAttester: // Attestation object diff --git a/protocol/v2/ssv/runner/proposer.go b/protocol/v2/ssv/runner/proposer.go index 4678c67731..795e6c645d 100644 --- a/protocol/v2/ssv/runner/proposer.go +++ b/protocol/v2/ssv/runner/proposer.go @@ -23,6 +23,7 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/logging/fields" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" "github.com/ssvlabs/ssv/protocol/v2/qbft/controller" ssvtypes "github.com/ssvlabs/ssv/protocol/v2/types" @@ -42,8 +43,7 @@ type ProposerRunner struct { } func NewProposerRunner( - domainType spectypes.DomainType, - beaconNetwork spectypes.BeaconNetwork, + networkConfig networkconfig.Network, share map[phase0.ValidatorIndex]*spectypes.Share, qbftController *controller.Controller, beacon beacon.BeaconNode, @@ -62,8 +62,7 @@ func NewProposerRunner( return &ProposerRunner{ BaseRunner: &BaseRunner{ RunnerRoleType: spectypes.RoleProposer, - DomainType: domainType, - BeaconNetwork: beaconNetwork, + NetworkConfig: networkConfig, Share: share, QBFTController: qbftController, highestDecidedSlot: highestDecidedSlot, @@ -214,7 +213,7 @@ func (r *ProposerRunner) ProcessConsensus(ctx context.Context, logger *zap.Logge Messages: []*spectypes.PartialSignatureMessage{msg}, } - msgID := spectypes.NewMsgID(r.BaseRunner.DomainType, r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) + msgID := spectypes.NewMsgID(r.BaseRunner.NetworkConfig.GetDomainType(), r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) encodedMsg, err := postConsensusMsg.Encode() if err != nil { return err @@ -351,7 +350,7 @@ func (r *ProposerRunner) ProcessPostConsensus(ctx context.Context, logger *zap.L recordDutyDuration(ctx, r.measurements.DutyDurationTime(), spectypes.BNRoleProposer, r.GetState().RunningInstance.State.Round) recordSuccessfulSubmission(ctx, uint32(successfullySubmittedProposals), - r.GetBeaconNode().GetBeaconNetwork().EstimatedEpochAtSlot(r.GetState().StartingDuty.DutySlot()), + r.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(r.GetState().StartingDuty.DutySlot()), spectypes.BNRoleProposer) return nil @@ -370,7 +369,7 @@ func (r *ProposerRunner) decidedBlindedBlock() bool { } func (r *ProposerRunner) expectedPreConsensusRootsAndDomain() ([]ssz.HashRoot, phase0.DomainType, error) { - epoch := r.BaseRunner.BeaconNetwork.EstimatedEpochAtSlot(r.GetState().StartingDuty.DutySlot()) + epoch := r.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(r.GetState().StartingDuty.DutySlot()) return []ssz.HashRoot{spectypes.SSZUint64(epoch)}, spectypes.DomainRandao, nil } @@ -414,7 +413,7 @@ func (r *ProposerRunner) executeDuty(ctx context.Context, logger *zap.Logger, du } // sign partial randao - epoch := r.GetBeaconNode().GetBeaconNetwork().EstimatedEpochAtSlot(duty.DutySlot()) + epoch := r.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(duty.DutySlot()) msg, err := r.BaseRunner.signBeaconObject(r, proposerDuty, spectypes.SSZUint64(epoch), duty.DutySlot(), spectypes.DomainRandao) if err != nil { return errors.Wrap(err, "could not sign randao") @@ -425,7 +424,7 @@ func (r *ProposerRunner) executeDuty(ctx context.Context, logger *zap.Logger, du Messages: []*spectypes.PartialSignatureMessage{msg}, } - msgID := spectypes.NewMsgID(r.BaseRunner.DomainType, r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) + msgID := spectypes.NewMsgID(r.BaseRunner.NetworkConfig.GetDomainType(), r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) encodedMsg, err := msgs.Encode() if err != nil { return err diff --git a/protocol/v2/ssv/runner/runner.go b/protocol/v2/ssv/runner/runner.go index 276115d9d2..b41492cbb3 100644 --- a/protocol/v2/ssv/runner/runner.go +++ b/protocol/v2/ssv/runner/runner.go @@ -12,6 +12,7 @@ import ( spectypes "github.com/ssvlabs/ssv-spec/types" "go.uber.org/zap" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" "github.com/ssvlabs/ssv/protocol/v2/qbft/controller" "github.com/ssvlabs/ssv/protocol/v2/ssv" @@ -62,8 +63,7 @@ type BaseRunner struct { State *State Share map[phase0.ValidatorIndex]*spectypes.Share QBFTController *controller.Controller - DomainType spectypes.DomainType - BeaconNetwork spectypes.BeaconNetwork + NetworkConfig networkconfig.Network RunnerRoleType spectypes.RunnerRole ssvtypes.OperatorSigner @@ -87,7 +87,7 @@ func (b *BaseRunner) MarshalJSON() ([]byte, error) { State *State Share map[phase0.ValidatorIndex]*spectypes.Share QBFTController *controller.Controller - BeaconNetwork spectypes.BeaconNetwork + BeaconConfig networkconfig.Beacon RunnerRoleType spectypes.RunnerRole highestDecidedSlot phase0.Slot } @@ -97,7 +97,7 @@ func (b *BaseRunner) MarshalJSON() ([]byte, error) { State: b.State, Share: b.Share, QBFTController: b.QBFTController, - BeaconNetwork: b.BeaconNetwork, + BeaconConfig: b.NetworkConfig, RunnerRoleType: b.RunnerRoleType, highestDecidedSlot: b.highestDecidedSlot, } @@ -130,8 +130,7 @@ func NewBaseRunner( state *State, share map[phase0.ValidatorIndex]*spectypes.Share, controller *controller.Controller, - domainType spectypes.DomainType, - beaconNetwork spectypes.BeaconNetwork, + networkConfig networkconfig.NetworkConfig, runnerRoleType spectypes.RunnerRole, highestDecidedSlot phase0.Slot, ) *BaseRunner { @@ -139,8 +138,7 @@ func NewBaseRunner( State: state, Share: share, QBFTController: controller, - BeaconNetwork: beaconNetwork, - DomainType: domainType, + NetworkConfig: networkConfig, RunnerRoleType: runnerRoleType, highestDecidedSlot: highestDecidedSlot, } diff --git a/protocol/v2/ssv/runner/runner_signatures.go b/protocol/v2/ssv/runner/runner_signatures.go index cf8b7c9958..2074732637 100644 --- a/protocol/v2/ssv/runner/runner_signatures.go +++ b/protocol/v2/ssv/runner/runner_signatures.go @@ -20,7 +20,7 @@ func (b *BaseRunner) signBeaconObject( slot spec.Slot, domainType spec.DomainType, ) (*spectypes.PartialSignatureMessage, error) { - epoch := runner.GetBaseRunner().BeaconNetwork.EstimatedEpochAtSlot(slot) + epoch := runner.GetBaseRunner().NetworkConfig.EstimatedEpochAtSlot(slot) domain, err := runner.GetBeaconNode().DomainData(epoch, domainType) if err != nil { return nil, errors.Wrap(err, "could not get beacon domain") diff --git a/protocol/v2/ssv/runner/runner_validations.go b/protocol/v2/ssv/runner/runner_validations.go index 293f22d77e..d2b2b86ba3 100644 --- a/protocol/v2/ssv/runner/runner_validations.go +++ b/protocol/v2/ssv/runner/runner_validations.go @@ -110,7 +110,7 @@ func (b *BaseRunner) verifyExpectedRoot(runner Runner, signedMsg *spectypes.Part // convert expected roots to map and mark unique roots when verified sortedExpectedRoots, err := func(expectedRootObjs []ssz.HashRoot) ([][32]byte, error) { - epoch := b.BeaconNetwork.EstimatedEpochAtSlot(b.State.StartingDuty.DutySlot()) + epoch := b.NetworkConfig.EstimatedEpochAtSlot(b.State.StartingDuty.DutySlot()) d, err := runner.GetBeaconNode().DomainData(epoch, domain) if err != nil { return nil, errors.Wrap(err, "could not get pre consensus root domain") diff --git a/protocol/v2/ssv/runner/sync_committee_aggregator.go b/protocol/v2/ssv/runner/sync_committee_aggregator.go index 25d790ee98..1d361d1cca 100644 --- a/protocol/v2/ssv/runner/sync_committee_aggregator.go +++ b/protocol/v2/ssv/runner/sync_committee_aggregator.go @@ -16,6 +16,7 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/logging/fields" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" "github.com/ssvlabs/ssv/protocol/v2/qbft/controller" ssvtypes "github.com/ssvlabs/ssv/protocol/v2/types" @@ -33,8 +34,7 @@ type SyncCommitteeAggregatorRunner struct { } func NewSyncCommitteeAggregatorRunner( - domainType spectypes.DomainType, - beaconNetwork spectypes.BeaconNetwork, + networkConfig networkconfig.Network, share map[phase0.ValidatorIndex]*spectypes.Share, qbftController *controller.Controller, beacon beacon.BeaconNode, @@ -51,8 +51,7 @@ func NewSyncCommitteeAggregatorRunner( return &SyncCommitteeAggregatorRunner{ BaseRunner: &BaseRunner{ RunnerRoleType: spectypes.RoleSyncCommitteeContribution, - DomainType: domainType, - BeaconNetwork: beaconNetwork, + NetworkConfig: networkConfig, Share: share, QBFTController: qbftController, highestDecidedSlot: highestDecidedSlot, @@ -204,7 +203,7 @@ func (r *SyncCommitteeAggregatorRunner) ProcessConsensus(ctx context.Context, lo Messages: msgs, } - msgID := spectypes.NewMsgID(r.BaseRunner.DomainType, r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) + msgID := spectypes.NewMsgID(r.BaseRunner.NetworkConfig.GetDomainType(), r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) encodedMsg, err := postConsensusMsg.Encode() if err != nil { @@ -316,7 +315,7 @@ func (r *SyncCommitteeAggregatorRunner) ProcessPostConsensus(ctx context.Context recordDutyDuration(ctx, r.measurements.DutyDurationTime(), spectypes.BNRoleSyncCommitteeContribution, r.GetState().RunningInstance.State.Round) recordSuccessfulSubmission(ctx, successfullySubmittedContributions, - r.GetBeaconNode().GetBeaconNetwork().EstimatedEpochAtSlot(r.GetState().StartingDuty.DutySlot()), + r.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(r.GetState().StartingDuty.DutySlot()), spectypes.BNRoleSyncCommitteeContribution) return nil @@ -329,7 +328,7 @@ func (r *SyncCommitteeAggregatorRunner) generateContributionAndProof(contrib alt SelectionProof: proof, } - epoch := r.BaseRunner.BeaconNetwork.EstimatedEpochAtSlot(r.GetState().StartingDuty.DutySlot()) + epoch := r.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(r.GetState().StartingDuty.DutySlot()) dContribAndProof, err := r.GetBeaconNode().DomainData(epoch, spectypes.DomainContributionAndProof) if err != nil { return nil, phase0.Root{}, errors.Wrap(err, "could not get domain data") @@ -413,7 +412,7 @@ func (r *SyncCommitteeAggregatorRunner) executeDuty(ctx context.Context, logger msgs.Messages = append(msgs.Messages, msg) } - msgID := spectypes.NewMsgID(r.BaseRunner.DomainType, r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) + msgID := spectypes.NewMsgID(r.BaseRunner.NetworkConfig.GetDomainType(), r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) encodedMsg, err := msgs.Encode() if err != nil { return err diff --git a/protocol/v2/ssv/runner/validator_registration.go b/protocol/v2/ssv/runner/validator_registration.go index 70937a7bc1..f5bfb39fd1 100644 --- a/protocol/v2/ssv/runner/validator_registration.go +++ b/protocol/v2/ssv/runner/validator_registration.go @@ -17,6 +17,7 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/logging/fields" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ssvtypes "github.com/ssvlabs/ssv/protocol/v2/types" ) @@ -34,8 +35,7 @@ type ValidatorRegistrationRunner struct { } func NewValidatorRegistrationRunner( - domainType spectypes.DomainType, - beaconNetwork spectypes.BeaconNetwork, + networkConfig networkconfig.Network, share map[phase0.ValidatorIndex]*spectypes.Share, beacon beacon.BeaconNode, network specqbft.Network, @@ -50,8 +50,7 @@ func NewValidatorRegistrationRunner( return &ValidatorRegistrationRunner{ BaseRunner: &BaseRunner{ RunnerRoleType: spectypes.RoleValidatorRegistration, - DomainType: domainType, - BeaconNetwork: beaconNetwork, + NetworkConfig: networkConfig, Share: share, }, @@ -173,7 +172,7 @@ func (r *ValidatorRegistrationRunner) executeDuty(ctx context.Context, logger *z Messages: []*spectypes.PartialSignatureMessage{msg}, } - msgID := spectypes.NewMsgID(r.BaseRunner.DomainType, r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) + msgID := spectypes.NewMsgID(r.BaseRunner.NetworkConfig.GetDomainType(), r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) encodedMsg, err := msgs.Encode() if err != nil { return err @@ -216,12 +215,12 @@ func (r *ValidatorRegistrationRunner) calculateValidatorRegistration(slot phase0 pk := phase0.BLSPubKey{} copy(pk[:], share.ValidatorPubKey[:]) - epoch := r.BaseRunner.BeaconNetwork.EstimatedEpochAtSlot(slot) + epoch := r.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(slot) return &v1.ValidatorRegistration{ FeeRecipient: share.FeeRecipientAddress, GasLimit: r.gasLimit, - Timestamp: r.BaseRunner.BeaconNetwork.EpochStartTime(epoch), + Timestamp: r.BaseRunner.NetworkConfig.EpochStartTime(epoch), Pubkey: pk, }, nil } diff --git a/protocol/v2/ssv/runner/voluntary_exit.go b/protocol/v2/ssv/runner/voluntary_exit.go index 576a895585..92f47565ca 100644 --- a/protocol/v2/ssv/runner/voluntary_exit.go +++ b/protocol/v2/ssv/runner/voluntary_exit.go @@ -14,6 +14,7 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/logging/fields" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ssvtypes "github.com/ssvlabs/ssv/protocol/v2/types" ) @@ -32,8 +33,7 @@ type VoluntaryExitRunner struct { } func NewVoluntaryExitRunner( - domainType spectypes.DomainType, - beaconNetwork spectypes.BeaconNetwork, + networkConfig networkconfig.Network, share map[phase0.ValidatorIndex]*spectypes.Share, beacon beacon.BeaconNode, network specqbft.Network, @@ -48,8 +48,7 @@ func NewVoluntaryExitRunner( return &VoluntaryExitRunner{ BaseRunner: &BaseRunner{ RunnerRoleType: spectypes.RoleVoluntaryExit, - DomainType: domainType, - BeaconNetwork: beaconNetwork, + NetworkConfig: networkConfig, Share: share, }, @@ -155,7 +154,7 @@ func (r *VoluntaryExitRunner) executeDuty(ctx context.Context, logger *zap.Logge Messages: []*spectypes.PartialSignatureMessage{msg}, } - msgID := spectypes.NewMsgID(r.BaseRunner.DomainType, r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) + msgID := spectypes.NewMsgID(r.BaseRunner.NetworkConfig.GetDomainType(), r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType) encodedMsg, err := msgs.Encode() if err != nil { return err @@ -190,7 +189,7 @@ func (r *VoluntaryExitRunner) executeDuty(ctx context.Context, logger *zap.Logge // Returns *phase0.VoluntaryExit object with current epoch and own validator index func (r *VoluntaryExitRunner) calculateVoluntaryExit() (*phase0.VoluntaryExit, error) { - epoch := r.BaseRunner.BeaconNetwork.EstimatedEpochAtSlot(r.BaseRunner.State.StartingDuty.DutySlot()) + epoch := r.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(r.BaseRunner.State.StartingDuty.DutySlot()) validatorIndex := r.GetState().StartingDuty.(*spectypes.ValidatorDuty).ValidatorIndex return &phase0.VoluntaryExit{ Epoch: epoch, diff --git a/protocol/v2/ssv/spectest/committee_msg_processing_type.go b/protocol/v2/ssv/spectest/committee_msg_processing_type.go index b887263d70..538aeeb688 100644 --- a/protocol/v2/ssv/spectest/committee_msg_processing_type.go +++ b/protocol/v2/ssv/spectest/committee_msg_processing_type.go @@ -19,6 +19,7 @@ import ( "github.com/ssvlabs/ssv/integration/qbft/tests" "github.com/ssvlabs/ssv/logging" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/ssv/queue" "github.com/ssvlabs/ssv/protocol/v2/ssv/validator" protocoltesting "github.com/ssvlabs/ssv/protocol/v2/testing" @@ -186,9 +187,9 @@ func overrideStateComparisonCommitteeSpecTest(t *testing.T, test *CommitteeSpecT committee.Shares = specCommittee.Share committee.CommitteeMember = &specCommittee.CommitteeMember - //for _, r := range committee.Runners { - // r.BaseRunner.BeaconNetwork = spectypes.BeaconTestNetwork - //} + for _, r := range committee.Runners { + r.BaseRunner.NetworkConfig = networkconfig.TestNetwork + } root, err := committee.GetRoot() require.NoError(t, err) diff --git a/protocol/v2/ssv/spectest/msg_processing_type.go b/protocol/v2/ssv/spectest/msg_processing_type.go index 92a9af188a..bf8bbec2c1 100644 --- a/protocol/v2/ssv/spectest/msg_processing_type.go +++ b/protocol/v2/ssv/spectest/msg_processing_type.go @@ -238,6 +238,8 @@ func overrideStateComparison(t *testing.T, test *MsgProcessingSpecTest, name str r, err = typescomparable.UnmarshalStateComparison(specDir, name, testType, r) require.NoError(t, err) + r.GetBaseRunner().NetworkConfig = networkconfig.TestNetwork + // override test.PostDutyRunnerState = r @@ -293,7 +295,7 @@ var baseCommitteeWithRunnerSample = func( ctx, cancel, logger, - runnerSample.GetBaseRunner().BeaconNetwork, + runnerSample.GetBaseRunner().NetworkConfig, spectestingutils.TestingCommitteeMember(keySetSample), createRunnerF, shareMap, diff --git a/protocol/v2/ssv/spectest/multi_start_new_runner_duty_type.go b/protocol/v2/ssv/spectest/multi_start_new_runner_duty_type.go index 8e301c686d..68919e3740 100644 --- a/protocol/v2/ssv/spectest/multi_start_new_runner_duty_type.go +++ b/protocol/v2/ssv/spectest/multi_start_new_runner_duty_type.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/ssv/runner" protocoltesting "github.com/ssvlabs/ssv/protocol/v2/testing" ) @@ -163,6 +164,8 @@ func overrideStateComparisonForStartNewRunnerDutySpecTest(t *testing.T, test *St r, err = typescomparable.UnmarshalStateComparison(specDir, name, testType, r) require.NoError(t, err) + r.GetBaseRunner().NetworkConfig = networkconfig.TestNetwork + // override test.PostDutyRunnerState = r diff --git a/protocol/v2/ssv/spectest/ssv_mapping_test.go b/protocol/v2/ssv/spectest/ssv_mapping_test.go index 298bd707a4..46020d3323 100644 --- a/protocol/v2/ssv/spectest/ssv_mapping_test.go +++ b/protocol/v2/ssv/spectest/ssv_mapping_test.go @@ -23,7 +23,6 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" - tests2 "github.com/ssvlabs/ssv/integration/qbft/tests" "github.com/ssvlabs/ssv/logging" "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/qbft/controller" @@ -366,7 +365,7 @@ func fixRunnerForRun(t *testing.T, runnerMap map[string]interface{}, ks *spectes base := &runner.BaseRunner{} byts, _ := json.Marshal(baseRunnerMap) require.NoError(t, json.Unmarshal(byts, &base)) - base.DomainType = networkconfig.TestNetwork.DomainType + base.NetworkConfig = networkconfig.TestNetwork logger := logging.TestLogger(t) @@ -382,9 +381,7 @@ func fixRunnerForRun(t *testing.T, runnerMap map[string]interface{}, ks *spectes } } - if (ret.GetBaseRunner().DomainType == spectypes.DomainType{}) { - ret.GetBaseRunner().DomainType = networkconfig.TestNetwork.DomainType - } + ret.GetBaseRunner().NetworkConfig = networkconfig.TestNetwork return ret } @@ -555,7 +552,7 @@ func fixCommitteeForRun(t *testing.T, ctx context.Context, logger *zap.Logger, c ctx, cancel, logger, - tests2.NewTestingBeaconNodeWrapped().GetBeaconNetwork(), + networkconfig.TestNetwork, &specCommittee.CommitteeMember, func(slot phase0.Slot, shareMap map[phase0.ValidatorIndex]*spectypes.Share, _ []spectypes.ShareValidatorPK, _ runner.CommitteeDutyGuard) (*runner.CommitteeRunner, error) { r := ssvtesting.CommitteeRunnerWithShareMap(logger, shareMap) diff --git a/protocol/v2/ssv/testing/runner.go b/protocol/v2/ssv/testing/runner.go index f2238ccc06..c080cff777 100644 --- a/protocol/v2/ssv/testing/runner.go +++ b/protocol/v2/ssv/testing/runner.go @@ -82,13 +82,13 @@ var ConstructBaseRunner = func( valCheck = ssv.BeaconVoteValueCheckF(km, spectestingutils.TestingDutySlot, []spectypes.ShareValidatorPK{share.SharePubKey}, spectestingutils.TestingDutyEpoch) case spectypes.RoleProposer: - valCheck = ssv.ProposerValueCheckF(km, spectypes.BeaconTestNetwork, + valCheck = ssv.ProposerValueCheckF(km, networkconfig.TestNetwork.BeaconConfig, (spectypes.ValidatorPK)(spectestingutils.TestingValidatorPubKey), spectestingutils.TestingValidatorIndex, share.SharePubKey) case spectypes.RoleAggregator: - valCheck = ssv.AggregatorValueCheckF(km, spectypes.BeaconTestNetwork, + valCheck = ssv.AggregatorValueCheckF(km, networkconfig.TestNetwork.BeaconConfig, (spectypes.ValidatorPK)(spectestingutils.TestingValidatorPubKey), spectestingutils.TestingValidatorIndex) case spectypes.RoleSyncCommitteeContribution: - valCheck = ssv.SyncCommitteeContributionValueCheckF(km, spectypes.BeaconTestNetwork, + valCheck = ssv.SyncCommitteeContributionValueCheckF(km, networkconfig.TestNetwork.BeaconConfig, (spectypes.ValidatorPK)(spectestingutils.TestingValidatorPubKey), spectestingutils.TestingValidatorIndex) default: valCheck = nil @@ -133,8 +133,7 @@ var ConstructBaseRunner = func( ) case spectypes.RoleAggregator: r, err = runner.NewAggregatorRunner( - networkconfig.TestNetwork.DomainType, - spectypes.BeaconTestNetwork, + networkconfig.TestNetwork, shareMap, contr, tests.NewTestingBeaconNodeWrapped(), @@ -146,8 +145,7 @@ var ConstructBaseRunner = func( ) case spectypes.RoleProposer: r, err = runner.NewProposerRunner( - networkconfig.TestNetwork.DomainType, - spectypes.BeaconTestNetwork, + networkconfig.TestNetwork, shareMap, contr, tests.NewTestingBeaconNodeWrapped(), @@ -161,8 +159,7 @@ var ConstructBaseRunner = func( ) case spectypes.RoleSyncCommitteeContribution: r, err = runner.NewSyncCommitteeAggregatorRunner( - networkconfig.TestNetwork.DomainType, - spectypes.BeaconTestNetwork, + networkconfig.TestNetwork, shareMap, contr, tests.NewTestingBeaconNodeWrapped(), @@ -174,8 +171,7 @@ var ConstructBaseRunner = func( ) case spectypes.RoleValidatorRegistration: r, err = runner.NewValidatorRegistrationRunner( - networkconfig.TestNetwork.DomainType, - spectypes.BeaconTestNetwork, + networkconfig.TestNetwork, shareMap, tests.NewTestingBeaconNodeWrapped(), net, @@ -185,8 +181,7 @@ var ConstructBaseRunner = func( ) case spectypes.RoleVoluntaryExit: r, err = runner.NewVoluntaryExitRunner( - networkconfig.TestNetwork.DomainType, - spectypes.BeaconTestNetwork, + networkconfig.TestNetwork, shareMap, tests.NewTestingBeaconNodeWrapped(), net, @@ -342,13 +337,13 @@ var ConstructBaseRunnerWithShareMap = func( valCheck = ssv.BeaconVoteValueCheckF(km, spectestingutils.TestingDutySlot, sharePubKeys, spectestingutils.TestingDutyEpoch) case spectypes.RoleProposer: - valCheck = ssv.ProposerValueCheckF(km, spectypes.BeaconTestNetwork, + valCheck = ssv.ProposerValueCheckF(km, networkconfig.TestNetwork.BeaconConfig, shareInstance.ValidatorPubKey, shareInstance.ValidatorIndex, shareInstance.SharePubKey) case spectypes.RoleAggregator: - valCheck = ssv.AggregatorValueCheckF(km, spectypes.BeaconTestNetwork, + valCheck = ssv.AggregatorValueCheckF(km, networkconfig.TestNetwork.BeaconConfig, shareInstance.ValidatorPubKey, shareInstance.ValidatorIndex) case spectypes.RoleSyncCommitteeContribution: - valCheck = ssv.SyncCommitteeContributionValueCheckF(km, spectypes.BeaconTestNetwork, + valCheck = ssv.SyncCommitteeContributionValueCheckF(km, networkconfig.TestNetwork.BeaconConfig, shareInstance.ValidatorPubKey, shareInstance.ValidatorIndex) default: valCheck = nil @@ -388,8 +383,7 @@ var ConstructBaseRunnerWithShareMap = func( ) case spectypes.RoleAggregator: r, err = runner.NewAggregatorRunner( - networkconfig.TestNetwork.DomainType, - spectypes.BeaconTestNetwork, + networkconfig.TestNetwork, shareMap, contr, tests.NewTestingBeaconNodeWrapped(), @@ -401,8 +395,7 @@ var ConstructBaseRunnerWithShareMap = func( ) case spectypes.RoleProposer: r, err = runner.NewProposerRunner( - networkconfig.TestNetwork.DomainType, - spectypes.BeaconTestNetwork, + networkconfig.TestNetwork, shareMap, contr, tests.NewTestingBeaconNodeWrapped(), @@ -416,8 +409,7 @@ var ConstructBaseRunnerWithShareMap = func( ) case spectypes.RoleSyncCommitteeContribution: r, err = runner.NewSyncCommitteeAggregatorRunner( - networkconfig.TestNetwork.DomainType, - spectypes.BeaconTestNetwork, + networkconfig.TestNetwork, shareMap, contr, tests.NewTestingBeaconNodeWrapped(), @@ -429,8 +421,7 @@ var ConstructBaseRunnerWithShareMap = func( ) case spectypes.RoleValidatorRegistration: r, err = runner.NewValidatorRegistrationRunner( - networkconfig.TestNetwork.DomainType, - spectypes.BeaconTestNetwork, + networkconfig.TestNetwork, shareMap, tests.NewTestingBeaconNodeWrapped(), net, @@ -440,8 +431,7 @@ var ConstructBaseRunnerWithShareMap = func( ) case spectypes.RoleVoluntaryExit: r, err = runner.NewVoluntaryExitRunner( - networkconfig.TestNetwork.DomainType, - spectypes.BeaconTestNetwork, + networkconfig.TestNetwork, shareMap, tests.NewTestingBeaconNodeWrapped(), net, diff --git a/protocol/v2/ssv/validator/committee.go b/protocol/v2/ssv/validator/committee.go index 44cf5ce2fd..85c6611313 100644 --- a/protocol/v2/ssv/validator/committee.go +++ b/protocol/v2/ssv/validator/committee.go @@ -14,6 +14,7 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/logging/fields" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/message" "github.com/ssvlabs/ssv/protocol/v2/ssv/queue" "github.com/ssvlabs/ssv/protocol/v2/ssv/runner" @@ -32,7 +33,7 @@ type Committee struct { ctx context.Context cancel context.CancelFunc - BeaconNetwork spectypes.BeaconNetwork + beaconConfig networkconfig.Beacon // mtx syncs access to Queues, Runners, Shares. mtx sync.RWMutex @@ -51,7 +52,7 @@ func NewCommittee( ctx context.Context, cancel context.CancelFunc, logger *zap.Logger, - beaconNetwork spectypes.BeaconNetwork, + beaconConfig networkconfig.Beacon, committeeMember *spectypes.CommitteeMember, createRunnerFn CommitteeRunnerFunc, shares map[phase0.ValidatorIndex]*spectypes.Share, @@ -62,7 +63,7 @@ func NewCommittee( } return &Committee{ logger: logger, - BeaconNetwork: beaconNetwork, + beaconConfig: beaconConfig, ctx: ctx, cancel: cancel, Queues: make(map[phase0.Slot]queueContainer), @@ -268,7 +269,7 @@ func (c *Committee) unsafePruneExpiredRunners(logger *zap.Logger, currentSlot ph for slot := range c.Runners { if slot <= minValidSlot { opIds := types.OperatorIDsFromOperators(c.CommitteeMember.Committee) - epoch := c.BeaconNetwork.EstimatedEpochAtSlot(slot) + epoch := c.beaconConfig.EstimatedEpochAtSlot(slot) committeeDutyID := fields.FormatCommitteeDutyID(opIds, epoch, slot) logger = logger.With(fields.DutyID(committeeDutyID)) logger.Debug("pruning expired committee runner", zap.Uint64("slot", uint64(slot))) diff --git a/protocol/v2/ssv/validator/committee_queue.go b/protocol/v2/ssv/validator/committee_queue.go index c77afc8022..a64bb2ab01 100644 --- a/protocol/v2/ssv/validator/committee_queue.go +++ b/protocol/v2/ssv/validator/committee_queue.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "time" specqbft "github.com/ssvlabs/ssv-spec/qbft" spectypes "github.com/ssvlabs/ssv-spec/types" @@ -70,7 +69,7 @@ func (c *Committee) StartConsumeQueue(logger *zap.Logger, duty *spectypes.Commit } // required to stop the queue consumer when timeout message is received by handler - queueCtx, cancelF := context.WithDeadline(c.ctx, time.Unix(c.BeaconNetwork.EstimatedTimeAtSlot(duty.Slot+runnerExpirySlots), 0)) + queueCtx, cancelF := context.WithDeadline(c.ctx, c.beaconConfig.EstimatedTimeAtSlot(duty.Slot+runnerExpirySlots)) go func() { defer cancelF() diff --git a/protocol/v2/ssv/validator/non_committee_validator.go b/protocol/v2/ssv/validator/non_committee_validator.go index 310828f439..8cc3fb137a 100644 --- a/protocol/v2/ssv/validator/non_committee_validator.go +++ b/protocol/v2/ssv/validator/non_committee_validator.go @@ -18,7 +18,6 @@ import ( "github.com/ssvlabs/ssv/logging/fields" "github.com/ssvlabs/ssv/message/validation" "github.com/ssvlabs/ssv/networkconfig" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" qbftcontroller "github.com/ssvlabs/ssv/protocol/v2/qbft/controller" qbftstorage "github.com/ssvlabs/ssv/protocol/v2/qbft/storage" "github.com/ssvlabs/ssv/protocol/v2/ssv" @@ -31,8 +30,7 @@ type CommitteeObserver struct { msgID spectypes.MessageID logger *zap.Logger Storage *storage.ParticipantStores - beaconNetwork beacon.BeaconNetwork - networkConfig networkconfig.NetworkConfig + beaconConfig networkconfig.Beacon ValidatorStore registrystorage.ValidatorStore newDecidedHandler qbftcontroller.NewDecidedHandler attesterRoots *ttlcache.Cache[phase0.Root, struct{}] @@ -45,7 +43,7 @@ type CommitteeObserver struct { type CommitteeObserverOptions struct { FullNode bool Logger *zap.Logger - NetworkConfig networkconfig.NetworkConfig + BeaconConfig networkconfig.Beacon Network specqbft.Network Storage *storage.ParticipantStores Operator *spectypes.CommitteeMember @@ -64,8 +62,7 @@ func NewCommitteeObserver(msgID spectypes.MessageID, opts CommitteeObserverOptio msgID: msgID, logger: opts.Logger, Storage: opts.Storage, - beaconNetwork: opts.NetworkConfig.Beacon, - networkConfig: opts.NetworkConfig, + beaconConfig: opts.BeaconConfig, ValidatorStore: opts.ValidatorStore, newDecidedHandler: opts.NewDecidedHandler, attesterRoots: opts.AttesterRoots, @@ -328,7 +325,7 @@ func (ncv *CommitteeObserver) OnProposalMsg(msg *queue.SSVMessage) error { ncv.logger.Fatal("unreachable: OnProposalMsg must be called only on qbft messages") } - epoch := ncv.beaconNetwork.EstimatedEpochAtSlot(phase0.Slot(qbftMsg.Height)) + epoch := ncv.beaconConfig.EstimatedEpochAtSlot(phase0.Slot(qbftMsg.Height)) if err := ncv.saveAttesterRoots(epoch, beaconVote, qbftMsg); err != nil { return err @@ -379,7 +376,7 @@ func (ncv *CommitteeObserver) saveSyncCommRoots(epoch phase0.Epoch, beaconVote * func (ncv *CommitteeObserver) postConsensusContainerCapacity() int { // #nosec G115 -- slots per epoch must be low epoch not to cause overflow - return int(ncv.networkConfig.SlotsPerEpoch) + validation.LateSlotAllowance + return int(ncv.beaconConfig.GetSlotsPerEpoch()) + validation.LateSlotAllowance } func constructAttestationData(vote *spectypes.BeaconVote, slot phase0.Slot, committeeIndex phase0.CommitteeIndex) *phase0.AttestationData { diff --git a/protocol/v2/ssv/validator/opts.go b/protocol/v2/ssv/validator/opts.go index 1466601171..62785c273a 100644 --- a/protocol/v2/ssv/validator/opts.go +++ b/protocol/v2/ssv/validator/opts.go @@ -19,7 +19,7 @@ const ( // Options represents options that should be passed to a new instance of Validator. type Options struct { - NetworkConfig networkconfig.NetworkConfig + NetworkConfig networkconfig.Network Network specqbft.Network Beacon beacon.BeaconNode Storage *storage.ParticipantStores diff --git a/protocol/v2/ssv/validator/startup.go b/protocol/v2/ssv/validator/startup.go index 63622c3cc5..adcbe42589 100644 --- a/protocol/v2/ssv/validator/startup.go +++ b/protocol/v2/ssv/validator/startup.go @@ -40,7 +40,7 @@ func (v *Validator) Start(logger *zap.Logger) (started bool, err error) { continue } - identifier := spectypes.NewMsgID(v.NetworkConfig.DomainType, share.ValidatorPubKey[:], role) + identifier := spectypes.NewMsgID(v.NetworkConfig.GetDomainType(), share.ValidatorPubKey[:], role) // TODO: P2P var valpk spectypes.ValidatorPK diff --git a/protocol/v2/ssv/validator/validator.go b/protocol/v2/ssv/validator/validator.go index 0895009583..a707ac3f0d 100644 --- a/protocol/v2/ssv/validator/validator.go +++ b/protocol/v2/ssv/validator/validator.go @@ -29,7 +29,7 @@ type Validator struct { ctx context.Context cancel context.CancelFunc - NetworkConfig networkconfig.NetworkConfig + NetworkConfig networkconfig.Network DutyRunners runner.ValidatorDutyRunners Network specqbft.Network @@ -104,7 +104,7 @@ func (v *Validator) StartDuty(ctx context.Context, logger *zap.Logger, duty spec // Log with duty ID. baseRunner := dutyRunner.GetBaseRunner() - v.dutyIDs.Set(spectypes.MapDutyToRunnerRole(vDuty.Type), fields.FormatDutyID(baseRunner.BeaconNetwork.EstimatedEpochAtSlot(vDuty.Slot), vDuty.Slot, vDuty.Type.String(), vDuty.ValidatorIndex)) + v.dutyIDs.Set(spectypes.MapDutyToRunnerRole(vDuty.Type), fields.FormatDutyID(baseRunner.NetworkConfig.EstimatedEpochAtSlot(vDuty.Slot), vDuty.Slot, vDuty.Type.String(), vDuty.ValidatorIndex)) logger = trySetDutyID(logger, v.dutyIDs, spectypes.MapDutyToRunnerRole(vDuty.Type)) // Log with height. diff --git a/protocol/v2/ssv/value_check.go b/protocol/v2/ssv/value_check.go index ad3d618e00..54c1060698 100644 --- a/protocol/v2/ssv/value_check.go +++ b/protocol/v2/ssv/value_check.go @@ -8,16 +8,18 @@ import ( "github.com/pkg/errors" specqbft "github.com/ssvlabs/ssv-spec/qbft" spectypes "github.com/ssvlabs/ssv-spec/types" + + "github.com/ssvlabs/ssv/networkconfig" ) func dutyValueCheck( duty *spectypes.ValidatorDuty, - network spectypes.BeaconNetwork, + beaconConfig networkconfig.Beacon, expectedType spectypes.BeaconRole, validatorPK spectypes.ValidatorPK, validatorIndex phase0.ValidatorIndex, ) error { - if network.EstimatedEpochAtSlot(duty.Slot) > network.EstimatedCurrentEpoch()+1 { + if beaconConfig.EstimatedEpochAtSlot(duty.Slot) > beaconConfig.EstimatedCurrentEpoch()+1 { return errors.New("duty epoch is into far future") } @@ -78,7 +80,7 @@ func BeaconVoteValueCheckF( func ProposerValueCheckF( signer spectypes.BeaconSigner, - network spectypes.BeaconNetwork, + beaconConfig networkconfig.Beacon, validatorPK spectypes.ValidatorPK, validatorIndex phase0.ValidatorIndex, sharePublicKey []byte, @@ -92,7 +94,7 @@ func ProposerValueCheckF( return errors.Wrap(err, "invalid value") } - if err := dutyValueCheck(&cd.Duty, network, spectypes.BNRoleProposer, validatorPK, validatorIndex); err != nil { + if err := dutyValueCheck(&cd.Duty, beaconConfig, spectypes.BNRoleProposer, validatorPK, validatorIndex); err != nil { return errors.Wrap(err, "duty invalid") } @@ -117,7 +119,7 @@ func ProposerValueCheckF( func AggregatorValueCheckF( signer spectypes.BeaconSigner, - network spectypes.BeaconNetwork, + beaconConfig networkconfig.Beacon, validatorPK spectypes.ValidatorPK, validatorIndex phase0.ValidatorIndex, ) specqbft.ProposedValueCheckF { @@ -130,7 +132,7 @@ func AggregatorValueCheckF( return errors.Wrap(err, "invalid value") } - if err := dutyValueCheck(&cd.Duty, network, spectypes.BNRoleAggregator, validatorPK, validatorIndex); err != nil { + if err := dutyValueCheck(&cd.Duty, beaconConfig, spectypes.BNRoleAggregator, validatorPK, validatorIndex); err != nil { return errors.Wrap(err, "duty invalid") } return nil @@ -139,7 +141,7 @@ func AggregatorValueCheckF( func SyncCommitteeContributionValueCheckF( signer spectypes.BeaconSigner, - network spectypes.BeaconNetwork, + beaconConfig networkconfig.Beacon, validatorPK spectypes.ValidatorPK, validatorIndex phase0.ValidatorIndex, ) specqbft.ProposedValueCheckF { @@ -152,7 +154,7 @@ func SyncCommitteeContributionValueCheckF( return errors.Wrap(err, "invalid value") } - if err := dutyValueCheck(&cd.Duty, network, spectypes.BNRoleSyncCommitteeContribution, validatorPK, validatorIndex); err != nil { + if err := dutyValueCheck(&cd.Duty, beaconConfig, spectypes.BNRoleSyncCommitteeContribution, validatorPK, validatorIndex); err != nil { return errors.Wrap(err, "duty invalid") } diff --git a/utils/testutils.go b/utils/testutils.go index 47d38ba30a..9355fa669a 100644 --- a/utils/testutils.go +++ b/utils/testutils.go @@ -9,7 +9,7 @@ import ( spectypes "github.com/ssvlabs/ssv-spec/types" "go.uber.org/mock/gomock" - mocknetwork "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon/mocks" + "github.com/ssvlabs/ssv/networkconfig" ) type SlotValue struct { @@ -29,7 +29,7 @@ func (sv *SlotValue) GetSlot() phase0.Slot { return sv.slot } -func SetupMockBeaconNetwork(t *testing.T, currentSlot *SlotValue) *mocknetwork.MockBeaconNetwork { +func SetupMockNetworkConfig(t *testing.T, domainType spectypes.DomainType, currentSlot *SlotValue) *networkconfig.MockNetwork { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -39,55 +39,55 @@ func SetupMockBeaconNetwork(t *testing.T, currentSlot *SlotValue) *mocknetwork.M } beaconNetwork := spectypes.HoleskyNetwork // it must be something known by ekm - mockBeaconNetwork := mocknetwork.NewMockBeaconNetwork(ctrl) + mockNetwork := networkconfig.NewMockNetwork(ctrl) - mockBeaconNetwork.EXPECT().GetBeaconNetwork().Return(beaconNetwork).AnyTimes() - mockBeaconNetwork.EXPECT().SlotsPerEpoch().Return(beaconNetwork.SlotsPerEpoch()).AnyTimes() - mockBeaconNetwork.EXPECT().EstimatedCurrentSlot().DoAndReturn( + mockNetwork.EXPECT().GetSlotsPerEpoch().Return(phase0.Slot(beaconNetwork.SlotsPerEpoch())).AnyTimes() + mockNetwork.EXPECT().EstimatedCurrentSlot().DoAndReturn( func() phase0.Slot { return currentSlot.GetSlot() }, ).AnyTimes() - mockBeaconNetwork.EXPECT().EstimatedCurrentEpoch().DoAndReturn( + mockNetwork.EXPECT().EstimatedCurrentEpoch().DoAndReturn( func() phase0.Epoch { return phase0.Epoch(uint64(currentSlot.GetSlot()) / beaconNetwork.SlotsPerEpoch()) }, ).AnyTimes() - mockBeaconNetwork.EXPECT().EstimatedEpochAtSlot(gomock.Any()).DoAndReturn( + mockNetwork.EXPECT().EstimatedEpochAtSlot(gomock.Any()).DoAndReturn( func(slot phase0.Slot) phase0.Epoch { return beaconNetwork.EstimatedEpochAtSlot(slot) }, ).AnyTimes() - mockBeaconNetwork.EXPECT().FirstSlotAtEpoch(gomock.Any()).DoAndReturn( + mockNetwork.EXPECT().FirstSlotAtEpoch(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) phase0.Slot { return beaconNetwork.FirstSlotAtEpoch(epoch) }, ).AnyTimes() - mockBeaconNetwork.EXPECT().IsFirstSlotOfEpoch(gomock.Any()).DoAndReturn( + mockNetwork.EXPECT().IsFirstSlotOfEpoch(gomock.Any()).DoAndReturn( func(slot phase0.Slot) bool { - return uint64(slot)%mockBeaconNetwork.SlotsPerEpoch() == 0 + return slot%mockNetwork.GetSlotsPerEpoch() == 0 }, ).AnyTimes() - mockBeaconNetwork.EXPECT().GetSlotStartTime(gomock.Any()).DoAndReturn( + mockNetwork.EXPECT().GetSlotStartTime(gomock.Any()).DoAndReturn( func(slot phase0.Slot) time.Time { - timeSinceGenesisStart := int64(uint64(slot) * uint64(beaconNetwork.SlotDurationSec().Seconds())) // #nosec G115 - minGenesisTime := int64(mockBeaconNetwork.GetBeaconNetwork().MinGenesisTime()) // #nosec G115 - start := time.Unix(minGenesisTime+timeSinceGenesisStart, 0) - return start + return mockNetwork.GetSlotStartTime(slot) }, ).AnyTimes() - mockBeaconNetwork.EXPECT().SlotDurationSec().DoAndReturn( + mockNetwork.EXPECT().GetSlotDuration().DoAndReturn( func() time.Duration { return 12 * time.Second }, ).AnyTimes() - mockBeaconNetwork.EXPECT().SlotsPerEpoch().DoAndReturn( - func() uint64 { + mockNetwork.EXPECT().GetSlotsPerEpoch().DoAndReturn( + func() phase0.Slot { return 32 }, ).AnyTimes() - return mockBeaconNetwork + mockNetwork.EXPECT().GetDomainType().Return(domainType).AnyTimes() + + mockNetwork.EXPECT().GetBeaconName().Return(string(beaconNetwork)).AnyTimes() + + return mockNetwork } From 1f30b56bc5122a8f8211f375cd5be92e8cb9fc3b Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 15 Apr 2025 21:37:58 -0300 Subject: [PATCH 04/34] some leftovers --- networkconfig/{config.go => network.go} | 1 + .../{config_mock.go => network_mock.go} | 0 protocol/v2/qbft/roundtimer/timer.go | 24 +++++++++---------- 3 files changed, 13 insertions(+), 12 deletions(-) rename networkconfig/{config.go => network.go} (98%) rename networkconfig/{config_mock.go => network_mock.go} (100%) diff --git a/networkconfig/config.go b/networkconfig/network.go similarity index 98% rename from networkconfig/config.go rename to networkconfig/network.go index 55f96360c4..b3580802be 100644 --- a/networkconfig/config.go +++ b/networkconfig/network.go @@ -30,6 +30,7 @@ func GetNetworkConfigByName(name string) (NetworkConfig, error) { type Network interface { NetworkName() string + String() string Beacon SSV } diff --git a/networkconfig/config_mock.go b/networkconfig/network_mock.go similarity index 100% rename from networkconfig/config_mock.go rename to networkconfig/network_mock.go diff --git a/protocol/v2/qbft/roundtimer/timer.go b/protocol/v2/qbft/roundtimer/timer.go index 87bc7d509b..d3e87db242 100644 --- a/protocol/v2/qbft/roundtimer/timer.go +++ b/protocol/v2/qbft/roundtimer/timer.go @@ -59,21 +59,21 @@ type RoundTimer struct { timeoutOptions TimeoutOptions // role is the role of the instance role spectypes.RunnerRole - // netCfg is the network network - netCfg networkconfig.Beacon + // beaconConfig is the beacon config + beaconConfig networkconfig.Beacon } // New creates a new instance of RoundTimer. func New(pctx context.Context, beaconConfig networkconfig.Beacon, role spectypes.RunnerRole, done OnRoundTimeoutF) *RoundTimer { ctx, cancelCtx := context.WithCancel(pctx) return &RoundTimer{ - mtx: &sync.RWMutex{}, - ctx: ctx, - cancelCtx: cancelCtx, - timer: nil, - done: done, - role: role, - netCfg: beaconConfig, + mtx: &sync.RWMutex{}, + ctx: ctx, + cancelCtx: cancelCtx, + timer: nil, + done: done, + role: role, + beaconConfig: beaconConfig, timeoutOptions: TimeoutOptions{ quickThreshold: QuickTimeoutThreshold, quick: QuickTimeout, @@ -111,10 +111,10 @@ func (t *RoundTimer) RoundTimeout(height specqbft.Height, round specqbft.Round) switch t.role { case spectypes.RoleCommittee: // third of the slot time - baseDuration = t.netCfg.GetSlotDuration() / 3 + baseDuration = t.beaconConfig.GetSlotDuration() / 3 case spectypes.RoleAggregator, spectypes.RoleSyncCommitteeContribution: // two-third of the slot time - baseDuration = t.netCfg.GetSlotDuration() / 3 * 2 + baseDuration = t.beaconConfig.GetSlotDuration() / 3 * 2 default: if round <= t.timeoutOptions.quickThreshold { return t.timeoutOptions.quick @@ -136,7 +136,7 @@ func (t *RoundTimer) RoundTimeout(height specqbft.Height, round specqbft.Round) timeoutDuration := baseDuration + additionalTimeout // Get the start time of the duty - dutyStartTime := t.netCfg.GetSlotStartTime(phase0.Slot(height)) + dutyStartTime := t.beaconConfig.GetSlotStartTime(phase0.Slot(height)) // Calculate the time until the duty should start plus the timeout duration return time.Until(dutyStartTime.Add(timeoutDuration)) From e94b3943b2bf31b891cc6323d4042f12c14d1d4f Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 15 Apr 2025 21:44:34 -0300 Subject: [PATCH 05/34] fix linter --- networkconfig/network.go | 1 - 1 file changed, 1 deletion(-) diff --git a/networkconfig/network.go b/networkconfig/network.go index b3580802be..55f96360c4 100644 --- a/networkconfig/network.go +++ b/networkconfig/network.go @@ -30,7 +30,6 @@ func GetNetworkConfigByName(name string) (NetworkConfig, error) { type Network interface { NetworkName() string - String() string Beacon SSV } From 927b30f69d542d0c01717976ae3041ee2c3f300a Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 15 Apr 2025 21:52:40 -0300 Subject: [PATCH 06/34] fix message validation tests --- networkconfig/beacon.go | 5 +++++ networkconfig/beacon_mock.go | 14 ++++++++++++++ networkconfig/network.go | 2 +- networkconfig/network_mock.go | 18 ++++++++++++++++-- networkconfig/ssv.go | 8 ++++---- utils/testutils.go | 11 ++++++++++- 6 files changed, 50 insertions(+), 8 deletions(-) diff --git a/networkconfig/beacon.go b/networkconfig/beacon.go index dc6270fcca..bea4a5bdc9 100644 --- a/networkconfig/beacon.go +++ b/networkconfig/beacon.go @@ -27,6 +27,7 @@ type Beacon interface { EstimatedTimeAtSlot(slot phase0.Slot) time.Time GetSlotDuration() time.Duration GetSlotsPerEpoch() phase0.Slot + GetGenesisTime() time.Time GetBeaconName() string } @@ -139,6 +140,10 @@ func (b BeaconConfig) GetSlotsPerEpoch() phase0.Slot { return b.SlotsPerEpoch } +func (b BeaconConfig) GetGenesisTime() time.Time { + return b.GenesisTime +} + func (b BeaconConfig) GetBeaconName() string { return b.BeaconName } diff --git a/networkconfig/beacon_mock.go b/networkconfig/beacon_mock.go index ec5fce2d2b..c89a5e8a35 100644 --- a/networkconfig/beacon_mock.go +++ b/networkconfig/beacon_mock.go @@ -209,6 +209,20 @@ func (mr *MockBeaconMockRecorder) GetEpochFirstSlot(epoch any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEpochFirstSlot", reflect.TypeOf((*MockBeacon)(nil).GetEpochFirstSlot), epoch) } +// GetGenesisTime mocks base method. +func (m *MockBeacon) GetGenesisTime() time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGenesisTime") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// GetGenesisTime indicates an expected call of GetGenesisTime. +func (mr *MockBeaconMockRecorder) GetGenesisTime() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGenesisTime", reflect.TypeOf((*MockBeacon)(nil).GetGenesisTime)) +} + // GetSlotDuration mocks base method. func (m *MockBeacon) GetSlotDuration() time.Duration { m.ctrl.T.Helper() diff --git a/networkconfig/network.go b/networkconfig/network.go index 55f96360c4..e70bf5f839 100644 --- a/networkconfig/network.go +++ b/networkconfig/network.go @@ -5,7 +5,7 @@ import ( "fmt" ) -//go:generate go tool -modfile=../tool.mod mockgen -package=networkconfig -destination=./config_mock.go -source=./config.go +//go:generate go tool -modfile=../tool.mod mockgen -package=networkconfig -destination=./network_mock.go -source=./network.go var SupportedConfigs = map[string]NetworkConfig{ Mainnet.Name: Mainnet, diff --git a/networkconfig/network_mock.go b/networkconfig/network_mock.go index 3945cbd1c5..a3e3c24103 100644 --- a/networkconfig/network_mock.go +++ b/networkconfig/network_mock.go @@ -1,9 +1,9 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: ./config.go +// Source: ./network.go // // Generated by this command: // -// mockgen -package=networkconfig -destination=./config_mock.go -source=./config.go +// mockgen -package=networkconfig -destination=./network_mock.go -source=./network.go // // Package networkconfig is a generated GoMock package. @@ -224,6 +224,20 @@ func (mr *MockNetworkMockRecorder) GetEpochFirstSlot(epoch any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEpochFirstSlot", reflect.TypeOf((*MockNetwork)(nil).GetEpochFirstSlot), epoch) } +// GetGenesisTime mocks base method. +func (m *MockNetwork) GetGenesisTime() time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGenesisTime") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// GetGenesisTime indicates an expected call of GetGenesisTime. +func (mr *MockNetworkMockRecorder) GetGenesisTime() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGenesisTime", reflect.TypeOf((*MockNetwork)(nil).GetGenesisTime)) +} + // GetSlotDuration mocks base method. func (m *MockNetwork) GetSlotDuration() time.Duration { m.ctrl.T.Helper() diff --git a/networkconfig/ssv.go b/networkconfig/ssv.go index fd47b58391..50ae99370e 100644 --- a/networkconfig/ssv.go +++ b/networkconfig/ssv.go @@ -3,23 +3,23 @@ package networkconfig import ( "math/big" - "github.com/ssvlabs/ssv-spec/types" + spectypes "github.com/ssvlabs/ssv-spec/types" ) //go:generate go tool -modfile=../tool.mod mockgen -package=networkconfig -destination=./ssv_mock.go -source=./ssv.go type SSV interface { - GetDomainType() types.DomainType // using spectypes.DomainType breaks mock generation + GetDomainType() spectypes.DomainType } type SSVConfig struct { - DomainType types.DomainType + DomainType spectypes.DomainType RegistrySyncOffset *big.Int RegistryContractAddr string // TODO: ethcommon.Address Bootnodes []string DiscoveryProtocolID [6]byte } -func (ssv SSVConfig) GetDomainType() types.DomainType { +func (ssv SSVConfig) GetDomainType() spectypes.DomainType { return ssv.DomainType } diff --git a/utils/testutils.go b/utils/testutils.go index 9355fa669a..a6f7e24900 100644 --- a/utils/testutils.go +++ b/utils/testutils.go @@ -69,7 +69,10 @@ func SetupMockNetworkConfig(t *testing.T, domainType spectypes.DomainType, curre ).AnyTimes() mockNetwork.EXPECT().GetSlotStartTime(gomock.Any()).DoAndReturn( func(slot phase0.Slot) time.Time { - return mockNetwork.GetSlotStartTime(slot) + timeSinceGenesisStart := time.Duration(slot) & beaconNetwork.SlotDurationSec() // #nosec G115 + minGenesisTime := mockNetwork.GetGenesisTime() // #nosec G115 + start := minGenesisTime.Add(timeSinceGenesisStart) + return start }, ).AnyTimes() @@ -85,6 +88,12 @@ func SetupMockNetworkConfig(t *testing.T, domainType spectypes.DomainType, curre }, ).AnyTimes() + mockNetwork.EXPECT().GetGenesisTime().DoAndReturn( + func() time.Time { + return time.Unix(int64(beaconNetwork.MinGenesisTime()), 0) + }, + ).AnyTimes() + mockNetwork.EXPECT().GetDomainType().Return(domainType).AnyTimes() mockNetwork.EXPECT().GetBeaconName().Return(string(beaconNetwork)).AnyTimes() From 59d18d5844791f7ceebdfdafb26ac60b75e331dd Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 15 Apr 2025 21:55:44 -0300 Subject: [PATCH 07/34] fix linter again --- utils/testutils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/testutils.go b/utils/testutils.go index a6f7e24900..8eb07a4f3e 100644 --- a/utils/testutils.go +++ b/utils/testutils.go @@ -90,7 +90,7 @@ func SetupMockNetworkConfig(t *testing.T, domainType spectypes.DomainType, curre mockNetwork.EXPECT().GetGenesisTime().DoAndReturn( func() time.Time { - return time.Unix(int64(beaconNetwork.MinGenesisTime()), 0) + return time.Unix(int64(beaconNetwork.MinGenesisTime()), 0) // #nosec G115 -- genesis time is never above int64 }, ).AnyTimes() From ee81f74a05623ce60177799dd8462805fb645681 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Wed, 16 Apr 2025 12:34:46 -0300 Subject: [PATCH 08/34] leftovers after merging --- network/discovery/util_test.go | 2 +- networkconfig/beacon.go | 5 +---- networkconfig/holesky-e2e.go | 2 +- networkconfig/holesky-stage.go | 2 +- networkconfig/holesky.go | 2 +- networkconfig/hoodi-stage.go | 2 +- networkconfig/hoodi.go | 2 +- networkconfig/local-testnet.go | 2 +- networkconfig/mainnet.go | 2 +- networkconfig/sepolia.go | 3 +-- networkconfig/test-network.go | 3 +-- 11 files changed, 11 insertions(+), 16 deletions(-) diff --git a/network/discovery/util_test.go b/network/discovery/util_test.go index 54fd4a476c..dd82da1804 100644 --- a/network/discovery/util_test.go +++ b/network/discovery/util_test.go @@ -97,7 +97,7 @@ func testingNetConfigWithForkEpoch(forkEpoch phase0.Epoch) networkconfig.Network return networkconfig.NetworkConfig{ Name: n.Name, BeaconConfig: networkconfig.BeaconConfig{ - Beacon: n.Beacon, + Beacon: n.Beacon, }, SSVConfig: networkconfig.SSVConfig{ DomainType: n.DomainType, diff --git a/networkconfig/beacon.go b/networkconfig/beacon.go index 6b619a6bb5..6dffbe5737 100644 --- a/networkconfig/beacon.go +++ b/networkconfig/beacon.go @@ -1,12 +1,9 @@ package networkconfig import ( - "github.com/attestantio/go-eth2-client/spec/phase0" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) type BeaconConfig struct { - Beacon beacon.BeaconNetwork - GenesisEpoch phase0.Epoch + Beacon beacon.BeaconNetwork } diff --git a/networkconfig/holesky-e2e.go b/networkconfig/holesky-e2e.go index fe418e79cc..0e8e060261 100644 --- a/networkconfig/holesky-e2e.go +++ b/networkconfig/holesky-e2e.go @@ -11,7 +11,7 @@ import ( var HoleskyE2E = NetworkConfig{ Name: "holesky-e2e", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0xee, 0x1}, diff --git a/networkconfig/holesky-stage.go b/networkconfig/holesky-stage.go index a0c57c2849..682feb604d 100644 --- a/networkconfig/holesky-stage.go +++ b/networkconfig/holesky-stage.go @@ -11,7 +11,7 @@ import ( var HoleskyStage = NetworkConfig{ Name: "holesky-stage", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), }, SSVConfig: SSVConfig{ DomainType: [4]byte{0x00, 0x00, 0x31, 0x13}, diff --git a/networkconfig/holesky.go b/networkconfig/holesky.go index 7991540132..7934182742 100644 --- a/networkconfig/holesky.go +++ b/networkconfig/holesky.go @@ -11,7 +11,7 @@ import ( var Holesky = NetworkConfig{ Name: "holesky", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), + Beacon: beacon.NewNetwork(spectypes.HoleskyNetwork), }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x2}, diff --git a/networkconfig/hoodi-stage.go b/networkconfig/hoodi-stage.go index 3ae7c36382..b013d11c2c 100644 --- a/networkconfig/hoodi-stage.go +++ b/networkconfig/hoodi-stage.go @@ -11,7 +11,7 @@ import ( var HoodiStage = NetworkConfig{ Name: "hoodi-stage", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), + Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), }, SSVConfig: SSVConfig{ DomainType: [4]byte{0x00, 0x00, 0x31, 0x14}, diff --git a/networkconfig/hoodi.go b/networkconfig/hoodi.go index e45a05502b..24292d2251 100644 --- a/networkconfig/hoodi.go +++ b/networkconfig/hoodi.go @@ -11,7 +11,7 @@ import ( var Hoodi = NetworkConfig{ Name: "hoodi", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), + Beacon: beacon.NewNetwork(spectypes.HoodiNetwork), }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x3}, diff --git a/networkconfig/local-testnet.go b/networkconfig/local-testnet.go index 0d00d25a70..6318ab4ac4 100644 --- a/networkconfig/local-testnet.go +++ b/networkconfig/local-testnet.go @@ -9,7 +9,7 @@ import ( var LocalTestnet = NetworkConfig{ Name: "local-testnet", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewLocalTestNetwork(spectypes.PraterNetwork), + Beacon: beacon.NewLocalTestNetwork(spectypes.PraterNetwork), }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoV2NetworkID.Byte(), 0x2}, diff --git a/networkconfig/mainnet.go b/networkconfig/mainnet.go index e87d9e2051..e8ce291a42 100644 --- a/networkconfig/mainnet.go +++ b/networkconfig/mainnet.go @@ -11,7 +11,7 @@ import ( var Mainnet = NetworkConfig{ Name: "mainnet", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.MainNetwork), + Beacon: beacon.NewNetwork(spectypes.MainNetwork), }, SSVConfig: SSVConfig{ DomainType: spectypes.AlanMainnet, diff --git a/networkconfig/sepolia.go b/networkconfig/sepolia.go index d17cfbbf71..cc05bfb9d4 100644 --- a/networkconfig/sepolia.go +++ b/networkconfig/sepolia.go @@ -11,8 +11,7 @@ import ( var Sepolia = NetworkConfig{ Name: "sepolia", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.SepoliaNetwork), - GenesisEpoch: 1, + Beacon: beacon.NewNetwork(spectypes.SepoliaNetwork), }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x69}, diff --git a/networkconfig/test-network.go b/networkconfig/test-network.go index 998d8d8fb4..bed1b4e5f5 100644 --- a/networkconfig/test-network.go +++ b/networkconfig/test-network.go @@ -11,8 +11,7 @@ import ( var TestNetwork = NetworkConfig{ Name: "testnet", BeaconConfig: BeaconConfig{ - Beacon: beacon.NewNetwork(spectypes.BeaconTestNetwork), - GenesisEpoch: 152834, + Beacon: beacon.NewNetwork(spectypes.BeaconTestNetwork), }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoNetworkID.Byte(), 0x2}, From 5d8631796439f32594d991c85d7b9e0c5b3beb18 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Thu, 17 Apr 2025 11:28:30 -0300 Subject: [PATCH 09/34] fix issues after merging --- beacon/goclient/attest_test.go | 2 +- beacon/goclient/events_test.go | 1 - beacon/goclient/goclient.go | 2 -- beacon/goclient/options.go | 4 ++-- cli/operator/node.go | 1 - protocol/v2/blockchain/beacon/client.go | 1 + 6 files changed, 4 insertions(+), 7 deletions(-) diff --git a/beacon/goclient/attest_test.go b/beacon/goclient/attest_test.go index f10a38db87..1b50c5b83d 100644 --- a/beacon/goclient/attest_test.go +++ b/beacon/goclient/attest_test.go @@ -18,8 +18,8 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/operator/slotticker" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" "github.com/ssvlabs/ssv/utils/hashmap" ) diff --git a/beacon/goclient/events_test.go b/beacon/goclient/events_test.go index 189a79720b..7e2b6d5fd3 100644 --- a/beacon/goclient/events_test.go +++ b/beacon/goclient/events_test.go @@ -15,7 +15,6 @@ import ( "github.com/ssvlabs/ssv/beacon/goclient/tests" "github.com/ssvlabs/ssv/networkconfig" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) func TestSubscribeToHeadEvents(t *testing.T) { diff --git a/beacon/goclient/goclient.go b/beacon/goclient/goclient.go index c4f88de54c..eacc9fdb21 100644 --- a/beacon/goclient/goclient.go +++ b/beacon/goclient/goclient.go @@ -19,14 +19,12 @@ import ( "github.com/pkg/errors" "github.com/rs/zerolog" specssv "github.com/ssvlabs/ssv-spec/ssv" - spectypes "github.com/ssvlabs/ssv-spec/types" "go.uber.org/zap" "tailscale.com/util/singleflight" "github.com/ssvlabs/ssv/logging/fields" "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/operator/slotticker" - beaconprotocol "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) const ( diff --git a/beacon/goclient/options.go b/beacon/goclient/options.go index 9e3cbd6162..89008c7c0b 100644 --- a/beacon/goclient/options.go +++ b/beacon/goclient/options.go @@ -4,13 +4,13 @@ import ( "context" "time" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" + "github.com/ssvlabs/ssv/networkconfig" ) // Options defines beacon client options type Options struct { Context context.Context - Network beacon.Network + BeaconConfig networkconfig.BeaconConfig BeaconNodeAddr string `yaml:"BeaconNodeAddr" env:"BEACON_NODE_ADDR" env-required:"true" env-description:"Beacon node URL(s). Multiple nodes are supported via semicolon-separated URLs (e.g. 'http://localhost:5052;http://localhost:5053')"` SyncDistanceTolerance uint64 `yaml:"SyncDistanceTolerance" env:"BEACON_SYNC_DISTANCE_TOLERANCE" env-default:"4" env-description:"Maximum number of slots behind head considered in-sync"` WithWeightedAttestationData bool `yaml:"WithWeightedAttestationData" env:"WITH_WEIGHTED_ATTESTATION_DATA" env-default:"false" env-description:"Enable attestation data scoring across multiple beacon nodes"` diff --git a/cli/operator/node.go b/cli/operator/node.go index 4866d881a0..9ab89c372a 100644 --- a/cli/operator/node.go +++ b/cli/operator/node.go @@ -59,7 +59,6 @@ import ( "github.com/ssvlabs/ssv/operator/validator" "github.com/ssvlabs/ssv/operator/validator/metadata" "github.com/ssvlabs/ssv/operator/validators" - beaconprotocol "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" qbftstorage "github.com/ssvlabs/ssv/protocol/v2/qbft/storage" "github.com/ssvlabs/ssv/protocol/v2/types" registrystorage "github.com/ssvlabs/ssv/registry/storage" diff --git a/protocol/v2/blockchain/beacon/client.go b/protocol/v2/blockchain/beacon/client.go index 8d97f1a559..b228cc52e6 100644 --- a/protocol/v2/blockchain/beacon/client.go +++ b/protocol/v2/blockchain/beacon/client.go @@ -2,6 +2,7 @@ package beacon import ( "context" + "time" eth2apiv1 "github.com/attestantio/go-eth2-client/api/v1" "github.com/attestantio/go-eth2-client/spec/bellatrix" From 4f72bd92be10070bbb341f867935ad10fb6f8c9c Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Thu, 17 Apr 2025 13:41:26 -0300 Subject: [PATCH 10/34] fix network name bug --- networkconfig/hoodi-stage.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networkconfig/hoodi-stage.go b/networkconfig/hoodi-stage.go index 4f3e1232a0..d07daa5671 100644 --- a/networkconfig/hoodi-stage.go +++ b/networkconfig/hoodi-stage.go @@ -11,7 +11,7 @@ import ( var HoodiStage = NetworkConfig{ Name: "hoodi-stage", BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.HoleskyNetwork), + BeaconName: string(spectypes.HoodiNetwork), SlotDuration: spectypes.HoodiNetwork.SlotDurationSec(), SlotsPerEpoch: phase0.Slot(spectypes.HoodiNetwork.SlotsPerEpoch()), ForkVersion: spectypes.HoodiNetwork.ForkVersion(), From ccbb20ee30bee09117dc64ba3eb611cc09c0c01f Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Thu, 17 Apr 2025 14:25:04 -0300 Subject: [PATCH 11/34] code review comments --- networkconfig/beacon.go | 12 ++++++------ operator/duties/validatorregistration.go | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/networkconfig/beacon.go b/networkconfig/beacon.go index 512c8eb6f4..91f54c903b 100644 --- a/networkconfig/beacon.go +++ b/networkconfig/beacon.go @@ -1,6 +1,7 @@ package networkconfig import ( + "fmt" "math" "time" @@ -42,7 +43,7 @@ type BeaconConfig struct { // GetSlotStartTime returns the start time for the given slot func (b BeaconConfig) GetSlotStartTime(slot phase0.Slot) time.Time { if slot > math.MaxInt64 { - panic("slot out of range") + panic(fmt.Sprintf("slot %d out of range", slot)) } durationSinceGenesisStart := time.Duration(slot) * b.SlotDuration // #nosec G115: slot cannot exceed math.MaxInt64 start := b.GenesisTime.Add(durationSinceGenesisStart) @@ -61,11 +62,10 @@ func (b BeaconConfig) EstimatedCurrentSlot() phase0.Slot { // EstimatedSlotAtTime estimates slot at the given time func (b BeaconConfig) EstimatedSlotAtTime(time time.Time) phase0.Slot { - genesis := b.GenesisTime - if time.Before(genesis) { - return 0 + if time.Before(b.GenesisTime) { + panic(fmt.Sprintf("time %v is before genesis time %v", time, b.GenesisTime)) } - timeAfterGenesis := time.Sub(genesis) + timeAfterGenesis := time.Sub(b.GenesisTime) return phase0.Slot(timeAfterGenesis / b.SlotDuration) // #nosec G115: genesis can't be negative } @@ -125,7 +125,7 @@ func (b BeaconConfig) EpochStartTime(epoch phase0.Epoch) time.Time { func (b BeaconConfig) EstimatedTimeAtSlot(slot phase0.Slot) time.Time { if slot > math.MaxInt64 { - panic("slot out of range") + panic(fmt.Sprintf("slot %d out of range", slot)) } d := time.Duration(slot) * b.SlotDuration // #nosec G115: slot cannot exceed math.MaxInt64 return b.GenesisTime.Add(d) diff --git a/operator/duties/validatorregistration.go b/operator/duties/validatorregistration.go index 40d6fb3c7f..541794a210 100644 --- a/operator/duties/validatorregistration.go +++ b/operator/duties/validatorregistration.go @@ -10,7 +10,7 @@ import ( ) // frequencyEpochs defines how frequently we want to submit validator-registrations. -const frequencyEpochs = phase0.Epoch(10) +const frequencyEpochs = 10 type ValidatorRegistrationHandler struct { baseHandler @@ -38,7 +38,7 @@ func (h *ValidatorRegistrationHandler) HandleDuties(ctx context.Context) { defer h.logger.Info("duty handler exited") // validator should be registered within frequencyEpochs epochs time in a corresponding slot - registrationSlots := h.beaconConfig.GetSlotsPerEpoch() * phase0.Slot(frequencyEpochs) + registrationSlots := h.beaconConfig.GetSlotsPerEpoch() * frequencyEpochs next := h.ticker.Next() for { From 3aa5db24ccdb4f5a75f25aa19960a6d5b1593782 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Wed, 23 Apr 2025 20:44:08 -0300 Subject: [PATCH 12/34] fix issues after merging --- beacon/goclient/current_fork_test.go | 12 ++--- beacon/goclient/genesis_test.go | 10 ++-- beacon/goclient/signing_test.go | 4 +- beacon/goclient/spec_test.go | 6 +-- cli/operator/node.go | 13 +++-- message/validation/validation.go | 3 +- migrations/migrations.go | 12 ++--- operator/duties/committee.go | 2 +- operator/duties/sync_committee.go | 2 +- operator/storage/storage.go | 4 +- operator/validator/metadata/syncer.go | 12 ++--- operator/validator/metadata/syncer_test.go | 10 ++-- protocol/v2/types/ssvshare.go | 8 +-- registry/storage/shares.go | 4 +- registry/storage/validatorstore.go | 18 +++---- ssvsigner/ekm/local_key_manager.go | 10 ++-- ssvsigner/ekm/remote_key_manager.go | 17 +++---- ssvsigner/ekm/remote_key_manager_test.go | 57 ++++++++++------------ ssvsigner/ekm/signer_storage.go | 6 ++- ssvsigner/ekm/slashing_protector.go | 9 +++- 20 files changed, 107 insertions(+), 112 deletions(-) diff --git a/beacon/goclient/current_fork_test.go b/beacon/goclient/current_fork_test.go index f2c58067f3..ff2c571e4f 100644 --- a/beacon/goclient/current_fork_test.go +++ b/beacon/goclient/current_fork_test.go @@ -11,10 +11,8 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" - "github.com/ssvlabs/ssv-spec/types" - "github.com/ssvlabs/ssv/beacon/goclient/tests" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" + "github.com/ssvlabs/ssv/networkconfig" ) const forkSchedulePath = "/eth/v1/config/fork_schedule" @@ -22,7 +20,7 @@ const forkSchedulePath = "/eth/v1/config/fork_schedule" func TestCurrentFork(t *testing.T) { ctx := context.Background() - network := beacon.NewNetwork(types.MainNetwork) + beaconConfig := networkconfig.Mainnet.BeaconConfig t.Run("success", func(t *testing.T) { mockServer := tests.MockServer(func(r *http.Request, resp json.RawMessage) (json.RawMessage, error) { @@ -55,7 +53,7 @@ func TestCurrentFork(t *testing.T) { zap.NewNop(), Options{ Context: ctx, - Network: network, + BeaconConfig: beaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, @@ -86,7 +84,7 @@ func TestCurrentFork(t *testing.T) { zap.NewNop(), Options{ Context: ctx, - Network: network, + BeaconConfig: beaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, @@ -126,7 +124,7 @@ func TestCurrentFork(t *testing.T) { zap.NewNop(), Options{ Context: ctx, - Network: network, + BeaconConfig: beaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, diff --git a/beacon/goclient/genesis_test.go b/beacon/goclient/genesis_test.go index 4894d194f9..20a07b28d4 100644 --- a/beacon/goclient/genesis_test.go +++ b/beacon/goclient/genesis_test.go @@ -10,10 +10,8 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" - "github.com/ssvlabs/ssv-spec/types" - "github.com/ssvlabs/ssv/beacon/goclient/tests" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" + "github.com/ssvlabs/ssv/networkconfig" ) const genesisPath = "/eth/v1/beacon/genesis" @@ -40,7 +38,7 @@ func TestGenesis(t *testing.T) { zap.NewNop(), Options{ Context: ctx, - Network: beacon.NewNetwork(types.MainNetwork), + BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, @@ -70,7 +68,7 @@ func TestGenesis(t *testing.T) { zap.NewNop(), Options{ Context: ctx, - Network: beacon.NewNetwork(types.MainNetwork), + BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, @@ -97,7 +95,7 @@ func TestGenesis(t *testing.T) { zap.NewNop(), Options{ Context: ctx, - Network: beacon.NewNetwork(types.MainNetwork), + BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, diff --git a/beacon/goclient/signing_test.go b/beacon/goclient/signing_test.go index 423c89ec34..172a35def1 100644 --- a/beacon/goclient/signing_test.go +++ b/beacon/goclient/signing_test.go @@ -12,7 +12,7 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/beacon/goclient/tests" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" + "github.com/ssvlabs/ssv/networkconfig" ) func Test_computeVoluntaryExitDomain(t *testing.T) { @@ -26,7 +26,7 @@ func Test_computeVoluntaryExitDomain(t *testing.T) { zap.NewNop(), Options{ Context: ctx, - Network: beacon.NewNetwork(spectypes.MainNetwork), + BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, diff --git a/beacon/goclient/spec_test.go b/beacon/goclient/spec_test.go index d806e82771..b54dd8afa8 100644 --- a/beacon/goclient/spec_test.go +++ b/beacon/goclient/spec_test.go @@ -8,10 +8,8 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" - "github.com/ssvlabs/ssv-spec/types" - "github.com/ssvlabs/ssv/beacon/goclient/tests" - "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" + "github.com/ssvlabs/ssv/networkconfig" ) func TestSpec(t *testing.T) { @@ -25,7 +23,7 @@ func TestSpec(t *testing.T) { zap.NewNop(), Options{ Context: ctx, - Network: beacon.NewNetwork(types.MainNetwork), + BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, diff --git a/cli/operator/node.go b/cli/operator/node.go index d1d706b9c0..3f76dda8f4 100644 --- a/cli/operator/node.go +++ b/cli/operator/node.go @@ -138,7 +138,7 @@ var StartNodeCmd = &cobra.Command{ logger.Fatal("could not setup network", zap.Error(err)) } cfg.DBOptions.Ctx = cmd.Context() - db, err := setupDB(logger, networkConfig.BeaconConfig) + db, err := setupDB(logger, networkConfig) if err != nil { logger.Fatal("could not setup db", zap.Error(err)) } @@ -299,7 +299,6 @@ var StartNodeCmd = &cobra.Command{ ssvSignerClient, consensusClient, db, - networkConfig, operatorDataStore.GetOperatorID, ) if err != nil { @@ -417,7 +416,7 @@ var StartNodeCmd = &cobra.Command{ logger, nodeStorage.Shares(), nodeStorage.ValidatorStore().WithOperatorID(operatorDataStore.GetOperatorID), - networkConfig, + networkConfig.BeaconConfig, consensusClient, fixedSubnets, metadata.WithSyncInterval(cfg.SSVOptions.ValidatorOptions.MetadataUpdateInterval), @@ -722,7 +721,7 @@ func setupGlobal() (*zap.Logger, error) { return zap.L(), nil } -func setupDB(logger *zap.Logger, networkConfig networkconfig.NetworkConfig) (*kv.BadgerDB, error) { +func setupDB(logger *zap.Logger, beaconConfig networkconfig.Beacon) (*kv.BadgerDB, error) { db, err := kv.New(logger, cfg.DBOptions) if err != nil { return nil, errors.Wrap(err, "failed to open db") @@ -736,9 +735,9 @@ func setupDB(logger *zap.Logger, networkConfig networkconfig.NetworkConfig) (*kv } migrationOpts := migrations.Options{ - Db: db, - DbPath: cfg.DBOptions.Path, - NetworkConfig: networkConfig, + Db: db, + DbPath: cfg.DBOptions.Path, + BeaconConfig: beaconConfig, } applied, err := migrations.Run(cfg.DBOptions.Ctx, logger, migrationOpts) if err != nil { diff --git a/message/validation/validation.go b/message/validation/validation.go index e07a7c7525..74eafe2e25 100644 --- a/message/validation/validation.go +++ b/message/validation/validation.go @@ -7,7 +7,6 @@ import ( "context" "encoding/hex" "fmt" - "github.com/ssvlabs/ssv/utils/casts" "slices" "sync" "time" @@ -26,7 +25,7 @@ import ( "github.com/ssvlabs/ssv/operator/duties/dutystore" "github.com/ssvlabs/ssv/protocol/v2/ssv/queue" ssvtypes "github.com/ssvlabs/ssv/protocol/v2/types" - "github.com/ssvlabs/ssv/registry/storage" + registrystorage "github.com/ssvlabs/ssv/registry/storage" "github.com/ssvlabs/ssv/storage/basedb" ) diff --git a/migrations/migrations.go b/migrations/migrations.go index 72dc88b7f9..8cb0d1a0dc 100644 --- a/migrations/migrations.go +++ b/migrations/migrations.go @@ -53,20 +53,20 @@ type Migrations []Migration // Options is the options for running migrations. type Options struct { - Db basedb.Database - NodeStorage operatorstorage.Storage - DbPath string - NetworkConfig networkconfig.NetworkConfig + Db basedb.Database + NodeStorage operatorstorage.Storage + DbPath string + BeaconConfig networkconfig.Beacon } // nolint func (o Options) nodeStorage(logger *zap.Logger) (operatorstorage.Storage, error) { - return operatorstorage.NewNodeStorage(o.NetworkConfig, logger, o.Db) + return operatorstorage.NewNodeStorage(o.BeaconConfig, logger, o.Db) } // nolint func (o Options) signerStorage(logger *zap.Logger) ekm.Storage { - return ekm.NewSignerStorage(o.Db, o.NetworkConfig.Beacon, logger) + return ekm.NewSignerStorage(o.Db, o.BeaconConfig, logger) } // Run executes the migrations. diff --git a/operator/duties/committee.go b/operator/duties/committee.go index 9b153b5bf3..325bee731e 100644 --- a/operator/duties/committee.go +++ b/operator/duties/committee.go @@ -193,7 +193,7 @@ func (h *CommitteeHandler) shouldExecuteAtt(duty *eth2apiv1.AttesterDuty, epoch func (h *CommitteeHandler) shouldExecuteSync(duty *eth2apiv1.SyncCommitteeDuty, slot phase0.Slot, epoch phase0.Epoch) bool { share, found := h.validatorProvider.Validator(duty.PubKey[:]) - if !found || !share.IsParticipating(h.network, epoch) { + if !found || !share.IsParticipating(h.beaconConfig, epoch) { return false } diff --git a/operator/duties/sync_committee.go b/operator/duties/sync_committee.go index 80e835d423..c7c25c1cfe 100644 --- a/operator/duties/sync_committee.go +++ b/operator/duties/sync_committee.go @@ -191,7 +191,7 @@ func (h *SyncCommitteeHandler) fetchAndProcessDuties(ctx context.Context, epoch } eligibleIndices := h.validatorController.FilterIndices(waitForInitial, func(s *types.SSVShare) bool { - return s.IsParticipating(h.network, epoch) + return s.IsParticipating(h.beaconConfig, epoch) }) if len(eligibleIndices) == 0 { diff --git a/operator/storage/storage.go b/operator/storage/storage.go index 1a67c69727..d540b6b14a 100644 --- a/operator/storage/storage.go +++ b/operator/storage/storage.go @@ -64,7 +64,7 @@ type storage struct { } // NewNodeStorage creates a new instance of Storage -func NewNodeStorage(networkConfig networkconfig.NetworkConfig, logger *zap.Logger, db basedb.Database) (Storage, error) { +func NewNodeStorage(beaconCfg networkconfig.Beacon, logger *zap.Logger, db basedb.Database) (Storage, error) { stg := &storage{ logger: logger, db: db, @@ -74,7 +74,7 @@ func NewNodeStorage(networkConfig networkconfig.NetworkConfig, logger *zap.Logge var err error - stg.shareStore, stg.validatorStore, err = registrystorage.NewSharesStorage(networkConfig, db, OperatorStoragePrefix) + stg.shareStore, stg.validatorStore, err = registrystorage.NewSharesStorage(beaconCfg, db, OperatorStoragePrefix) if err != nil { return nil, err } diff --git a/operator/validator/metadata/syncer.go b/operator/validator/metadata/syncer.go index 7525da1fe3..6bd095a8b9 100644 --- a/operator/validator/metadata/syncer.go +++ b/operator/validator/metadata/syncer.go @@ -32,7 +32,7 @@ type Syncer struct { logger *zap.Logger shareStorage shareStorage validatorStore selfValidatorStore - networkConfig networkconfig.NetworkConfig + beaconConfig networkconfig.BeaconConfig beaconNode beacon.BeaconNode fixedSubnets networkcommons.Subnets syncInterval time.Duration @@ -54,7 +54,7 @@ func NewSyncer( logger *zap.Logger, shareStorage shareStorage, validatorStore selfValidatorStore, - networkConfig networkconfig.NetworkConfig, + beaconConfig networkconfig.BeaconConfig, beaconNode beacon.BeaconNode, fixedSubnets networkcommons.Subnets, opts ...Option, @@ -63,7 +63,7 @@ func NewSyncer( logger: logger, shareStorage: shareStorage, validatorStore: validatorStore, - networkConfig: networkConfig, + beaconConfig: beaconConfig, beaconNode: beaconNode, fixedSubnets: fixedSubnets, syncInterval: defaultSyncInterval, @@ -254,14 +254,14 @@ func (s *Syncer) syncNextBatch(ctx context.Context, subnetsBuf *big.Int) (SyncBa pubKeys[i] = share.ValidatorPubKey } - indicesBefore := s.allActiveIndices(ctx, s.networkConfig.Beacon.GetBeaconNetwork().EstimatedCurrentEpoch()) + indicesBefore := s.allActiveIndices(ctx, s.beaconConfig.EstimatedCurrentEpoch()) validators, err := s.Sync(ctx, pubKeys) if err != nil { return SyncBatch{}, false, fmt.Errorf("sync: %w", err) } - indicesAfter := s.allActiveIndices(ctx, s.networkConfig.Beacon.GetBeaconNetwork().EstimatedCurrentEpoch()) + indicesAfter := s.allActiveIndices(ctx, s.beaconConfig.EstimatedCurrentEpoch()) update := SyncBatch{ IndicesBefore: indicesBefore, @@ -325,7 +325,7 @@ func (s *Syncer) allActiveIndices(_ context.Context, epoch phase0.Epoch) []phase // TODO: use context, return if it's done s.shareStorage.Range(nil, func(share *ssvtypes.SSVShare) bool { - if share.IsParticipating(s.networkConfig, epoch) { + if share.IsParticipating(s.beaconConfig, epoch) { indices = append(indices, share.ValidatorIndex) } return true diff --git a/operator/validator/metadata/syncer_test.go b/operator/validator/metadata/syncer_test.go index 12d477bed4..a77c512cca 100644 --- a/operator/validator/metadata/syncer_test.go +++ b/operator/validator/metadata/syncer_test.go @@ -98,7 +98,7 @@ func TestUpdateValidatorMetadata(t *testing.T) { noSubnets, err := commons.FromString("0x00000000000000000000000000000000") require.NoError(t, err) - syncer := NewSyncer(logger, sharesStorage, validatorStore, networkconfig.TestNetwork, beaconNode, noSubnets) + syncer := NewSyncer(logger, sharesStorage, validatorStore, networkconfig.TestNetwork.BeaconConfig, beaconNode, noSubnets) _, err = syncer.Sync(context.TODO(), []spectypes.ValidatorPK{tc.testPublicKey}) if tc.sharesStorageErr != nil { require.ErrorIs(t, err, tc.sharesStorageErr) @@ -425,7 +425,7 @@ func TestSyncer_Stream(t *testing.T) { shareStorage: mockShareStorage, validatorStore: mockValidatorStore, beaconNode: defaultMockBeaconNode, - networkConfig: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork.BeaconConfig, syncInterval: testSyncInterval, streamInterval: testStreamInterval, updateSendTimeout: testUpdateSendTimeout, @@ -524,7 +524,7 @@ func TestSyncer_Stream(t *testing.T) { shareStorage: mockShareStorage, validatorStore: mockValidatorStore, beaconNode: errMockBeaconNode, - networkConfig: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork.BeaconConfig, syncInterval: testSyncInterval, streamInterval: testStreamInterval, updateSendTimeout: testUpdateSendTimeout, @@ -598,7 +598,7 @@ func TestSyncer_Stream(t *testing.T) { shareStorage: mockShareStorage, validatorStore: mockValidatorStore, beaconNode: defaultMockBeaconNode, - networkConfig: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork.BeaconConfig, syncInterval: testSyncInterval, streamInterval: testStreamInterval, updateSendTimeout: testUpdateSendTimeout, @@ -673,7 +673,7 @@ func TestWithUpdateInterval(t *testing.T) { logger, mockShareStorage, mockValidatorStore, - networkconfig.TestNetwork, + networkconfig.TestNetwork.BeaconConfig, mockBeaconNode, noSubnets, WithSyncInterval(interval), diff --git a/protocol/v2/types/ssvshare.go b/protocol/v2/types/ssvshare.go index abc8c918cf..0e3d888c32 100644 --- a/protocol/v2/types/ssvshare.go +++ b/protocol/v2/types/ssvshare.go @@ -102,8 +102,8 @@ func (s *SSVShare) Slashed() bool { // IsParticipating returns true if the validator can participate in *any* SSV duty at the given epoch. // Note: the validator may be eligible only for sync committee, but not to attest and propose. See IsParticipatingAndAttesting. // Requirements: not liquidated and attesting or exited in the current or previous sync committee period. -func (s *SSVShare) IsParticipating(cfg networkconfig.NetworkConfig, epoch phase0.Epoch) bool { - return !s.Liquidated && s.IsSyncCommitteeEligible(cfg, epoch) +func (s *SSVShare) IsParticipating(beaconCfg networkconfig.Beacon, epoch phase0.Epoch) bool { + return !s.Liquidated && s.IsSyncCommitteeEligible(beaconCfg, epoch) } // IsParticipatingAndAttesting returns true if the validator can participate in *all* SSV duties at the given epoch. @@ -112,7 +112,7 @@ func (s *SSVShare) IsParticipatingAndAttesting(epoch phase0.Epoch) bool { return !s.Liquidated && s.IsAttesting(epoch) } -func (s *SSVShare) IsSyncCommitteeEligible(cfg networkconfig.NetworkConfig, epoch phase0.Epoch) bool { +func (s *SSVShare) IsSyncCommitteeEligible(beaconCfg networkconfig.Beacon, epoch phase0.Epoch) bool { if s.IsAttesting(epoch) { return true } @@ -120,7 +120,7 @@ func (s *SSVShare) IsSyncCommitteeEligible(cfg networkconfig.NetworkConfig, epoc if s.Status.IsExited() || s.Status == eth2apiv1.ValidatorStateWithdrawalPossible || s.Status == eth2apiv1.ValidatorStateActiveSlashed { // if validator exited within Current Period OR Current Period - 1, then it is eligible // because Sync committees are assigned EPOCHS_PER_SYNC_COMMITTEE_PERIOD in advance - if epoch >= s.ExitEpoch && cfg.Beacon.EstimatedSyncCommitteePeriodAtEpoch(epoch)-cfg.Beacon.EstimatedSyncCommitteePeriodAtEpoch(s.ExitEpoch) <= 1 { + if epoch >= s.ExitEpoch && beaconCfg.EstimatedSyncCommitteePeriodAtEpoch(epoch)-beaconCfg.EstimatedSyncCommitteePeriodAtEpoch(s.ExitEpoch) <= 1 { return true } } diff --git a/registry/storage/shares.go b/registry/storage/shares.go index 3a5911930d..aa494a7939 100644 --- a/registry/storage/shares.go +++ b/registry/storage/shares.go @@ -121,7 +121,7 @@ func (s *Share) Decode(data []byte) error { return nil } -func NewSharesStorage(networkConfig networkconfig.NetworkConfig, db basedb.Database, prefix []byte) (Shares, ValidatorStore, error) { +func NewSharesStorage(beaconCfg networkconfig.Beacon, db basedb.Database, prefix []byte) (Shares, ValidatorStore, error) { storage := &sharesStorage{ shares: make(map[string]*types.SSVShare), db: db, @@ -134,7 +134,7 @@ func NewSharesStorage(networkConfig networkconfig.NetworkConfig, db basedb.Datab storage.validatorStore = newValidatorStore( func() []*types.SSVShare { return storage.List(nil) }, func(pk []byte) (*types.SSVShare, bool) { return storage.Get(nil, pk) }, - networkConfig, + beaconCfg, ) if err := storage.validatorStore.handleSharesAdded(slices.Collect(maps.Values(storage.shares))...); err != nil { return nil, nil, err diff --git a/registry/storage/validatorstore.go b/registry/storage/validatorstore.go index de8782dd1f..51c7e98848 100644 --- a/registry/storage/validatorstore.go +++ b/registry/storage/validatorstore.go @@ -55,9 +55,9 @@ type Committee struct { } // IsParticipating returns whether any validator in the committee should participate in the given epoch. -func (c *Committee) IsParticipating(cfg networkconfig.NetworkConfig, epoch phase0.Epoch) bool { +func (c *Committee) IsParticipating(beaconCfg networkconfig.Beacon, epoch phase0.Epoch) bool { for _, validator := range c.Validators { - if validator.IsParticipating(cfg, epoch) { + if validator.IsParticipating(beaconCfg, epoch) { return true } } @@ -78,7 +78,7 @@ type validatorStore struct { byCommitteeID map[spectypes.CommitteeID]*Committee byOperatorID map[spectypes.OperatorID]*sharesAndCommittees - networkConfig networkconfig.NetworkConfig + beaconCfg networkconfig.Beacon mu sync.RWMutex } @@ -86,7 +86,7 @@ type validatorStore struct { func newValidatorStore( shares func() []*types.SSVShare, shareByPubKey func([]byte) (*types.SSVShare, bool), - networkConfig networkconfig.NetworkConfig, + beaconCfg networkconfig.Beacon, ) *validatorStore { return &validatorStore{ shares: shares, @@ -94,7 +94,7 @@ func newValidatorStore( byValidatorIndex: make(map[phase0.ValidatorIndex]*types.SSVShare), byCommitteeID: make(map[spectypes.CommitteeID]*Committee), byOperatorID: make(map[spectypes.OperatorID]*sharesAndCommittees), - networkConfig: networkConfig, + beaconCfg: beaconCfg, } } @@ -121,7 +121,7 @@ func (c *validatorStore) Validators() []*types.SSVShare { func (c *validatorStore) ParticipatingValidators(epoch phase0.Epoch) []*types.SSVShare { var validators []*types.SSVShare for _, share := range c.shares() { - if share.IsParticipating(c.networkConfig, epoch) { + if share.IsParticipating(c.beaconCfg, epoch) { validators = append(validators, share) } } @@ -163,7 +163,7 @@ func (c *validatorStore) ParticipatingCommittees(epoch phase0.Epoch) []*Committe var committees []*Committee for _, committee := range c.byCommitteeID { - if committee.IsParticipating(c.networkConfig, epoch) { + if committee.IsParticipating(c.beaconCfg, epoch) { committees = append(committees, committee) } } @@ -199,7 +199,7 @@ func (c *validatorStore) SelfParticipatingValidators(epoch phase0.Epoch) []*type shares := c.OperatorValidators(c.operatorID()) var participating []*types.SSVShare for _, share := range shares { - if share.IsParticipating(c.networkConfig, epoch) { + if share.IsParticipating(c.beaconCfg, epoch) { participating = append(participating, share) } } @@ -221,7 +221,7 @@ func (c *validatorStore) SelfParticipatingCommittees(epoch phase0.Epoch) []*Comm committees := c.OperatorCommittees(c.operatorID()) var participating []*Committee for _, committee := range committees { - if committee.IsParticipating(c.networkConfig, epoch) { + if committee.IsParticipating(c.beaconCfg, epoch) { participating = append(participating, committee) } } diff --git a/ssvsigner/ekm/local_key_manager.go b/ssvsigner/ekm/local_key_manager.go index 487535a5f7..f055cc3ca8 100644 --- a/ssvsigner/ekm/local_key_manager.go +++ b/ssvsigner/ekm/local_key_manager.go @@ -53,7 +53,6 @@ type LocalKeyManager struct { wallet core.Wallet walletLock *sync.RWMutex signer signer.ValidatorSigner - domain spectypes.DomainType operatorDecrypter keys.OperatorDecrypter slashingProtector } @@ -62,10 +61,10 @@ type LocalKeyManager struct { func NewLocalKeyManager( logger *zap.Logger, db basedb.Database, - network networkconfig.NetworkConfig, + beaconConfig networkconfig.Beacon, operatorPrivKey keys.OperatorPrivateKey, ) (*LocalKeyManager, error) { - signerStore := NewSignerStorage(db, network.Beacon, logger) + signerStore := NewSignerStorage(db, beaconConfig, logger) if err := signerStore.SetEncryptionKey(operatorPrivKey.EKMHash()); err != nil { return nil, err } @@ -91,14 +90,13 @@ func NewLocalKeyManager( } } - beaconSigner := signer.NewSimpleSigner(wallet, protection, core.Network(network.Beacon.GetBeaconNetwork())) + beaconSigner := signer.NewSimpleSigner(wallet, protection, core.Network(beaconConfig.GetBeaconName())) return &LocalKeyManager{ wallet: wallet, walletLock: &sync.RWMutex{}, signer: beaconSigner, - domain: network.DomainType, - slashingProtector: NewSlashingProtector(logger, signerStore, protection), + slashingProtector: NewSlashingProtector(logger, beaconConfig, signerStore, protection), operatorDecrypter: operatorPrivKey, }, nil } diff --git a/ssvsigner/ekm/remote_key_manager.go b/ssvsigner/ekm/remote_key_manager.go index 60effb1ecc..f3618d45e9 100644 --- a/ssvsigner/ekm/remote_key_manager.go +++ b/ssvsigner/ekm/remote_key_manager.go @@ -40,7 +40,7 @@ import ( // RemoteKeyManager doesn't use operator private key as it's stored externally in the remote signer. type RemoteKeyManager struct { logger *zap.Logger - netCfg networkconfig.NetworkConfig + beaconConfig networkconfig.Beacon signerClient signerClient consensusClient consensusClient getOperatorId func() spectypes.OperatorID @@ -68,14 +68,13 @@ type consensusClient interface { // the provided consensusClient to get the current fork/genesis for sign requests. func NewRemoteKeyManager( logger *zap.Logger, - netCfg networkconfig.NetworkConfig, + beaconConfig networkconfig.Beacon, signerClient signerClient, consensusClient consensusClient, db basedb.Database, - networkConfig networkconfig.NetworkConfig, getOperatorId func() spectypes.OperatorID, ) (*RemoteKeyManager, error) { - signerStore := NewSignerStorage(db, networkConfig.Beacon, logger) + signerStore := NewSignerStorage(db, beaconConfig, logger) protection := slashingprotection.NewNormalProtection(signerStore) operatorPubKeyString, err := signerClient.OperatorIdentity(context.Background()) // TODO: use context @@ -90,10 +89,10 @@ func NewRemoteKeyManager( return &RemoteKeyManager{ logger: logger, - netCfg: netCfg, + beaconConfig: beaconConfig, signerClient: signerClient, consensusClient: consensusClient, - slashingProtector: NewSlashingProtector(logger, signerStore, protection), + slashingProtector: NewSlashingProtector(logger, beaconConfig, signerStore, protection), getOperatorId: getOperatorId, operatorPubKey: operatorPubKey, signLocks: map[signKey]*sync.RWMutex{}, @@ -154,7 +153,7 @@ func (km *RemoteKeyManager) SignBeaconObject( slot phase0.Slot, signatureDomain phase0.DomainType, ) (spectypes.Signature, phase0.Root, error) { - epoch := km.netCfg.Beacon.EstimatedEpochAtSlot(slot) + epoch := km.beaconConfig.EstimatedEpochAtSlot(slot) forkInfo, err := km.getForkInfo(ctx, epoch) if err != nil { @@ -316,7 +315,7 @@ func (km *RemoteKeyManager) handleDomainAttester( return nil, errors.New("could not cast obj to AttestationData") } - network := core.Network(km.netCfg.Beacon.GetBeaconNetwork()) + network := core.Network(km.beaconConfig.GetBeaconName()) if !signer.IsValidFarFutureEpoch(network, data.Target.Epoch) { return nil, fmt.Errorf("target epoch too far into the future") } @@ -449,7 +448,7 @@ func (km *RemoteKeyManager) handleDomainProposer( blockSlot := ret.BlockHeader.Slot - network := core.Network(km.netCfg.Beacon.GetBeaconNetwork()) + network := core.Network(km.beaconConfig.GetBeaconName()) if !signer.IsValidFarFutureSlot(network, blockSlot) { return nil, fmt.Errorf("proposed block slot too far into the future") } diff --git a/ssvsigner/ekm/remote_key_manager_test.go b/ssvsigner/ekm/remote_key_manager_test.go index 880d4f0fe1..dc3409c384 100644 --- a/ssvsigner/ekm/remote_key_manager_test.go +++ b/ssvsigner/ekm/remote_key_manager_test.go @@ -54,7 +54,7 @@ func (s *RemoteKeyManagerTestSuite) TestRemoteKeyManagerWithMockedOperatorKey() rm := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: s.client, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -84,7 +84,7 @@ func (s *RemoteKeyManagerTestSuite) TestRemoveShareWithMockedOperatorKey() { rm := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: s.client, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -134,7 +134,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignError() { rm := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: mockRemoteSigner, slashingProtector: mockSlashingProtector, operatorPubKey: mockOperatorPublicKey, @@ -161,7 +161,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() rm := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: s.client, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -695,7 +695,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { rm := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: s.client, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -739,7 +739,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -786,7 +786,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -842,7 +842,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -898,7 +898,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -954,7 +954,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1031,7 +1031,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1108,7 +1108,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1187,7 +1187,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1266,7 +1266,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1370,7 +1370,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1476,7 +1476,7 @@ func (s *RemoteKeyManagerTestSuite) TestAddShareErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1504,7 +1504,7 @@ func (s *RemoteKeyManagerTestSuite) TestAddShareErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1535,7 +1535,7 @@ func (s *RemoteKeyManagerTestSuite) TestRemoveShareErrorCases() { rm := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: s.client, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1559,7 +1559,7 @@ func (s *RemoteKeyManagerTestSuite) TestRemoveShareErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1586,7 +1586,7 @@ func (s *RemoteKeyManagerTestSuite) TestRemoveShareErrorCases() { rmTest := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: clientMock, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1634,7 +1634,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignSSVMessage() { rm := &RemoteKeyManager{ logger: zap.NewNop(), - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: mockRemoteSigner, getOperatorId: func() spectypes.OperatorID { return 1 }, } @@ -1691,7 +1691,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectAdditionalDomains() { rm := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: s.client, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1809,7 +1809,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectMoreDomains() { rm := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: s.client, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -1986,7 +1986,7 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectTypeCastErrors() { rm := &RemoteKeyManager{ logger: s.logger, - netCfg: networkconfig.TestNetwork, + beaconConfig: networkconfig.TestNetwork, signerClient: s.client, consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, @@ -2161,11 +2161,10 @@ QwIDAQAB _, err := NewRemoteKeyManager( logger, - networkconfig.TestNetwork, + networkCfg, s.client, s.consensusClient, s.db, - networkCfg, getOperatorId, ) @@ -2192,11 +2191,10 @@ func (s *RemoteKeyManagerTestSuite) TestNewRemoteKeyManager_OperatorIdentity_Wro _, err := NewRemoteKeyManager( logger, - networkconfig.TestNetwork, + networkCfg, s.client, s.consensusClient, s.db, - networkCfg, getOperatorId, ) @@ -2222,11 +2220,10 @@ func (s *RemoteKeyManagerTestSuite) TestNewRemoteKeyManager_OperatorIdentity_Err _, err := NewRemoteKeyManager( logger, - networkconfig.TestNetwork, + networkCfg, s.client, s.consensusClient, s.db, - networkCfg, getOperatorId, ) diff --git a/ssvsigner/ekm/signer_storage.go b/ssvsigner/ekm/signer_storage.go index f3de2d2f51..6867e46f7a 100644 --- a/ssvsigner/ekm/signer_storage.go +++ b/ssvsigner/ekm/signer_storage.go @@ -44,7 +44,11 @@ const ( // TODO: review if we need all of them type Storage interface { registry.RegistryStore - core.Storage + + // Name returns storage name. + Name() string + core.WalletStorage + core.AccountStorage core.SlashingStore RemoveHighestAttestation(pubKey []byte) error diff --git a/ssvsigner/ekm/slashing_protector.go b/ssvsigner/ekm/slashing_protector.go index bd63bde016..62b999b0f1 100644 --- a/ssvsigner/ekm/slashing_protector.go +++ b/ssvsigner/ekm/slashing_protector.go @@ -7,6 +7,8 @@ import ( "github.com/ssvlabs/eth2-key-manager/core" slashingprotection "github.com/ssvlabs/eth2-key-manager/slashing_protection" "go.uber.org/zap" + + "github.com/ssvlabs/ssv/networkconfig" ) // slashing_protector.go provides SlashingProtector, a wrapper around @@ -42,17 +44,20 @@ type slashingProtector interface { // or proposal is slashable. type SlashingProtector struct { logger *zap.Logger + beaconCfg networkconfig.Beacon signerStore Storage protection *slashingprotection.NormalProtection } func NewSlashingProtector( logger *zap.Logger, + beaconCfg networkconfig.Beacon, signerStore Storage, protection *slashingprotection.NormalProtection, ) *SlashingProtector { return &SlashingProtector{ logger: logger, + beaconCfg: beaconCfg, signerStore: signerStore, protection: protection, } @@ -110,7 +115,7 @@ func (sp *SlashingProtector) UpdateHighestProposal(pubKey phase0.BLSPubKey, slot // BumpSlashingProtection updates the slashing protection data for a given public key. func (sp *SlashingProtector) BumpSlashingProtection(pubKey phase0.BLSPubKey) error { - currentSlot := sp.signerStore.BeaconNetwork().EstimatedCurrentSlot() + currentSlot := sp.beaconCfg.EstimatedCurrentSlot() // Update highest attestation data for slashing protection. if err := sp.updateHighestAttestation(pubKey, currentSlot); err != nil { @@ -133,7 +138,7 @@ func (sp *SlashingProtector) updateHighestAttestation(pubKey phase0.BLSPubKey, s return fmt.Errorf("could not retrieve highest attestation: %w", err) } - currentEpoch := sp.signerStore.BeaconNetwork().EstimatedEpochAtSlot(slot) + currentEpoch := sp.beaconCfg.EstimatedEpochAtSlot(slot) minimalSP := sp.computeMinimalAttestationSP(currentEpoch) // Check if the retrieved highest attestation data is valid and not outdated. From 3781bf954d82df404c0d23d82f0a2ced8fb542a7 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Wed, 23 Apr 2025 20:46:02 -0300 Subject: [PATCH 13/34] update go.mod --- go.mod | 2 +- go.sum | 2 ++ ssvsigner/go.mod | 2 +- ssvsigner/go.sum | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 040924f00f..8e4a1248ed 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/spf13/cobra v1.8.1 github.com/ssvlabs/eth2-key-manager v1.5.2 github.com/ssvlabs/ssv-spec v1.1.3 - github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250422001600-57842541ad25 + github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250423234408-3aa5db24ccdb github.com/status-im/keycard-go v0.2.0 github.com/stretchr/testify v1.9.0 github.com/wealdtech/go-eth2-types/v2 v2.8.1 diff --git a/go.sum b/go.sum index 64c2c28a5d..cc69141c1b 100644 --- a/go.sum +++ b/go.sum @@ -758,6 +758,8 @@ github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250422001600-57842541ad25 h1:xQlQzbn4F1Hx9drnUCvIb6rmavqI0CM9x8Fbnata5K8= github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250422001600-57842541ad25/go.mod h1:dIR/Qidjw4QD5I3frpPJYpW4PcZcxwLAO8EVwYu6Dos= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250423234408-3aa5db24ccdb h1:israZhWrV2VLqzCC+Ex6AmtPOU3XC44qss+Ymq5fVLU= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250423234408-3aa5db24ccdb/go.mod h1:W5GpcIOHIMljFQCwRgEArJOfRIr4lMVKxm0IOuwn8bE= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/ssvsigner/go.mod b/ssvsigner/go.mod index fbaa652b89..ed97c5bd0d 100644 --- a/ssvsigner/go.mod +++ b/ssvsigner/go.mod @@ -26,7 +26,7 @@ require ( github.com/microsoft/go-crypto-openssl v0.2.9 github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 github.com/ssvlabs/eth2-key-manager v1.5.2 - github.com/ssvlabs/ssv v1.2.1-0.20250422001600-57842541ad25 + github.com/ssvlabs/ssv v1.2.1-0.20250423234408-3aa5db24ccdb github.com/ssvlabs/ssv-spec v1.1.3 github.com/stretchr/testify v1.9.0 github.com/valyala/fasthttp v1.58.0 diff --git a/ssvsigner/go.sum b/ssvsigner/go.sum index e6336953cd..fabb8391d5 100644 --- a/ssvsigner/go.sum +++ b/ssvsigner/go.sum @@ -326,6 +326,8 @@ github.com/ssvlabs/ssv v1.2.1-0.20250417212959-488df74ac5aa h1:ZgTwLPE16f2GqrRUq github.com/ssvlabs/ssv v1.2.1-0.20250417212959-488df74ac5aa/go.mod h1:7AvQK0AmkqmOVRgHmwfhgbzW9hR/FxyiROWp5thiXhw= github.com/ssvlabs/ssv v1.2.1-0.20250422001600-57842541ad25 h1:Jw69olUGu8oIZf5JGDi69wqdrpBz+cbBi9aPV/CiJKk= github.com/ssvlabs/ssv v1.2.1-0.20250422001600-57842541ad25/go.mod h1:dWtV013maPZ1QhqbilGPPBuYNm65+QK/mFB3xbY/Scs= +github.com/ssvlabs/ssv v1.2.1-0.20250423234408-3aa5db24ccdb h1:huTuQ+20/Aa8w00OXu5B9W/+Umu6Of/xWAihxCMZvws= +github.com/ssvlabs/ssv v1.2.1-0.20250423234408-3aa5db24ccdb/go.mod h1:CJ1M0F7auIXCdL6R5yZtdVt391VoMosF3wmFtiuHiOg= github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo8= github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= From 8a79160019405a2bb00e273a5acf68ccdd948a85 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Fri, 25 Apr 2025 06:19:52 -0300 Subject: [PATCH 14/34] fix ekm tests --- ssvsigner/ekm/local_key_manager_test.go | 12 ++-- ssvsigner/ekm/remote_key_manager_test.go | 7 +-- ssvsigner/ekm/signer_storage.go | 5 +- ssvsigner/ekm/signer_storage_test.go | 6 +- ssvsigner/ekm/slashing_protector_test.go | 80 ++++++++++++------------ 5 files changed, 51 insertions(+), 59 deletions(-) diff --git a/ssvsigner/ekm/local_key_manager_test.go b/ssvsigner/ekm/local_key_manager_test.go index b2ddeb864c..b8abb95125 100644 --- a/ssvsigner/ekm/local_key_manager_test.go +++ b/ssvsigner/ekm/local_key_manager_test.go @@ -35,7 +35,7 @@ const ( pk2Str = "8796fafa576051372030a75c41caafea149e4368aebaca21c9f90d9974b3973d5cee7d7874e4ec9ec59fb2c8945b3e01" ) -func testKeyManager(t *testing.T, network *networkconfig.NetworkConfig, operatorPrivateKey keys.OperatorPrivateKey) (KeyManager, *networkconfig.NetworkConfig) { +func testKeyManager(t *testing.T, network networkconfig.Network, operatorPrivateKey keys.OperatorPrivateKey) (KeyManager, networkconfig.Network) { threshold.Init() logger := logging.TestLogger(t) @@ -44,12 +44,10 @@ func testKeyManager(t *testing.T, network *networkconfig.NetworkConfig, operator require.NoError(t, err) if network == nil { - network = &networkconfig.NetworkConfig{} - network.Beacon = utils.SetupMockBeaconNetwork(t, nil) - network.DomainType = networkconfig.TestNetwork.DomainType + network = utils.SetupMockNetworkConfig(t, networkconfig.TestNetwork.DomainType, nil) } - km, err := NewLocalKeyManager(logger, db, *network, operatorPrivateKey) + km, err := NewLocalKeyManager(logger, db, network, operatorPrivateKey) require.NoError(t, err) sk1 := &bls.SecretKey{} @@ -88,7 +86,7 @@ func TestEncryptedKeyManager(t *testing.T) { db, err := getBaseStorage(logger) require.NoError(t, err) - signerStorage := NewSignerStorage(db, networkconfig.TestNetwork.Beacon.GetNetwork(), logger) + signerStorage := NewSignerStorage(db, networkconfig.TestNetwork, logger) err = signerStorage.SetEncryptionKey(encryptionKey) require.NoError(t, err) @@ -151,7 +149,7 @@ func TestSignBeaconObject(t *testing.T) { require.NoError(t, km.AddShare(context.Background(), encryptedSK1, phase0.BLSPubKey(sk1.GetPublicKey().Serialize()))) - currentSlot := network.Beacon.EstimatedCurrentSlot() + currentSlot := network.EstimatedCurrentSlot() highestProposal := currentSlot + minSPProposalSlotGap + 1 t.Run("Sign Deneb block", func(t *testing.T) { diff --git a/ssvsigner/ekm/remote_key_manager_test.go b/ssvsigner/ekm/remote_key_manager_test.go index e61353ed71..c17273058c 100644 --- a/ssvsigner/ekm/remote_key_manager_test.go +++ b/ssvsigner/ekm/remote_key_manager_test.go @@ -26,6 +26,7 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/networkconfig" + "github.com/ssvlabs/ssv/ssvsigner" ) @@ -2164,8 +2165,6 @@ func (s *RemoteKeyManagerTestSuite) TestNewRemoteKeyManager() { s.txn.On("Commit").Return(nil).Maybe() s.txn.On("Rollback").Return(nil).Maybe() - networkCfg := networkconfig.NetworkConfig{} - const sampleRSAPublicKey = ` -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArVzXJ1Xm3YIY8QYs2MFL @@ -2206,8 +2205,6 @@ func (s *RemoteKeyManagerTestSuite) TestNewRemoteKeyManager_OperatorIdentity_Wro s.txn.On("Commit").Return(nil).Maybe() s.txn.On("Rollback").Return(nil).Maybe() - networkCfg := networkconfig.NetworkConfig{} - invalidPubKey := "invalid-public-key-format" s.client.On("OperatorIdentity", mock.Anything).Return(invalidPubKey, nil) @@ -2236,8 +2233,6 @@ func (s *RemoteKeyManagerTestSuite) TestNewRemoteKeyManager_OperatorIdentity_Err s.txn.On("Commit").Return(nil).Maybe() s.txn.On("Rollback").Return(nil).Maybe() - networkCfg := networkconfig.NetworkConfig{} - s.client.On("OperatorIdentity", mock.Anything).Return("", errors.New("err")) logger, _ := zap.NewDevelopment() diff --git a/ssvsigner/ekm/signer_storage.go b/ssvsigner/ekm/signer_storage.go index 6867e46f7a..bbcb0e39c5 100644 --- a/ssvsigner/ekm/signer_storage.go +++ b/ssvsigner/ekm/signer_storage.go @@ -45,10 +45,7 @@ const ( type Storage interface { registry.RegistryStore - // Name returns storage name. - Name() string - core.WalletStorage - core.AccountStorage + core.Storage core.SlashingStore RemoveHighestAttestation(pubKey []byte) error diff --git a/ssvsigner/ekm/signer_storage_test.go b/ssvsigner/ekm/signer_storage_test.go index a95ff3e8ca..c1f9fc8bea 100644 --- a/ssvsigner/ekm/signer_storage_test.go +++ b/ssvsigner/ekm/signer_storage_test.go @@ -40,7 +40,7 @@ func newStorageForTest(t *testing.T) (Storage, func()) { return nil, func() {} } - s := NewSignerStorage(db, networkconfig.TestNetwork.Beacon.GetNetwork(), logger) + s := NewSignerStorage(db, networkconfig.TestNetwork, logger) return s, func() { db.Close() } @@ -361,7 +361,7 @@ func TestStorageUtilityFunctions(t *testing.T) { require.NoError(t, err) defer db.Close() - signerStorage := NewSignerStorage(db, networkconfig.TestNetwork.Beacon.GetNetwork(), logger) + signerStorage := NewSignerStorage(db, networkconfig.TestNetwork, logger) err = signerStorage.SetEncryptionKey("aabbccddee") require.NoError(t, err) @@ -379,7 +379,7 @@ func TestStorageUtilityFunctions(t *testing.T) { require.NoError(t, err) defer db.Close() - signerStorage := NewSignerStorage(db, networkconfig.TestNetwork.Beacon.GetNetwork(), logger) + signerStorage := NewSignerStorage(db, networkconfig.TestNetwork, logger) // create a test account wallet := hd.NewWallet(&core.WalletContext{Storage: signerStorage}) diff --git a/ssvsigner/ekm/slashing_protector_test.go b/ssvsigner/ekm/slashing_protector_test.go index b9b3bcb6d5..904812194f 100644 --- a/ssvsigner/ekm/slashing_protector_test.go +++ b/ssvsigner/ekm/slashing_protector_test.go @@ -12,13 +12,15 @@ import ( slashingprotection "github.com/ssvlabs/eth2-key-manager/slashing_protection" spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/ssvlabs/ssv-spec/types/testingutils" + "github.com/ssvlabs/ssv/networkconfig" "github.com/stretchr/testify/require" "github.com/ssvlabs/ssv/logging" - "github.com/ssvlabs/ssv/ssvsigner/keys" "github.com/ssvlabs/ssv/storage/basedb" "github.com/ssvlabs/ssv/storage/kv" "github.com/ssvlabs/ssv/utils" + + "github.com/ssvlabs/ssv/ssvsigner/keys" ) func TestSlashing(t *testing.T) { @@ -37,8 +39,8 @@ func TestSlashing(t *testing.T) { require.NoError(t, km.AddShare(context.Background(), encryptedSK1, phase0.BLSPubKey(sk1.GetPublicKey().Serialize()))) - currentSlot := network.Beacon.EstimatedCurrentSlot() - currentEpoch := network.Beacon.EstimatedEpochAtSlot(currentSlot) + currentSlot := network.EstimatedCurrentSlot() + currentEpoch := network.EstimatedEpochAtSlot(currentSlot) highestTarget := currentEpoch + minSPAttestationEpochGap + 1 highestSource := highestTarget - 1 @@ -256,8 +258,8 @@ func TestConcurrentSlashingProtectionAttData(t *testing.T) { sk1 := &bls.SecretKey{} require.NoError(t, sk1.SetHexString(sk1Str)) - currentSlot := network.Beacon.EstimatedCurrentSlot() - currentEpoch := network.Beacon.EstimatedEpochAtSlot(currentSlot) + currentSlot := network.EstimatedCurrentSlot() + currentEpoch := network.EstimatedEpochAtSlot(currentSlot) highestTarget := currentEpoch + minSPAttestationEpochGap + 1 highestSource := highestTarget - 1 @@ -336,7 +338,7 @@ func TestConcurrentSlashingProtectionBeaconBlock(t *testing.T) { sk1 := &bls.SecretKey{} require.NoError(t, sk1.SetHexString(sk1Str)) - currentSlot := network.Beacon.EstimatedCurrentSlot() + currentSlot := network.EstimatedCurrentSlot() highestProposal := currentSlot + minSPProposalSlotGap + 1 blockContents := testingutils.TestingBlockContentsDeneb @@ -431,8 +433,8 @@ func TestConcurrentSlashingProtectionWithMultipleKeysAttData(t *testing.T) { require.NoError(t, km.AddShare(context.Background(), encryptedPrivKey, phase0.BLSPubKey(validator.sk.GetPublicKey().Serialize()))) } - currentSlot := network.Beacon.EstimatedCurrentSlot() - currentEpoch := network.Beacon.EstimatedEpochAtSlot(currentSlot) + currentSlot := network.EstimatedCurrentSlot() + currentEpoch := network.EstimatedEpochAtSlot(currentSlot) highestTarget := currentEpoch + minSPAttestationEpochGap + 1 highestSource := highestTarget - 1 @@ -535,7 +537,7 @@ func TestConcurrentSlashingProtectionWithMultipleKeysBeaconBlock(t *testing.T) { require.NoError(t, km.AddShare(context.Background(), encryptedPrivKey, phase0.BLSPubKey(validator.sk.GetPublicKey().Serialize()))) } - currentSlot := network.Beacon.EstimatedCurrentSlot() + currentSlot := network.EstimatedCurrentSlot() highestProposal := currentSlot + minSPProposalSlotGap + 1 blockContents := testingutils.TestingBlockContentsDeneb @@ -621,7 +623,7 @@ func TestComprehensiveSlashingBlockProposal(t *testing.T) { require.NoError(t, km.AddShare(context.Background(), encryptedPrivKey, sharePubKey)) // --- First Block Proposal --- - slotToSign := network.Beacon.EstimatedCurrentSlot() + 5 // Sign a block slightly in the future + slotToSign := network.EstimatedCurrentSlot() + 5 // Sign a block slightly in the future // Check directly with IsBeaconBlockSlashable err = km.IsBeaconBlockSlashable(sharePubKey, slotToSign) @@ -700,10 +702,10 @@ func TestSlashableBlockDoubleProposal(t *testing.T) { require.NoError(t, err) defer db.Close() - mockBeacon := utils.SetupMockBeaconNetwork(t, nil) - signerStore := NewSignerStorage(db, mockBeacon, logger) + mockNetworkConfig := utils.SetupMockNetworkConfig(t, networkconfig.TestNetwork.DomainType, nil) + signerStore := NewSignerStorage(db, mockNetworkConfig, logger) protection := slashingprotection.NewNormalProtection(signerStore) - protector := NewSlashingProtector(logger, signerStore, protection) + protector := NewSlashingProtector(logger, mockNetworkConfig, signerStore, protection) // Initialize test share key require.NoError(t, bls.Init(bls.BLS12_381)) @@ -716,7 +718,7 @@ func TestSlashableBlockDoubleProposal(t *testing.T) { require.NoError(t, err, "Failed to bump slashing protection") // --- First Block Proposal --- - slotToSign := mockBeacon.EstimatedCurrentSlot() + 5 // Sign a block slightly in the future + slotToSign := mockNetworkConfig.EstimatedCurrentSlot() + 5 // Sign a block slightly in the future // Check if first block at this slot is slashable - should not be err = protector.IsBeaconBlockSlashable(sharePubKey, slotToSign) @@ -756,10 +758,10 @@ func TestSlashableAttestationDoubleVote(t *testing.T) { require.NoError(t, err) defer db.Close() - mockBeacon := utils.SetupMockBeaconNetwork(t, nil) - signerStore := NewSignerStorage(db, mockBeacon, logger) + mockNetworkConfig := utils.SetupMockNetworkConfig(t, networkconfig.TestNetwork.DomainType, nil) + signerStore := NewSignerStorage(db, mockNetworkConfig, logger) protection := slashingprotection.NewNormalProtection(signerStore) - protector := NewSlashingProtector(logger, signerStore, protection) + protector := NewSlashingProtector(logger, mockNetworkConfig, signerStore, protection) // Initialize test share key require.NoError(t, bls.Init(bls.BLS12_381)) @@ -772,8 +774,8 @@ func TestSlashableAttestationDoubleVote(t *testing.T) { require.NoError(t, err, "Failed to bump slashing protection") // --- First Attestation --- - epochToSign := mockBeacon.EstimatedCurrentEpoch() + 2 - slotToSign := mockBeacon.FirstSlotAtEpoch(epochToSign) + epochToSign := mockNetworkConfig.EstimatedCurrentEpoch() + 2 + slotToSign := mockNetworkConfig.FirstSlotAtEpoch(epochToSign) attData1 := testingutils.TestingAttestationData(spec.DataVersionPhase0) attData1.Slot = slotToSign @@ -807,7 +809,7 @@ func TestSlashableAttestationDoubleVote(t *testing.T) { // --- Third Attestation (Higher Target Epoch) --- epochToSignHigher := epochToSign + 1 - slotToSignHigher := mockBeacon.FirstSlotAtEpoch(epochToSignHigher) + slotToSignHigher := mockNetworkConfig.FirstSlotAtEpoch(epochToSignHigher) attData3 := testingutils.TestingAttestationData(spec.DataVersionPhase0) attData3.Slot = slotToSignHigher @@ -832,10 +834,10 @@ func TestSlashableAttestationSurroundingVote(t *testing.T) { require.NoError(t, err) defer db.Close() - mockBeacon := utils.SetupMockBeaconNetwork(t, nil) - signerStore := NewSignerStorage(db, mockBeacon, logger) + mockNetworkConfig := utils.SetupMockNetworkConfig(t, networkconfig.TestNetwork.DomainType, nil) + signerStore := NewSignerStorage(db, mockNetworkConfig, logger) protection := slashingprotection.NewNormalProtection(signerStore) - protector := NewSlashingProtector(logger, signerStore, protection) + protector := NewSlashingProtector(logger, mockNetworkConfig, signerStore, protection) // Initialize test share key require.NoError(t, bls.Init(bls.BLS12_381)) @@ -848,9 +850,9 @@ func TestSlashableAttestationSurroundingVote(t *testing.T) { require.NoError(t, err, "Failed to bump slashing protection") // --- First Attestation (Inner) --- - innerSourceEpoch := mockBeacon.EstimatedCurrentEpoch() + 2 + innerSourceEpoch := mockNetworkConfig.EstimatedCurrentEpoch() + 2 innerTargetEpoch := innerSourceEpoch + 1 - innerSlot := mockBeacon.FirstSlotAtEpoch(innerTargetEpoch) // Slot within the target epoch + innerSlot := mockNetworkConfig.FirstSlotAtEpoch(innerTargetEpoch) // Slot within the target epoch attDataInner := testingutils.TestingAttestationData(spec.DataVersionPhase0) attDataInner.Slot = innerSlot @@ -869,7 +871,7 @@ func TestSlashableAttestationSurroundingVote(t *testing.T) { // --- Second Attestation (Surrounding) --- outerSourceEpoch := innerSourceEpoch - 1 // Lower source outerTargetEpoch := innerTargetEpoch + 1 // Higher target - outerSlot := mockBeacon.FirstSlotAtEpoch(outerTargetEpoch) + outerSlot := mockNetworkConfig.FirstSlotAtEpoch(outerTargetEpoch) attDataOuter := testingutils.TestingAttestationData(spec.DataVersionPhase0) attDataOuter.Slot = outerSlot @@ -885,7 +887,7 @@ func TestSlashableAttestationSurroundingVote(t *testing.T) { // --- Third Attestation (Non-Surrounding, Higher) --- higherSourceEpoch := innerSourceEpoch // Same source as inner higherTargetEpoch := outerTargetEpoch // Same target as outer (but source is higher than outer's source) - higherSlot := mockBeacon.FirstSlotAtEpoch(higherTargetEpoch) + higherSlot := mockNetworkConfig.FirstSlotAtEpoch(higherTargetEpoch) attDataHigher := testingutils.TestingAttestationData(spec.DataVersionPhase0) attDataHigher.Slot = higherSlot @@ -911,10 +913,10 @@ func TestSlashingDBIntegrity(t *testing.T) { db, err := kv.New(logger, basedb.Options{Path: dbPath}) require.NoError(t, err) - mockBeacon := utils.SetupMockBeaconNetwork(t, nil) - signerStore := NewSignerStorage(db, mockBeacon, logger) + mockNetworkConfig := utils.SetupMockNetworkConfig(t, networkconfig.TestNetwork.DomainType, nil) + signerStore := NewSignerStorage(db, mockNetworkConfig, logger) protection := slashingprotection.NewNormalProtection(signerStore) - protector := NewSlashingProtector(logger, signerStore, protection) + protector := NewSlashingProtector(logger, mockNetworkConfig, signerStore, protection) // Initialize test share key require.NoError(t, bls.Init(bls.BLS12_381)) @@ -927,7 +929,7 @@ func TestSlashingDBIntegrity(t *testing.T) { require.NoError(t, err, "DB Integrity: Failed to bump slashing protection (Phase 1)") // Sign a block - slotToSign := mockBeacon.EstimatedCurrentSlot() + 5 + slotToSign := mockNetworkConfig.EstimatedCurrentSlot() + 5 err = protector.IsBeaconBlockSlashable(sharePubKey, slotToSign) require.NoError(t, err, "DB Integrity: First block should not be slashable (Phase 1)") @@ -947,9 +949,9 @@ func TestSlashingDBIntegrity(t *testing.T) { require.NoError(t, err) defer db2.Close() - signerStore2 := NewSignerStorage(db2, mockBeacon, logger) + signerStore2 := NewSignerStorage(db2, mockNetworkConfig, logger) protection2 := slashingprotection.NewNormalProtection(signerStore2) - protector2 := NewSlashingProtector(logger, signerStore2, protection2) + protector2 := NewSlashingProtector(logger, mockNetworkConfig, signerStore2, protection2) // Attempt to sign the *same* block again - should fail due to persisted data t.Log("Attempting to sign the same block again - should fail") @@ -969,10 +971,10 @@ func TestSlashingConcurrency(t *testing.T) { require.NoError(t, err) defer db.Close() - mockBeacon := utils.SetupMockBeaconNetwork(t, nil) - signerStore := NewSignerStorage(db, mockBeacon, logger) + mockNetworkConfig := utils.SetupMockNetworkConfig(t, networkconfig.TestNetwork.DomainType, nil) + signerStore := NewSignerStorage(db, mockNetworkConfig, logger) protection := slashingprotection.NewNormalProtection(signerStore) - protector := NewSlashingProtector(logger, signerStore, protection) + protector := NewSlashingProtector(logger, mockNetworkConfig, signerStore, protection) // Initialize test share key require.NoError(t, bls.Init(bls.BLS12_381)) @@ -985,7 +987,7 @@ func TestSlashingConcurrency(t *testing.T) { require.NoError(t, err, "Concurrency: Failed to bump slashing protection") // Sign a valid block first to establish a baseline - slotToSign := mockBeacon.EstimatedCurrentSlot() + 5 + slotToSign := mockNetworkConfig.EstimatedCurrentSlot() + 5 err = protector.IsBeaconBlockSlashable(sharePubKey, slotToSign) require.NoError(t, err, "Concurrency: First block should not be slashable") @@ -1033,8 +1035,8 @@ func TestSlashingConcurrency(t *testing.T) { } case 3: // Check a new attestation - epoch := mockBeacon.EstimatedCurrentEpoch() + phase0.Epoch(routineID%10) + 1 - slot := mockBeacon.FirstSlotAtEpoch(epoch) + epoch := mockNetworkConfig.EstimatedCurrentEpoch() + phase0.Epoch(routineID%10) + 1 + slot := mockNetworkConfig.FirstSlotAtEpoch(epoch) attData := &phase0.AttestationData{ Slot: slot, Index: 0, From def906be9a560a84ce230d2953952ed514e04913 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Fri, 25 Apr 2025 06:20:56 -0300 Subject: [PATCH 15/34] remove unused import --- message/validation/validation.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/message/validation/validation.go b/message/validation/validation.go index a7821c47d0..74eafe2e25 100644 --- a/message/validation/validation.go +++ b/message/validation/validation.go @@ -11,8 +11,6 @@ import ( "sync" "time" - "github.com/ssvlabs/ssv/utils/casts" - "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/jellydator/ttlcache/v3" pubsub "github.com/libp2p/go-libp2p-pubsub" From 54f7f9a4338adb77473a264268372948d9639531 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Fri, 25 Apr 2025 06:23:06 -0300 Subject: [PATCH 16/34] update go.mod --- go.mod | 2 +- go.sum | 6 ++++-- ssvsigner/go.mod | 2 +- ssvsigner/go.sum | 2 ++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 36df992de3..ee97acb567 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/spf13/cobra v1.8.1 github.com/ssvlabs/eth2-key-manager v1.5.2 github.com/ssvlabs/ssv-spec v1.1.3 - github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250424103603-719a5867d010 + github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250425092056-def906be9a56 github.com/status-im/keycard-go v0.2.0 github.com/stretchr/testify v1.9.0 github.com/wealdtech/go-eth2-types/v2 v2.8.1 diff --git a/go.sum b/go.sum index d0318d97dc..f199467212 100644 --- a/go.sum +++ b/go.sum @@ -756,10 +756,12 @@ github.com/ssvlabs/go-eth2-client v0.6.31-0.20250417062221-9cd9b891d4d6 h1:26sqP github.com/ssvlabs/go-eth2-client v0.6.31-0.20250417062221-9cd9b891d4d6/go.mod h1:fvULSL9WtNskkOB4i+Yyr6BKpNHXvmpGZj9969fCrfY= github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo8= github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250424103603-719a5867d010 h1:9jnKiOWtFEokR/wCbvUvsIqlGrJGGAZtMBlpuqV2b3Q= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250424103603-719a5867d010/go.mod h1:HkcbtVHpGBPnJjdWWd08Z3lv7l0VWejJU80yUUqY5Go= github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250423234408-3aa5db24ccdb h1:israZhWrV2VLqzCC+Ex6AmtPOU3XC44qss+Ymq5fVLU= github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250423234408-3aa5db24ccdb/go.mod h1:W5GpcIOHIMljFQCwRgEArJOfRIr4lMVKxm0IOuwn8bE= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250424103603-719a5867d010 h1:9jnKiOWtFEokR/wCbvUvsIqlGrJGGAZtMBlpuqV2b3Q= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250424103603-719a5867d010/go.mod h1:HkcbtVHpGBPnJjdWWd08Z3lv7l0VWejJU80yUUqY5Go= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250425092056-def906be9a56 h1:zUgvDPwrYS3gUSORZHGZSSpTKRFZqwi/6ipjdb7NLsY= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250425092056-def906be9a56/go.mod h1:asx2GF46/MDVdE1fY1aF96bY9rXOk/qU+tR53EQ+Nac= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/ssvsigner/go.mod b/ssvsigner/go.mod index 407f82bb07..9969c498a7 100644 --- a/ssvsigner/go.mod +++ b/ssvsigner/go.mod @@ -26,7 +26,7 @@ require ( github.com/microsoft/go-crypto-openssl v0.2.9 github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 github.com/ssvlabs/eth2-key-manager v1.5.2 - github.com/ssvlabs/ssv v1.2.1-0.20250423234408-3aa5db24ccdb + github.com/ssvlabs/ssv v1.2.1-0.20250425092056-def906be9a56 github.com/ssvlabs/ssv-spec v1.1.3 github.com/stretchr/testify v1.9.0 github.com/valyala/fasthttp v1.58.0 diff --git a/ssvsigner/go.sum b/ssvsigner/go.sum index 4f58c0ca03..ec46cba287 100644 --- a/ssvsigner/go.sum +++ b/ssvsigner/go.sum @@ -326,6 +326,8 @@ github.com/ssvlabs/ssv v1.2.1-0.20250422001600-57842541ad25 h1:Jw69olUGu8oIZf5JG github.com/ssvlabs/ssv v1.2.1-0.20250422001600-57842541ad25/go.mod h1:dWtV013maPZ1QhqbilGPPBuYNm65+QK/mFB3xbY/Scs= github.com/ssvlabs/ssv v1.2.1-0.20250423234408-3aa5db24ccdb h1:huTuQ+20/Aa8w00OXu5B9W/+Umu6Of/xWAihxCMZvws= github.com/ssvlabs/ssv v1.2.1-0.20250423234408-3aa5db24ccdb/go.mod h1:CJ1M0F7auIXCdL6R5yZtdVt391VoMosF3wmFtiuHiOg= +github.com/ssvlabs/ssv v1.2.1-0.20250425092056-def906be9a56 h1:m+G44jhSDRyOtAUU7VhxEWCuslKBuQgxVEbC1x8cdXA= +github.com/ssvlabs/ssv v1.2.1-0.20250425092056-def906be9a56/go.mod h1:qHNj7PT/qi1Eya4c3c92C2gk38DvM8Ih2HOv3QleGp8= github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo8= github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= From 04b36a6cbdbb702748242b067c443d19f99e81aa Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Mon, 12 May 2025 14:00:49 -0300 Subject: [PATCH 17/34] fix issues after merging --- message/validation/common_checks.go | 2 +- message/validation/validation.go | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/message/validation/common_checks.go b/message/validation/common_checks.go index 328367675f..a35af807bd 100644 --- a/message/validation/common_checks.go +++ b/message/validation/common_checks.go @@ -40,7 +40,7 @@ func (mv *messageValidator) messageLateness(slot phase0.Slot, role spectypes.Run case spectypes.RoleProposer, spectypes.RoleSyncCommitteeContribution: ttl = 1 + LateSlotAllowance case spectypes.RoleCommittee, spectypes.RoleAggregator: - ttl = MaxStoredSlots(mv.netCfg) + ttl = mv.maxStoredSlots() case spectypes.RoleValidatorRegistration, spectypes.RoleVoluntaryExit: return 0 } diff --git a/message/validation/validation.go b/message/validation/validation.go index 2e30703418..6e528295c7 100644 --- a/message/validation/validation.go +++ b/message/validation/validation.go @@ -82,14 +82,10 @@ func New( pectraForkEpoch phase0.Epoch, opts ...Option, ) MessageValidator { - ttl := time.Duration(MaxStoredSlots(netCfg)) * netCfg.SlotDurationSec() // #nosec G115 -- amount of slots cannot exceed int64 - mv := &messageValidator{ logger: zap.NewNop(), netCfg: netCfg, - state: ttlcache.New( - ttlcache.WithTTL[spectypes.MessageID, *ValidatorState](ttl), - ), + validationLockCache: ttlcache.New[spectypes.MessageID, *sync.Mutex](), validatorStore: validatorStore, operators: operators, @@ -98,6 +94,11 @@ func New( pectraForkEpoch: pectraForkEpoch, } + ttl := time.Duration(mv.maxStoredSlots()) * netCfg.GetSlotDuration() // #nosec G115 -- amount of slots cannot exceed int64 + mv.state = ttlcache.New( + ttlcache.WithTTL[spectypes.MessageID, *ValidatorState](ttl), + ) + for _, opt := range opts { opt(mv) } @@ -307,14 +308,14 @@ func (mv *messageValidator) validatorState(messageID spectypes.MessageID, commit cs := &ValidatorState{ operators: make([]*OperatorState, len(committee)), - storedSlotCount: MaxStoredSlots(mv.netCfg), + storedSlotCount: mv.maxStoredSlots(), } mv.state.Set(messageID, cs, ttlcache.DefaultTTL) return cs } -// MaxStoredSlots stores max amount of slots message validation stores. +// maxStoredSlots stores max amount of slots message validation stores. // It's exported to allow usage outside of message validation -func MaxStoredSlots(netCfg networkconfig.NetworkConfig) phase0.Slot { - return phase0.Slot(netCfg.GetSlotsPerEpoch()) + LateSlotAllowance +func (mv *messageValidator) maxStoredSlots() phase0.Slot { + return mv.netCfg.GetSlotsPerEpoch() + LateSlotAllowance } From ffd78bf65257ce3ac996d74a620de2799a954e85 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 20 May 2025 18:27:43 -0300 Subject: [PATCH 18/34] format/imports --- beacon/goclient/goclient.go | 7 +++---- protocol/v2/blockchain/beacon/client.go | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/beacon/goclient/goclient.go b/beacon/goclient/goclient.go index 6c211aa54e..ba5cda4381 100644 --- a/beacon/goclient/goclient.go +++ b/beacon/goclient/goclient.go @@ -19,7 +19,6 @@ import ( "github.com/jellydator/ttlcache/v3" "github.com/pkg/errors" "github.com/rs/zerolog" - specssv "github.com/ssvlabs/ssv-spec/ssv" "go.uber.org/zap" "tailscale.com/util/singleflight" @@ -120,10 +119,10 @@ const ( // GoClient implementing Beacon struct type GoClient struct { - log *zap.Logger + log *zap.Logger beaconConfig networkconfig.BeaconConfig - clients []Client - multiClient MultiClient + clients []Client + multiClient MultiClient syncDistanceTolerance phase0.Slot nodeSyncingFn func(ctx context.Context, opts *api.NodeSyncingOpts) (*api.Response[*apiv1.SyncState], error) diff --git a/protocol/v2/blockchain/beacon/client.go b/protocol/v2/blockchain/beacon/client.go index 428071a60e..05c894898a 100644 --- a/protocol/v2/blockchain/beacon/client.go +++ b/protocol/v2/blockchain/beacon/client.go @@ -11,7 +11,6 @@ import ( "github.com/attestantio/go-eth2-client/spec/bellatrix" "github.com/attestantio/go-eth2-client/spec/phase0" ssz "github.com/ferranbt/fastssz" - "github.com/ssvlabs/ssv-spec/types" "github.com/ssvlabs/ssv/networkconfig" ) From 46eb61c07f0110aaefca1fa85746dbb313f30ff5 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 20 May 2025 18:29:58 -0300 Subject: [PATCH 19/34] revert preparationSlots type change --- operator/duties/sync_committee.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/operator/duties/sync_committee.go b/operator/duties/sync_committee.go index 9810863d41..be0b06d7a8 100644 --- a/operator/duties/sync_committee.go +++ b/operator/duties/sync_committee.go @@ -25,7 +25,7 @@ type SyncCommitteeHandler struct { // preparationSlots is the number of slots ahead of the sync committee // period change at which to prepare the relevant duties. - preparationSlots phase0.Slot + preparationSlots uint64 } func NewSyncCommitteeHandler(duties *dutystore.SyncCommitteeDuties) *SyncCommitteeHandler { @@ -66,7 +66,7 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { // Prepare relevant duties 1.5 epochs (48 slots) ahead of the sync committee period change. // The 1.5 epochs timing helps ensure setup occurs when the beacon node is likely less busy. - h.preparationSlots = h.beaconConfig.GetSlotsPerEpoch() * 3 / 2 + h.preparationSlots = uint64(h.beaconConfig.GetSlotsPerEpoch()) * 3 / 2 if h.shouldFetchNextPeriod(h.beaconConfig.EstimatedCurrentSlot()) { h.fetchNextPeriod = true @@ -93,7 +93,7 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { // if we have reached the preparation slots -1, prepare the next period duties in the next slot. periodSlots := h.slotsPerPeriod() - if slot%periodSlots == periodSlots-h.preparationSlots-1 { + if uint64(slot)%periodSlots == periodSlots-h.preparationSlots-1 { h.fetchNextPeriod = true } @@ -320,9 +320,9 @@ func calculateSubscriptions(endEpoch phase0.Epoch, duties []*eth2apiv1.SyncCommi func (h *SyncCommitteeHandler) shouldFetchNextPeriod(slot phase0.Slot) bool { periodSlots := h.slotsPerPeriod() - return slot%periodSlots > periodSlots-h.preparationSlots-2 + return uint64(slot)%periodSlots > periodSlots-h.preparationSlots-2 } -func (h *SyncCommitteeHandler) slotsPerPeriod() phase0.Slot { - return phase0.Slot(h.beaconConfig.EpochsPerSyncCommitteePeriod()) * h.beaconConfig.GetSlotsPerEpoch() +func (h *SyncCommitteeHandler) slotsPerPeriod() uint64 { + return uint64(phase0.Slot(h.beaconConfig.EpochsPerSyncCommitteePeriod()) * h.beaconConfig.GetSlotsPerEpoch()) } From 6adb4d5192ffdc36b5165b83cc9465a030627787 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 20 May 2025 20:39:07 -0300 Subject: [PATCH 20/34] use uint64 for amount of slots and epochs --- beacon/goclient/goclient.go | 2 +- beacon/goclient/validator.go | 4 +- doppelganger/doppelganger.go | 2 +- message/validation/common_checks.go | 10 ++--- message/validation/consensus_state.go | 4 +- message/validation/consensus_state_test.go | 43 +++++++++---------- message/validation/const.go | 4 +- message/validation/validation.go | 2 +- networkconfig/beacon.go | 22 +++++----- networkconfig/beacon_mock.go | 8 ++-- networkconfig/holesky-e2e.go | 3 +- networkconfig/holesky-stage.go | 3 +- networkconfig/holesky.go | 3 +- networkconfig/hoodi-stage.go | 3 +- networkconfig/hoodi.go | 3 +- networkconfig/local-testnet.go | 3 +- networkconfig/mainnet.go | 3 +- networkconfig/network_mock.go | 8 ++-- networkconfig/sepolia.go | 3 +- networkconfig/test-network.go | 3 +- operator/duties/attester.go | 8 ++-- operator/duties/committee.go | 2 +- operator/duties/committee_test.go | 6 +-- operator/duties/proposer.go | 2 +- operator/duties/scheduler_test.go | 8 ++-- operator/duties/sync_committee.go | 4 +- operator/duties/sync_committee_test.go | 6 +-- operator/duties/validatorregistration.go | 2 +- operator/duties/voluntary_exit.go | 2 +- operator/fee_recipient/controller.go | 2 +- operator/fee_recipient/controller_test.go | 10 ++--- .../ssv/validator/non_committee_validator.go | 2 +- utils/testutils.go | 4 +- 33 files changed, 91 insertions(+), 103 deletions(-) diff --git a/beacon/goclient/goclient.go b/beacon/goclient/goclient.go index ba5cda4381..8266732a23 100644 --- a/beacon/goclient/goclient.go +++ b/beacon/goclient/goclient.go @@ -208,7 +208,7 @@ func New( ttlcache.WithTTL[phase0.Slot, *phase0.AttestationData](2 * opt.BeaconConfig.SlotDuration), ), blockRootToSlotCache: ttlcache.New(ttlcache.WithCapacity[phase0.Root, phase0.Slot]( - uint64(opt.BeaconConfig.SlotsPerEpoch) * BlockRootToSlotCacheCapacityEpochs), + opt.BeaconConfig.SlotsPerEpoch * BlockRootToSlotCacheCapacityEpochs), ), commonTimeout: commonTimeout, longTimeout: longTimeout, diff --git a/beacon/goclient/validator.go b/beacon/goclient/validator.go index 08356449af..9d4dab04f8 100644 --- a/beacon/goclient/validator.go +++ b/beacon/goclient/validator.go @@ -103,9 +103,9 @@ func (gc *GoClient) registrationSubmitter(ctx context.Context, slotTickerProvide } // Distribute the registrations evenly across the epoch based on the pubkeys. - slotInEpoch := currentSlot % gc.beaconConfig.SlotsPerEpoch + slotInEpoch := uint64(currentSlot) % gc.beaconConfig.SlotsPerEpoch validatorDescriptor := xxhash.Sum64(validatorPk[:]) - shouldSubmit := phase0.Slot(validatorDescriptor)%gc.beaconConfig.SlotsPerEpoch == slotInEpoch + shouldSubmit := validatorDescriptor%gc.beaconConfig.SlotsPerEpoch == slotInEpoch if r.new || shouldSubmit { r.new = false diff --git a/doppelganger/doppelganger.go b/doppelganger/doppelganger.go index e845ad19c4..d9ebab9654 100644 --- a/doppelganger/doppelganger.go +++ b/doppelganger/doppelganger.go @@ -196,7 +196,7 @@ func (h *handler) Start(ctx context.Context) error { // Perform liveness checks during the first run or at the last slot of the epoch. // This ensures that the beacon node has had enough time to observe blocks and attestations, // preventing delays in marking a validator as safe. - if (!firstRun && currentSlot%slotsPerEpoch != slotsPerEpoch-1) || startEpoch == currentEpoch { + if (!firstRun && uint64(currentSlot)%slotsPerEpoch != slotsPerEpoch-1) || startEpoch == currentEpoch { continue } diff --git a/message/validation/common_checks.go b/message/validation/common_checks.go index a35af807bd..cc1c63929b 100644 --- a/message/validation/common_checks.go +++ b/message/validation/common_checks.go @@ -35,7 +35,7 @@ func (mv *messageValidator) messageEarliness(slot phase0.Slot, receivedAt time.T // messageLateness returns how late message is or 0 if it's not func (mv *messageValidator) messageLateness(slot phase0.Slot, role spectypes.RunnerRole, receivedAt time.Time) time.Duration { - var ttl phase0.Slot + var ttl uint64 switch role { case spectypes.RoleProposer, spectypes.RoleSyncCommitteeContribution: ttl = 1 + LateSlotAllowance @@ -45,7 +45,7 @@ func (mv *messageValidator) messageLateness(slot phase0.Slot, role spectypes.Run return 0 } - deadline := mv.netCfg.GetSlotStartTime(slot + ttl). + deadline := mv.netCfg.GetSlotStartTime(slot + phase0.Slot(ttl)). Add(lateMessageMargin) return receivedAt.Sub(deadline) @@ -95,18 +95,18 @@ func (mv *messageValidator) dutyLimit(msgID spectypes.MessageID, slot phase0.Slo // Skip duty search if validators * 2 exceeds slots per epoch, // as the maximum duties per epoch is capped at the number of slots. // This avoids unnecessary checks. - if validatorIndexCount < uint64(slotsPerEpoch)/2 { + if validatorIndexCount < slotsPerEpoch/2 { // Check if there is at least one validator in the sync committee. // If so, the duty limit is equal to the number of slots per epoch. period := mv.netCfg.EstimatedSyncCommitteePeriodAtEpoch(mv.netCfg.EstimatedEpochAtSlot(slot)) for _, i := range validatorIndices { if mv.dutyStore.SyncCommittee.Duty(period, i) != nil { - return uint64(slotsPerEpoch), true + return slotsPerEpoch, true } } } - return min(uint64(slotsPerEpoch), 2*validatorIndexCount), true + return min(slotsPerEpoch, 2*validatorIndexCount), true default: return 0, false diff --git a/message/validation/consensus_state.go b/message/validation/consensus_state.go index a3adb606e6..5079221ff8 100644 --- a/message/validation/consensus_state.go +++ b/message/validation/consensus_state.go @@ -7,7 +7,7 @@ import ( // ValidatorState keeps track of the signers for a given public key and role. type ValidatorState struct { operators []*OperatorState - storedSlotCount phase0.Slot + storedSlotCount uint64 } func (cs *ValidatorState) Signer(idx int) *OperatorState { @@ -26,7 +26,7 @@ type OperatorState struct { prevEpochDuties uint64 } -func newOperatorState(size phase0.Slot) *OperatorState { +func newOperatorState(size uint64) *OperatorState { return &OperatorState{ signers: make([]*SignerState, size), } diff --git a/message/validation/consensus_state_test.go b/message/validation/consensus_state_test.go index eb8faca0eb..80b9f7a22d 100644 --- a/message/validation/consensus_state_test.go +++ b/message/validation/consensus_state_test.go @@ -3,61 +3,60 @@ package validation import ( "testing" - "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/stretchr/testify/require" ) func TestOperatorState(t *testing.T) { t.Run("TestNewOperatorState", func(t *testing.T) { - size := phase0.Slot(10) + const size = 10 os := newOperatorState(size) require.NotNil(t, os) - require.Equal(t, len(os.signers), int(size)) + require.Equal(t, len(os.signers), size) }) t.Run("TestGetAndSet", func(t *testing.T) { - size := phase0.Slot(10) + const size = 10 os := newOperatorState(size) - slot := phase0.Slot(5) - epoch := phase0.Epoch(1) + const slot = 5 + const epoch = 1 signerState := &SignerState{Slot: slot} os.Set(slot, epoch, signerState) retrievedState := os.Get(slot) require.NotNil(t, retrievedState) - require.Equal(t, retrievedState.Slot, slot) + require.EqualValues(t, retrievedState.Slot, slot) }) t.Run("TestGetInvalidSlot", func(t *testing.T) { - size := phase0.Slot(10) + const size = 10 os := newOperatorState(size) - slot := phase0.Slot(5) + const slot = 5 retrievedState := os.Get(slot) require.Nil(t, retrievedState) }) t.Run("TestMaxSlot", func(t *testing.T) { - size := phase0.Slot(10) + const size = 10 os := newOperatorState(size) - slot := phase0.Slot(5) - epoch := phase0.Epoch(1) + const slot = 5 + const epoch = 1 signerState := &SignerState{Slot: slot} os.Set(slot, epoch, signerState) - require.Equal(t, os.MaxSlot(), slot) + require.EqualValues(t, os.MaxSlot(), slot) }) t.Run("TestDutyCount", func(t *testing.T) { - size := phase0.Slot(10) + const size = 10 os := newOperatorState(size) - slot := phase0.Slot(5) - epoch := phase0.Epoch(1) + const slot = 5 + const epoch = 1 signerState1 := &SignerState{Slot: slot} os.Set(slot, epoch, signerState1) @@ -65,8 +64,8 @@ func TestOperatorState(t *testing.T) { require.Equal(t, os.DutyCount(epoch), uint64(1)) require.Equal(t, os.DutyCount(epoch-1), uint64(0)) - slot2 := phase0.Slot(6) - epoch2 := phase0.Epoch(2) + const slot2 = 6 + const epoch2 = 2 signerState2 := &SignerState{Slot: slot2} os.Set(slot2, epoch2, signerState2) @@ -77,17 +76,17 @@ func TestOperatorState(t *testing.T) { }) t.Run("TestIncrementLastEpochDuties", func(t *testing.T) { - size := phase0.Slot(10) + const size = 10 os := newOperatorState(size) - slot := phase0.Slot(5) - epoch := phase0.Epoch(1) + const slot = 5 + const epoch = 1 signerState1 := &SignerState{Slot: slot} os.Set(slot, epoch, signerState1) require.Equal(t, os.DutyCount(epoch), uint64(1)) - slot2 := phase0.Slot(6) + const slot2 = 6 signerState2 := &SignerState{Slot: slot2} os.Set(slot2, epoch, signerState2) diff --git a/message/validation/const.go b/message/validation/const.go index a7ae4208f4..4efaee7d25 100644 --- a/message/validation/const.go +++ b/message/validation/const.go @@ -2,8 +2,6 @@ package validation import ( "time" - - "github.com/attestantio/go-eth2-client/spec/phase0" ) // To add some encoding overhead for ssz, we use (N + N/encodingOverheadDivisor + 4) for a structure with expected size N @@ -15,7 +13,7 @@ const ( clockErrorTolerance = time.Millisecond * 50 allowedRoundsInFuture = 1 allowedRoundsInPast = 2 - LateSlotAllowance = phase0.Slot(2) + LateSlotAllowance = 2 syncCommitteeSize = 512 rsaSignatureSize = 256 operatorIDSize = 8 // uint64 diff --git a/message/validation/validation.go b/message/validation/validation.go index 8f5ddc65cd..90968a5f7a 100644 --- a/message/validation/validation.go +++ b/message/validation/validation.go @@ -330,6 +330,6 @@ func (mv *messageValidator) validatorState(key peerIDWithMessageID, committee [] // maxStoredSlots stores max amount of slots message validation stores. // It's exported to allow usage outside of message validation -func (mv *messageValidator) maxStoredSlots() phase0.Slot { +func (mv *messageValidator) maxStoredSlots() uint64 { return mv.netCfg.GetSlotsPerEpoch() + LateSlotAllowance } diff --git a/networkconfig/beacon.go b/networkconfig/beacon.go index 91f54c903b..a520e70c2a 100644 --- a/networkconfig/beacon.go +++ b/networkconfig/beacon.go @@ -19,7 +19,7 @@ type Beacon interface { EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch IsFirstSlotOfEpoch(slot phase0.Slot) bool GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot - EpochsPerSyncCommitteePeriod() phase0.Epoch + EpochsPerSyncCommitteePeriod() uint64 EstimatedSyncCommitteePeriodAtEpoch(epoch phase0.Epoch) uint64 FirstEpochOfSyncPeriod(period uint64) phase0.Epoch LastSlotOfSyncPeriod(period uint64) phase0.Slot @@ -27,7 +27,7 @@ type Beacon interface { EpochStartTime(epoch phase0.Epoch) time.Time EstimatedTimeAtSlot(slot phase0.Slot) time.Time GetSlotDuration() time.Duration - GetSlotsPerEpoch() phase0.Slot + GetSlotsPerEpoch() uint64 GetGenesisTime() time.Time GetBeaconName() string } @@ -35,7 +35,7 @@ type Beacon interface { type BeaconConfig struct { BeaconName string SlotDuration time.Duration - SlotsPerEpoch phase0.Slot + SlotsPerEpoch uint64 ForkVersion phase0.Version GenesisTime time.Time } @@ -77,32 +77,32 @@ func (b BeaconConfig) EstimatedCurrentEpoch() phase0.Epoch { // EstimatedEpochAtSlot estimates epoch at the given slot func (b BeaconConfig) EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch { - return phase0.Epoch(slot / b.SlotsPerEpoch) + return phase0.Epoch(uint64(slot) / b.SlotsPerEpoch) } // IsFirstSlotOfEpoch estimates epoch at the given slot func (b BeaconConfig) IsFirstSlotOfEpoch(slot phase0.Slot) bool { - return slot%b.SlotsPerEpoch == 0 + return uint64(slot)%b.SlotsPerEpoch == 0 } // GetEpochFirstSlot returns the beacon node first slot in epoch func (b BeaconConfig) GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot { - return phase0.Slot(epoch) * b.SlotsPerEpoch + return phase0.Slot(uint64(epoch) * b.SlotsPerEpoch) } // EpochsPerSyncCommitteePeriod returns the number of epochs per sync committee period. -func (b BeaconConfig) EpochsPerSyncCommitteePeriod() phase0.Epoch { +func (b BeaconConfig) EpochsPerSyncCommitteePeriod() uint64 { return 256 } // EstimatedSyncCommitteePeriodAtEpoch estimates the current sync committee period at the given Epoch func (b BeaconConfig) EstimatedSyncCommitteePeriodAtEpoch(epoch phase0.Epoch) uint64 { - return uint64(epoch / b.EpochsPerSyncCommitteePeriod()) + return uint64(epoch) / b.EpochsPerSyncCommitteePeriod() } // FirstEpochOfSyncPeriod calculates the first epoch of the given sync period. func (b BeaconConfig) FirstEpochOfSyncPeriod(period uint64) phase0.Epoch { - return phase0.Epoch(period) * b.EpochsPerSyncCommitteePeriod() + return phase0.Epoch(period * b.EpochsPerSyncCommitteePeriod()) } // LastSlotOfSyncPeriod calculates the first epoch of the given sync period. @@ -114,7 +114,7 @@ func (b BeaconConfig) LastSlotOfSyncPeriod(period uint64) phase0.Slot { } func (b BeaconConfig) FirstSlotAtEpoch(epoch phase0.Epoch) phase0.Slot { - return phase0.Slot(epoch) * b.SlotsPerEpoch + return phase0.Slot(uint64(epoch) * b.SlotsPerEpoch) } func (b BeaconConfig) EpochStartTime(epoch phase0.Epoch) time.Time { @@ -135,7 +135,7 @@ func (b BeaconConfig) GetSlotDuration() time.Duration { return b.SlotDuration } -func (b BeaconConfig) GetSlotsPerEpoch() phase0.Slot { +func (b BeaconConfig) GetSlotsPerEpoch() uint64 { return b.SlotsPerEpoch } diff --git a/networkconfig/beacon_mock.go b/networkconfig/beacon_mock.go index c89a5e8a35..fb9ea9c819 100644 --- a/networkconfig/beacon_mock.go +++ b/networkconfig/beacon_mock.go @@ -56,10 +56,10 @@ func (mr *MockBeaconMockRecorder) EpochStartTime(epoch any) *gomock.Call { } // EpochsPerSyncCommitteePeriod mocks base method. -func (m *MockBeacon) EpochsPerSyncCommitteePeriod() phase0.Epoch { +func (m *MockBeacon) EpochsPerSyncCommitteePeriod() uint64 { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EpochsPerSyncCommitteePeriod") - ret0, _ := ret[0].(phase0.Epoch) + ret0, _ := ret[0].(uint64) return ret0 } @@ -266,10 +266,10 @@ func (mr *MockBeaconMockRecorder) GetSlotStartTime(slot any) *gomock.Call { } // GetSlotsPerEpoch mocks base method. -func (m *MockBeacon) GetSlotsPerEpoch() phase0.Slot { +func (m *MockBeacon) GetSlotsPerEpoch() uint64 { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSlotsPerEpoch") - ret0, _ := ret[0].(phase0.Slot) + ret0, _ := ret[0].(uint64) return ret0 } diff --git a/networkconfig/holesky-e2e.go b/networkconfig/holesky-e2e.go index d005809910..f464cc13cc 100644 --- a/networkconfig/holesky-e2e.go +++ b/networkconfig/holesky-e2e.go @@ -4,7 +4,6 @@ import ( "math/big" "time" - "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -13,7 +12,7 @@ var HoleskyE2E = NetworkConfig{ BeaconConfig: BeaconConfig{ BeaconName: string(spectypes.HoleskyNetwork), SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), - SlotsPerEpoch: phase0.Slot(spectypes.HoleskyNetwork.SlotsPerEpoch()), + SlotsPerEpoch: spectypes.HoleskyNetwork.SlotsPerEpoch(), ForkVersion: spectypes.HoleskyNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, diff --git a/networkconfig/holesky-stage.go b/networkconfig/holesky-stage.go index 153c51265a..97aa69c291 100644 --- a/networkconfig/holesky-stage.go +++ b/networkconfig/holesky-stage.go @@ -4,7 +4,6 @@ import ( "math/big" "time" - "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -13,7 +12,7 @@ var HoleskyStage = NetworkConfig{ BeaconConfig: BeaconConfig{ BeaconName: string(spectypes.HoleskyNetwork), SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), - SlotsPerEpoch: phase0.Slot(spectypes.HoleskyNetwork.SlotsPerEpoch()), + SlotsPerEpoch: spectypes.HoleskyNetwork.SlotsPerEpoch(), ForkVersion: spectypes.HoleskyNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, diff --git a/networkconfig/holesky.go b/networkconfig/holesky.go index 77300907a1..4629c7ce34 100644 --- a/networkconfig/holesky.go +++ b/networkconfig/holesky.go @@ -4,7 +4,6 @@ import ( "math/big" "time" - "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -13,7 +12,7 @@ var Holesky = NetworkConfig{ BeaconConfig: BeaconConfig{ BeaconName: string(spectypes.HoleskyNetwork), SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), - SlotsPerEpoch: phase0.Slot(spectypes.HoleskyNetwork.SlotsPerEpoch()), + SlotsPerEpoch: spectypes.HoleskyNetwork.SlotsPerEpoch(), ForkVersion: spectypes.HoleskyNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, diff --git a/networkconfig/hoodi-stage.go b/networkconfig/hoodi-stage.go index d07daa5671..e28511f599 100644 --- a/networkconfig/hoodi-stage.go +++ b/networkconfig/hoodi-stage.go @@ -4,7 +4,6 @@ import ( "math/big" "time" - "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -13,7 +12,7 @@ var HoodiStage = NetworkConfig{ BeaconConfig: BeaconConfig{ BeaconName: string(spectypes.HoodiNetwork), SlotDuration: spectypes.HoodiNetwork.SlotDurationSec(), - SlotsPerEpoch: phase0.Slot(spectypes.HoodiNetwork.SlotsPerEpoch()), + SlotsPerEpoch: spectypes.HoodiNetwork.SlotsPerEpoch(), ForkVersion: spectypes.HoodiNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.HoodiNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, diff --git a/networkconfig/hoodi.go b/networkconfig/hoodi.go index 551d030301..03799d694b 100644 --- a/networkconfig/hoodi.go +++ b/networkconfig/hoodi.go @@ -4,7 +4,6 @@ import ( "math/big" "time" - "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -13,7 +12,7 @@ var Hoodi = NetworkConfig{ BeaconConfig: BeaconConfig{ BeaconName: string(spectypes.HoodiNetwork), SlotDuration: spectypes.HoodiNetwork.SlotDurationSec(), - SlotsPerEpoch: phase0.Slot(spectypes.HoodiNetwork.SlotsPerEpoch()), + SlotsPerEpoch: spectypes.HoodiNetwork.SlotsPerEpoch(), ForkVersion: spectypes.HoodiNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.HoodiNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, diff --git a/networkconfig/local-testnet.go b/networkconfig/local-testnet.go index 7c96e2c4f8..bd94686743 100644 --- a/networkconfig/local-testnet.go +++ b/networkconfig/local-testnet.go @@ -3,7 +3,6 @@ package networkconfig import ( "time" - "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -12,7 +11,7 @@ var LocalTestnet = NetworkConfig{ BeaconConfig: BeaconConfig{ BeaconName: string(spectypes.PraterNetwork), SlotDuration: spectypes.PraterNetwork.SlotDurationSec(), - SlotsPerEpoch: phase0.Slot(spectypes.PraterNetwork.SlotsPerEpoch()), + SlotsPerEpoch: spectypes.PraterNetwork.SlotsPerEpoch(), ForkVersion: spectypes.PraterNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.PraterNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, diff --git a/networkconfig/mainnet.go b/networkconfig/mainnet.go index 56bdeb0b73..d82490ce27 100644 --- a/networkconfig/mainnet.go +++ b/networkconfig/mainnet.go @@ -4,7 +4,6 @@ import ( "math/big" "time" - "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -13,7 +12,7 @@ var Mainnet = NetworkConfig{ BeaconConfig: BeaconConfig{ BeaconName: string(spectypes.MainNetwork), SlotDuration: spectypes.MainNetwork.SlotDurationSec(), - SlotsPerEpoch: phase0.Slot(spectypes.MainNetwork.SlotsPerEpoch()), + SlotsPerEpoch: spectypes.MainNetwork.SlotsPerEpoch(), ForkVersion: spectypes.MainNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.MainNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, diff --git a/networkconfig/network_mock.go b/networkconfig/network_mock.go index a3e3c24103..425399874d 100644 --- a/networkconfig/network_mock.go +++ b/networkconfig/network_mock.go @@ -57,10 +57,10 @@ func (mr *MockNetworkMockRecorder) EpochStartTime(epoch any) *gomock.Call { } // EpochsPerSyncCommitteePeriod mocks base method. -func (m *MockNetwork) EpochsPerSyncCommitteePeriod() phase0.Epoch { +func (m *MockNetwork) EpochsPerSyncCommitteePeriod() uint64 { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EpochsPerSyncCommitteePeriod") - ret0, _ := ret[0].(phase0.Epoch) + ret0, _ := ret[0].(uint64) return ret0 } @@ -281,10 +281,10 @@ func (mr *MockNetworkMockRecorder) GetSlotStartTime(slot any) *gomock.Call { } // GetSlotsPerEpoch mocks base method. -func (m *MockNetwork) GetSlotsPerEpoch() phase0.Slot { +func (m *MockNetwork) GetSlotsPerEpoch() uint64 { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetSlotsPerEpoch") - ret0, _ := ret[0].(phase0.Slot) + ret0, _ := ret[0].(uint64) return ret0 } diff --git a/networkconfig/sepolia.go b/networkconfig/sepolia.go index 5359d1059d..49c0066177 100644 --- a/networkconfig/sepolia.go +++ b/networkconfig/sepolia.go @@ -4,7 +4,6 @@ import ( "math/big" "time" - "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -13,7 +12,7 @@ var Sepolia = NetworkConfig{ BeaconConfig: BeaconConfig{ BeaconName: string(spectypes.SepoliaNetwork), SlotDuration: spectypes.SepoliaNetwork.SlotDurationSec(), - SlotsPerEpoch: phase0.Slot(spectypes.SepoliaNetwork.SlotsPerEpoch()), + SlotsPerEpoch: spectypes.SepoliaNetwork.SlotsPerEpoch(), ForkVersion: spectypes.SepoliaNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.SepoliaNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, diff --git a/networkconfig/test-network.go b/networkconfig/test-network.go index 9bda6da4b0..9a3ee5ceff 100644 --- a/networkconfig/test-network.go +++ b/networkconfig/test-network.go @@ -4,7 +4,6 @@ import ( "math/big" "time" - "github.com/attestantio/go-eth2-client/spec/phase0" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -13,7 +12,7 @@ var TestNetwork = NetworkConfig{ BeaconConfig: BeaconConfig{ BeaconName: string(spectypes.BeaconTestNetwork), SlotDuration: spectypes.BeaconTestNetwork.SlotDurationSec(), - SlotsPerEpoch: phase0.Slot(spectypes.BeaconTestNetwork.SlotsPerEpoch()), + SlotsPerEpoch: spectypes.BeaconTestNetwork.SlotsPerEpoch(), ForkVersion: spectypes.BeaconTestNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.BeaconTestNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, diff --git a/operator/duties/attester.go b/operator/duties/attester.go index 3e2eff745e..25012f376b 100644 --- a/operator/duties/attester.go +++ b/operator/duties/attester.go @@ -86,12 +86,12 @@ func (h *AttesterHandler) HandleDuties(ctx context.Context) { // If we have reached the mid-point of the epoch, fetch the duties for the next epoch in the next slot. // This allows us to set them up at a time when the beacon node should be less busy. - if slot%slotsPerEpoch == slotsPerEpoch/2-1 { + if uint64(slot)%slotsPerEpoch == slotsPerEpoch/2-1 { h.fetchNextEpoch = true } // last slot of epoch - if slot%slotsPerEpoch == slotsPerEpoch-1 { + if uint64(slot)%slotsPerEpoch == slotsPerEpoch-1 { h.duties.ResetEpoch(currentEpoch - 1) } @@ -276,7 +276,7 @@ func (h *AttesterHandler) shouldExecute(duty *eth2apiv1.AttesterDuty) bool { // execute task if slot already began and not pass 1 epoch var attestationPropagationSlotRange = h.beaconConfig.GetSlotsPerEpoch() - if currentSlot >= duty.Slot && currentSlot-duty.Slot <= attestationPropagationSlotRange { + if currentSlot >= duty.Slot && uint64(currentSlot-duty.Slot) <= attestationPropagationSlotRange { return true } if currentSlot+1 == duty.Slot { @@ -313,5 +313,5 @@ func toBeaconCommitteeSubscription(duty *eth2apiv1.AttesterDuty, role spectypes. func (h *AttesterHandler) shouldFetchNexEpoch(slot phase0.Slot) bool { slotsPerEpoch := h.beaconConfig.GetSlotsPerEpoch() - return slot%slotsPerEpoch > slotsPerEpoch/2-2 + return uint64(slot)%slotsPerEpoch > slotsPerEpoch/2-2 } diff --git a/operator/duties/committee.go b/operator/duties/committee.go index 5b216c1713..d4bf5ab043 100644 --- a/operator/duties/committee.go +++ b/operator/duties/committee.go @@ -190,7 +190,7 @@ func (h *CommitteeHandler) shouldExecuteAtt(duty *eth2apiv1.AttesterDuty, epoch // execute task if slot already began and not pass 1 epoch var attestationPropagationSlotRange = h.beaconConfig.GetSlotsPerEpoch() - if currentSlot >= duty.Slot && currentSlot-duty.Slot <= attestationPropagationSlotRange { + if currentSlot >= duty.Slot && uint64(currentSlot-duty.Slot) <= attestationPropagationSlotRange { return true } if currentSlot+1 == duty.Slot { diff --git a/operator/duties/committee_test.go b/operator/duties/committee_test.go index 92a74d1596..537bdc14e0 100644 --- a/operator/duties/committee_test.go +++ b/operator/duties/committee_test.go @@ -30,19 +30,19 @@ func setupCommitteeDutiesMock( s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedSyncCommitteePeriodAtEpoch(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) uint64 { - return uint64(epoch / s.beaconConfig.EpochsPerSyncCommitteePeriod()) + return uint64(epoch) / s.beaconConfig.EpochsPerSyncCommitteePeriod() }, ).AnyTimes() s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().FirstEpochOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Epoch { - return phase0.Epoch(period) * s.beaconConfig.EpochsPerSyncCommitteePeriod() + return phase0.Epoch(period * s.beaconConfig.EpochsPerSyncCommitteePeriod()) }, ).AnyTimes() s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetEpochFirstSlot(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) phase0.Slot { - return phase0.Slot(epoch) * s.beaconConfig.GetSlotsPerEpoch() + return phase0.Slot(uint64(epoch) * s.beaconConfig.GetSlotsPerEpoch()) }, ).AnyTimes() diff --git a/operator/duties/proposer.go b/operator/duties/proposer.go index 80d20cbf79..71af520802 100644 --- a/operator/duties/proposer.go +++ b/operator/duties/proposer.go @@ -83,7 +83,7 @@ func (h *ProposerHandler) HandleDuties(ctx context.Context) { cancel() // last slot of epoch - if slot%h.beaconConfig.GetSlotsPerEpoch() == h.beaconConfig.GetSlotsPerEpoch()-1 { + if uint64(slot)%h.beaconConfig.GetSlotsPerEpoch() == h.beaconConfig.GetSlotsPerEpoch()-1 { h.duties.ResetEpoch(currentEpoch - 1) h.fetchFirst = true } diff --git a/operator/duties/scheduler_test.go b/operator/duties/scheduler_test.go index 424195715e..faa34c6492 100644 --- a/operator/duties/scheduler_test.go +++ b/operator/duties/scheduler_test.go @@ -110,7 +110,7 @@ func setupSchedulerAndMocks(t *testing.T, handlers []dutyHandler, currentSlot *S mockBeaconNode.EXPECT().SubscribeToHeadEvents(ctx, "duty_scheduler", gomock.Any()).Return(nil) s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetSlotDuration().Return(150 * time.Millisecond).AnyTimes() - s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetSlotsPerEpoch().Return(phase0.Slot(32)).AnyTimes() + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetSlotsPerEpoch().Return(uint64(32)).AnyTimes() s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetSlotStartTime(gomock.Any()).DoAndReturn( func(slot phase0.Slot) time.Time { return time.Now() @@ -118,7 +118,7 @@ func setupSchedulerAndMocks(t *testing.T, handlers []dutyHandler, currentSlot *S ).AnyTimes() s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedEpochAtSlot(gomock.Any()).DoAndReturn( func(slot phase0.Slot) phase0.Epoch { - return phase0.Epoch(slot / s.beaconConfig.GetSlotsPerEpoch()) + return phase0.Epoch(uint64(slot) / s.beaconConfig.GetSlotsPerEpoch()) }, ).AnyTimes() @@ -130,11 +130,11 @@ func setupSchedulerAndMocks(t *testing.T, handlers []dutyHandler, currentSlot *S s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedCurrentEpoch().DoAndReturn( func() phase0.Epoch { - return phase0.Epoch(currentSlot.Get() / s.beaconConfig.GetSlotsPerEpoch()) + return phase0.Epoch(uint64(currentSlot.Get()) / s.beaconConfig.GetSlotsPerEpoch()) }, ).AnyTimes() - s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EpochsPerSyncCommitteePeriod().Return(phase0.Epoch(256)).AnyTimes() + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EpochsPerSyncCommitteePeriod().Return(uint64(256)).AnyTimes() // Create a pool to wait for the scheduler to finish. schedulerPool := pool.New().WithErrors().WithContext(ctx) diff --git a/operator/duties/sync_committee.go b/operator/duties/sync_committee.go index be0b06d7a8..ec84d80c52 100644 --- a/operator/duties/sync_committee.go +++ b/operator/duties/sync_committee.go @@ -66,7 +66,7 @@ func (h *SyncCommitteeHandler) HandleDuties(ctx context.Context) { // Prepare relevant duties 1.5 epochs (48 slots) ahead of the sync committee period change. // The 1.5 epochs timing helps ensure setup occurs when the beacon node is likely less busy. - h.preparationSlots = uint64(h.beaconConfig.GetSlotsPerEpoch()) * 3 / 2 + h.preparationSlots = h.beaconConfig.GetSlotsPerEpoch() * 3 / 2 if h.shouldFetchNextPeriod(h.beaconConfig.EstimatedCurrentSlot()) { h.fetchNextPeriod = true @@ -324,5 +324,5 @@ func (h *SyncCommitteeHandler) shouldFetchNextPeriod(slot phase0.Slot) bool { } func (h *SyncCommitteeHandler) slotsPerPeriod() uint64 { - return uint64(phase0.Slot(h.beaconConfig.EpochsPerSyncCommitteePeriod()) * h.beaconConfig.GetSlotsPerEpoch()) + return h.beaconConfig.EpochsPerSyncCommitteePeriod() * h.beaconConfig.GetSlotsPerEpoch() } diff --git a/operator/duties/sync_committee_test.go b/operator/duties/sync_committee_test.go index a333401819..2cae5238fe 100644 --- a/operator/duties/sync_committee_test.go +++ b/operator/duties/sync_committee_test.go @@ -29,13 +29,13 @@ func setupSyncCommitteeDutiesMock( s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedSyncCommitteePeriodAtEpoch(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) uint64 { - return uint64(epoch / s.beaconConfig.EpochsPerSyncCommitteePeriod()) + return uint64(epoch) / s.beaconConfig.EpochsPerSyncCommitteePeriod() }, ).AnyTimes() s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().FirstEpochOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Epoch { - return phase0.Epoch(period) * s.beaconConfig.EpochsPerSyncCommitteePeriod() + return phase0.Epoch(period * s.beaconConfig.EpochsPerSyncCommitteePeriod()) }, ).AnyTimes() @@ -50,7 +50,7 @@ func setupSyncCommitteeDutiesMock( s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetEpochFirstSlot(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) phase0.Slot { - return phase0.Slot(epoch) * s.beaconConfig.GetSlotsPerEpoch() + return phase0.Slot(uint64(epoch) * s.beaconConfig.GetSlotsPerEpoch()) }, ).AnyTimes() diff --git a/operator/duties/validatorregistration.go b/operator/duties/validatorregistration.go index 4037263e87..cbfc301902 100644 --- a/operator/duties/validatorregistration.go +++ b/operator/duties/validatorregistration.go @@ -58,7 +58,7 @@ func (h *ValidatorRegistrationHandler) HandleDuties(ctx context.Context) { // Only attesting validators are eligible for registration duties. continue } - if phase0.Slot(share.ValidatorIndex)%registrationSlots != slot%registrationSlots { + if uint64(share.ValidatorIndex)%registrationSlots != uint64(slot)%registrationSlots { continue } diff --git a/operator/duties/voluntary_exit.go b/operator/duties/voluntary_exit.go index e06597772b..e8041bd8f5 100644 --- a/operator/duties/voluntary_exit.go +++ b/operator/duties/voluntary_exit.go @@ -115,7 +115,7 @@ func (h *VoluntaryExitHandler) processExecution(ctx context.Context, slot phase0 } h.dutyQueue = pendingDuties - h.duties.RemoveSlot(slot - h.beaconConfig.GetSlotsPerEpoch()) + h.duties.RemoveSlot(slot - phase0.Slot(h.beaconConfig.GetSlotsPerEpoch())) if dutyCount := len(dutiesForExecution); dutyCount != 0 { h.dutiesExecutor.ExecuteDuties(ctx, dutiesForExecution) diff --git a/operator/fee_recipient/controller.go b/operator/fee_recipient/controller.go index 1bbc688cdc..a8a787959f 100644 --- a/operator/fee_recipient/controller.go +++ b/operator/fee_recipient/controller.go @@ -76,7 +76,7 @@ func (rc *recipientController) listenToTicker(ctx context.Context) { <-ticker.Next() slot := ticker.Slot() // submit if first time or if first slot in epoch - if firstTimeSubmitted && slot%rc.beaconConfig.SlotsPerEpoch != (rc.beaconConfig.SlotsPerEpoch/2) { + if firstTimeSubmitted && uint64(slot)%rc.beaconConfig.SlotsPerEpoch != (rc.beaconConfig.SlotsPerEpoch/2) { continue } firstTimeSubmitted = true diff --git a/operator/fee_recipient/controller_test.go b/operator/fee_recipient/controller_test.go index 889cceee15..d7cef406ed 100644 --- a/operator/fee_recipient/controller_test.go +++ b/operator/fee_recipient/controller_test.go @@ -80,11 +80,11 @@ func TestSubmitProposal(t *testing.T) { go frCtrl.Start(t.Context()) slots := []phase0.Slot{ - 1, // first time - 2, // should not call submit - 20, // should not call submit - beaconConfig.SlotsPerEpoch / 2, // halfway through epoch - 63, // should not call submit + 1, // first time + 2, // should not call submit + 20, // should not call submit + phase0.Slot(beaconConfig.SlotsPerEpoch / 2), // halfway through epoch + 63, // should not call submit } for _, s := range slots { diff --git a/protocol/v2/ssv/validator/non_committee_validator.go b/protocol/v2/ssv/validator/non_committee_validator.go index 42dff9703c..741b49b58d 100644 --- a/protocol/v2/ssv/validator/non_committee_validator.go +++ b/protocol/v2/ssv/validator/non_committee_validator.go @@ -405,7 +405,7 @@ func (ncv *CommitteeObserver) saveSyncCommRoots( func (ncv *CommitteeObserver) postConsensusContainerCapacity() int { // #nosec G115 -- slots per epoch must be low epoch not to cause overflow - return int(ncv.beaconConfig.GetSlotsPerEpoch()) + int(validation.LateSlotAllowance) + return int(ncv.beaconConfig.GetSlotsPerEpoch()) + validation.LateSlotAllowance } func constructAttestationData(vote *spectypes.BeaconVote, slot phase0.Slot, committeeIndex phase0.CommitteeIndex) *phase0.AttestationData { diff --git a/utils/testutils.go b/utils/testutils.go index 8eb07a4f3e..312d3e9c34 100644 --- a/utils/testutils.go +++ b/utils/testutils.go @@ -41,7 +41,7 @@ func SetupMockNetworkConfig(t *testing.T, domainType spectypes.DomainType, curre beaconNetwork := spectypes.HoleskyNetwork // it must be something known by ekm mockNetwork := networkconfig.NewMockNetwork(ctrl) - mockNetwork.EXPECT().GetSlotsPerEpoch().Return(phase0.Slot(beaconNetwork.SlotsPerEpoch())).AnyTimes() + mockNetwork.EXPECT().GetSlotsPerEpoch().Return(beaconNetwork.SlotsPerEpoch()).AnyTimes() mockNetwork.EXPECT().EstimatedCurrentSlot().DoAndReturn( func() phase0.Slot { return currentSlot.GetSlot() @@ -64,7 +64,7 @@ func SetupMockNetworkConfig(t *testing.T, domainType spectypes.DomainType, curre ).AnyTimes() mockNetwork.EXPECT().IsFirstSlotOfEpoch(gomock.Any()).DoAndReturn( func(slot phase0.Slot) bool { - return slot%mockNetwork.GetSlotsPerEpoch() == 0 + return uint64(slot)%mockNetwork.GetSlotsPerEpoch() == 0 }, ).AnyTimes() mockNetwork.EXPECT().GetSlotStartTime(gomock.Any()).DoAndReturn( From 7274f17e49255479299ea9ddb71d62e81542c6d5 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Mon, 26 May 2025 10:16:54 -0300 Subject: [PATCH 21/34] use github.com/ssvlabs/eth2-key-manager@v1.5.5 --- go.mod | 4 +--- go.sum | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index ee97acb567..d74ddc95b3 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( github.com/sanity-io/litter v1.5.6 github.com/sourcegraph/conc v0.3.0 github.com/spf13/cobra v1.8.1 - github.com/ssvlabs/eth2-key-manager v1.5.2 + github.com/ssvlabs/eth2-key-manager v1.5.5 github.com/ssvlabs/ssv-spec v1.1.3 github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250425092056-def906be9a56 github.com/status-im/keycard-go v0.2.0 @@ -268,6 +268,4 @@ replace github.com/google/flatbuffers => github.com/google/flatbuffers v1.11.0 replace github.com/dgraph-io/ristretto => github.com/dgraph-io/ristretto v0.1.1-0.20211108053508-297c39e6640f -replace github.com/ssvlabs/eth2-key-manager => github.com/ssvlabs/eth2-key-manager v1.5.4-0.20250321004656-079eb6f1f94f - replace github.com/attestantio/go-eth2-client => github.com/ssvlabs/go-eth2-client v0.6.31-0.20250417062221-9cd9b891d4d6 diff --git a/go.sum b/go.sum index f199467212..091645e499 100644 --- a/go.sum +++ b/go.sum @@ -750,16 +750,12 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= -github.com/ssvlabs/eth2-key-manager v1.5.4-0.20250321004656-079eb6f1f94f h1:b1+GWbY6rNsg1Yl5yzunIfrtMkkyqt4cRbBn+mdf484= -github.com/ssvlabs/eth2-key-manager v1.5.4-0.20250321004656-079eb6f1f94f/go.mod h1:yeUzAP+SBJXgeXPiGBrLeLuHIQCpeJZV7Jz3Fwzm/zk= +github.com/ssvlabs/eth2-key-manager v1.5.5 h1:AzwNowGvcmVpRCVHq10FVnpkVIUpoDo5YbJWNMnYA8Q= +github.com/ssvlabs/eth2-key-manager v1.5.5/go.mod h1:yeUzAP+SBJXgeXPiGBrLeLuHIQCpeJZV7Jz3Fwzm/zk= github.com/ssvlabs/go-eth2-client v0.6.31-0.20250417062221-9cd9b891d4d6 h1:26sqPsxh434N7emUfOcLJ9oPGnnsz8XOHzKRZVKu4LU= github.com/ssvlabs/go-eth2-client v0.6.31-0.20250417062221-9cd9b891d4d6/go.mod h1:fvULSL9WtNskkOB4i+Yyr6BKpNHXvmpGZj9969fCrfY= github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo8= github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250423234408-3aa5db24ccdb h1:israZhWrV2VLqzCC+Ex6AmtPOU3XC44qss+Ymq5fVLU= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250423234408-3aa5db24ccdb/go.mod h1:W5GpcIOHIMljFQCwRgEArJOfRIr4lMVKxm0IOuwn8bE= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250424103603-719a5867d010 h1:9jnKiOWtFEokR/wCbvUvsIqlGrJGGAZtMBlpuqV2b3Q= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250424103603-719a5867d010/go.mod h1:HkcbtVHpGBPnJjdWWd08Z3lv7l0VWejJU80yUUqY5Go= github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250425092056-def906be9a56 h1:zUgvDPwrYS3gUSORZHGZSSpTKRFZqwi/6ipjdb7NLsY= github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250425092056-def906be9a56/go.mod h1:asx2GF46/MDVdE1fY1aF96bY9rXOk/qU+tR53EQ+Nac= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= From b244241fb48615945c622f3637514d7764217b02 Mon Sep 17 00:00:00 2001 From: y0sher Date: Mon, 26 May 2025 18:47:04 +0300 Subject: [PATCH 22/34] spec-alignment --- scripts/spec-alignment/differ.config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/spec-alignment/differ.config.yaml b/scripts/spec-alignment/differ.config.yaml index de2a69931f..4ce7015ad9 100644 --- a/scripts/spec-alignment/differ.config.yaml +++ b/scripts/spec-alignment/differ.config.yaml @@ -1,4 +1,4 @@ -ApprovedChanges: ["115ccce93a478b9a", "c8f122c9fb83793e", "220aede0f8fa5a4a", "fb9cab4ffb28869a", "3ca2431a8d79bc3a", "ca49cf46baf0a367", "50e5bb7eda99594e", "870a3a66aeccd737","4e22a08543b079b","56ceb03cd44ff702","188adfe8914e04c1","2438f9c5b82b69a3","1a716ee3bdb3170","90b166f78390af18","68219b82a1d9d829","c4c4caa5d0938b85","dfe99ce1d27b6cb1","35f5dab1f128d193","9a3973b64d7e8932","f33f07301a770d03","3e9e0dddfad3b302","d4fef6512374c1f5","b49f54cb45787e4b","59b2375130aef5df","f094cd0460432170","8e51881e527dd603","a7d6d58d9fa06379","1d124224ca4d0fe3","39ea06bfd1477d2d","7e2550bab51f22b2","87ebd29bd49fc52f","ef39dd5223e0d080","fe14e7f0503ea188","6146023d4d5708a2","aebb8e4348b6d667","973a2e6704dbf3","fb4cac598a68c592","257c7eb81d6eb245","2a8e94fe037e13fd","5e7eb878de54eec6","960a9c64cd4ec93c","57dfd255520bd849","ec333ff8a708db69","1cc1ff39ad91ee69","5714652b88e2d44f","7a53b3b037c56325","8c02ef1964464c30","19a268910a20da3d","af6e01ed565029f3","318b5169ac4dabb6","372c6b332e8ba699","c0d8a364c0db855a","4287381be4fb1841","b1614afc1da7794f","c214975412f3fd7","8bbf7eba3fa0cf7e","8e4ec8debe331b36","7a671d8fcefc3793","e2b0e9c6454c1c08","6707ecfefa5fec21","d5a7389d730464f1","8dfae3b3223d2de0","a81c092c985de728","968df5082c727ed6","9e53c73ee60b1cc2","9d265e99dd31d4f5","a34619e078d2e42f","17e8cec4f0625d53","e913f373aa88f333","cfc1e05c372d88dc","e5de6901d78b8833","57c1885b43dd8d19","e8a49856a5edd893","22ea21d10a2f861c","954e4fce01631c4e","108b9575f7c1d4bc","1f8d076449068f64","5a7ad98296703f6","159536003eeddac8","8ca8f82e67ddd3dd","16ebe47404323cc1","48bfe5cf1e578b47","dd83182b693a7216","308d21d9830f7047","6dde03147e012b1a","730c3e5e59393b7d","5b44a4b425ecc397","df5debc50ec8babc","92a41554b2910bb8","c36c680554dde59f","447feaa5cdc1a010","fda90c61f44cb149","cdbb4930eced584c","274336ec1127e6c0","2a496f5b3ad542d2","6b395912dde33b0e","cac56ec14994216b","8850900b5d9bcc65","15e7706486c6359e","cc22f28953b787ea","3bad6ae11596a574","8f84422a240d889c","5b265432dfbbaac7","43794bf5953db193","7975821460ebe1e7","173c505e12aabb8f","47ee0d148148a56f","8cc38593ebe049b6","bda3aec7157b095a","248712911696a851","f4d9c910f1dbaef7","1a2146fcad37acb8","b0b146f9bdab64b6","edfd442b4d725fbb","122f053573538a32","d720d714a20833e1", "f9c984e71b685f9b","8c6b4fee5a4c13ce","c0a8d2019a2c30d5", "717bef26105c733f","2f70630c27062353","2f70337ba7566a69","dd607a44e1341e6b","5210501625ac3de5","f786bf475b5085aa","18a66ed6e613d9c1","e8943e7741f6843d","276a489bd5a00032","ba3bba59f10bf6b","3c50ce0c8089d871","89ee72f6c610ab84","c92b95a85da2cb11","927ea6aed3f98f20","9338904026a0ce37","9683cfa19dc544a3","4d3fa2b8dfcb5f5b", "f19e9a2b295bcfb3", "b10199b2de6f03b8", "1afc17e358f9ca79","4b58762c0b433442","d293ec1bc61bb707","3e88c3b49d093605","4890ff80c88cc41d","5227ff3a225dd20d","81a60407a3a0ba80","db2ad807eb66254a","d308bd7c553ccdcf","bdaf172971637cbe","6ade9202843071fe","2fe8e14083997744","19c9a5362d1e1d3a","5956f803d239f178","92c55a4548a8b760","9a95524213bccfff","2f51a7338b86c229","e96966a281d74505","3ee479b9cbbc3a1d","82b392ba39c6c594","b9d2404e5c570019","24f528d85fb021f2","fe9609a785305d81","b0934079dcd986cc","a9c520a19b26049","d19a9403fd732d94","74a928f5dcb2fdd9","cbbfdb5e68cdac80","10e39d2ceda91f34","f99a004cf6697875","8fa5e8ebf7d223ec","6c80c145ba705243","fbabbc90d0b4178a","ab0c7f24e551ca6","af38a11cb8682c75","b110cba51df9f8d2","c4ff2ed3d20dc419","9295a5bb10efcec7","ab56ea44a75f898a","ff51ef26ab53ba58","df3771e2589008f9","106e5689655bcfc6","f90e0fb6883bff93","667656095cec39ee","9a5597af260c748a","9168b9cfb0cb98c8","875393173d59b0f2","a347ee50e92f7334","91073f39440ab37f","1bbcbe4e8194370d","2169fe3af9e88ab9","a85dccf18844fc79","2bf91d3c3920c5c8","f4ce01b385c68a2","4366899a2cb05197","6f0aecc3342b13c0","874b67f800dd74d6","587785bbbcdc2016","d7397265deb360a6","d9fabd130a8ecdfb","707b55fec1513c90","e51b0346b0d4b612","417e005d18c1f7d4","306964e5ede31618","8c7ca4bb2b8abe1e","b878d79c5774d12d","15599c2b2bd60293","a7891090c37daba1","4192f3dd9bdddea8","ba5b31e5a1adb8e2","dadf83703db9234","3fd72034ab5b908","e939b25394581c4","67d24278154582d6","bc6a77eea2a1ba4b","41fa2c6b8e3aed38","1b6e3c30093fcd6e","98377d7e6f0eea0a","267886c6b07733d7","280250b5f6148515","1b79a8c6288d49d8","47c23de3a5c71c7e","de0f0cd6b40ee150","e91f5b3d583f23af","2036a5ff6aed3717","5ed363e465b9c98b","3ed6b5d40fb4a3b0","e7219eac943d306f","186382b7e69faced","943be3ce709a99d3","3a8800d72c312f75","b9bf74de5674c15d","cb9ad84a103b6499","acdcac18a6e34419", "ee323f91ee6f543c","be9935e5c2bedaef","60ac8eb415e6c748","119e95426dc4affb","e918003e25abf4cd","44c0efaa4b189434","de6ef5f1aa07b38d","b71a695e14c7e892","c9b7984a5d2604b5","72e9cd10959558de","82f692ac2f5817f3","3e0d3d7ade790448","52595c2a99ba6031","ea6ad19cdc29b230","695cba9190654139","4418aa6010632480","e27b9c1ea1c64357","fe62097e8814c106","1cfd3a3660a62879","ddf404c2905d3b26","8ac6baea1b755066","2bc023c7e062f24b","8c43f241aeac6d75","832fc9a9a2b71d00","34e8b7999dfb14b5","ccc48c575f7ab4eb","9de0e5d104caf802","e46f98bfca35d4a0","db882c2be6efd7d4","6577bf381d78bae2","f66dbe09241b5a4","48884cab13bd3903","fd6796ea6d131c3","dfde38eed6f3305d","9b895440c1743c4e","783942f921da9985","e0c97cefd6558c77","75c75fa4503282","680487ae23f269a1","9b70726386e38170","ef7b63d9848dc185","3fe59bc388b9ef3","dd93140e21e6f919","143c7821cd65bcac","70d29c9e7a4ef797","b26376133e68b3db","31a354962a9bcfa0","50e62cbde34516ee","9273478f6feccd62","eddf20a67e3fddef","5a44c960cc4178dd","5499865be87b7e00","446545b04b35fba","8887c18020ddb307","3adda38e5fadcfb","9f105a95e82012a4","50cea598241b0bc9","6396e2866ef1b30","1c0da45940bfa76f","22b9026cb0221ce0","2011029b33aad319", "60f1d510640499ac","396137c9cb425893","7fd407d5e8c91bd4","a037c260bd97c7d2","d50f3cbac505793d","b841fc54d2df22d9","389037ae98d33f26", "f265acf7423fa9b1"] +ApprovedChanges: ["115ccce93a478b9a", "c8f122c9fb83793e", "220aede0f8fa5a4a", "fb9cab4ffb28869a", "3ca2431a8d79bc3a", "ca49cf46baf0a367", "50e5bb7eda99594e", "870a3a66aeccd737","4e22a08543b079b","56ceb03cd44ff702","188adfe8914e04c1","2438f9c5b82b69a3","1a716ee3bdb3170","90b166f78390af18","68219b82a1d9d829","c4c4caa5d0938b85","dfe99ce1d27b6cb1","35f5dab1f128d193","9a3973b64d7e8932","f33f07301a770d03","3e9e0dddfad3b302","d4fef6512374c1f5","b49f54cb45787e4b","59b2375130aef5df","f094cd0460432170","8e51881e527dd603","a7d6d58d9fa06379","1d124224ca4d0fe3","39ea06bfd1477d2d","7e2550bab51f22b2","87ebd29bd49fc52f","ef39dd5223e0d080","fe14e7f0503ea188","6146023d4d5708a2","aebb8e4348b6d667","973a2e6704dbf3","fb4cac598a68c592","257c7eb81d6eb245","2a8e94fe037e13fd","5e7eb878de54eec6","960a9c64cd4ec93c","57dfd255520bd849","ec333ff8a708db69","1cc1ff39ad91ee69","5714652b88e2d44f","7a53b3b037c56325","8c02ef1964464c30","19a268910a20da3d","af6e01ed565029f3","318b5169ac4dabb6","372c6b332e8ba699","c0d8a364c0db855a","4287381be4fb1841","b1614afc1da7794f","c214975412f3fd7","8bbf7eba3fa0cf7e","8e4ec8debe331b36","7a671d8fcefc3793","e2b0e9c6454c1c08","6707ecfefa5fec21","d5a7389d730464f1","8dfae3b3223d2de0","a81c092c985de728","968df5082c727ed6","9e53c73ee60b1cc2","9d265e99dd31d4f5","a34619e078d2e42f","17e8cec4f0625d53","e913f373aa88f333","cfc1e05c372d88dc","e5de6901d78b8833","57c1885b43dd8d19","e8a49856a5edd893","22ea21d10a2f861c","954e4fce01631c4e","108b9575f7c1d4bc","1f8d076449068f64","5a7ad98296703f6","159536003eeddac8","8ca8f82e67ddd3dd","16ebe47404323cc1","48bfe5cf1e578b47","dd83182b693a7216","308d21d9830f7047","6dde03147e012b1a","730c3e5e59393b7d","5b44a4b425ecc397","df5debc50ec8babc","92a41554b2910bb8","c36c680554dde59f","447feaa5cdc1a010","fda90c61f44cb149","cdbb4930eced584c","274336ec1127e6c0","2a496f5b3ad542d2","6b395912dde33b0e","cac56ec14994216b","8850900b5d9bcc65","15e7706486c6359e","cc22f28953b787ea","3bad6ae11596a574","8f84422a240d889c","5b265432dfbbaac7","43794bf5953db193","7975821460ebe1e7","173c505e12aabb8f","47ee0d148148a56f","8cc38593ebe049b6","bda3aec7157b095a","248712911696a851","f4d9c910f1dbaef7","1a2146fcad37acb8","b0b146f9bdab64b6","edfd442b4d725fbb","122f053573538a32","d720d714a20833e1", "f9c984e71b685f9b","8c6b4fee5a4c13ce","c0a8d2019a2c30d5", "717bef26105c733f","2f70630c27062353","2f70337ba7566a69","dd607a44e1341e6b","5210501625ac3de5","f786bf475b5085aa","18a66ed6e613d9c1","e8943e7741f6843d","276a489bd5a00032","ba3bba59f10bf6b","3c50ce0c8089d871","89ee72f6c610ab84","c92b95a85da2cb11","927ea6aed3f98f20","9338904026a0ce37","9683cfa19dc544a3","4d3fa2b8dfcb5f5b", "f19e9a2b295bcfb3", "b10199b2de6f03b8", "1afc17e358f9ca79","4b58762c0b433442","d293ec1bc61bb707","3e88c3b49d093605","4890ff80c88cc41d","5227ff3a225dd20d","81a60407a3a0ba80","db2ad807eb66254a","d308bd7c553ccdcf","bdaf172971637cbe","6ade9202843071fe","2fe8e14083997744","19c9a5362d1e1d3a","5956f803d239f178","92c55a4548a8b760","9a95524213bccfff","2f51a7338b86c229","e96966a281d74505","3ee479b9cbbc3a1d","82b392ba39c6c594","b9d2404e5c570019","24f528d85fb021f2","fe9609a785305d81","b0934079dcd986cc","a9c520a19b26049","d19a9403fd732d94","74a928f5dcb2fdd9","cbbfdb5e68cdac80","10e39d2ceda91f34","f99a004cf6697875","8fa5e8ebf7d223ec","6c80c145ba705243","fbabbc90d0b4178a","ab0c7f24e551ca6","af38a11cb8682c75","b110cba51df9f8d2","c4ff2ed3d20dc419","9295a5bb10efcec7","ab56ea44a75f898a","ff51ef26ab53ba58","df3771e2589008f9","106e5689655bcfc6","f90e0fb6883bff93","667656095cec39ee","9a5597af260c748a","9168b9cfb0cb98c8","875393173d59b0f2","a347ee50e92f7334","91073f39440ab37f","1bbcbe4e8194370d","2169fe3af9e88ab9","a85dccf18844fc79","2bf91d3c3920c5c8","f4ce01b385c68a2","4366899a2cb05197","6f0aecc3342b13c0","874b67f800dd74d6","587785bbbcdc2016","d7397265deb360a6","d9fabd130a8ecdfb","707b55fec1513c90","e51b0346b0d4b612","417e005d18c1f7d4","306964e5ede31618","8c7ca4bb2b8abe1e","b878d79c5774d12d","15599c2b2bd60293","a7891090c37daba1","4192f3dd9bdddea8","ba5b31e5a1adb8e2","dadf83703db9234","3fd72034ab5b908","e939b25394581c4","67d24278154582d6","bc6a77eea2a1ba4b","41fa2c6b8e3aed38","1b6e3c30093fcd6e","98377d7e6f0eea0a","267886c6b07733d7","280250b5f6148515","1b79a8c6288d49d8","47c23de3a5c71c7e","de0f0cd6b40ee150","e91f5b3d583f23af","2036a5ff6aed3717","5ed363e465b9c98b","3ed6b5d40fb4a3b0","e7219eac943d306f","186382b7e69faced","943be3ce709a99d3","3a8800d72c312f75","b9bf74de5674c15d","cb9ad84a103b6499","acdcac18a6e34419", "ee323f91ee6f543c","be9935e5c2bedaef","60ac8eb415e6c748","119e95426dc4affb","e918003e25abf4cd","44c0efaa4b189434","de6ef5f1aa07b38d","b71a695e14c7e892","c9b7984a5d2604b5","72e9cd10959558de","82f692ac2f5817f3","3e0d3d7ade790448","52595c2a99ba6031","ea6ad19cdc29b230","695cba9190654139","4418aa6010632480","e27b9c1ea1c64357","fe62097e8814c106","1cfd3a3660a62879","ddf404c2905d3b26","8ac6baea1b755066","2bc023c7e062f24b","8c43f241aeac6d75","832fc9a9a2b71d00","34e8b7999dfb14b5","ccc48c575f7ab4eb","9de0e5d104caf802","e46f98bfca35d4a0","db882c2be6efd7d4","6577bf381d78bae2","f66dbe09241b5a4","48884cab13bd3903","fd6796ea6d131c3","dfde38eed6f3305d","9b895440c1743c4e","783942f921da9985","e0c97cefd6558c77","75c75fa4503282","680487ae23f269a1","9b70726386e38170","ef7b63d9848dc185","3fe59bc388b9ef3","dd93140e21e6f919","143c7821cd65bcac","70d29c9e7a4ef797","b26376133e68b3db","31a354962a9bcfa0","50e62cbde34516ee","9273478f6feccd62","eddf20a67e3fddef","5a44c960cc4178dd","5499865be87b7e00","446545b04b35fba","8887c18020ddb307","3adda38e5fadcfb","9f105a95e82012a4","50cea598241b0bc9","6396e2866ef1b30","1c0da45940bfa76f","22b9026cb0221ce0","2011029b33aad319", "60f1d510640499ac","396137c9cb425893","7fd407d5e8c91bd4","a037c260bd97c7d2","d50f3cbac505793d","b841fc54d2df22d9","389037ae98d33f26", "f265acf7423fa9b1", "e710070bfb15d3ab","262a19d18869cedd","881fc8fbb6a4edb1","31bc6100f3d4db08","c7ce0261a1b6014f","1bd46741a98043b0","14dd874e7df81b37","3ddc92a39c324d69","f99137aa4377841c","5be5c4ce7d3212da","f2972b2906912d3a","c411b0f9f069c032","96631f77414215f5","3426003abbd5ebf0","e1d82f0619360a5","e07da5b414afe6a6","859884a25fccea80","8651bdc20c1946f3","6ccbcb02e457e66","98c46ae55d1d4e39","f9480b2e48319466","b3e7d9382b320d70","a20ea51df8b7d65b","9133b167cc5a601d","a748ad5c74850749","7f816e2f33da3186","1067c9a5622c3508","2314d7fa0b387cff","634abeefa604ee2","38faed802f80914b","bcb381e843ace421","5797f56a84b7ebef","b523eed171e5b6bf","601862214795ec47","11587bf00d05a4e2","78bcb24d3483e47a"] IgnoredIdentifiers: - logger From 992906be76e9d746dd2de07f887a1a57eb2dadec Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 27 May 2025 17:12:20 +0400 Subject: [PATCH 23/34] feat(networkconfig,beacon/goclient): get beacon config from beacon node (#2153) * beacon/goclient: get beacon config from beacon node * use beacon config obtained from beacon node * log config as JSON * delete a comment * use Stringer to log node * guard beacon config reads with mutex * add a timeout log * delete hardcoded beacon configs * Revert "delete hardcoded beacon configs" This reverts commit c2e2f8f0124c0c65a088a3957fdeda4008f85bf2. * fix issues after merging * code review comments * unexport supportedSSVConfigs * fix a context bug * pass network config name * feat(networkconfig): CLI for custom SSV config generation (#2156) * networkconfig: CLI for custom SSV config generation * implement JSON marshaling and YAML marshaling/unmarshaling * remove TotalEthereumValidators * simplify marshaling/unmarshaling logic * fix markdown formatting * use yaml@v3 * add tests * simplify unmarshaling * fix linter * add missing fields to LocalTestnet --- beacon/goclient/aggregator.go | 8 +- beacon/goclient/attest_test.go | 16 -- beacon/goclient/current_fork_test.go | 3 - beacon/goclient/events_test.go | 5 +- beacon/goclient/genesis_test.go | 43 +++- beacon/goclient/goclient.go | 148 ++++++----- beacon/goclient/goclient_test.go | 63 +---- beacon/goclient/signing.go | 3 +- beacon/goclient/signing_test.go | 1 - beacon/goclient/spec.go | 78 +++++- beacon/goclient/spec_test.go | 1 - .../goclient/sync_committee_contribution.go | 5 +- beacon/goclient/validator.go | 5 +- cli/GENERATE_CONFIG.md | 160 ++++++++++++ cli/bootnode/boot_node.go | 2 +- cli/generate_config.go | 149 +++++++++++ cli/operator/node.go | 91 +++---- exporter/api/query_handlers_test.go | 12 +- ...onfiglock_add_alan_fork_to_network_name.go | 7 - networkconfig/beacon.go | 10 + networkconfig/holesky-e2e.go | 3 +- networkconfig/holesky-stage.go | 3 +- networkconfig/holesky.go | 3 +- networkconfig/hoodi-stage.go | 3 +- networkconfig/hoodi.go | 3 +- networkconfig/local-testnet.go | 6 +- networkconfig/mainnet.go | 3 +- networkconfig/network.go | 25 +- networkconfig/sepolia.go | 3 +- networkconfig/ssv.go | 106 +++++++- networkconfig/ssv_test.go | 232 ++++++++++++++++++ networkconfig/test-network.go | 3 +- operator/node.go | 6 +- protocol/v2/blockchain/beacon/client.go | 3 - utils/boot_node/node.go | 14 +- 35 files changed, 958 insertions(+), 268 deletions(-) create mode 100644 cli/GENERATE_CONFIG.md create mode 100644 cli/generate_config.go create mode 100644 networkconfig/ssv_test.go diff --git a/beacon/goclient/aggregator.go b/beacon/goclient/aggregator.go index 1285d9c375..9939a7309b 100644 --- a/beacon/goclient/aggregator.go +++ b/beacon/goclient/aggregator.go @@ -39,7 +39,7 @@ func (gc *GoClient) SubmitAggregateSelectionProof( if err != nil { return nil, DataVersionNil, fmt.Errorf("failed to get attestation data: %w", err) } - if gc.DataVersion(gc.beaconConfig.EstimatedEpochAtSlot(attData.Slot)) < spec.DataVersionElectra { + if gc.DataVersion(gc.getBeaconConfig().EstimatedEpochAtSlot(attData.Slot)) < spec.DataVersionElectra { attData.Index = committeeIndex } @@ -201,9 +201,9 @@ func isAggregator(committeeCount uint64, slotSig []byte) bool { // waitToSlotTwoThirds waits until two-third of the slot has transpired (SECONDS_PER_SLOT * 2 / 3 seconds after slot start time) func (gc *GoClient) waitToSlotTwoThirds(slot phase0.Slot) { - oneThird := gc.beaconConfig.SlotDuration / 3 /* one third of slot duration */ - - finalTime := gc.beaconConfig.GetSlotStartTime(slot).Add(2 * oneThird) + config := gc.getBeaconConfig() + oneThird := config.SlotDuration / 3 /* one third of slot duration */ + finalTime := config.GetSlotStartTime(slot).Add(2 * oneThird) wait := time.Until(finalTime) if wait <= 0 { return diff --git a/beacon/goclient/attest_test.go b/beacon/goclient/attest_test.go index ab7c2c208f..14d23a2ed1 100644 --- a/beacon/goclient/attest_test.go +++ b/beacon/goclient/attest_test.go @@ -18,8 +18,6 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap" - "github.com/ssvlabs/ssv/networkconfig" - "github.com/ssvlabs/ssv/operator/slotticker" "github.com/ssvlabs/ssv/utils/hashmap" ) @@ -204,17 +202,10 @@ func TestGoClient_GetAttestationData_Simple(t *testing.T) { t.Context(), zap.NewNop(), Options{ - BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: server.URL, CommonTimeout: 1 * time.Second, LongTimeout: 1 * time.Second, }, - func() slotticker.SlotTicker { - return slotticker.New(zap.NewNop(), slotticker.Config{ - SlotDuration: 12 * time.Second, - GenesisTime: time.Now(), - }) - }, ) require.NoError(t, err) @@ -500,18 +491,11 @@ func createClient( ctx, zap.NewNop(), Options{ - BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: beaconServerURL, CommonTimeout: defaultHardTimeout, LongTimeout: time.Second, WithWeightedAttestationData: withWeightedAttestationData, }, - func() slotticker.SlotTicker { - return slotticker.New(zap.NewNop(), slotticker.Config{ - SlotDuration: 12 * time.Second, - GenesisTime: time.Now(), - }) - }, ) return client, err } diff --git a/beacon/goclient/current_fork_test.go b/beacon/goclient/current_fork_test.go index ac68855a0e..70c8582c27 100644 --- a/beacon/goclient/current_fork_test.go +++ b/beacon/goclient/current_fork_test.go @@ -55,7 +55,6 @@ func TestCurrentFork(t *testing.T) { CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, }, - tests.MockSlotTickerProvider, ) require.NoError(t, err) @@ -86,7 +85,6 @@ func TestCurrentFork(t *testing.T) { CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, }, - tests.MockSlotTickerProvider, ) require.NoError(t, err) @@ -126,7 +124,6 @@ func TestCurrentFork(t *testing.T) { CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, }, - tests.MockSlotTickerProvider, ) require.NoError(t, err) diff --git a/beacon/goclient/events_test.go b/beacon/goclient/events_test.go index f316a49c9a..e807992d9e 100644 --- a/beacon/goclient/events_test.go +++ b/beacon/goclient/events_test.go @@ -13,7 +13,6 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/beacon/goclient/tests" - "github.com/ssvlabs/ssv/networkconfig" ) func TestSubscribeToHeadEvents(t *testing.T) { @@ -84,9 +83,7 @@ func eventsTestClient(t *testing.T, serverURL string) *GoClient { zap.NewNop(), Options{ BeaconNodeAddr: serverURL, - BeaconConfig: networkconfig.Mainnet.BeaconConfig, - }, - tests.MockSlotTickerProvider) + }) require.NoError(t, err) return server diff --git a/beacon/goclient/genesis_test.go b/beacon/goclient/genesis_test.go index 095aa145ba..f9aec19ca4 100644 --- a/beacon/goclient/genesis_test.go +++ b/beacon/goclient/genesis_test.go @@ -14,7 +14,10 @@ import ( "github.com/ssvlabs/ssv/networkconfig" ) -const genesisPath = "/eth/v1/beacon/genesis" +const ( + genesisPath = "/eth/v1/beacon/genesis" + specPath = "/eth/v1/config/spec" +) func TestGenesis(t *testing.T) { ctx := context.Background() @@ -30,6 +33,29 @@ func TestGenesis(t *testing.T) { } }`), nil } + if r.URL.Path == specPath { + return json.RawMessage(`{ + "data": { + "CONFIG_NAME": "holesky", + "GENESIS_FORK_VERSION": "0x00000000", + "CAPELLA_FORK_VERSION": "0x04017000", + "MIN_GENESIS_TIME": "1695902100", + "SECONDS_PER_SLOT": "12", + "SLOTS_PER_EPOCH": "32", + "EPOCHS_PER_SYNC_COMMITTEE_PERIOD": "256", + "SYNC_COMMITTEE_SIZE": "512", + "SYNC_COMMITTEE_SUBNET_COUNT": "4", + "TARGET_AGGREGATORS_PER_COMMITTEE": "16", + "TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE": "16", + "INTERVALS_PER_SLOT": "3", + "ALTAIR_FORK_EPOCH": "74240", + "BELLATRIX_FORK_EPOCH": "144896", + "CAPELLA_FORK_EPOCH": "194048", + "DENEB_FORK_EPOCH": "269568", + "ELECTRA_FORK_EPOCH": "18446744073709551615" + } + }`), nil + } return resp, nil }) defer mockServer.Close() @@ -43,7 +69,6 @@ func TestGenesis(t *testing.T) { CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, }, - tests.MockSlotTickerProvider, ) require.NoError(t, err) @@ -73,13 +98,10 @@ func TestGenesis(t *testing.T) { CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, }, - tests.MockSlotTickerProvider, ) - require.NoError(t, err) - - _, err = client.Genesis(ctx) require.Error(t, err) - require.Contains(t, err.Error(), "genesis response data is nil") + require.Contains(t, err.Error(), "timed out awaiting config initialization") // node cannot initialize if it cannot get genesis + require.Nil(t, client) }) t.Run("error", func(t *testing.T) { @@ -100,12 +122,9 @@ func TestGenesis(t *testing.T) { CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, }, - tests.MockSlotTickerProvider, ) - require.NoError(t, err) - - _, err = client.Genesis(ctx) require.Error(t, err) - require.Contains(t, err.Error(), "failed to request genesis") + require.Contains(t, err.Error(), "timed out awaiting config initialization") // node cannot initialize if it cannot get genesis + require.Nil(t, client) }) } diff --git a/beacon/goclient/goclient.go b/beacon/goclient/goclient.go index 8266732a23..0bd2a40347 100644 --- a/beacon/goclient/goclient.go +++ b/beacon/goclient/goclient.go @@ -119,10 +119,14 @@ const ( // GoClient implementing Beacon struct type GoClient struct { - log *zap.Logger - beaconConfig networkconfig.BeaconConfig - clients []Client - multiClient MultiClient + log *zap.Logger + + beaconConfigMu sync.RWMutex + beaconConfig *networkconfig.BeaconConfig + beaconConfigInit chan struct{} + + clients []Client + multiClient MultiClient syncDistanceTolerance phase0.Slot nodeSyncingFn func(ctx context.Context, opts *api.NodeSyncingOpts) (*api.Response[*apiv1.SyncState], error) @@ -164,7 +168,6 @@ type GoClient struct { lastProcessedEventSlotLock sync.Mutex lastProcessedEventSlot phase0.Slot - genesisForkVersion phase0.Version ForkLock sync.RWMutex ForkEpochElectra phase0.Epoch ForkEpochDeneb phase0.Epoch @@ -182,11 +185,8 @@ func New( ctx context.Context, logger *zap.Logger, opt Options, - slotTickerProvider slotticker.Provider, ) (*GoClient, error) { - logger.Info("consensus client: connecting", - fields.Address(opt.BeaconNodeAddr), - fields.Network(opt.BeaconConfig.GetBeaconName())) + logger.Info("consensus client: connecting", fields.Address(opt.BeaconNodeAddr)) commonTimeout := opt.CommonTimeout if commonTimeout == 0 { @@ -198,18 +198,10 @@ func New( } client := &GoClient{ - log: logger.Named("consensus_client"), - beaconConfig: opt.BeaconConfig, - syncDistanceTolerance: phase0.Slot(opt.SyncDistanceTolerance), - registrations: map[phase0.BLSPubKey]*validatorRegistration{}, - attestationDataCache: ttlcache.New( - // we only fetch attestation data during the slot of the relevant duty (and never later), - // hence caching it for 2 slots is sufficient - ttlcache.WithTTL[phase0.Slot, *phase0.AttestationData](2 * opt.BeaconConfig.SlotDuration), - ), - blockRootToSlotCache: ttlcache.New(ttlcache.WithCapacity[phase0.Root, phase0.Slot]( - opt.BeaconConfig.SlotsPerEpoch * BlockRootToSlotCacheCapacityEpochs), - ), + log: logger.Named("consensus_client"), + beaconConfigInit: make(chan struct{}), + syncDistanceTolerance: phase0.Slot(opt.SyncDistanceTolerance), + registrations: map[phase0.BLSPubKey]*validatorRegistration{}, commonTimeout: commonTimeout, longTimeout: longTimeout, withWeightedAttestationData: opt.WithWeightedAttestationData, @@ -217,7 +209,6 @@ func New( weightedAttestationDataSoftTimeout: time.Duration(float64(commonTimeout) / 2.5), weightedAttestationDataHardTimeout: commonTimeout, supportedTopics: []EventTopic{EventTopicHead, EventTopicBlock}, - genesisForkVersion: opt.BeaconConfig.ForkVersion, // Initialize forks with FAR_FUTURE_EPOCH. ForkEpochAltair: math.MaxUint64, ForkEpochBellatrix: math.MaxUint64, @@ -249,6 +240,41 @@ func New( client.nodeSyncingFn = client.nodeSyncing + initCtx, initCtxCancel := context.WithTimeout(ctx, client.longTimeout) + defer initCtxCancel() + + select { + case <-initCtx.Done(): + logger.Warn("timeout occurred while waiting for beacon config initialization", + zap.Duration("timeout", client.longTimeout), + zap.Error(initCtx.Err()), + ) + return nil, fmt.Errorf("timed out awaiting config initialization: %w", initCtx.Err()) + case <-client.beaconConfigInit: + } + + config := client.getBeaconConfig() + if config == nil { + return nil, fmt.Errorf("no beacon config set") + } + + client.blockRootToSlotCache = ttlcache.New( + ttlcache.WithCapacity[phase0.Root, phase0.Slot](config.SlotsPerEpoch * BlockRootToSlotCacheCapacityEpochs), + ) + + client.attestationDataCache = ttlcache.New( + // we only fetch attestation data during the slot of the relevant duty (and never later), + // hence caching it for 2 slots is sufficient + ttlcache.WithTTL[phase0.Slot, *phase0.AttestationData](2 * config.SlotDuration), + ) + + slotTickerProvider := func() slotticker.SlotTicker { + return slotticker.New(logger, slotticker.Config{ + SlotDuration: config.SlotDuration, + GenesisTime: config.GenesisTime, + }) + } + go client.registrationSubmitter(ctx, slotTickerProvider) // Start automatic expired item deletion for attestationDataCache. go client.attestationDataCache.Start() @@ -261,6 +287,13 @@ func New( return client, nil } +// getBeaconConfig provides thread-safe access to the beacon configuration +func (gc *GoClient) getBeaconConfig() *networkconfig.BeaconConfig { + gc.beaconConfigMu.RLock() + defer gc.beaconConfigMu.RUnlock() + return gc.beaconConfig +} + func (gc *GoClient) initMultiClient(ctx context.Context) error { var services []eth2client.Service for _, client := range gc.clients { @@ -310,48 +343,46 @@ func (gc *GoClient) addSingleClient(ctx context.Context, addr string) error { func (gc *GoClient) singleClientHooks() *eth2clienthttp.Hooks { return ð2clienthttp.Hooks{ OnActive: func(ctx context.Context, s *eth2clienthttp.Service) { + logger := gc.log.With( + fields.Name(s.Name()), + fields.Address(s.Address()), + ) // If err is nil, nodeVersionResp is never nil. nodeVersionResp, err := s.NodeVersion(ctx, &api.NodeVersionOpts{}) if err != nil { - gc.log.Error(clResponseErrMsg, - zap.String("address", s.Address()), + logger.Error(clResponseErrMsg, zap.String("api", "NodeVersion"), zap.Error(err), ) return } - gc.log.Info("consensus client connected", - fields.Name(s.Name()), - fields.Address(s.Address()), + logger.Info("consensus client connected", zap.String("client", string(ParseNodeClient(nodeVersionResp.Data))), zap.String("version", nodeVersionResp.Data), ) - genesis, err := genesisForClient(ctx, gc.log, s) + beaconConfig, err := gc.fetchBeaconConfig(ctx, s) if err != nil { - gc.log.Error(clResponseErrMsg, - zap.String("address", s.Address()), - zap.String("api", "Genesis"), + logger.Error(clResponseErrMsg, + zap.String("api", "fetchBeaconConfig"), zap.Error(err), ) return } - if expected, err := gc.assertSameGenesisVersion(genesis.GenesisForkVersion); err != nil { - gc.log.Fatal("client returned unexpected genesis fork version, make sure all clients use the same Ethereum network", - zap.String("address", s.Address()), - zap.Any("client_genesis", genesis.GenesisForkVersion), - zap.Any("expected_genesis", expected), - zap.Error(err), + currentConfig, err := gc.applyBeaconConfig(s.Address(), beaconConfig) + if err != nil { + logger.Fatal("client returned unexpected beacon config, make sure all clients use the same Ethereum network", + zap.Stringer("client_config", beaconConfig), + zap.Stringer("expected_config", currentConfig), ) return // Tests may override Fatal's behavior } - spec, err := specImpl(ctx, gc.log, s) + spec, err := specForClient(ctx, logger, s) if err != nil { - gc.log.Error(clResponseErrMsg, - zap.String("address", s.Address()), + logger.Error(clResponseErrMsg, zap.String("api", "Spec"), zap.Error(err), ) @@ -359,16 +390,15 @@ func (gc *GoClient) singleClientHooks() *eth2clienthttp.Hooks { } if err := gc.checkForkValues(spec); err != nil { - gc.log.Error("failed to check fork values", - zap.String("address", s.Address()), + logger.Error("failed to check fork values", zap.Error(err), ) return } gc.ForkLock.RLock() - gc.log.Info("retrieved fork epochs", - zap.String("node_addr", s.Address()), - zap.Uint64("current_data_version", uint64(gc.DataVersion(gc.beaconConfig.EstimatedCurrentEpoch()))), + config := gc.getBeaconConfig() + logger.Info("retrieved fork epochs", + zap.Uint64("current_data_version", uint64(gc.DataVersion(config.EstimatedCurrentEpoch()))), zap.Uint64("altair", uint64(gc.ForkEpochAltair)), zap.Uint64("bellatrix", uint64(gc.ForkEpochBellatrix)), zap.Uint64("capella", uint64(gc.ForkEpochCapella)), @@ -398,18 +428,26 @@ func (gc *GoClient) singleClientHooks() *eth2clienthttp.Hooks { } } -// assertSameGenesis checks if genesis is same. -// Clients may have different values returned by Spec call, -// so we decided that it's best to assert that GenesisForkVersion is the same. -// To add more assertions, we check the whole apiv1.Genesis (GenesisTime and GenesisValidatorsRoot) -// as they should be same too. -func (gc *GoClient) assertSameGenesisVersion(genesisVersion phase0.Version) (phase0.Version, error) { - if gc.genesisForkVersion != genesisVersion { - fmt.Printf("genesis fork version mismatch, expected %v, got %v", gc.genesisForkVersion, genesisVersion) - return gc.genesisForkVersion, fmt.Errorf("genesis fork version mismatch, expected %v, got %v", gc.genesisForkVersion, genesisVersion) +func (gc *GoClient) applyBeaconConfig(nodeAddress string, beaconConfig networkconfig.BeaconConfig) (networkconfig.BeaconConfig, error) { + gc.beaconConfigMu.Lock() + defer gc.beaconConfigMu.Unlock() + + if gc.beaconConfig == nil { + gc.beaconConfig = &beaconConfig + close(gc.beaconConfigInit) + + gc.log.Info("beacon config has been initialized", + zap.Stringer("beacon_config", beaconConfig), + fields.Address(nodeAddress), + ) + return beaconConfig, nil + } + + if *gc.beaconConfig != beaconConfig { + return *gc.beaconConfig, fmt.Errorf("beacon config misalign, current %v, got %v", gc.beaconConfig, beaconConfig) } - return gc.genesisForkVersion, nil + return *gc.beaconConfig, nil } func (gc *GoClient) nodeSyncing(ctx context.Context, opts *api.NodeSyncingOpts) (*api.Response[*apiv1.SyncState], error) { diff --git a/beacon/goclient/goclient_test.go b/beacon/goclient/goclient_test.go index dc9241d599..ab17fb7dfa 100644 --- a/beacon/goclient/goclient_test.go +++ b/beacon/goclient/goclient_test.go @@ -15,7 +15,6 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/beacon/goclient/tests" - "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" ) @@ -135,6 +134,10 @@ func TestTimeouts(t *testing.T) { fastServer := tests.MockServer(func(r *http.Request, resp json.RawMessage) (json.RawMessage, error) { time.Sleep(commonTimeout / 2) switch r.URL.Path { + case "/eth/v1/config/spec": + case "/eth/v1/beacon/genesis": + case "/eth/v1/node/syncing": + case "/eth/v1/node/version": case "/eth/v2/debug/beacon/states/head": time.Sleep(longTimeout / 2) } @@ -153,72 +156,14 @@ func TestTimeouts(t *testing.T) { } } -func TestAssertSameGenesisVersionWhenSame(t *testing.T) { - networkConfigs := []networkconfig.NetworkConfig{ - networkconfig.Mainnet, - networkconfig.Holesky, - networkconfig.LocalTestnet, - networkconfig.TestNetwork, - } - - for _, netCfg := range networkConfigs { - callback := func(r *http.Request, resp json.RawMessage) (json.RawMessage, error) { - if r.URL.Path == "/eth/v1/beacon/genesis" { - resp2 := json.RawMessage(fmt.Sprintf(`{"data": { - "genesis_time": "1606824023", - "genesis_validators_root": "0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95", - "genesis_fork_version": "%s" - }}`, netCfg.ForkVersion)) - return resp2, nil - } - return resp, nil - } - - server := tests.MockServer(callback) - defer server.Close() - t.Run(fmt.Sprintf("When genesis versions are the same (%s)", netCfg.BeaconName), func(t *testing.T) { - c, err := mockClientWithNetwork(t.Context(), server.URL, 100*time.Millisecond, 500*time.Millisecond, netCfg.BeaconConfig) - require.NoError(t, err, "failed to create client") - client := c.(*GoClient) - - output, err := client.assertSameGenesisVersion(netCfg.ForkVersion) - require.Equal(t, netCfg.ForkVersion, output) - require.NoError(t, err, "failed to assert same genesis version: %s", err) - }) - } -} - -func TestAssertSameGenesisVersionWhenDifferent(t *testing.T) { - networkConfig := networkconfig.Mainnet - - t.Run("When genesis versions are different", func(t *testing.T) { - server := tests.MockServer(nil) - defer server.Close() - c, err := mockClientWithNetwork(t.Context(), server.URL, 100*time.Millisecond, 500*time.Millisecond, networkConfig.BeaconConfig) - require.NoError(t, err, "failed to create client") - client := c.(*GoClient) - forkVersion := phase0.Version{0x01, 0x02, 0x03, 0x04} - - output, err := client.assertSameGenesisVersion(forkVersion) - require.Equal(t, networkConfig.ForkVersion, output, "expected genesis version to be %s, got %s", networkConfig.ForkVersion, output) - require.Error(t, err, "expected error when genesis versions are different") - }) -} - func mockClient(ctx context.Context, serverURL string, commonTimeout, longTimeout time.Duration) (beacon.BeaconNode, error) { - return mockClientWithNetwork(ctx, serverURL, commonTimeout, longTimeout, networkconfig.Mainnet.BeaconConfig) -} - -func mockClientWithNetwork(ctx context.Context, serverURL string, commonTimeout, longTimeout time.Duration, beaconConfig networkconfig.BeaconConfig) (beacon.BeaconNode, error) { return New( ctx, zap.NewNop(), Options{ - BeaconConfig: beaconConfig, BeaconNodeAddr: serverURL, CommonTimeout: commonTimeout, LongTimeout: longTimeout, }, - tests.MockSlotTickerProvider, ) } diff --git a/beacon/goclient/signing.go b/beacon/goclient/signing.go index 0897fedef9..570d027c74 100644 --- a/beacon/goclient/signing.go +++ b/beacon/goclient/signing.go @@ -31,6 +31,7 @@ func (gc *GoClient) voluntaryExitDomain(ctx context.Context) (phase0.Domain, err } func (gc *GoClient) computeVoluntaryExitDomain(ctx context.Context) (phase0.Domain, error) { + // TODO: pull from beacon node specResponse, err := gc.Spec(ctx) if err != nil { return phase0.Domain{}, fmt.Errorf("fetch spec: %w", err) @@ -80,7 +81,7 @@ func (gc *GoClient) DomainData( // to (Mainnet, Hoodi, etc.) var appDomain phase0.Domain forkData := phase0.ForkData{ - CurrentVersion: gc.beaconConfig.ForkVersion, + CurrentVersion: gc.getBeaconConfig().ForkVersion, GenesisValidatorsRoot: phase0.Root{}, } root, err := forkData.HashTreeRoot() diff --git a/beacon/goclient/signing_test.go b/beacon/goclient/signing_test.go index a737a144a8..298ad6e141 100644 --- a/beacon/goclient/signing_test.go +++ b/beacon/goclient/signing_test.go @@ -31,7 +31,6 @@ func Test_computeVoluntaryExitDomain(t *testing.T) { CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, }, - tests.MockSlotTickerProvider, ) require.NoError(t, err) diff --git a/beacon/goclient/spec.go b/beacon/goclient/spec.go index 8b3660d8f7..5874ed350a 100644 --- a/beacon/goclient/spec.go +++ b/beacon/goclient/spec.go @@ -8,15 +8,87 @@ import ( client "github.com/attestantio/go-eth2-client" "github.com/attestantio/go-eth2-client/api" + eth2clienthttp "github.com/attestantio/go-eth2-client/http" "go.uber.org/zap" + + "github.com/ssvlabs/ssv/networkconfig" +) + +const ( + DefaultSlotDuration = 12 * time.Second + DefaultSlotsPerEpoch = uint64(32) ) +// BeaconConfig returns the network Beacon configuration +func (gc *GoClient) BeaconConfig() networkconfig.BeaconConfig { + // BeaconConfig must be called if GoClient is initialized (gc.beaconConfig is set) + // It fails otherwise. + config := gc.getBeaconConfig() + return *config +} + +// fetchBeaconConfig must be called once on GoClient's initialization +func (gc *GoClient) fetchBeaconConfig(ctx context.Context, client *eth2clienthttp.Service) (networkconfig.BeaconConfig, error) { + specResponse, err := specForClient(ctx, gc.log, client) + if err != nil { + gc.log.Error(clResponseErrMsg, zap.String("api", "Spec"), zap.Error(err)) + return networkconfig.BeaconConfig{}, fmt.Errorf("failed to obtain spec response: %w", err) + } + + // types of most values are already cast: https://github.com/attestantio/go-eth2-client/blob/v0.21.7/http/spec.go#L78 + + networkNameRaw, ok := specResponse["CONFIG_NAME"] + if !ok { + return networkconfig.BeaconConfig{}, fmt.Errorf("config name not known by chain") + } + + networkName, ok := networkNameRaw.(string) + if !ok { + return networkconfig.BeaconConfig{}, fmt.Errorf("failed to decode config name") + } + + slotDuration := DefaultSlotDuration + if slotDurationRaw, ok := specResponse["SECONDS_PER_SLOT"]; ok { + if slotDurationDecoded, ok := slotDurationRaw.(time.Duration); ok { + slotDuration = slotDurationDecoded + } else { + gc.log.Warn("seconds per slot not known by chain, using default value", + zap.Any("value", slotDuration)) + } + } + + slotsPerEpoch := DefaultSlotsPerEpoch + if slotsPerEpochRaw, ok := specResponse["SLOTS_PER_EPOCH"]; ok { + if slotsPerEpochDecoded, ok := slotsPerEpochRaw.(uint64); ok { + slotsPerEpoch = slotsPerEpochDecoded + } else { + gc.log.Warn("slots per epoch not known by chain, using default value", + zap.Uint64("value", slotsPerEpoch)) + } + } + + genesisResponse, err := genesisForClient(ctx, gc.log, client) + if err != nil { + gc.log.Error(clResponseErrMsg, zap.String("api", "Genesis"), zap.Error(err)) + return networkconfig.BeaconConfig{}, fmt.Errorf("failed to obtain genesis response: %w", err) + } + + beaconConfig := networkconfig.BeaconConfig{ + BeaconName: networkName, + SlotDuration: slotDuration, + SlotsPerEpoch: slotsPerEpoch, + ForkVersion: genesisResponse.GenesisForkVersion, + GenesisTime: genesisResponse.GenesisTime, + } + + return beaconConfig, nil +} + func (gc *GoClient) Spec(ctx context.Context) (map[string]any, error) { - return specImpl(ctx, gc.log, gc.multiClient) + return specForClient(ctx, gc.log, gc.multiClient) } -// It's used in both Spec and singleClientHooks, so we need some common implementation to avoid code repetition. -func specImpl(ctx context.Context, log *zap.Logger, provider client.Service) (map[string]any, error) { +func specForClient(ctx context.Context, log *zap.Logger, provider client.Service) (map[string]any, error) { start := time.Now() specResponse, err := provider.(client.SpecProvider).Spec(ctx, &api.SpecOpts{}) recordRequestDuration(ctx, "Spec", provider.Address(), http.MethodGet, time.Since(start), err) diff --git a/beacon/goclient/spec_test.go b/beacon/goclient/spec_test.go index 9467f9abf1..da28b512eb 100644 --- a/beacon/goclient/spec_test.go +++ b/beacon/goclient/spec_test.go @@ -28,7 +28,6 @@ func TestSpec(t *testing.T) { CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, }, - tests.MockSlotTickerProvider, ) require.NoError(t, err) diff --git a/beacon/goclient/sync_committee_contribution.go b/beacon/goclient/sync_committee_contribution.go index 609709ec4c..2e43ae4634 100644 --- a/beacon/goclient/sync_committee_contribution.go +++ b/beacon/goclient/sync_committee_contribution.go @@ -153,8 +153,9 @@ func (gc *GoClient) SubmitSignedContributionAndProof( // waitForOneThirdSlotDuration waits until one-third of the slot has transpired (SECONDS_PER_SLOT / 3 seconds after slot start time) func (gc *GoClient) waitForOneThirdSlotDuration(slot phase0.Slot) { - delay := gc.beaconConfig.SlotDuration / 3 /* a third of the slot duration */ - finalTime := gc.beaconConfig.GetSlotStartTime(slot).Add(delay) + config := gc.getBeaconConfig() + delay := config.SlotDuration / 3 /* a third of the slot duration */ + finalTime := config.GetSlotStartTime(slot).Add(delay) wait := time.Until(finalTime) if wait <= 0 { return diff --git a/beacon/goclient/validator.go b/beacon/goclient/validator.go index 9d4dab04f8..e16dce98b8 100644 --- a/beacon/goclient/validator.go +++ b/beacon/goclient/validator.go @@ -103,9 +103,10 @@ func (gc *GoClient) registrationSubmitter(ctx context.Context, slotTickerProvide } // Distribute the registrations evenly across the epoch based on the pubkeys. - slotInEpoch := uint64(currentSlot) % gc.beaconConfig.SlotsPerEpoch + config := gc.getBeaconConfig() + slotInEpoch := uint64(currentSlot) % config.SlotsPerEpoch validatorDescriptor := xxhash.Sum64(validatorPk[:]) - shouldSubmit := validatorDescriptor%gc.beaconConfig.SlotsPerEpoch == slotInEpoch + shouldSubmit := validatorDescriptor%config.SlotsPerEpoch == slotInEpoch if r.new || shouldSubmit { r.new = false diff --git a/cli/GENERATE_CONFIG.md b/cli/GENERATE_CONFIG.md new file mode 100644 index 0000000000..470b63d28a --- /dev/null +++ b/cli/GENERATE_CONFIG.md @@ -0,0 +1,160 @@ +# SSV Config Generator + +**SSV Config Generator** is a command-line tool designed to generate configuration file for SSV Node. It streamlines the setup process by allowing users to specify various parameters through flags, which are then compiled into a YAML configuration file. This tool ensures that the SSV network setup is consistent, customizable, and easy to manage. + +## Table of Contents + +- [Usage](#usage) + - [Flags](#flags) +- [Examples](#examples) +- [Configuration](#configuration) + +## Usage + +The `generate-config` command allows you to generate a YAML configuration file by specifying various parameters through command-line flags. + +### Syntax + +```bash + ssvnode generate-config [flags] +``` + +### Flags + +| Flag | Type | Default | Description | +|--------------------------------------|--------|-----------------------------------|----------------------------------------------------------------------------| +| `--output-path` | string | `./config/config.local.yaml` | Output path for the generated configuration file. | +| `--log-level` | string | `info` | Sets the logging level (e.g., `debug`, `info`, `warn`, `error`). | +| `--db-path` | string | `./data/db` | Path to the database directory. | +| `--discovery` | string | `mdns` | Discovery method. | +| `--consensus-client` | string | _Mandatory_ | Address of the consensus client (e.g., `http://localhost:9000`). | +| `--execution-client` | string | _Mandatory_ | Address of the execution client (e.g., `http://localhost:8545`). | +| `--operator-private-key` | string | | Secret key for the operator. | +| `--metrics-api-port` | int | `0` | Port number for the Metrics API (set to `0` to disable). | +| `--ssv-domain` | string | Derived from local testnet config | Hex-encoded domain type (prefixed with `0x`). | +| `--ssv-registry-sync-offset` | uint64 | Derived from local testnet config | Registry sync offset for the network. | +| `--ssv-registry-contract-addr` | string | Derived from local testnet config | Ethereum address of the network registry contract (e.g., `0xYourAddress`). | +| `--ssv-bootnodes` | string | Derived from local testnet config | Comma-separated list of network bootnodes. | +| `--ssv-discovery-protocol-id` | string | Derived from local testnet config | Hex-encoded discovery protocol ID (prefixed with `0x`). | +| `--ssv-alan-fork-epoch` | uint64 | Derived from local testnet config | Epoch at which the Alan fork occurs in the network. | +| `--ssv-max-validators-per-committee` | int | Derived from local testnet config | Max validators per committee. | + + +**Note:** The `--consensus-client` and `--execution-client` flags are mandatory and must be provided when running the CLI. + +## Examples + +### Basic Configuration + +Generate a configuration file with default settings, specifying only the mandatory flags: + +```bash +ssvnode generate-config \ + --consensus-client "http://localhost:9000" \ + --execution-client "http://localhost:8545" +``` + +This command generates a `config.local.yaml` file in the `./config` directory with default settings for all other parameters. + +### Custom Output Path and Log Level + +Generate a configuration file with a custom output path and set the log level to `debug`: + +```bash +ssvnode generate-config \ + --consensus-client "http://consensus.example.com:9000" \ + --execution-client "http://execution.example.com:8545" \ + --output-path "/etc/ssv/config.yaml" \ + --log-level "debug" +``` + +### Specify Operator Private Key and Enable Metrics API + +Generate a configuration with an operator's private key and enable the Metrics API on port `8080`: + +```bash +ssvnode generate-config \ + --consensus-client "http://consensus.example.com:9000" \ + --execution-client "http://execution.example.com:8545" \ + --operator-private-key "your-operator-private-key" \ + --metrics-api-port 8080 +``` + +### Advanced Network Configuration + +Customize network settings such as bootnodes, discovery protocol ID, fork epoch, etc: + +```bash +ssvnode generate-config \ + --consensus-client "http://consensus.example.com:9000" \ + --execution-client "http://execution.example.com:8545" \ + --ssv-domain "0x12345678" \ + --ssv-registry-sync-offset 50 \ + --ssv-registry-contract-addr "0xYourRegistryContractAddress" \ + --ssv-bootnodes "enode://bootnode1@127.0.0.1:30303,enode://bootnode2@127.0.0.1:30304" \ + --ssv-discovery-protocol-id "0x1234567890ab" \ + --ssv-max-validators-per-committee 560 +``` + +## Configuration + +The generated YAML configuration file (`config.local.yaml` by default) follows the structure defined by the `Config` struct. Below is an overview of each section and its corresponding fields: + +### YAML Structure + +```yaml +global: + LogLevel: info +db: + Path: ./data/db +eth2: + BeaconNodeAddr: http://localhost:9000 +eth1: + ETH1Addr: http://localhost:8545 +p2p: + Discovery: mdns +ssv: + Network: LocalTestnetSSV + CustomNetwork: + DomainType: "0x12345678" + RegistrySyncOffset: 0 + RegistryContractAddr: "0xYourRegistryContractAddress" + Bootnodes: + - "enode://bootnode1@127.0.0.1:30303" + - "enode://bootnode2@127.0.0.1:30304" + DiscoveryProtocolID: "0x1234567890ab" +OperatorPrivateKey: your-operator-private-key +MetricsAPIPort: 8080 +``` + +### Sections + +- **global** + - `LogLevel`: Specifies the logging level (e.g., `debug`, `info`, `warn`, `error`). + +- **db** + - `Path`: Path to the database directory. + +- **eth2** + - `BeaconNodeAddr`: Address of the consensus client (Beacon Node). + +- **eth1** + - `ETH1Addr`: Address of the execution client (ETH1 Node). + +- **p2p** + - `Discovery`: Peer-to-peer discovery method (e.g., `mdns`). + +- **ssv** + - `Network`: Name of the network. + - `CustomNetwork`: Contains custom network parameters. + - `DomainType`: Hex-encoded domain type (prefixed with `0x`). + - `RegistrySyncOffset`: Registry sync offset for the network. + - `RegistryContractAddr`: Ethereum address of the network registry contract. + - `Bootnodes`: List of network bootnodes. + - `DiscoveryProtocolID`: Hex-encoded discovery protocol ID (prefixed with `0x`). + +- **OperatorPrivateKey** + - `OperatorPrivateKey`: Secret key for the operator. + +- **MetricsAPIPort** + - `MetricsAPIPort`: Port number for the Metrics API. \ No newline at end of file diff --git a/cli/bootnode/boot_node.go b/cli/bootnode/boot_node.go index 2b1a564ef3..475ad0b4b7 100644 --- a/cli/bootnode/boot_node.go +++ b/cli/bootnode/boot_node.go @@ -54,7 +54,7 @@ var StartBootNodeCmd = &cobra.Command{ logger.Info(fmt.Sprintf("starting %v", commons.GetBuildData())) - networkConfig, err := networkconfig.GetNetworkConfigByName(cfg.Options.Network) + networkConfig, err := networkconfig.GetSSVConfigByName(cfg.Options.Network) if err != nil { logger.Fatal("failed to get network config", zap.Error(err)) } diff --git a/cli/generate_config.go b/cli/generate_config.go new file mode 100644 index 0000000000..41de6e6d58 --- /dev/null +++ b/cli/generate_config.go @@ -0,0 +1,149 @@ +package cli + +import ( + "encoding/hex" + "fmt" + "log" + "math/big" + "os" + "strings" + + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/spf13/cobra" + spectypes "github.com/ssvlabs/ssv-spec/types" + "gopkg.in/yaml.v3" + + "github.com/ssvlabs/ssv/networkconfig" +) + +const ( + defaultOutputPath = "./config/config.local.yaml" + defaultLogLevel = "info" + defaultDBPath = "./data/db" + defaultDiscovery = "mdns" + sliceSeparator = "," + configFilePermissions = 0644 +) + +var ( + defaultNetwork = networkconfig.LocalTestnet +) + +var ( + outputPath string + logLevel string + dbPath string + discovery string + consensusClient string + executionClient string + operatorPrivateKey string + metricsAPIPort int + ssvDomain string + ssvRegistrySyncOffset uint64 + ssvRegistryContractAddr string + ssvBootnodes string + ssvDiscoveryProtocolID string +) + +type SSVConfig struct { + Global struct { + LogLevel string `yaml:"LogLevel,omitempty"` + } `yaml:"global,omitempty"` + DB struct { + Path string `yaml:"Path,omitempty"` + } `yaml:"db,omitempty"` + ConsensusClient struct { + Address string `yaml:"BeaconNodeAddr,omitempty"` + } `yaml:"eth2,omitempty"` + ExecutionClient struct { + Address string `yaml:"ETH1Addr,omitempty"` + } `yaml:"eth1,omitempty"` + P2P struct { + Discovery string `yaml:"Discovery,omitempty"` + } `yaml:"p2p,omitempty"` + SSV struct { + NetworkName string `yaml:"Network,omitempty" env:"NETWORK" env-description:"Network is the network of this node,omitempty"` + CustomNetwork *networkconfig.SSVConfig `yaml:"CustomNetwork,omitempty" env:"CUSTOM_NETWORK" env-description:"Custom network parameters,omitempty"` + } `yaml:"ssv,omitempty"` + OperatorPrivateKey string `yaml:"OperatorPrivateKey,omitempty"` + MetricsAPIPort int `yaml:"MetricsAPIPort,omitempty"` +} + +// generateConfigCmd is the command to generate ssv operator config. +var generateConfigCmd = &cobra.Command{ + Use: "generate-config", + Short: "generates ssv operator config", + Run: func(cmd *cobra.Command, args []string) { + parsedDomain, err := hex.DecodeString(strings.TrimPrefix(ssvDomain, "0x")) + if err != nil { + log.Fatalf("Failed to decode network domain: %v", err) + } + + parsedDiscoveryProtocolID, err := hex.DecodeString(strings.TrimPrefix(ssvDiscoveryProtocolID, "0x")) + if err != nil { + log.Fatalf("Failed to decode discovery protocol ID: %v", err) + } + + var parsedDiscoveryProtocolIDArr [6]byte + if len(parsedDiscoveryProtocolID) != 0 { + parsedDiscoveryProtocolIDArr = [6]byte(parsedDiscoveryProtocolID) + } + + var bootnodes []string + if ssvBootnodes != "" { + bootnodes = strings.Split(ssvBootnodes, sliceSeparator) + } + + var config SSVConfig + config.Global.LogLevel = logLevel + config.DB.Path = dbPath + config.ConsensusClient.Address = consensusClient + config.ExecutionClient.Address = executionClient + config.P2P.Discovery = discovery + config.OperatorPrivateKey = operatorPrivateKey + config.MetricsAPIPort = metricsAPIPort + config.SSV.CustomNetwork = &networkconfig.SSVConfig{ + DomainType: spectypes.DomainType(parsedDomain), + RegistrySyncOffset: new(big.Int).SetUint64(ssvRegistrySyncOffset), + RegistryContractAddr: ethcommon.HexToAddress(ssvRegistryContractAddr), + Bootnodes: bootnodes, + DiscoveryProtocolID: parsedDiscoveryProtocolIDArr, + } + + data, err := yaml.Marshal(&config) + if err != nil { + log.Fatalf("Failed to marshal YAML: %v", err) + } + + err = os.WriteFile(outputPath, data, configFilePermissions) + if err != nil { + log.Fatalf("Failed to write file: %v", err) + } + + log.Printf("Saved config into '%s':", outputPath) + fmt.Println(string(data)) + }, +} + +func init() { + generateConfigCmd.Flags().StringVarP(&outputPath, "output-path", "o", defaultOutputPath, "Output path for generated config") + generateConfigCmd.Flags().StringVar(&logLevel, "log-level", defaultLogLevel, "Log level") + generateConfigCmd.Flags().StringVar(&dbPath, "db-path", defaultDBPath, "DB path") + generateConfigCmd.Flags().StringVar(&discovery, "discovery", defaultDiscovery, "Discovery") + generateConfigCmd.Flags().StringVar(&consensusClient, "consensus-client", "", "Consensus client (required)") + _ = generateConfigCmd.MarkFlagRequired("consensus-client") + generateConfigCmd.Flags().StringVar(&executionClient, "execution-client", "", "Execution client (required)") + _ = generateConfigCmd.MarkFlagRequired("execution-client") + generateConfigCmd.Flags().StringVar(&operatorPrivateKey, "operator-private-key", "", "Secret key") + generateConfigCmd.Flags().IntVar(&metricsAPIPort, "metrics-api-port", 0, "Metrics API port") + + ssvDomainDefault := "0x" + hex.EncodeToString(defaultNetwork.DomainType[:]) + generateConfigCmd.Flags().StringVar(&ssvDomain, "ssv-domain", ssvDomainDefault, "SSV domain type") + generateConfigCmd.Flags().Uint64Var(&ssvRegistrySyncOffset, "ssv-registry-sync-offset", defaultNetwork.RegistrySyncOffset.Uint64(), "SSV registry sync offset") + generateConfigCmd.Flags().StringVar(&ssvRegistryContractAddr, "ssv-registry-contract-addr", defaultNetwork.RegistryContractAddr.String(), "SSV registry contract addr") + generateConfigCmd.Flags().StringVar(&ssvBootnodes, "ssv-bootnodes", strings.Join(defaultNetwork.Bootnodes, sliceSeparator), "SSV bootnodes (comma-separated)") + ssvDiscoveryProtocolIDDefault := "0x" + hex.EncodeToString(defaultNetwork.DiscoveryProtocolID[:]) + generateConfigCmd.Flags().StringVar(&ssvDiscoveryProtocolID, "ssv-discovery-protocol-id", ssvDiscoveryProtocolIDDefault, "SSV discovery protocol ID") + + RootCmd.AddCommand(generateConfigCmd) +} diff --git a/cli/operator/node.go b/cli/operator/node.go index 8d7b23e62b..a08f4626f2 100644 --- a/cli/operator/node.go +++ b/cli/operator/node.go @@ -16,7 +16,6 @@ import ( "time" "github.com/attestantio/go-eth2-client/spec/phase0" - ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ilyakaznacheev/cleanenv" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -142,10 +141,23 @@ var StartNodeCmd = &cobra.Command{ } }() - networkConfig, err := setupSSVNetwork(logger) + ssvNetworkConfig, err := setupSSVNetwork(logger) if err != nil { logger.Fatal("could not setup network", zap.Error(err)) } + + consensusClient, err := goclient.New(cmd.Context(), logger, cfg.ConsensusClient) + if err != nil { + logger.Fatal("failed to create beacon go-client", zap.Error(err), + fields.Address(cfg.ConsensusClient.BeaconNodeAddr)) + } + + networkConfig := networkconfig.NetworkConfig{ + Name: cfg.SSVOptions.NetworkName, + SSVConfig: ssvNetworkConfig, + BeaconConfig: consensusClient.BeaconConfig(), + } + cfg.DBOptions.Ctx = cmd.Context() db, err := setupDB(logger, networkConfig) if err != nil { @@ -261,17 +273,7 @@ var StartNodeCmd = &cobra.Command{ } cfg.P2pNetworkConfig.Ctx = cmd.Context() - - slotTickerProvider := func() slotticker.SlotTicker { - return slotticker.New(logger, slotticker.Config{ - SlotDuration: networkConfig.SlotDuration, - GenesisTime: networkConfig.GenesisTime, - }) - } - - cfg.ConsensusClient.BeaconConfig = networkConfig.BeaconConfig operatorDataStore := setupOperatorDataStore(logger, nodeStorage, operatorPubKeyBase64) - consensusClient := setupConsensusClient(cmd.Context(), logger, slotTickerProvider) executionAddrList := strings.Split(cfg.ExecutionClient.Addr, ";") // TODO: Decide what symbol to use as a separator. Bootnodes are currently separated by ";". Deployment bot currently uses ",". if len(executionAddrList) == 0 { @@ -284,7 +286,7 @@ var StartNodeCmd = &cobra.Command{ ec, err := executionclient.New( cmd.Context(), executionAddrList[0], - ethcommon.HexToAddress(networkConfig.RegistryContractAddr), + ssvNetworkConfig.RegistryContractAddr, executionclient.WithLogger(logger), executionclient.WithFollowDistance(executionclient.DefaultFollowDistance), executionclient.WithConnectionTimeout(cfg.ExecutionClient.ConnectionTimeout), @@ -302,7 +304,7 @@ var StartNodeCmd = &cobra.Command{ ec, err := executionclient.NewMulti( cmd.Context(), executionAddrList, - ethcommon.HexToAddress(networkConfig.RegistryContractAddr), + ssvNetworkConfig.RegistryContractAddr, executionclient.WithLoggerMulti(logger), executionclient.WithFollowDistanceMulti(executionclient.DefaultFollowDistance), executionclient.WithConnectionTimeoutMulti(cfg.ExecutionClient.ConnectionTimeout), @@ -419,6 +421,13 @@ var StartNodeCmd = &cobra.Command{ storageMap.Add(storageRole, s) } + slotTickerProvider := func() slotticker.SlotTicker { + return slotticker.New(logger, slotticker.Config{ + SlotDuration: networkConfig.SlotDuration, + GenesisTime: networkConfig.GenesisTime, + }) + } + if cfg.SSVOptions.ValidatorOptions.Exporter { retain := cfg.SSVOptions.ValidatorOptions.ExporterRetainSlots threshold := cfg.SSVOptions.NetworkConfig.EstimatedCurrentSlot() @@ -704,7 +713,6 @@ func validateConfig(nodeStorage operatorstorage.Storage, networkName string, usi return fmt.Errorf("incompatible config change: %w", err) } } else { - if err := nodeStorage.SaveConfig(nil, currentConfig); err != nil { return fmt.Errorf("failed to store config: %w", err) } @@ -891,30 +899,41 @@ func ensureOperatorPubKey(nodeStorage operatorstorage.Storage, operatorPubKeyBas return nil } -func setupSSVNetwork(logger *zap.Logger) (networkconfig.NetworkConfig, error) { - networkConfig, err := networkconfig.GetNetworkConfigByName(cfg.SSVOptions.NetworkName) - if err != nil { - return networkconfig.NetworkConfig{}, err +func setupSSVNetwork(logger *zap.Logger) (networkconfig.SSVConfig, error) { + var ssvConfig networkconfig.SSVConfig + + if cfg.SSVOptions.CustomNetwork != nil { + ssvConfig = *cfg.SSVOptions.CustomNetwork + logger.Info("using custom network config") + } else if cfg.SSVOptions.NetworkName != "" { + snc, err := networkconfig.GetSSVConfigByName(cfg.SSVOptions.NetworkName) + if err != nil { + return ssvConfig, err + } + ssvConfig = snc + logger.Info("found network config by name", + zap.String("name", cfg.SSVOptions.NetworkName), + ) } if cfg.SSVOptions.CustomDomainType != "" { if !strings.HasPrefix(cfg.SSVOptions.CustomDomainType, "0x") { - return networkconfig.NetworkConfig{}, errors.New("custom domain type must be a hex string") + return networkconfig.SSVConfig{}, errors.New("custom domain type must be a hex string") } domainBytes, err := hex.DecodeString(cfg.SSVOptions.CustomDomainType[2:]) if err != nil { - return networkconfig.NetworkConfig{}, errors.Wrap(err, "failed to decode custom domain type") + return networkconfig.SSVConfig{}, errors.Wrap(err, "failed to decode custom domain type") } if len(domainBytes) != 4 { - return networkconfig.NetworkConfig{}, errors.New("custom domain type must be 4 bytes") + return networkconfig.SSVConfig{}, errors.New("custom domain type must be 4 bytes") } // https://github.com/ssvlabs/ssv/pull/1808 incremented the post-fork domain type by 1, so we have to maintain the compatibility. postForkDomain := binary.BigEndian.Uint32(domainBytes) + 1 - binary.BigEndian.PutUint32(networkConfig.DomainType[:], postForkDomain) + binary.BigEndian.PutUint32(ssvConfig.DomainType[:], postForkDomain) - logger.Info("running with custom domain type", - fields.Domain(networkConfig.DomainType), + logger.Warn("running with custom domain type; it's deprecated, consider using custom network instead", + fields.Domain(ssvConfig.DomainType), ) } @@ -924,14 +943,12 @@ func setupSSVNetwork(logger *zap.Logger) (networkconfig.NetworkConfig, error) { } logger.Info("setting ssv network", - fields.Network(networkConfig.Name), - fields.Domain(networkConfig.DomainType), + zap.Any("config", ssvConfig), zap.String("nodeType", nodeType), - zap.Any("beaconNetwork", networkConfig.GetBeaconName()), - zap.String("registryContract", networkConfig.RegistryContractAddr), + zap.String("registryContract", ssvConfig.RegistryContractAddr.String()), ) - return networkConfig, nil + return ssvConfig, nil } func setupP2P(logger *zap.Logger, db basedb.Database) network.P2PNetwork { @@ -949,20 +966,6 @@ func setupP2P(logger *zap.Logger, db basedb.Database) network.P2PNetwork { return n } -func setupConsensusClient( - ctx context.Context, - logger *zap.Logger, - slotTickerProvider slotticker.Provider, -) *goclient.GoClient { - cl, err := goclient.New(ctx, logger, cfg.ConsensusClient, slotTickerProvider) - if err != nil { - logger.Fatal("failed to create beacon go-client", zap.Error(err), - fields.Address(cfg.ConsensusClient.BeaconNodeAddr)) - } - - return cl -} - // syncContractEvents blocks until historical events are synced and then spawns a goroutine syncing ongoing events. func syncContractEvents( ctx context.Context, diff --git a/exporter/api/query_handlers_test.go b/exporter/api/query_handlers_test.go index 1f4b79a47f..e86cd246fd 100644 --- a/exporter/api/query_handlers_test.go +++ b/exporter/api/query_handlers_test.go @@ -105,7 +105,7 @@ func TestHandleDecidedQuery(t *testing.T) { for _, role := range roles { pk := sks[1].GetPublicKey() - networkConfig, err := networkconfig.GetNetworkConfigByName(networkconfig.HoleskyStage.Name) + ssvConfig, err := networkconfig.GetSSVConfigByName(networkconfig.HoleskyStage.Name) require.NoError(t, err) decided250Seq, err := protocoltesting.CreateMultipleStoredInstances(rsaKeys, specqbft.Height(0), specqbft.Height(250), func(height specqbft.Height) ([]spectypes.OperatorID, *specqbft.Message) { return oids, &specqbft.Message{ @@ -131,7 +131,7 @@ func TestHandleDecidedQuery(t *testing.T) { t.Run("valid range", func(t *testing.T) { nm := newParticipantsAPIMsg(pk.SerializeToHexStr(), spectypes.BNRoleAttester, 0, 250) h := NewHandler(l) - h.HandleParticipantsQuery(ibftStorage, nm, networkConfig.DomainType) + h.HandleParticipantsQuery(ibftStorage, nm, ssvConfig.DomainType) require.NotNil(t, nm.Msg.Data) msgs, ok := nm.Msg.Data.([]*ParticipantsAPI) @@ -142,7 +142,7 @@ func TestHandleDecidedQuery(t *testing.T) { t.Run("invalid range", func(t *testing.T) { nm := newParticipantsAPIMsg(pk.SerializeToHexStr(), spectypes.BNRoleAttester, 400, 404) h := NewHandler(l) - h.HandleParticipantsQuery(ibftStorage, nm, networkConfig.DomainType) + h.HandleParticipantsQuery(ibftStorage, nm, ssvConfig.DomainType) require.NotNil(t, nm.Msg.Data) data, ok := nm.Msg.Data.([]string) require.True(t, ok) @@ -152,7 +152,7 @@ func TestHandleDecidedQuery(t *testing.T) { t.Run("non-existing validator", func(t *testing.T) { nm := newParticipantsAPIMsg("xxx", spectypes.BNRoleAttester, 400, 404) h := NewHandler(l) - h.HandleParticipantsQuery(ibftStorage, nm, networkConfig.DomainType) + h.HandleParticipantsQuery(ibftStorage, nm, ssvConfig.DomainType) require.NotNil(t, nm.Msg.Data) errs, ok := nm.Msg.Data.([]string) require.True(t, ok) @@ -162,7 +162,7 @@ func TestHandleDecidedQuery(t *testing.T) { t.Run("non-existing role", func(t *testing.T) { nm := newParticipantsAPIMsg(pk.SerializeToHexStr(), math.MaxUint64, 0, 250) h := NewHandler(l) - h.HandleParticipantsQuery(ibftStorage, nm, networkConfig.DomainType) + h.HandleParticipantsQuery(ibftStorage, nm, ssvConfig.DomainType) require.NotNil(t, nm.Msg.Data) errs, ok := nm.Msg.Data.([]string) require.True(t, ok) @@ -172,7 +172,7 @@ func TestHandleDecidedQuery(t *testing.T) { t.Run("non-existing storage", func(t *testing.T) { nm := newParticipantsAPIMsg(pk.SerializeToHexStr(), spectypes.BNRoleSyncCommitteeContribution, 0, 250) h := NewHandler(l) - h.HandleParticipantsQuery(ibftStorage, nm, networkConfig.DomainType) + h.HandleParticipantsQuery(ibftStorage, nm, ssvConfig.DomainType) require.NotNil(t, nm.Msg.Data) errs, ok := nm.Msg.Data.([]string) require.True(t, ok) diff --git a/migrations/migration_4_configlock_add_alan_fork_to_network_name.go b/migrations/migration_4_configlock_add_alan_fork_to_network_name.go index 6a49712c01..03e99cc5f9 100644 --- a/migrations/migration_4_configlock_add_alan_fork_to_network_name.go +++ b/migrations/migration_4_configlock_add_alan_fork_to_network_name.go @@ -6,7 +6,6 @@ import ( "go.uber.org/zap" - "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/storage/basedb" ) @@ -27,12 +26,6 @@ var migration_4_configlock_add_alan_fork_to_network_name = Migration{ // If config is not found, it means the node is not initialized yet if found { - networkConfig, err := networkconfig.GetNetworkConfigByName(config.NetworkName) - if err != nil { - return fmt.Errorf("failed to get network config by name: %w", err) - } - - config.NetworkName = networkConfig.NetworkName() if err := nodeStorage.SaveConfig(txn, config); err != nil { return fmt.Errorf("failed to save config: %w", err) } diff --git a/networkconfig/beacon.go b/networkconfig/beacon.go index a520e70c2a..c014076bba 100644 --- a/networkconfig/beacon.go +++ b/networkconfig/beacon.go @@ -1,6 +1,7 @@ package networkconfig import ( + "encoding/json" "fmt" "math" "time" @@ -40,6 +41,15 @@ type BeaconConfig struct { GenesisTime time.Time } +func (b BeaconConfig) String() string { + marshaled, err := json.Marshal(b) + if err != nil { + panic(err) + } + + return string(marshaled) +} + // GetSlotStartTime returns the start time for the given slot func (b BeaconConfig) GetSlotStartTime(slot phase0.Slot) time.Time { if slot > math.MaxInt64 { diff --git a/networkconfig/holesky-e2e.go b/networkconfig/holesky-e2e.go index f464cc13cc..a879cca299 100644 --- a/networkconfig/holesky-e2e.go +++ b/networkconfig/holesky-e2e.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -18,7 +19,7 @@ var HoleskyE2E = NetworkConfig{ }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0xee, 0x1}, - RegistryContractAddr: "0x58410bef803ecd7e63b23664c586a6db72daf59c", + RegistryContractAddr: ethcommon.HexToAddress("0x58410bef803ecd7e63b23664c586a6db72daf59c"), RegistrySyncOffset: big.NewInt(405579), Bootnodes: []string{}, }, diff --git a/networkconfig/holesky-stage.go b/networkconfig/holesky-stage.go index 97aa69c291..a28cc3cf72 100644 --- a/networkconfig/holesky-stage.go +++ b/networkconfig/holesky-stage.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -19,7 +20,7 @@ var HoleskyStage = NetworkConfig{ SSVConfig: SSVConfig{ DomainType: [4]byte{0x00, 0x00, 0x31, 0x13}, RegistrySyncOffset: new(big.Int).SetInt64(84599), - RegistryContractAddr: "0x0d33801785340072C452b994496B19f196b7eE15", + RegistryContractAddr: ethcommon.HexToAddress("0x0d33801785340072C452b994496B19f196b7eE15"), DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, Bootnodes: []string{ // Public bootnode: diff --git a/networkconfig/holesky.go b/networkconfig/holesky.go index 4629c7ce34..801d9c3cad 100644 --- a/networkconfig/holesky.go +++ b/networkconfig/holesky.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -19,7 +20,7 @@ var Holesky = NetworkConfig{ SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x2}, RegistrySyncOffset: new(big.Int).SetInt64(181612), - RegistryContractAddr: "0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA", + RegistryContractAddr: ethcommon.HexToAddress("0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA"), DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, Bootnodes: []string{ // SSV Labs diff --git a/networkconfig/hoodi-stage.go b/networkconfig/hoodi-stage.go index e28511f599..42ffc5d917 100644 --- a/networkconfig/hoodi-stage.go +++ b/networkconfig/hoodi-stage.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -19,7 +20,7 @@ var HoodiStage = NetworkConfig{ SSVConfig: SSVConfig{ DomainType: [4]byte{0x00, 0x00, 0x31, 0x14}, RegistrySyncOffset: new(big.Int).SetInt64(1004), - RegistryContractAddr: "0x0aaace4e8affc47c6834171c88d342a4abd8f105", + RegistryContractAddr: ethcommon.HexToAddress("0x0aaace4e8affc47c6834171c88d342a4abd8f105"), DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, Bootnodes: []string{ // SSV Labs diff --git a/networkconfig/hoodi.go b/networkconfig/hoodi.go index 03799d694b..78f0263743 100644 --- a/networkconfig/hoodi.go +++ b/networkconfig/hoodi.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -19,7 +20,7 @@ var Hoodi = NetworkConfig{ SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x3}, RegistrySyncOffset: new(big.Int).SetInt64(1065), - RegistryContractAddr: "0x58410Bef803ECd7E63B23664C586A6DB72DAf59c", + RegistryContractAddr: ethcommon.HexToAddress("0x58410Bef803ECd7E63B23664C586A6DB72DAf59c"), DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, Bootnodes: []string{ // SSV Labs diff --git a/networkconfig/local-testnet.go b/networkconfig/local-testnet.go index bd94686743..eb998639f9 100644 --- a/networkconfig/local-testnet.go +++ b/networkconfig/local-testnet.go @@ -1,8 +1,10 @@ package networkconfig import ( + "math/big" "time" + ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -17,9 +19,11 @@ var LocalTestnet = NetworkConfig{ }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoV2NetworkID.Byte(), 0x2}, - RegistryContractAddr: "0xC3CD9A0aE89Fff83b71b58b6512D43F8a41f363D", + RegistrySyncOffset: new(big.Int).SetInt64(0), + RegistryContractAddr: ethcommon.HexToAddress("0xC3CD9A0aE89Fff83b71b58b6512D43F8a41f363D"), Bootnodes: []string{ "enr:-Li4QLR4Y1VbwiqFYKy6m-WFHRNDjhMDZ_qJwIABu2PY9BHjIYwCKpTvvkVmZhu43Q6zVA29sEUhtz10rQjDJkK3Hd-GAYiGrW2Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhCLdu_SJc2VjcDI1NmsxoQJTcI7GHPw-ZqIflPZYYDK_guurp_gsAFF5Erns3-PAvIN0Y3CCE4mDdWRwgg-h", }, + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, }, } diff --git a/networkconfig/mainnet.go b/networkconfig/mainnet.go index d82490ce27..1e475cd140 100644 --- a/networkconfig/mainnet.go +++ b/networkconfig/mainnet.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -19,7 +20,7 @@ var Mainnet = NetworkConfig{ SSVConfig: SSVConfig{ DomainType: spectypes.AlanMainnet, RegistrySyncOffset: new(big.Int).SetInt64(17507487), - RegistryContractAddr: "0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1", + RegistryContractAddr: ethcommon.HexToAddress("0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1"), DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, Bootnodes: []string{ // SSV Labs diff --git a/networkconfig/network.go b/networkconfig/network.go index e70bf5f839..cafc335ea1 100644 --- a/networkconfig/network.go +++ b/networkconfig/network.go @@ -7,27 +7,8 @@ import ( //go:generate go tool -modfile=../tool.mod mockgen -package=networkconfig -destination=./network_mock.go -source=./network.go -var SupportedConfigs = map[string]NetworkConfig{ - Mainnet.Name: Mainnet, - Holesky.Name: Holesky, - HoleskyStage.Name: HoleskyStage, - LocalTestnet.Name: LocalTestnet, - HoleskyE2E.Name: HoleskyE2E, - Hoodi.Name: Hoodi, - HoodiStage.Name: HoodiStage, - Sepolia.Name: Sepolia, -} - const forkName = "alan" -func GetNetworkConfigByName(name string) (NetworkConfig, error) { - if network, ok := SupportedConfigs[name]; ok { - return network, nil - } - - return NetworkConfig{}, fmt.Errorf("network not supported: %v", name) -} - type Network interface { NetworkName() string Beacon @@ -41,12 +22,12 @@ type NetworkConfig struct { } func (n NetworkConfig) String() string { - b, err := json.MarshalIndent(n, "", "\t") + jsonBytes, err := json.Marshal(n) if err != nil { - return "" + panic(err) } - return string(b) + return string(jsonBytes) } func (n NetworkConfig) NetworkName() string { diff --git a/networkconfig/sepolia.go b/networkconfig/sepolia.go index 49c0066177..02ea111d2e 100644 --- a/networkconfig/sepolia.go +++ b/networkconfig/sepolia.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -19,7 +20,7 @@ var Sepolia = NetworkConfig{ SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x69}, RegistrySyncOffset: new(big.Int).SetInt64(7795814), - RegistryContractAddr: "0x261419B48F36EdF420743E9f91bABF4856e76f99", + RegistryContractAddr: ethcommon.HexToAddress("0x261419B48F36EdF420743E9f91bABF4856e76f99"), DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, Bootnodes: []string{ // SSV Labs diff --git a/networkconfig/ssv.go b/networkconfig/ssv.go index 50ae99370e..61d3d18959 100644 --- a/networkconfig/ssv.go +++ b/networkconfig/ssv.go @@ -1,13 +1,36 @@ package networkconfig import ( + "encoding/json" + "fmt" "math/big" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" spectypes "github.com/ssvlabs/ssv-spec/types" ) //go:generate go tool -modfile=../tool.mod mockgen -package=networkconfig -destination=./ssv_mock.go -source=./ssv.go +var supportedSSVConfigs = map[string]SSVConfig{ + Mainnet.Name: Mainnet.SSVConfig, + Holesky.Name: Holesky.SSVConfig, + HoleskyStage.Name: HoleskyStage.SSVConfig, + LocalTestnet.Name: LocalTestnet.SSVConfig, + HoleskyE2E.Name: HoleskyE2E.SSVConfig, + Hoodi.Name: Hoodi.SSVConfig, + HoodiStage.Name: HoodiStage.SSVConfig, + Sepolia.Name: Sepolia.SSVConfig, +} + +func GetSSVConfigByName(name string) (SSVConfig, error) { + if network, ok := supportedSSVConfigs[name]; ok { + return network, nil + } + + return SSVConfig{}, fmt.Errorf("network not supported: %v", name) +} + type SSV interface { GetDomainType() spectypes.DomainType } @@ -15,11 +38,88 @@ type SSV interface { type SSVConfig struct { DomainType spectypes.DomainType RegistrySyncOffset *big.Int - RegistryContractAddr string // TODO: ethcommon.Address + RegistryContractAddr ethcommon.Address Bootnodes []string DiscoveryProtocolID [6]byte } -func (ssv SSVConfig) GetDomainType() spectypes.DomainType { - return ssv.DomainType +func (s SSVConfig) String() string { + marshaled, err := json.Marshal(s) + if err != nil { + panic(err) + } + + return string(marshaled) +} + +type marshaledConfig struct { + DomainType hexutil.Bytes `json:"DomainType,omitempty" yaml:"DomainType,omitempty"` + RegistrySyncOffset *big.Int `json:"RegistrySyncOffset,omitempty" yaml:"RegistrySyncOffset,omitempty"` + RegistryContractAddr ethcommon.Address `json:"RegistryContractAddr,omitempty" yaml:"RegistryContractAddr,omitempty"` + Bootnodes []string `json:"Bootnodes,omitempty" yaml:"Bootnodes,omitempty"` + DiscoveryProtocolID hexutil.Bytes `json:"DiscoveryProtocolID,omitempty" yaml:"DiscoveryProtocolID,omitempty"` +} + +// Helper method to avoid duplication between MarshalJSON and MarshalYAML +func (s SSVConfig) marshal() marshaledConfig { + aux := marshaledConfig{ + DomainType: s.DomainType[:], + RegistrySyncOffset: s.RegistrySyncOffset, + RegistryContractAddr: s.RegistryContractAddr, + Bootnodes: s.Bootnodes, + DiscoveryProtocolID: s.DiscoveryProtocolID[:], + } + + return aux +} + +func (s SSVConfig) MarshalJSON() ([]byte, error) { + return json.Marshal(s.marshal()) +} + +func (s SSVConfig) MarshalYAML() (interface{}, error) { + return s.marshal(), nil +} + +// Helper method to avoid duplication between UnmarshalJSON and UnmarshalYAML +func (s *SSVConfig) unmarshalFromConfig(aux marshaledConfig) error { + if len(aux.DomainType) != 4 { + return fmt.Errorf("invalid domain type length: expected 4 bytes, got %d", len(aux.DomainType)) + } + + if len(aux.DiscoveryProtocolID) != 6 { + return fmt.Errorf("invalid discovery protocol ID length: expected 6 bytes, got %d", len(aux.DiscoveryProtocolID)) + } + + *s = SSVConfig{ + DomainType: spectypes.DomainType(aux.DomainType), + RegistrySyncOffset: aux.RegistrySyncOffset, + RegistryContractAddr: aux.RegistryContractAddr, + Bootnodes: aux.Bootnodes, + DiscoveryProtocolID: [6]byte(aux.DiscoveryProtocolID), + } + + return nil +} + +func (s *SSVConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { + var aux marshaledConfig + if err := unmarshal(&aux); err != nil { + return err + } + + return s.unmarshalFromConfig(aux) +} + +func (s *SSVConfig) UnmarshalJSON(data []byte) error { + var aux marshaledConfig + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + + return s.unmarshalFromConfig(aux) +} + +func (s SSVConfig) GetDomainType() spectypes.DomainType { + return s.DomainType } diff --git a/networkconfig/ssv_test.go b/networkconfig/ssv_test.go new file mode 100644 index 0000000000..8872d6b4a3 --- /dev/null +++ b/networkconfig/ssv_test.go @@ -0,0 +1,232 @@ +package networkconfig + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "math/big" + "reflect" + "sort" + "testing" + + ethcommon "github.com/ethereum/go-ethereum/common" + spectypes "github.com/ssvlabs/ssv-spec/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" +) + +func TestSSVConfig_MarshalUnmarshalJSON(t *testing.T) { + // Create a sample SSVConfig + originalConfig := SSVConfig{ + DomainType: spectypes.DomainType{0x01, 0x02, 0x03, 0x04}, + RegistrySyncOffset: big.NewInt(123456), + RegistryContractAddr: ethcommon.HexToAddress("0x123456789abcdef0123456789abcdef012345678"), + Bootnodes: []string{"bootnode1", "bootnode2"}, + DiscoveryProtocolID: [6]byte{0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}, + } + + // Marshal to JSON + jsonBytes, err := json.Marshal(originalConfig) + require.NoError(t, err) + + // Unmarshal from JSON + var unmarshaledConfig SSVConfig + err = json.Unmarshal(jsonBytes, &unmarshaledConfig) + require.NoError(t, err) + + // Marshal again after unmarshaling + remarshaledBytes, err := json.Marshal(unmarshaledConfig) + require.NoError(t, err) + + // Compare the original and remarshaled JSON bytes + assert.JSONEq(t, string(jsonBytes), string(remarshaledBytes)) + + // Compare the original and unmarshaled structs + assert.Equal(t, originalConfig.DomainType, unmarshaledConfig.DomainType) + assert.Equal(t, originalConfig.RegistrySyncOffset.Int64(), unmarshaledConfig.RegistrySyncOffset.Int64()) + assert.Equal(t, originalConfig.RegistryContractAddr, unmarshaledConfig.RegistryContractAddr) + assert.Equal(t, originalConfig.Bootnodes, unmarshaledConfig.Bootnodes) + assert.Equal(t, originalConfig.DiscoveryProtocolID, unmarshaledConfig.DiscoveryProtocolID) +} + +func TestSSVConfig_MarshalUnmarshalYAML(t *testing.T) { + // Create a sample SSVConfig + originalConfig := SSVConfig{ + DomainType: spectypes.DomainType{0x01, 0x02, 0x03, 0x04}, + RegistrySyncOffset: big.NewInt(123456), + RegistryContractAddr: ethcommon.HexToAddress("0x123456789abcdef0123456789abcdef012345678"), + Bootnodes: []string{"bootnode1", "bootnode2"}, + DiscoveryProtocolID: [6]byte{0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}, + } + + // Marshal to YAML + yamlBytes, err := yaml.Marshal(originalConfig) + require.NoError(t, err) + + // Unmarshal from YAML + var unmarshaledConfig SSVConfig + err = yaml.Unmarshal(yamlBytes, &unmarshaledConfig) + require.NoError(t, err) + + // Marshal again after unmarshaling + remarshaledBytes, err := yaml.Marshal(unmarshaledConfig) + require.NoError(t, err) + + // Compare the original and unmarshaled structs + assert.Equal(t, originalConfig.DomainType, unmarshaledConfig.DomainType) + assert.Equal(t, originalConfig.RegistrySyncOffset.Int64(), unmarshaledConfig.RegistrySyncOffset.Int64()) + assert.Equal(t, originalConfig.RegistryContractAddr, unmarshaledConfig.RegistryContractAddr) + assert.Equal(t, originalConfig.Bootnodes, unmarshaledConfig.Bootnodes) + assert.Equal(t, originalConfig.DiscoveryProtocolID, unmarshaledConfig.DiscoveryProtocolID) + + // Compare the original and remarshaled YAML bytes + // YAML doesn't preserve order by default, so we need to compare the unmarshaled content + var originalYAMLMap map[string]interface{} + var remarshaledYAMLMap map[string]interface{} + + err = yaml.Unmarshal(yamlBytes, &originalYAMLMap) + require.NoError(t, err) + + err = yaml.Unmarshal(remarshaledBytes, &remarshaledYAMLMap) + require.NoError(t, err) + + assert.Equal(t, originalYAMLMap, remarshaledYAMLMap) +} + +// hashStructJSON creates a deterministic hash of a struct by marshaling to sorted JSON +func hashStructJSON(v interface{}) (string, error) { + // Create a JSON encoder that sorts map keys + buffer := &bytes.Buffer{} + encoder := json.NewEncoder(buffer) + encoder.SetIndent("", "") + encoder.SetEscapeHTML(false) + + if err := encoder.Encode(v); err != nil { + return "", err + } + + // Compute SHA-256 hash + hasher := sha256.New() + hasher.Write(buffer.Bytes()) + return hex.EncodeToString(hasher.Sum(nil)), nil +} + +// TestFieldPreservation ensures that all fields are properly preserved during +// marshal/unmarshal operations and that we can detect changes to the struct +func TestFieldPreservation(t *testing.T) { + t.Run("test all fields are present after marshaling", func(t *testing.T) { + // Get all field names from SSVConfig + configType := reflect.TypeOf(SSVConfig{}) + marshaledType := reflect.TypeOf(marshaledConfig{}) + + var configFields, marshaledFields []string + + for i := 0; i < configType.NumField(); i++ { + configFields = append(configFields, configType.Field(i).Name) + } + + for i := 0; i < marshaledType.NumField(); i++ { + marshaledFields = append(marshaledFields, marshaledType.Field(i).Name) + } + + // Sort fields for deterministic comparison + sort.Strings(configFields) + sort.Strings(marshaledFields) + + // Ensure the same fields exist in both structs + assert.Equal(t, configFields, marshaledFields, "SSVConfig and marshaledConfig should have the same fields") + }) + + t.Run("hash comparison JSON", func(t *testing.T) { + // Create a sample config + config := SSVConfig{ + DomainType: spectypes.DomainType{0x01, 0x02, 0x03, 0x04}, + RegistrySyncOffset: big.NewInt(123456), + RegistryContractAddr: ethcommon.HexToAddress("0x123456789abcdef0123456789abcdef012345678"), + Bootnodes: []string{"bootnode1", "bootnode2"}, + DiscoveryProtocolID: [6]byte{0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}, + } + + // Marshal and unmarshal to test preservation + jsonBytes, err := json.Marshal(config) + require.NoError(t, err) + + var unmarshaled SSVConfig + err = json.Unmarshal(jsonBytes, &unmarshaled) + require.NoError(t, err) + + // Hash the original and unmarshaled struct + originalHash, err := hashStructJSON(config) + require.NoError(t, err) + + unmarshaledHash, err := hashStructJSON(unmarshaled) + require.NoError(t, err) + + // The hashes should match if all fields are preserved + assert.Equal(t, originalHash, unmarshaledHash, "Hash mismatch indicates fields weren't properly preserved in JSON") + + // Store the expected hash - this will fail if a new field is added without updating the tests + expectedJSONHash := "3afe88f355185266dfd842df18a096ea8f40dd28f8b022710aedca1d09d59cef" + assert.Equal(t, expectedJSONHash, originalHash, + "Hash has changed. If you've added a new field, please update the expected hash in this test.") + }) + + t.Run("hash comparison YAML", func(t *testing.T) { + // Create a sample config + config := SSVConfig{ + DomainType: spectypes.DomainType{0x01, 0x02, 0x03, 0x04}, + RegistrySyncOffset: big.NewInt(123456), + RegistryContractAddr: ethcommon.HexToAddress("0x123456789abcdef0123456789abcdef012345678"), + Bootnodes: []string{"bootnode1", "bootnode2"}, + DiscoveryProtocolID: [6]byte{0x05, 0x06, 0x07, 0x08, 0x09, 0x0a}, + } + + // Marshal and unmarshal to test preservation + yamlBytes, err := yaml.Marshal(config) + require.NoError(t, err) + + var unmarshaled SSVConfig + err = yaml.Unmarshal(yamlBytes, &unmarshaled) + require.NoError(t, err) + + // For YAML, convert to JSON for consistent hashing + originalHash, err := hashStructJSON(config) + require.NoError(t, err) + + unmarshaledHash, err := hashStructJSON(unmarshaled) + require.NoError(t, err) + + // The hashes should match if all fields are preserved + assert.Equal(t, originalHash, unmarshaledHash, "Hash mismatch indicates fields weren't properly preserved in YAML") + }) +} + +// TestExistingNetworkConfigs validates that all predefined network configs +// can be marshaled and unmarshaled correctly +func TestExistingNetworkConfigs(t *testing.T) { + for networkName, config := range supportedSSVConfigs { + t.Run(networkName, func(t *testing.T) { + // JSON test + jsonBytes, err := json.Marshal(config) + require.NoError(t, err) + + var jsonUnmarshaled SSVConfig + err = json.Unmarshal(jsonBytes, &jsonUnmarshaled) + require.NoError(t, err) + + assert.Equal(t, config.DomainType, jsonUnmarshaled.DomainType) + + // YAML test + yamlBytes, err := yaml.Marshal(config) + require.NoError(t, err) + + var yamlUnmarshaled SSVConfig + err = yaml.Unmarshal(yamlBytes, &yamlUnmarshaled) + require.NoError(t, err) + + assert.Equal(t, config.DomainType, yamlUnmarshaled.DomainType) + }) + } +} diff --git a/networkconfig/test-network.go b/networkconfig/test-network.go index 9a3ee5ceff..34e6e6fac2 100644 --- a/networkconfig/test-network.go +++ b/networkconfig/test-network.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -19,7 +20,7 @@ var TestNetwork = NetworkConfig{ SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoNetworkID.Byte(), 0x2}, RegistrySyncOffset: new(big.Int).SetInt64(9015219), - RegistryContractAddr: "0x4B133c68A084B8A88f72eDCd7944B69c8D545f03", + RegistryContractAddr: ethcommon.HexToAddress("0x4B133c68A084B8A88f72eDCd7944B69c8D545f03"), Bootnodes: []string{ "enr:-Li4QFIQzamdvTxGJhvcXG_DFmCeyggSffDnllY5DiU47pd_K_1MRnSaJimWtfKJ-MD46jUX9TwgW5Jqe0t4pH41RYWGAYuFnlyth2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhCLdu_SJc2VjcDI1NmsxoQN4v-N9zFYwEqzGPBBX37q24QPFvAVUtokIo1fblIsmTIN0Y3CCE4uDdWRwgg-j", }, diff --git a/operator/node.go b/operator/node.go index 0fcf7f1225..278e812c73 100644 --- a/operator/node.go +++ b/operator/node.go @@ -26,9 +26,9 @@ import ( // Options contains options to create the node type Options struct { - // NetworkName is the network name of this node - NetworkName string `yaml:"Network" env:"NETWORK" env-default:"mainnet" env-description:"Ethereum network to connect to (mainnet, holesky, sepolia, etc.)"` - CustomDomainType string `yaml:"CustomDomainType" env:"CUSTOM_DOMAIN_TYPE" env-default:"" env-description:"Override SSV domain type for network isolation. Warning: Please modify only if you are certain of the implications. This would be incremented by 1 after Alan fork (e.g., 0x01020304 → 0x01020305 post-fork)"` + NetworkName string `yaml:"Network" env:"NETWORK" env-default:"mainnet" env-description:"Ethereum network to connect to (mainnet, holesky, sepolia, etc.). For backwards compatibility it's ignored if CustomNetwork is set"` + CustomNetwork *networkconfig.SSVConfig `yaml:"CustomNetwork" env:"CUSTOM_NETWORK" env-description:"Custom SSV network configuration"` + CustomDomainType string `yaml:"CustomDomainType" env:"CUSTOM_DOMAIN_TYPE" env-default:"" env-description:"Override SSV domain type for network isolation. Warning: Please modify only if you are certain of the implications. This would be incremented by 1 after Alan fork (e.g., 0x01020304 → 0x01020305 post-fork)"` // DEPRECATED: use CustomNetwork instead. NetworkConfig networkconfig.NetworkConfig BeaconNode beaconprotocol.BeaconNode // TODO: consider renaming to ConsensusClient ExecutionClient executionclient.Provider diff --git a/protocol/v2/blockchain/beacon/client.go b/protocol/v2/blockchain/beacon/client.go index 05c894898a..18dd29a6f4 100644 --- a/protocol/v2/blockchain/beacon/client.go +++ b/protocol/v2/blockchain/beacon/client.go @@ -11,8 +11,6 @@ import ( "github.com/attestantio/go-eth2-client/spec/bellatrix" "github.com/attestantio/go-eth2-client/spec/phase0" ssz "github.com/ferranbt/fastssz" - - "github.com/ssvlabs/ssv/networkconfig" ) // TODO: add missing tests @@ -142,7 +140,6 @@ type BeaconNode interface { // Options for controller struct creation type Options struct { Context context.Context - BeaconConfig networkconfig.BeaconConfig BeaconNodeAddr string `yaml:"BeaconNodeAddr" env:"BEACON_NODE_ADDR" env-required:"true" env-description:"Beacon node URL(s). Multiple nodes are supported via semicolon-separated URLs (e.g. 'http://localhost:5052;http://localhost:5053')"` SyncDistanceTolerance uint64 `yaml:"SyncDistanceTolerance" env:"BEACON_SYNC_DISTANCE_TOLERANCE" env-default:"4" env-description:"Maximum number of slots behind head considered in-sync"` WithWeightedAttestationData bool `yaml:"WithWeightedAttestationData" env:"WITH_WEIGHTED_ATTESTATION_DATA" env-default:"false" env-description:"Enable attestation data scoring across multiple beacon nodes"` diff --git a/utils/boot_node/node.go b/utils/boot_node/node.go index 77dca55ea0..6debfdd583 100644 --- a/utils/boot_node/node.go +++ b/utils/boot_node/node.go @@ -50,11 +50,11 @@ type bootNode struct { externalIP string tcpPort uint16 dbPath string - network networkconfig.NetworkConfig + ssvConfig networkconfig.SSVConfig } // New is the constructor of ssvNode -func New(logger *zap.Logger, networkConfig networkconfig.NetworkConfig, opts Options) (Node, error) { +func New(logger *zap.Logger, ssvConfig networkconfig.SSVConfig, opts Options) (Node, error) { return &bootNode{ logger: logger.Named(logging.NameBootNode), privateKey: opts.PrivateKey, @@ -63,7 +63,7 @@ func New(logger *zap.Logger, networkConfig networkconfig.NetworkConfig, opts Opt externalIP: opts.ExternalIP, tcpPort: opts.TCPPort, dbPath: opts.DbPath, - network: networkConfig, + ssvConfig: ssvConfig, }, nil } @@ -110,9 +110,9 @@ func (n *bootNode) Start(ctx context.Context) error { listener := n.createListener(ipAddr, n.discv5port, privKey) node := listener.LocalNode().Node() n.logger.Info("Running", - zap.String("node", node.String()), - zap.String("network", n.network.Name), - fields.ProtocolID(n.network.DiscoveryProtocolID), + zap.Stringer("node", node), + zap.Stringer("config", n.ssvConfig), + fields.ProtocolID(n.ssvConfig.DiscoveryProtocolID), ) handler := &handler{ @@ -171,7 +171,7 @@ func (n *bootNode) createListener(ipAddr string, port uint16, privateKey *ecdsa. listener, err := discover.ListenV5(conn, localNode, discover.Config{ PrivateKey: privateKey, - V5ProtocolID: &n.network.DiscoveryProtocolID, + V5ProtocolID: &n.ssvConfig.DiscoveryProtocolID, }) if err != nil { log.Fatal(err) From 7ce717ae9dadafd77aeeec47644926a732ee92b5 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 27 May 2025 10:32:47 -0300 Subject: [PATCH 24/34] update go.mod --- go.mod | 2 +- go.sum | 2 ++ ssvsigner/go.mod | 4 ++-- ssvsigner/go.sum | 3 +++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 91e265f902..0a50b7a2cc 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/spf13/cobra v1.8.1 github.com/ssvlabs/eth2-key-manager v1.5.5 github.com/ssvlabs/ssv-spec v1.1.3 - github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250512164336-eaf440d63581 + github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527132358-45464863718a github.com/status-im/keycard-go v0.2.0 github.com/stretchr/testify v1.9.0 github.com/wealdtech/go-eth2-types/v2 v2.8.1 diff --git a/go.sum b/go.sum index e6638377d9..d1ff79c833 100644 --- a/go.sum +++ b/go.sum @@ -758,6 +758,8 @@ github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250512164336-eaf440d63581 h1:BTh8A1s2HNIHrussld4QZTguuRO1tuqqkyvT+0kThpE= github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250512164336-eaf440d63581/go.mod h1:HkcbtVHpGBPnJjdWWd08Z3lv7l0VWejJU80yUUqY5Go= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527132358-45464863718a h1:3ITXI8KXYlhjrmxDgJlXV/NPp2lAXWXfVjj5Qt8dG7o= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527132358-45464863718a/go.mod h1:/Emoj7oqjC+r1rr5UYI4+XCqfw2/LXlutZCPInXpkx0= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/ssvsigner/go.mod b/ssvsigner/go.mod index b6e9853bcd..58a821de4a 100644 --- a/ssvsigner/go.mod +++ b/ssvsigner/go.mod @@ -25,8 +25,8 @@ require ( github.com/holiman/uint256 v1.3.2 github.com/microsoft/go-crypto-openssl v0.2.9 github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 - github.com/ssvlabs/eth2-key-manager v1.5.2 - github.com/ssvlabs/ssv v1.2.1-0.20250512164336-eaf440d63581 + github.com/ssvlabs/eth2-key-manager v1.5.5 + github.com/ssvlabs/ssv v1.2.1-0.20250527132358-45464863718a github.com/ssvlabs/ssv-spec v1.1.3 github.com/stretchr/testify v1.9.0 github.com/valyala/fasthttp v1.58.0 diff --git a/ssvsigner/go.sum b/ssvsigner/go.sum index 4a60f08b08..49e5bdbaed 100644 --- a/ssvsigner/go.sum +++ b/ssvsigner/go.sum @@ -322,8 +322,11 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/ssvlabs/eth2-key-manager v1.5.2 h1:gF+8FJkoV1VXpVCPspyVW/Jdky0kt9Pndk88W8ePqx8= github.com/ssvlabs/eth2-key-manager v1.5.2/go.mod h1:yeUzAP+SBJXgeXPiGBrLeLuHIQCpeJZV7Jz3Fwzm/zk= +github.com/ssvlabs/eth2-key-manager v1.5.5/go.mod h1:yeUzAP+SBJXgeXPiGBrLeLuHIQCpeJZV7Jz3Fwzm/zk= github.com/ssvlabs/ssv v1.2.1-0.20250512164336-eaf440d63581 h1:Tp0RSFcC70HFzCikFvLdnx8+xBTl2muZLERX9TGvmT8= github.com/ssvlabs/ssv v1.2.1-0.20250512164336-eaf440d63581/go.mod h1:BbVBaDhZhJqqeXYM18RUxebPVcdMTtxLVEs21uktSpg= +github.com/ssvlabs/ssv v1.2.1-0.20250527132358-45464863718a h1:quMN/FOHKACUsWZhuCfGSRuccak5dw/Nw9ZpI69mY+4= +github.com/ssvlabs/ssv v1.2.1-0.20250527132358-45464863718a/go.mod h1:/6NNYfzIHtxMQpmTRRQw2q0ej1NhVSf5Ds+JALkggAw= github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo8= github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= From 21e346ced09bac0f1b633f86218ff5a74e0322ef Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 27 May 2025 18:04:44 +0400 Subject: [PATCH 25/34] networkconfig: make hardcoded values configurable (#2164) * beacon/goclient: get beacon config from beacon node * use beacon config obtained from beacon node * log config as JSON * networkconfig: CLI for custom SSV config generation * implement JSON marshaling and YAML marshaling/unmarshaling * remove TotalEthereumValidators * simplify marshaling/unmarshaling logic * fix markdown formatting * use yaml@v3 * add tests * simplify unmarshaling * delete a comment * use Stringer to log node * guard beacon config reads with mutex * add a timeout log * delete hardcoded beacon configs * Revert "delete hardcoded beacon configs" This reverts commit c2e2f8f0124c0c65a088a3957fdeda4008f85bf2. * networkconfig: make hardcoded values configurable * fix issues after merging * code review comments * fix issues after merging * delete outer metrics for genesisForClient * rewrite modulo calculation * code review comments * unexport supportedSSVConfigs * revert the modulo calculation * add EpochDuration mock * G115 * fill missing fields in configs * add a comment about eth spec * fix error text * use genesis validators root from config in computeVoluntaryExitDomain * fix linter * fix a typo * remove redundant comments * fix a context bug * fix issues after merging * pass network config name --- beacon/goclient/aggregator.go | 10 +- beacon/goclient/signing.go | 10 +- beacon/goclient/spec.go | 93 ++++++++- .../goclient/sync_committee_contribution.go | 9 +- beacon/goclient/types.go | 8 +- message/validation/const.go | 1 - message/validation/partial_validation.go | 3 +- message/validation/validation.go | 4 +- network/topics/controller_test.go | 1 - network/topics/params/helpers.go | 4 - network/topics/params/message_rate.go | 179 +++++++++++------- network/topics/params/message_rate_test.go | 4 +- network/topics/params/peer_score.go | 23 +-- network/topics/params/scores_test.go | 11 +- network/topics/params/topic_score.go | 19 +- network/topics/pubsub.go | 3 +- network/topics/scoring.go | 4 +- networkconfig/beacon.go | 50 +++-- networkconfig/beacon_mock.go | 70 +++++-- networkconfig/holesky-e2e.go | 20 +- networkconfig/holesky-stage.go | 13 +- networkconfig/holesky.go | 20 +- networkconfig/hoodi-stage.go | 13 +- networkconfig/hoodi.go | 20 +- networkconfig/local-testnet.go | 22 ++- networkconfig/mainnet.go | 20 +- networkconfig/network_mock.go | 70 +++++-- networkconfig/sepolia.go | 17 +- networkconfig/ssv.go | 44 +++-- networkconfig/test-network.go | 20 +- operator/duties/committee_test.go | 6 +- operator/duties/scheduler.go | 8 +- operator/duties/scheduler_test.go | 4 +- operator/duties/sync_committee.go | 2 +- operator/duties/sync_committee_test.go | 4 +- operator/validator/controller.go | 2 +- utils/testutils.go | 4 + 37 files changed, 540 insertions(+), 275 deletions(-) diff --git a/beacon/goclient/aggregator.go b/beacon/goclient/aggregator.go index 9939a7309b..077eed75d2 100644 --- a/beacon/goclient/aggregator.go +++ b/beacon/goclient/aggregator.go @@ -30,7 +30,7 @@ func (gc *GoClient) SubmitAggregateSelectionProof( gc.waitToSlotTwoThirds(slot) // differ from spec because we need to subscribe to subnet - isAggregator := isAggregator(committeeLength, slotSig) + isAggregator := gc.isAggregator(committeeLength, slotSig) if !isAggregator { return nil, DataVersionNil, fmt.Errorf("validator is not an aggregator") } @@ -188,8 +188,8 @@ func (gc *GoClient) SubmitSignedAggregateSelectionProof( // committee = get_beacon_committee(state, slot, index) // modulo = max(1, len(committee) // TARGET_AGGREGATORS_PER_COMMITTEE) // return bytes_to_uint64(hash(slot_signature)[0:8]) % modulo == 0 -func isAggregator(committeeCount uint64, slotSig []byte) bool { - modulo := committeeCount / TargetAggregatorsPerCommittee +func (gc *GoClient) isAggregator(committeeCount uint64, slotSig []byte) bool { + modulo := committeeCount / gc.beaconConfig.TargetAggregatorsPerCommittee if modulo == 0 { // Modulo must be at least 1. modulo = 1 @@ -202,8 +202,8 @@ func isAggregator(committeeCount uint64, slotSig []byte) bool { // waitToSlotTwoThirds waits until two-third of the slot has transpired (SECONDS_PER_SLOT * 2 / 3 seconds after slot start time) func (gc *GoClient) waitToSlotTwoThirds(slot phase0.Slot) { config := gc.getBeaconConfig() - oneThird := config.SlotDuration / 3 /* one third of slot duration */ - finalTime := config.GetSlotStartTime(slot).Add(2 * oneThird) + oneInterval := config.IntervalDuration() + finalTime := config.GetSlotStartTime(slot).Add(2 * oneInterval) wait := time.Until(finalTime) if wait <= 0 { return diff --git a/beacon/goclient/signing.go b/beacon/goclient/signing.go index 570d027c74..5c00ce6828 100644 --- a/beacon/goclient/signing.go +++ b/beacon/goclient/signing.go @@ -48,16 +48,10 @@ func (gc *GoClient) computeVoluntaryExitDomain(ctx context.Context) (phase0.Doma } forkData := &phase0.ForkData{ - CurrentVersion: forkVersion, + CurrentVersion: forkVersion, + GenesisValidatorsRoot: gc.getBeaconConfig().GenesisValidatorsRoot, } - genesis, err := gc.Genesis(ctx) - if err != nil { - return phase0.Domain{}, fmt.Errorf("failed to obtain genesis response: %w", err) - } - - forkData.GenesisValidatorsRoot = genesis.GenesisValidatorsRoot - root, err := forkData.HashTreeRoot() if err != nil { return phase0.Domain{}, fmt.Errorf("failed to calculate signature domain, err: %w", err) diff --git a/beacon/goclient/spec.go b/beacon/goclient/spec.go index 5874ed350a..02f3809edd 100644 --- a/beacon/goclient/spec.go +++ b/beacon/goclient/spec.go @@ -15,8 +15,14 @@ import ( ) const ( - DefaultSlotDuration = 12 * time.Second - DefaultSlotsPerEpoch = uint64(32) + DefaultSlotDuration = 12 * time.Second + DefaultSlotsPerEpoch = uint64(32) + DefaultEpochsPerSyncCommitteePeriod = uint64(256) + DefaultSyncCommitteeSize = uint64(512) + DefaultSyncCommitteeSubnetCount = uint64(4) + DefaultTargetAggregatorsPerSyncSubcommittee = uint64(16) + DefaultTargetAggregatorsPerCommittee = uint64(16) + DefaultIntervalsPerSlot = uint64(3) ) // BeaconConfig returns the network Beacon configuration @@ -39,7 +45,7 @@ func (gc *GoClient) fetchBeaconConfig(ctx context.Context, client *eth2clienthtt networkNameRaw, ok := specResponse["CONFIG_NAME"] if !ok { - return networkconfig.BeaconConfig{}, fmt.Errorf("config name not known by chain") + return networkconfig.BeaconConfig{}, fmt.Errorf("config name wasn't found in beacon node response") } networkName, ok := networkNameRaw.(string) @@ -52,7 +58,7 @@ func (gc *GoClient) fetchBeaconConfig(ctx context.Context, client *eth2clienthtt if slotDurationDecoded, ok := slotDurationRaw.(time.Duration); ok { slotDuration = slotDurationDecoded } else { - gc.log.Warn("seconds per slot not known by chain, using default value", + gc.log.Warn("seconds per slot wasn't found in beacon node response, using default value", zap.Any("value", slotDuration)) } } @@ -62,11 +68,71 @@ func (gc *GoClient) fetchBeaconConfig(ctx context.Context, client *eth2clienthtt if slotsPerEpochDecoded, ok := slotsPerEpochRaw.(uint64); ok { slotsPerEpoch = slotsPerEpochDecoded } else { - gc.log.Warn("slots per epoch not known by chain, using default value", + gc.log.Warn("slots per epoch wasn't found in beacon node response, using default value", zap.Uint64("value", slotsPerEpoch)) } } + epochsPerSyncCommitteePeriod := DefaultEpochsPerSyncCommitteePeriod + if epochsPerSyncCommitteePeriodRaw, ok := specResponse["EPOCHS_PER_SYNC_COMMITTEE_PERIOD"]; ok { + if epochsPerSyncCommitteePeriodDecoded, ok := epochsPerSyncCommitteePeriodRaw.(uint64); ok { + epochsPerSyncCommitteePeriod = epochsPerSyncCommitteePeriodDecoded + } else { + gc.log.Warn("epochs per sync committee wasn't found in beacon node response, using default value", + zap.Any("value", epochsPerSyncCommitteePeriod)) + } + } + + syncCommitteeSize := DefaultSyncCommitteeSize + if syncCommitteeSizeRaw, ok := specResponse["SYNC_COMMITTEE_SIZE"]; ok { + if syncCommitteeSizeDecoded, ok := syncCommitteeSizeRaw.(uint64); ok { + syncCommitteeSize = syncCommitteeSizeDecoded + } else { + gc.log.Warn("sync committee size wasn't found in beacon node response, using default value", + zap.Any("value", syncCommitteeSize)) + } + } + + targetAggregatorsPerCommittee := DefaultTargetAggregatorsPerCommittee + if targetAggregatorsPerCommitteeRaw, ok := specResponse["TARGET_AGGREGATORS_PER_COMMITTEE"]; ok { + if targetAggregatorsPerCommitteeDecoded, ok := targetAggregatorsPerCommitteeRaw.(uint64); ok { + targetAggregatorsPerCommittee = targetAggregatorsPerCommitteeDecoded + } else { + gc.log.Warn("target aggregators per committee wasn't found in beacon node response, using default value", + zap.Any("value", targetAggregatorsPerCommittee)) + } + } + + targetAggregatorsPerSyncSubcommittee := DefaultTargetAggregatorsPerSyncSubcommittee + if targetAggregatorsPerSyncSubcommitteeRaw, ok := specResponse["TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE"]; ok { + if targetAggregatorsPerSyncSubcommitteeDecoded, ok := targetAggregatorsPerSyncSubcommitteeRaw.(uint64); ok { + targetAggregatorsPerSyncSubcommittee = targetAggregatorsPerSyncSubcommitteeDecoded + } else { + gc.log.Warn("target aggregators per sync subcommittee wasn't found in beacon node response, using default value", + zap.Any("value", targetAggregatorsPerSyncSubcommittee)) + } + } + + intervalsPerSlot := DefaultIntervalsPerSlot + if intervalsPerSlotRaw, ok := specResponse["INTERVALS_PER_SLOT"]; ok { + if intervalsPerSlotDecoded, ok := intervalsPerSlotRaw.(uint64); ok { + intervalsPerSlot = intervalsPerSlotDecoded + } else { + gc.log.Warn("intervals per slot wasn't found in beacon node response, using default value", + zap.Any("value", intervalsPerSlot)) + } + } + + syncCommitteeSubnetCount := DefaultSyncCommitteeSubnetCount + if syncCommitteeSubnetCountRaw, ok := specResponse["SYNC_COMMITTEE_SUBNET_COUNT"]; ok { + if syncCommitteeSubnetCountDecoded, ok := syncCommitteeSubnetCountRaw.(uint64); ok { + syncCommitteeSubnetCount = syncCommitteeSubnetCountDecoded + } else { + gc.log.Warn("sync committee subnet count wasn't found in beacon node response, using default value", + zap.Any("value", syncCommitteeSubnetCount)) + } + } + genesisResponse, err := genesisForClient(ctx, gc.log, client) if err != nil { gc.log.Error(clResponseErrMsg, zap.String("api", "Genesis"), zap.Error(err)) @@ -74,11 +140,18 @@ func (gc *GoClient) fetchBeaconConfig(ctx context.Context, client *eth2clienthtt } beaconConfig := networkconfig.BeaconConfig{ - BeaconName: networkName, - SlotDuration: slotDuration, - SlotsPerEpoch: slotsPerEpoch, - ForkVersion: genesisResponse.GenesisForkVersion, - GenesisTime: genesisResponse.GenesisTime, + BeaconName: networkName, + SlotDuration: slotDuration, + SlotsPerEpoch: slotsPerEpoch, + EpochsPerSyncCommitteePeriod: epochsPerSyncCommitteePeriod, + SyncCommitteeSize: syncCommitteeSize, + SyncCommitteeSubnetCount: syncCommitteeSubnetCount, + TargetAggregatorsPerSyncSubcommittee: targetAggregatorsPerSyncSubcommittee, + TargetAggregatorsPerCommittee: targetAggregatorsPerCommittee, + IntervalsPerSlot: intervalsPerSlot, + ForkVersion: genesisResponse.GenesisForkVersion, + GenesisTime: genesisResponse.GenesisTime, + GenesisValidatorsRoot: genesisResponse.GenesisValidatorsRoot, } return beaconConfig, nil diff --git a/beacon/goclient/sync_committee_contribution.go b/beacon/goclient/sync_committee_contribution.go index 2e43ae4634..0a50bfcaf5 100644 --- a/beacon/goclient/sync_committee_contribution.go +++ b/beacon/goclient/sync_committee_contribution.go @@ -24,7 +24,10 @@ func (gc *GoClient) IsSyncCommitteeAggregator(proof []byte) bool { hash := sha256.Sum256(proof) // Keep the signature if it's an aggregator. - modulo := SyncCommitteeSize / SyncCommitteeSubnetCount / TargetAggregatorsPerSyncSubcommittee + cfg := gc.BeaconConfig() + + // as per spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/validator.md#aggregation-selection + modulo := cfg.SyncCommitteeSize / cfg.SyncCommitteeSubnetCount / cfg.TargetAggregatorsPerSyncSubcommittee if modulo == uint64(0) { // Modulo must be at least 1. modulo = 1 @@ -34,7 +37,7 @@ func (gc *GoClient) IsSyncCommitteeAggregator(proof []byte) bool { // SyncCommitteeSubnetID returns sync committee subnet ID from subcommittee index func (gc *GoClient) SyncCommitteeSubnetID(index phase0.CommitteeIndex) uint64 { - return uint64(index) / (SyncCommitteeSize / SyncCommitteeSubnetCount) + return uint64(index) / (gc.BeaconConfig().SyncCommitteeSize / gc.BeaconConfig().SyncCommitteeSubnetCount) } // GetSyncCommitteeContribution returns @@ -154,7 +157,7 @@ func (gc *GoClient) SubmitSignedContributionAndProof( // waitForOneThirdSlotDuration waits until one-third of the slot has transpired (SECONDS_PER_SLOT / 3 seconds after slot start time) func (gc *GoClient) waitForOneThirdSlotDuration(slot phase0.Slot) { config := gc.getBeaconConfig() - delay := config.SlotDuration / 3 /* a third of the slot duration */ + delay := config.IntervalDuration() finalTime := config.GetSlotStartTime(slot).Add(delay) wait := time.Until(finalTime) if wait <= 0 { diff --git a/beacon/goclient/types.go b/beacon/goclient/types.go index 9589c2a87c..28a4325674 100644 --- a/beacon/goclient/types.go +++ b/beacon/goclient/types.go @@ -7,12 +7,6 @@ import ( ) var ( - SyncCommitteeSize uint64 = 512 - SyncCommitteeSubnetCount uint64 = 4 - TargetAggregatorsPerSyncSubcommittee uint64 = 16 - EpochsPerSyncCommitteePeriod uint64 = 256 - TargetAggregatorsPerCommittee uint64 = 16 // FarFutureEpoch is the null representation of an epoch. - FarFutureEpoch phase0.Epoch = math.MaxUint64 - IntervalsPerSlot uint64 = 3 + FarFutureEpoch phase0.Epoch = math.MaxUint64 ) diff --git a/message/validation/const.go b/message/validation/const.go index 4efaee7d25..1f40abfc7d 100644 --- a/message/validation/const.go +++ b/message/validation/const.go @@ -14,7 +14,6 @@ const ( allowedRoundsInFuture = 1 allowedRoundsInPast = 2 LateSlotAllowance = 2 - syncCommitteeSize = 512 rsaSignatureSize = 256 operatorIDSize = 8 // uint64 slotSize = 8 // uint64 diff --git a/message/validation/partial_validation.go b/message/validation/partial_validation.go index a298427a6c..cb6f8300ed 100644 --- a/message/validation/partial_validation.go +++ b/message/validation/partial_validation.go @@ -197,7 +197,8 @@ func (mv *messageValidator) validatePartialSigMessagesByDutyLogic( if signedSSVMessage.SSVMessage.MsgID.GetRoleType() == spectypes.RoleCommittee { // Rule: The number of signatures must be <= min(2*V, V + SYNC_COMMITTEE_SIZE) where V is the number of validators assigned to the cluster - if partialSignatureMessageCount > min(2*clusterValidatorCount, clusterValidatorCount+syncCommitteeSize) { + // #nosec G115 + if partialSignatureMessageCount > min(2*clusterValidatorCount, clusterValidatorCount+int(mv.netCfg.GetSyncCommitteeSize())) { return ErrTooManyPartialSignatureMessages } diff --git a/message/validation/validation.go b/message/validation/validation.go index 90968a5f7a..c5e330dc54 100644 --- a/message/validation/validation.go +++ b/message/validation/validation.go @@ -246,7 +246,6 @@ func (mv *messageValidator) getValidationLock(key peerIDWithMessageID) *sync.Mut lock := &sync.Mutex{} - epochDuration := time.Duration(mv.netCfg.GetSlotsPerEpoch()) * mv.netCfg.GetSlotDuration() // #nosec G115 - slots per epoch never exceeds math.MaxInt64 // validationLockTTL specifies how much time a particular validation lock is meant to // live. It must be large enough for validation lock to never expire while we still are // expecting to process messages targeting that same validation lock. For a message @@ -255,8 +254,7 @@ func (mv *messageValidator) getValidationLock(key peerIDWithMessageID) *sync.Mut // be allowed to take place). // 2 epoch duration is a safe TTL to use - message validation will reject processing // for any message older than that. - validationLockTTL := 2 * epochDuration - mv.validationLockCache.Set(key, lock, validationLockTTL) + mv.validationLockCache.Set(key, lock, 2*mv.netCfg.EpochDuration()) return lock, nil }) diff --git a/network/topics/controller_test.go b/network/topics/controller_test.go index 6e03c5b23d..8e7a40b28b 100644 --- a/network/topics/controller_test.go +++ b/network/topics/controller_test.go @@ -399,7 +399,6 @@ func newPeer(ctx context.Context, logger *zap.Logger, t *testing.T, msgValidator Scoring: &topics.ScoringConfig{ IPWhitelist: nil, IPColocationWeight: 0, - OneEpochDuration: time.Minute, }, MsgValidator: msgValidator, ScoreInspector: scoreInspector, diff --git a/network/topics/params/helpers.go b/network/topics/params/helpers.go index cbbd47f502..e6efe59f65 100644 --- a/network/topics/params/helpers.go +++ b/network/topics/params/helpers.go @@ -7,10 +7,6 @@ import ( "github.com/pkg/errors" ) -const ( - oneEpochDuration = (12 * time.Second) * 32 -) - // scoreDecay determines the decay rate from the provided time period till // the decayToZero value. Ex: ( 1 -> 0.01) func scoreDecay(totalDecayDuration time.Duration, decayIntervalDuration time.Duration) float64 { diff --git a/network/topics/params/message_rate.go b/network/topics/params/message_rate.go index a64f4a07d8..66e3d53b0d 100644 --- a/network/topics/params/message_rate.go +++ b/network/topics/params/message_rate.go @@ -2,49 +2,79 @@ package params import ( "math" + "time" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/registry/storage" ) -// Ethereum parameters +// Threshold and limit parameters const ( - EthereumValidators = 1000000.0 // TODO: get from network? - SyncCommitteeSize = 512.0 // TODO: get from network? - EstimatedAttestationCommitteeSize = EthereumValidators / 2048.0 - AggregatorProbability = 16.0 / EstimatedAttestationCommitteeSize - ProposalProbability = 1.0 / EthereumValidators - SyncCommitteeProbability = SyncCommitteeSize / EthereumValidators - SyncCommitteeAggProb = SyncCommitteeProbability * 16.0 / (SyncCommitteeSize / 4.0) - MaxValidatorsPerCommittee = 560.0 - SlotsPerEpoch = 32.0 // TODO: get from network? - MaxAttestationDutiesPerEpochForCommittee = SlotsPerEpoch - SingleSCDutiesLimit = 0 + // SingleSCDutiesLimit represents the limit of the number of committee duties in an epoch + // with only sync committee beacon duties (no attestation) taken for a very big number of validators. + // To help reasoning it, note that for a very big number of validators all slots in the epoch + // will have an attestation with high probability and, thus, + // the committee duties with only sync committee beacon duties tends to 0. + SingleSCDutiesLimit = 0 + // MaxValidatorsPerCommitteeListCut serves as a threshold size for creating a cache + // that computes the expected number of duties given a committee size. + // For each committee size, we can compute the precise expected number of duties. + // However, for big enough committees (considered as bigger than the following constant), + // results are pretty much the same. So we create a list of const values only up to the following value. + // For values that exceed it, the function shall return a default limit answer + // (e.g. number of committees duties per epoch -> 32). + // TODO: It depends on duties per epoch, 32 duties per epoch maps to MaxValidatorsPerCommitteeListCut=560. If the value of duties per epoch changes, this value needs to be adjusted (need to run Monte Carlo simulation for that number). + MaxValidatorsPerCommitteeListCut = 560 ) -// Expected number of messages per duty step - -func consensusMessages(n int) int { - return 1 + n + n + 2 // 1 Proposal + n Prepares + n Commits + 2 Decideds (average) +type rateCalculator struct { + netCfg networkconfig.NetworkConfig + generatedExpectedNumberOfCommitteeDutiesPerEpochDueToAttestation []float64 + generatedExpectedSingleSCCommitteeDutiesPerEpoch []float64 } -func partialSignatureMessages(n int) int { - return n -} +func newRateCalculator(netCfg networkconfig.NetworkConfig) *rateCalculator { + rc := &rateCalculator{ + netCfg: netCfg, + generatedExpectedNumberOfCommitteeDutiesPerEpochDueToAttestation: []float64{}, + generatedExpectedSingleSCCommitteeDutiesPerEpoch: []float64{}, + } -func dutyWithPreConsensus(n int) int { - // Pre-Consensus + Consensus + Post-Consensus - return partialSignatureMessages(n) + consensusMessages(n) + partialSignatureMessages(n) + rc.generateCachedValues() + + return rc } -func dutyWithoutPreConsensus(n int) int { - // Consensus + Post-Consensus - return consensusMessages(n) + partialSignatureMessages(n) +// Calculates the message rate for a topic given its committees' configurations (number of operators and number of validators) +func (rc *rateCalculator) calculateMessageRateForTopic(committees []*storage.Committee) float64 { + if len(committees) == 0 { + return 0 + } + + totalMsgRate := 0.0 + + for _, committee := range committees { + committeeSize := len(committee.Operators) + numValidators := len(committee.Validators) + + totalMsgRate += rc.expectedNumberOfCommitteeDutiesPerEpochDueToAttestationCached(numValidators) * float64(dutyWithoutPreConsensus(committeeSize)) + totalMsgRate += rc.expectedSingleSCCommitteeDutiesPerEpochCached(numValidators) * float64(dutyWithoutPreConsensus(committeeSize)) + totalMsgRate += float64(numValidators) * rc.AggregatorProbability() * float64(dutyWithPreConsensus(committeeSize)) + totalMsgRate += float64(numValidators) * float64(rc.netCfg.GetSlotsPerEpoch()) * rc.ProposalProbability() * float64(dutyWithPreConsensus(committeeSize)) + totalMsgRate += float64(numValidators) * float64(rc.netCfg.GetSlotsPerEpoch()) * rc.SyncCommitteeAggProb() * float64(dutyWithPreConsensus(committeeSize)) + } + + // Convert rate to seconds + totalEpochSeconds := float64(rc.netCfg.EpochDuration() / time.Second) + totalMsgRate = totalMsgRate / totalEpochSeconds + + return totalMsgRate } // Expected number of committee duties per epoch due to attestations -func expectedNumberOfCommitteeDutiesPerEpochDueToAttestation(numValidators int) float64 { +func (rc *rateCalculator) calcExpectedNumberOfCommitteeDutiesPerEpochDueToAttestation(numValidators int) float64 { k := float64(numValidators) - n := SlotsPerEpoch + n := float64(rc.netCfg.GetSlotsPerEpoch()) // Probability that all validators are not assigned to slot i probabilityAllNotOnSlotI := math.Pow((n-1)/n, k) @@ -59,77 +89,94 @@ func expectedNumberOfCommitteeDutiesPerEpochDueToAttestation(numValidators int) } // Expected committee duties per epoch that are due to only sync committee beacon duties -func expectedSingleSCCommitteeDutiesPerEpoch(numValidators int) float64 { +func (rc *rateCalculator) calcExpectedSingleSCCommitteeDutiesPerEpoch(numValidators int) float64 { // Probability that a validator is not in sync committee - chanceOfNotBeingInSyncCommittee := 1.0 - SyncCommitteeProbability + chanceOfNotBeingInSyncCommittee := 1.0 - rc.SyncCommitteeProbability() // Probability that all validators are not in sync committee chanceThatAllValidatorsAreNotInSyncCommittee := math.Pow(chanceOfNotBeingInSyncCommittee, float64(numValidators)) // Probability that at least one validator is in sync committee chanceOfAtLeastOneValidatorBeingInSyncCommittee := 1.0 - chanceThatAllValidatorsAreNotInSyncCommittee // Expected number of slots with no attestation duty - expectedSlotsWithNoDuty := 32.0 - expectedNumberOfCommitteeDutiesPerEpochDueToAttestationCached(numValidators) + expectedSlotsWithNoDuty := 32.0 - rc.calcExpectedNumberOfCommitteeDutiesPerEpochDueToAttestation(numValidators) // Expected number of committee duties per epoch created due to only sync committee duties return chanceOfAtLeastOneValidatorBeingInSyncCommittee * expectedSlotsWithNoDuty } -// Cache costly calculations +func (rc *rateCalculator) generateCachedValues() { + // Cache costly calculations -func generateCachedValues(generator func(int) float64, threshold int) []float64 { - results := make([]float64, 0, threshold) + expectedCommNumber := make([]float64, 0, MaxValidatorsPerCommitteeListCut) + expectedSingleSCC := make([]float64, 0, MaxValidatorsPerCommitteeListCut) - for i := 0; i < threshold; i++ { - results = append(results, generator(i)) + for i := 0; i < MaxValidatorsPerCommitteeListCut; i++ { + expectedCommNumber = append(expectedCommNumber, rc.calcExpectedNumberOfCommitteeDutiesPerEpochDueToAttestation(i)) + expectedSingleSCC = append(expectedSingleSCC, rc.calcExpectedSingleSCCommitteeDutiesPerEpoch(i)) } - return results + rc.generatedExpectedNumberOfCommitteeDutiesPerEpochDueToAttestation = expectedCommNumber + rc.generatedExpectedSingleSCCommitteeDutiesPerEpoch = expectedSingleSCC } -var generatedExpectedNumberOfCommitteeDutiesPerEpochDueToAttestation = generateCachedValues(expectedNumberOfCommitteeDutiesPerEpochDueToAttestation, MaxValidatorsPerCommittee) - -func expectedNumberOfCommitteeDutiesPerEpochDueToAttestationCached(numValidators int) float64 { +func (rc *rateCalculator) expectedNumberOfCommitteeDutiesPerEpochDueToAttestationCached(numValidators int) float64 { // If the committee has more validators than our computed cache, we return the limit value - if numValidators >= MaxValidatorsPerCommittee { - return MaxAttestationDutiesPerEpochForCommittee + if numValidators >= MaxValidatorsPerCommitteeListCut { + return float64(rc.MaxAttestationDutiesPerEpochForCommittee()) } - return generatedExpectedNumberOfCommitteeDutiesPerEpochDueToAttestation[numValidators] + return rc.generatedExpectedNumberOfCommitteeDutiesPerEpochDueToAttestation[numValidators] } -var generatedExpectedSingleSCCommitteeDutiesPerEpoch = generateCachedValues(expectedSingleSCCommitteeDutiesPerEpoch, MaxValidatorsPerCommittee) - -func expectedSingleSCCommitteeDutiesPerEpochCached(numValidators int) float64 { +func (rc *rateCalculator) expectedSingleSCCommitteeDutiesPerEpochCached(numValidators int) float64 { // If the committee has more validators than our computed cache, we return the limit value - if numValidators >= MaxValidatorsPerCommittee { + if numValidators >= MaxValidatorsPerCommitteeListCut { return SingleSCDutiesLimit } - return generatedExpectedSingleSCCommitteeDutiesPerEpoch[numValidators] + return rc.generatedExpectedSingleSCCommitteeDutiesPerEpoch[numValidators] } -// Calculates the message rate for a topic given its committees' configurations (number of operators and number of validators) -func calculateMessageRateForTopic(committees []*storage.Committee) float64 { - if len(committees) == 0 { - return 0 - } +func (rc *rateCalculator) AggregatorProbability() float64 { + return 16.0 / rc.EstimatedAttestationCommitteeSize() +} - totalMsgRate := 0.0 +func (rc *rateCalculator) ProposalProbability() float64 { + return 1.0 / float64(rc.netCfg.TotalEthereumValidators) +} - for _, committee := range committees { - committeeSize := len(committee.Operators) - numValidators := len(committee.Validators) +func (rc *rateCalculator) SyncCommitteeProbability() float64 { + return float64(rc.netCfg.GetSyncCommitteeSize()) / float64(rc.netCfg.TotalEthereumValidators) +} - totalMsgRate += expectedNumberOfCommitteeDutiesPerEpochDueToAttestationCached(numValidators) * float64(dutyWithoutPreConsensus(committeeSize)) - totalMsgRate += expectedSingleSCCommitteeDutiesPerEpochCached(numValidators) * float64(dutyWithoutPreConsensus(committeeSize)) - totalMsgRate += float64(numValidators) * AggregatorProbability * float64(dutyWithPreConsensus(committeeSize)) - totalMsgRate += float64(numValidators) * SlotsPerEpoch * ProposalProbability * float64(dutyWithPreConsensus(committeeSize)) - totalMsgRate += float64(numValidators) * SlotsPerEpoch * SyncCommitteeAggProb * float64(dutyWithPreConsensus(committeeSize)) - } +func (rc *rateCalculator) SyncCommitteeAggProb() float64 { + return rc.SyncCommitteeProbability() * 16.0 / (float64(rc.netCfg.GetSyncCommitteeSize()) / 4.0) +} - // Convert rate to seconds - totalEpochSeconds := float64(SlotsPerEpoch * 12) - totalMsgRate = totalMsgRate / totalEpochSeconds +func (rc *rateCalculator) MaxAttestationDutiesPerEpochForCommittee() uint64 { + return rc.netCfg.GetSlotsPerEpoch() +} - return totalMsgRate +func (rc *rateCalculator) EstimatedAttestationCommitteeSize() float64 { + return float64(rc.netCfg.TotalEthereumValidators) / 2048.0 +} + +// Expected number of messages per duty step + +func consensusMessages(n int) int { + return 1 + n + n + 2 // 1 Proposal + n Prepares + n Commits + 2 Decideds (average) +} + +func partialSignatureMessages(n int) int { + return n +} + +func dutyWithPreConsensus(n int) int { + // Pre-Consensus + Consensus + Post-Consensus + return partialSignatureMessages(n) + consensusMessages(n) + partialSignatureMessages(n) +} + +func dutyWithoutPreConsensus(n int) int { + // Consensus + Post-Consensus + return consensusMessages(n) + partialSignatureMessages(n) } diff --git a/network/topics/params/message_rate_test.go b/network/topics/params/message_rate_test.go index 64aeae1956..dd571603ad 100644 --- a/network/topics/params/message_rate_test.go +++ b/network/topics/params/message_rate_test.go @@ -7,6 +7,7 @@ import ( spectypes "github.com/ssvlabs/ssv-spec/types" "github.com/stretchr/testify/require" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/types" "github.com/ssvlabs/ssv/registry/storage" ) @@ -78,7 +79,8 @@ func TestCalculateMessageRateForTopic(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - msgRate := calculateMessageRateForTopic(tt.args.committees) + rc := newRateCalculator(networkconfig.TestNetwork) + msgRate := rc.calculateMessageRateForTopic(tt.args.committees) require.InDelta(t, tt.want, msgRate, tt.want*0.001) }) } diff --git a/network/topics/params/peer_score.go b/network/topics/params/peer_score.go index 323e53c6a7..7b0d063f16 100644 --- a/network/topics/params/peer_score.go +++ b/network/topics/params/peer_score.go @@ -6,6 +6,8 @@ import ( pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/peer" + + "github.com/ssvlabs/ssv/networkconfig" ) const ( @@ -17,10 +19,9 @@ const ( opportunisticGraftThreshold = 5 // Overall parameters - topicScoreCap = 32.72 - decayInterval = 32 * (time.Second * 12) // One epoch - decayToZero = 0.01 - retainScore = 100 * 32 * 12 * time.Second + topicScoreCap = 32.72 + decayToZero = 0.01 + retainScoreEpochMultiplier = 100 // P5 appSpecificWeight = 0 @@ -45,13 +46,9 @@ func PeerScoreThresholds() *pubsub.PeerScoreThresholds { } // PeerScoreParams returns peer score params according to the given options -func PeerScoreParams(oneEpoch, msgIDCacheTTL time.Duration, disableColocation bool, ipWhilelist ...*net.IPNet) *pubsub.PeerScoreParams { - if oneEpoch == 0 { - oneEpoch = oneEpochDuration - } - +func PeerScoreParams(netCfg networkconfig.NetworkConfig, msgIDCacheTTL time.Duration, disableColocation bool, ipWhitelist ...*net.IPNet) *pubsub.PeerScoreParams { // P7 calculation - behaviourPenaltyDecay := scoreDecay(oneEpoch*10, decayInterval) + behaviourPenaltyDecay := scoreDecay(netCfg.EpochDuration()*10, netCfg.EpochDuration()) maxAllowedRatePerDecayInterval := 10.0 targetVal, _ := decayConvergence(behaviourPenaltyDecay, maxAllowedRatePerDecayInterval) targetVal = targetVal - behaviourPenaltyThreshold @@ -66,9 +63,9 @@ func PeerScoreParams(oneEpoch, msgIDCacheTTL time.Duration, disableColocation bo Topics: make(map[string]*pubsub.TopicScoreParams), // Overall parameters TopicScoreCap: topicScoreCap, - DecayInterval: decayInterval, + DecayInterval: netCfg.EpochDuration(), DecayToZero: decayToZero, - RetainScore: retainScore, + RetainScore: retainScoreEpochMultiplier * netCfg.EpochDuration(), SeenMsgTTL: msgIDCacheTTL, // P5 @@ -80,7 +77,7 @@ func PeerScoreParams(oneEpoch, msgIDCacheTTL time.Duration, disableColocation bo // P6 IPColocationFactorWeight: finalIPColocationFactorWeight, IPColocationFactorThreshold: ipColocationFactorThreshold, - IPColocationFactorWhitelist: ipWhilelist, + IPColocationFactorWhitelist: ipWhitelist, // P7 BehaviourPenaltyWeight: behaviourPenaltyWeight, diff --git a/network/topics/params/scores_test.go b/network/topics/params/scores_test.go index 245943dfd5..324c4d5606 100644 --- a/network/topics/params/scores_test.go +++ b/network/topics/params/scores_test.go @@ -9,6 +9,7 @@ import ( pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/stretchr/testify/require" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/registry/storage" ) @@ -22,7 +23,7 @@ func TestTopicScoreParams(t *testing.T) { "subnet topic 0 validators", func() *Options { validators := uint64(0) - opts := NewSubnetTopicOpts(validators, 128, []*storage.Committee{}) + opts := NewSubnetTopicOpts(networkconfig.TestNetwork, validators, 128, []*storage.Committee{}) return opts }, nil, @@ -31,7 +32,7 @@ func TestTopicScoreParams(t *testing.T) { "subnet topic 1k validators", func() *Options { validators := uint64(1000) - opts := NewSubnetTopicOpts(validators, 128, createTestingSingleCommittees(validators)) + opts := NewSubnetTopicOpts(networkconfig.TestNetwork, validators, 128, createTestingSingleCommittees(validators)) return opts }, nil, @@ -40,7 +41,7 @@ func TestTopicScoreParams(t *testing.T) { "subnet topic 10k validators", func() *Options { validators := uint64(10_000) - opts := NewSubnetTopicOpts(validators, 128, createTestingSingleCommittees(validators)) + opts := NewSubnetTopicOpts(networkconfig.TestNetwork, validators, 128, createTestingSingleCommittees(validators)) return opts }, nil, @@ -49,7 +50,7 @@ func TestTopicScoreParams(t *testing.T) { "subnet topic 51k validators", func() *Options { validators := uint64(51_000) - opts := NewSubnetTopicOpts(validators, 128, createTestingSingleCommittees(validators)) + opts := NewSubnetTopicOpts(networkconfig.TestNetwork, validators, 128, createTestingSingleCommittees(validators)) return opts }, nil, @@ -76,7 +77,7 @@ func TestTopicScoreParams(t *testing.T) { } func TestPeerScoreParams(t *testing.T) { - peerScoreParams := PeerScoreParams(oneEpochDuration, 550*(time.Millisecond*700), false) + peerScoreParams := PeerScoreParams(networkconfig.TestNetwork, 550*(time.Millisecond*700), false) raw, err := peerScoreParamsString(peerScoreParams) require.NoError(t, err) require.NotNil(t, raw) diff --git a/network/topics/params/topic_score.go b/network/topics/params/topic_score.go index d8366ad288..fb9a8efad8 100644 --- a/network/topics/params/topic_score.go +++ b/network/topics/params/topic_score.go @@ -7,6 +7,7 @@ import ( pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/pkg/errors" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/registry/storage" ) @@ -96,7 +97,7 @@ type Options struct { func (o *Options) defaults() { // Network if o.Network.OneEpochDuration == 0 { - o.Network.OneEpochDuration = oneEpochDuration + o.Network.OneEpochDuration = 12 * time.Second * 32 } if o.Network.TotalTopicsWeight == 0 { o.Network.TotalTopicsWeight = totalTopicsWeight @@ -150,35 +151,38 @@ func (o *Options) maxScore() float64 { } // NewOpts creates new TopicOpts instance -func NewOpts(activeValidators uint64, subnets int) *Options { +func NewOpts(epochDuration time.Duration, activeValidators uint64, subnets int) *Options { return &Options{ Network: NetworkOpts{ ActiveValidators: activeValidators, Subnets: subnets, + OneEpochDuration: epochDuration, }, Topic: TopicOpts{}, } } // NewSubnetTopicOpts creates new TopicOpts for a subnet topic -func NewSubnetTopicOpts(activeValidators uint64, subnets int, committees []*storage.Committee) *Options { +func NewSubnetTopicOpts(netCfg networkconfig.NetworkConfig, activeValidators uint64, subnets int, committees []*storage.Committee) *Options { // Create options with default values - opts := NewOpts(activeValidators, subnets) + opts := NewOpts(netCfg.EpochDuration(), activeValidators, subnets) opts.defaults() // Set topic weight with equal weights opts.Topic.TopicWeight = opts.Network.TotalTopicsWeight / float64(opts.Network.Subnets) + rc := newRateCalculator(netCfg) + // Set the expected message rate for the topic - opts.Topic.ExpectedMsgRate = calculateMessageRateForTopic(committees) + opts.Topic.ExpectedMsgRate = rc.calculateMessageRateForTopic(committees) return opts } // NewSubnetTopicOpts creates new TopicOpts for a subnet topic -func NewSubnetTopicOptsValidators(activeValidators uint64, subnets int) *Options { +func NewSubnetTopicOptsValidators(netCfg networkconfig.NetworkConfig, activeValidators uint64, subnets int) *Options { // Create options with default values - opts := NewOpts(activeValidators, subnets) + opts := NewOpts(netCfg.EpochDuration(), activeValidators, subnets) opts.defaults() // Set topic weight with equal weights @@ -201,6 +205,7 @@ func TopicParams(opts *Options) (*pubsub.TopicScoreParams, error) { // Set to default if not set opts.defaults() + decayInterval := opts.Network.OneEpochDuration expectedMessagesPerDecayInterval := opts.Topic.ExpectedMsgRate * decayInterval.Seconds() // P1 diff --git a/network/topics/pubsub.go b/network/topics/pubsub.go index 5154309918..9576c9f0bc 100644 --- a/network/topics/pubsub.go +++ b/network/topics/pubsub.go @@ -76,7 +76,6 @@ type PubSubConfig struct { type ScoringConfig struct { IPWhitelist []*net.IPNet IPColocationWeight float64 - OneEpochDuration time.Duration } // PubsubBundle includes the pubsub router, plus involved components @@ -167,7 +166,7 @@ func NewPubSub(ctx context.Context, logger *zap.Logger, cfg *PubSubConfig, commi } // Get overall score params - peerScoreParams := params.PeerScoreParams(cfg.Scoring.OneEpochDuration, cfg.MsgIDCacheTTL, cfg.DisableIPRateLimit, cfg.Scoring.IPWhitelist...) + peerScoreParams := params.PeerScoreParams(cfg.NetworkConfig, cfg.MsgIDCacheTTL, cfg.DisableIPRateLimit, cfg.Scoring.IPWhitelist...) // Define score inspector if inspector == nil { diff --git a/network/topics/scoring.go b/network/topics/scoring.go index 64e6a4cca8..272fd7fc27 100644 --- a/network/topics/scoring.go +++ b/network/topics/scoring.go @@ -5,7 +5,6 @@ import ( "math" "strconv" "strings" - "time" pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/libp2p/go-libp2p/core/peer" @@ -22,7 +21,6 @@ import ( func DefaultScoringConfig() *ScoringConfig { return &ScoringConfig{ IPColocationWeight: -35.11, - OneEpochDuration: (12 * time.Second) * 32, } } @@ -207,7 +205,7 @@ func topicScoreParams(logger *zap.Logger, cfg *PubSubConfig, committeesProvider logger.Debug("got filtered committees for score params") // Create topic options - opts := params.NewSubnetTopicOpts(totalValidators, commons.SubnetsCount, topicCommittees) + opts := params.NewSubnetTopicOpts(cfg.NetworkConfig, totalValidators, commons.SubnetsCount, topicCommittees) // Generate topic parameters tp, err := params.TopicParams(opts) diff --git a/networkconfig/beacon.go b/networkconfig/beacon.go index c014076bba..94114ca754 100644 --- a/networkconfig/beacon.go +++ b/networkconfig/beacon.go @@ -20,25 +20,35 @@ type Beacon interface { EstimatedEpochAtSlot(slot phase0.Slot) phase0.Epoch IsFirstSlotOfEpoch(slot phase0.Slot) bool GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot - EpochsPerSyncCommitteePeriod() uint64 + GetEpochsPerSyncCommitteePeriod() uint64 EstimatedSyncCommitteePeriodAtEpoch(epoch phase0.Epoch) uint64 FirstEpochOfSyncPeriod(period uint64) phase0.Epoch LastSlotOfSyncPeriod(period uint64) phase0.Slot FirstSlotAtEpoch(epoch phase0.Epoch) phase0.Slot EpochStartTime(epoch phase0.Epoch) time.Time EstimatedTimeAtSlot(slot phase0.Slot) time.Time + IntervalDuration() time.Duration + EpochDuration() time.Duration GetSlotDuration() time.Duration GetSlotsPerEpoch() uint64 GetGenesisTime() time.Time + GetSyncCommitteeSize() uint64 GetBeaconName() string } type BeaconConfig struct { - BeaconName string - SlotDuration time.Duration - SlotsPerEpoch uint64 - ForkVersion phase0.Version - GenesisTime time.Time + BeaconName string + SlotDuration time.Duration + SlotsPerEpoch uint64 + EpochsPerSyncCommitteePeriod uint64 + SyncCommitteeSize uint64 + SyncCommitteeSubnetCount uint64 + TargetAggregatorsPerSyncSubcommittee uint64 + TargetAggregatorsPerCommittee uint64 + IntervalsPerSlot uint64 + ForkVersion phase0.Version + GenesisTime time.Time + GenesisValidatorsRoot phase0.Root } func (b BeaconConfig) String() string { @@ -100,19 +110,19 @@ func (b BeaconConfig) GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot { return phase0.Slot(uint64(epoch) * b.SlotsPerEpoch) } -// EpochsPerSyncCommitteePeriod returns the number of epochs per sync committee period. -func (b BeaconConfig) EpochsPerSyncCommitteePeriod() uint64 { - return 256 +// GetEpochsPerSyncCommitteePeriod returns the number of epochs per sync committee period. +func (b BeaconConfig) GetEpochsPerSyncCommitteePeriod() uint64 { + return b.EpochsPerSyncCommitteePeriod } // EstimatedSyncCommitteePeriodAtEpoch estimates the current sync committee period at the given Epoch func (b BeaconConfig) EstimatedSyncCommitteePeriodAtEpoch(epoch phase0.Epoch) uint64 { - return uint64(epoch) / b.EpochsPerSyncCommitteePeriod() + return uint64(epoch) / b.GetEpochsPerSyncCommitteePeriod() } // FirstEpochOfSyncPeriod calculates the first epoch of the given sync period. func (b BeaconConfig) FirstEpochOfSyncPeriod(period uint64) phase0.Epoch { - return phase0.Epoch(period * b.EpochsPerSyncCommitteePeriod()) + return phase0.Epoch(period * b.GetEpochsPerSyncCommitteePeriod()) } // LastSlotOfSyncPeriod calculates the first epoch of the given sync period. @@ -141,6 +151,20 @@ func (b BeaconConfig) EstimatedTimeAtSlot(slot phase0.Slot) time.Time { return b.GenesisTime.Add(d) } +func (b BeaconConfig) IntervalDuration() time.Duration { + if b.IntervalsPerSlot > math.MaxInt64 { + panic("intervals per slot out of range") + } + return b.SlotDuration / time.Duration(b.IntervalsPerSlot) // #nosec G115: intervals per slot cannot exceed math.MaxInt64 +} + +func (b BeaconConfig) EpochDuration() time.Duration { + if b.SlotsPerEpoch > math.MaxInt64 { + panic("slots per epoch out of range") + } + return b.SlotDuration * time.Duration(b.SlotsPerEpoch) // #nosec G115: slot cannot exceed math.MaxInt64 +} + func (b BeaconConfig) GetSlotDuration() time.Duration { return b.SlotDuration } @@ -153,6 +177,10 @@ func (b BeaconConfig) GetGenesisTime() time.Time { return b.GenesisTime } +func (b BeaconConfig) GetSyncCommitteeSize() uint64 { + return b.SyncCommitteeSize +} + func (b BeaconConfig) GetBeaconName() string { return b.BeaconName } diff --git a/networkconfig/beacon_mock.go b/networkconfig/beacon_mock.go index fb9ea9c819..b889e605cc 100644 --- a/networkconfig/beacon_mock.go +++ b/networkconfig/beacon_mock.go @@ -41,32 +41,32 @@ func (m *MockBeacon) EXPECT() *MockBeaconMockRecorder { return m.recorder } -// EpochStartTime mocks base method. -func (m *MockBeacon) EpochStartTime(epoch phase0.Epoch) time.Time { +// EpochDuration mocks base method. +func (m *MockBeacon) EpochDuration() time.Duration { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EpochStartTime", epoch) - ret0, _ := ret[0].(time.Time) + ret := m.ctrl.Call(m, "EpochDuration") + ret0, _ := ret[0].(time.Duration) return ret0 } -// EpochStartTime indicates an expected call of EpochStartTime. -func (mr *MockBeaconMockRecorder) EpochStartTime(epoch any) *gomock.Call { +// EpochDuration indicates an expected call of EpochDuration. +func (mr *MockBeaconMockRecorder) EpochDuration() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochStartTime", reflect.TypeOf((*MockBeacon)(nil).EpochStartTime), epoch) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochDuration", reflect.TypeOf((*MockBeacon)(nil).EpochDuration)) } -// EpochsPerSyncCommitteePeriod mocks base method. -func (m *MockBeacon) EpochsPerSyncCommitteePeriod() uint64 { +// EpochStartTime mocks base method. +func (m *MockBeacon) EpochStartTime(epoch phase0.Epoch) time.Time { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EpochsPerSyncCommitteePeriod") - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "EpochStartTime", epoch) + ret0, _ := ret[0].(time.Time) return ret0 } -// EpochsPerSyncCommitteePeriod indicates an expected call of EpochsPerSyncCommitteePeriod. -func (mr *MockBeaconMockRecorder) EpochsPerSyncCommitteePeriod() *gomock.Call { +// EpochStartTime indicates an expected call of EpochStartTime. +func (mr *MockBeaconMockRecorder) EpochStartTime(epoch any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochsPerSyncCommitteePeriod", reflect.TypeOf((*MockBeacon)(nil).EpochsPerSyncCommitteePeriod)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochStartTime", reflect.TypeOf((*MockBeacon)(nil).EpochStartTime), epoch) } // EstimatedCurrentEpoch mocks base method. @@ -209,6 +209,20 @@ func (mr *MockBeaconMockRecorder) GetEpochFirstSlot(epoch any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEpochFirstSlot", reflect.TypeOf((*MockBeacon)(nil).GetEpochFirstSlot), epoch) } +// GetEpochsPerSyncCommitteePeriod mocks base method. +func (m *MockBeacon) GetEpochsPerSyncCommitteePeriod() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEpochsPerSyncCommitteePeriod") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// GetEpochsPerSyncCommitteePeriod indicates an expected call of GetEpochsPerSyncCommitteePeriod. +func (mr *MockBeaconMockRecorder) GetEpochsPerSyncCommitteePeriod() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEpochsPerSyncCommitteePeriod", reflect.TypeOf((*MockBeacon)(nil).GetEpochsPerSyncCommitteePeriod)) +} + // GetGenesisTime mocks base method. func (m *MockBeacon) GetGenesisTime() time.Time { m.ctrl.T.Helper() @@ -279,6 +293,34 @@ func (mr *MockBeaconMockRecorder) GetSlotsPerEpoch() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotsPerEpoch", reflect.TypeOf((*MockBeacon)(nil).GetSlotsPerEpoch)) } +// GetSyncCommitteeSize mocks base method. +func (m *MockBeacon) GetSyncCommitteeSize() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSyncCommitteeSize") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// GetSyncCommitteeSize indicates an expected call of GetSyncCommitteeSize. +func (mr *MockBeaconMockRecorder) GetSyncCommitteeSize() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSyncCommitteeSize", reflect.TypeOf((*MockBeacon)(nil).GetSyncCommitteeSize)) +} + +// IntervalDuration mocks base method. +func (m *MockBeacon) IntervalDuration() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IntervalDuration") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// IntervalDuration indicates an expected call of IntervalDuration. +func (mr *MockBeaconMockRecorder) IntervalDuration() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntervalDuration", reflect.TypeOf((*MockBeacon)(nil).IntervalDuration)) +} + // IsFirstSlotOfEpoch mocks base method. func (m *MockBeacon) IsFirstSlotOfEpoch(slot phase0.Slot) bool { m.ctrl.T.Helper() diff --git a/networkconfig/holesky-e2e.go b/networkconfig/holesky-e2e.go index a879cca299..efa627fe98 100644 --- a/networkconfig/holesky-e2e.go +++ b/networkconfig/holesky-e2e.go @@ -2,25 +2,19 @@ package networkconfig import ( "math/big" - "time" ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) var HoleskyE2E = NetworkConfig{ - Name: "holesky-e2e", - BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.HoleskyNetwork), - SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.HoleskyNetwork.SlotsPerEpoch(), - ForkVersion: spectypes.HoleskyNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 - }, + Name: "holesky-e2e", + BeaconConfig: Holesky.BeaconConfig, SSVConfig: SSVConfig{ - DomainType: spectypes.DomainType{0x0, 0x0, 0xee, 0x1}, - RegistryContractAddr: ethcommon.HexToAddress("0x58410bef803ecd7e63b23664c586a6db72daf59c"), - RegistrySyncOffset: big.NewInt(405579), - Bootnodes: []string{}, + DomainType: spectypes.DomainType{0x0, 0x0, 0xee, 0x1}, + RegistryContractAddr: ethcommon.HexToAddress("0x58410bef803ecd7e63b23664c586a6db72daf59c"), + RegistrySyncOffset: big.NewInt(405579), + Bootnodes: []string{}, + TotalEthereumValidators: Holesky.TotalEthereumValidators, }, } diff --git a/networkconfig/holesky-stage.go b/networkconfig/holesky-stage.go index a28cc3cf72..219aef756a 100644 --- a/networkconfig/holesky-stage.go +++ b/networkconfig/holesky-stage.go @@ -2,21 +2,13 @@ package networkconfig import ( "math/big" - "time" ethcommon "github.com/ethereum/go-ethereum/common" - spectypes "github.com/ssvlabs/ssv-spec/types" ) var HoleskyStage = NetworkConfig{ - Name: "holesky-stage", - BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.HoleskyNetwork), - SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.HoleskyNetwork.SlotsPerEpoch(), - ForkVersion: spectypes.HoleskyNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 - }, + Name: "holesky-stage", + BeaconConfig: Holesky.BeaconConfig, SSVConfig: SSVConfig{ DomainType: [4]byte{0x00, 0x00, 0x31, 0x13}, RegistrySyncOffset: new(big.Int).SetInt64(84599), @@ -29,5 +21,6 @@ var HoleskyStage = NetworkConfig{ // Private bootnode: "enr:-Ja4QDRUBjWOvVfGxpxvv3FqaCy3psm7IsKu5ETb1GXiexGYDFppD33t7AHRfmQddoAkBiyb7pt4t7ZN0sNB9CsW4I-GAZGOmChMgmlkgnY0gmlwhAorXxuJc2VjcDI1NmsxoQP_bBE-ZYvaXKBR3dRYMN5K_lZP-q-YsBzDZEtxH_4T_YNzc3YBg3RjcIITioN1ZHCCD6I", }, + TotalEthereumValidators: Holesky.TotalEthereumValidators, }, } diff --git a/networkconfig/holesky.go b/networkconfig/holesky.go index 801d9c3cad..2aa8a9bc30 100644 --- a/networkconfig/holesky.go +++ b/networkconfig/holesky.go @@ -4,18 +4,27 @@ import ( "math/big" "time" + "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" spectypes "github.com/ssvlabs/ssv-spec/types" ) var Holesky = NetworkConfig{ Name: "holesky", BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.HoleskyNetwork), - SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.HoleskyNetwork.SlotsPerEpoch(), - ForkVersion: spectypes.HoleskyNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + BeaconName: string(spectypes.HoleskyNetwork), + SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), + SlotsPerEpoch: spectypes.HoleskyNetwork.SlotsPerEpoch(), + EpochsPerSyncCommitteePeriod: 256, + SyncCommitteeSize: 512, + SyncCommitteeSubnetCount: 4, + TargetAggregatorsPerSyncSubcommittee: 16, + TargetAggregatorsPerCommittee: 16, + IntervalsPerSlot: 3, + ForkVersion: spectypes.HoleskyNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1")), }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x2}, @@ -26,5 +35,6 @@ var Holesky = NetworkConfig{ // SSV Labs "enr:-Ja4QKFD3u5tZob7xukp-JKX9QJMFqqI68cItsE4tBbhsOyDR0M_1UUjb35hbrqvTP3bnXO_LnKh-jNLTeaUqN4xiduGAZKaP_sagmlkgnY0gmlwhDb0fh6Jc2VjcDI1NmsxoQMw_H2anuiqP9NmEaZwbUfdvPFog7PvcKmoVByDa576SINzc3YBg3RjcIITioN1ZHCCD6I", }, + TotalEthereumValidators: 1757795, // active_validators from https://holesky.beaconcha.in/index/data on Nov 20, 2024 }, } diff --git a/networkconfig/hoodi-stage.go b/networkconfig/hoodi-stage.go index 42ffc5d917..36ee870d92 100644 --- a/networkconfig/hoodi-stage.go +++ b/networkconfig/hoodi-stage.go @@ -2,21 +2,13 @@ package networkconfig import ( "math/big" - "time" ethcommon "github.com/ethereum/go-ethereum/common" - spectypes "github.com/ssvlabs/ssv-spec/types" ) var HoodiStage = NetworkConfig{ - Name: "hoodi-stage", - BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.HoodiNetwork), - SlotDuration: spectypes.HoodiNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.HoodiNetwork.SlotsPerEpoch(), - ForkVersion: spectypes.HoodiNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.HoodiNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 - }, + Name: "hoodi-stage", + BeaconConfig: Hoodi.BeaconConfig, SSVConfig: SSVConfig{ DomainType: [4]byte{0x00, 0x00, 0x31, 0x14}, RegistrySyncOffset: new(big.Int).SetInt64(1004), @@ -26,5 +18,6 @@ var HoodiStage = NetworkConfig{ // SSV Labs "enr:-Ja4QJZcaYfS0GpX-5xREVBa26a-E-QHMFek-EndsJdgM6loIM7pfbJwPDCNK1VzPkUhMjwcTTuNASiHU6X-sjsrxFmGAZWjNu06gmlkgnY0gmlwhErcGnyJc2VjcDI1NmsxoQP_bBE-ZYvaXKBR3dRYMN5K_lZP-q-YsBzDZEtxH_4T_YNzc3YBg3RjcIITioN1ZHCCD6I", }, + TotalEthereumValidators: Hoodi.TotalEthereumValidators, }, } diff --git a/networkconfig/hoodi.go b/networkconfig/hoodi.go index 78f0263743..31af8e0c95 100644 --- a/networkconfig/hoodi.go +++ b/networkconfig/hoodi.go @@ -4,18 +4,27 @@ import ( "math/big" "time" + "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" spectypes "github.com/ssvlabs/ssv-spec/types" ) var Hoodi = NetworkConfig{ Name: "hoodi", BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.HoodiNetwork), - SlotDuration: spectypes.HoodiNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.HoodiNetwork.SlotsPerEpoch(), - ForkVersion: spectypes.HoodiNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.HoodiNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + BeaconName: string(spectypes.HoodiNetwork), + SlotDuration: spectypes.HoodiNetwork.SlotDurationSec(), + SlotsPerEpoch: spectypes.HoodiNetwork.SlotsPerEpoch(), + EpochsPerSyncCommitteePeriod: 256, + SyncCommitteeSize: 512, + SyncCommitteeSubnetCount: 4, + TargetAggregatorsPerSyncSubcommittee: 16, + TargetAggregatorsPerCommittee: 16, + IntervalsPerSlot: 3, + ForkVersion: spectypes.HoodiNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.HoodiNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x212f13fc4df078b6cb7db228f1c8307566dcecf900867401a92023d7ba99cb5f")), }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x3}, @@ -26,5 +35,6 @@ var Hoodi = NetworkConfig{ // SSV Labs "enr:-Ja4QIKlyNFuFtTOnVoavqwmpgSJXfhSmhpdSDOUhf5-FBr7bBxQRvG6VrpUvlkr8MtpNNuMAkM33AseduSaOhd9IeWGAZWjRbnvgmlkgnY0gmlwhCNVVTCJc2VjcDI1NmsxoQNTTyiJPoZh502xOZpHSHAfR-94NaXLvi5J4CNHMh2tjoNzc3YBg3RjcIITioN1ZHCCD6I", }, + TotalEthereumValidators: 1107955, // active_validators from https://hoodi.beaconcha.in/index/data on Apr 18, 2025 }, } diff --git a/networkconfig/local-testnet.go b/networkconfig/local-testnet.go index eb998639f9..5a40e88b0c 100644 --- a/networkconfig/local-testnet.go +++ b/networkconfig/local-testnet.go @@ -4,18 +4,27 @@ import ( "math/big" "time" + "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" spectypes "github.com/ssvlabs/ssv-spec/types" ) var LocalTestnet = NetworkConfig{ Name: "local-testnet", BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.PraterNetwork), - SlotDuration: spectypes.PraterNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.PraterNetwork.SlotsPerEpoch(), - ForkVersion: spectypes.PraterNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.PraterNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + BeaconName: string(spectypes.PraterNetwork), + SlotDuration: spectypes.PraterNetwork.SlotDurationSec(), + SlotsPerEpoch: spectypes.PraterNetwork.SlotsPerEpoch(), + EpochsPerSyncCommitteePeriod: 256, + SyncCommitteeSize: 512, + SyncCommitteeSubnetCount: 4, + TargetAggregatorsPerSyncSubcommittee: 16, + TargetAggregatorsPerCommittee: 16, + IntervalsPerSlot: 3, + ForkVersion: spectypes.PraterNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.PraterNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb")), }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoV2NetworkID.Byte(), 0x2}, @@ -24,6 +33,7 @@ var LocalTestnet = NetworkConfig{ Bootnodes: []string{ "enr:-Li4QLR4Y1VbwiqFYKy6m-WFHRNDjhMDZ_qJwIABu2PY9BHjIYwCKpTvvkVmZhu43Q6zVA29sEUhtz10rQjDJkK3Hd-GAYiGrW2Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhCLdu_SJc2VjcDI1NmsxoQJTcI7GHPw-ZqIflPZYYDK_guurp_gsAFF5Erns3-PAvIN0Y3CCE4mDdWRwgg-h", }, - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + TotalEthereumValidators: TestNetwork.TotalEthereumValidators, }, } diff --git a/networkconfig/mainnet.go b/networkconfig/mainnet.go index 1e475cd140..995ff156d2 100644 --- a/networkconfig/mainnet.go +++ b/networkconfig/mainnet.go @@ -4,18 +4,27 @@ import ( "math/big" "time" + "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" spectypes "github.com/ssvlabs/ssv-spec/types" ) var Mainnet = NetworkConfig{ Name: "mainnet", BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.MainNetwork), - SlotDuration: spectypes.MainNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.MainNetwork.SlotsPerEpoch(), - ForkVersion: spectypes.MainNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.MainNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + BeaconName: string(spectypes.MainNetwork), + SlotDuration: spectypes.MainNetwork.SlotDurationSec(), + SlotsPerEpoch: spectypes.MainNetwork.SlotsPerEpoch(), + EpochsPerSyncCommitteePeriod: 256, + SyncCommitteeSize: 512, + SyncCommitteeSubnetCount: 4, + TargetAggregatorsPerSyncSubcommittee: 16, + TargetAggregatorsPerCommittee: 16, + IntervalsPerSlot: 3, + ForkVersion: spectypes.MainNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.MainNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95")), }, SSVConfig: SSVConfig{ DomainType: spectypes.AlanMainnet, @@ -35,5 +44,6 @@ var Mainnet = NetworkConfig{ // CryptoManufaktur "enr:-Li4QH7FwJcL8gJj0zHAITXqghMkG-A5bfWh2-3Q7vosy9D1BS8HZk-1ITuhK_rfzG3v_UtBDI6uNJZWpdcWfrQFCxKGAYnQ1DRCh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLb3g2Jc2VjcDI1NmsxoQKeSDcZWSaY9FC723E9yYX1Li18bswhLNlxBZdLfgOKp4N0Y3CCE4mDdWRwgg-h", }, + TotalEthereumValidators: 1064860, // active_validators from https://mainnet.beaconcha.in/index/data on Apr 18, 2025 }, } diff --git a/networkconfig/network_mock.go b/networkconfig/network_mock.go index 425399874d..85e12572dc 100644 --- a/networkconfig/network_mock.go +++ b/networkconfig/network_mock.go @@ -42,32 +42,32 @@ func (m *MockNetwork) EXPECT() *MockNetworkMockRecorder { return m.recorder } -// EpochStartTime mocks base method. -func (m *MockNetwork) EpochStartTime(epoch phase0.Epoch) time.Time { +// EpochDuration mocks base method. +func (m *MockNetwork) EpochDuration() time.Duration { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EpochStartTime", epoch) - ret0, _ := ret[0].(time.Time) + ret := m.ctrl.Call(m, "EpochDuration") + ret0, _ := ret[0].(time.Duration) return ret0 } -// EpochStartTime indicates an expected call of EpochStartTime. -func (mr *MockNetworkMockRecorder) EpochStartTime(epoch any) *gomock.Call { +// EpochDuration indicates an expected call of EpochDuration. +func (mr *MockNetworkMockRecorder) EpochDuration() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochStartTime", reflect.TypeOf((*MockNetwork)(nil).EpochStartTime), epoch) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochDuration", reflect.TypeOf((*MockNetwork)(nil).EpochDuration)) } -// EpochsPerSyncCommitteePeriod mocks base method. -func (m *MockNetwork) EpochsPerSyncCommitteePeriod() uint64 { +// EpochStartTime mocks base method. +func (m *MockNetwork) EpochStartTime(epoch phase0.Epoch) time.Time { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EpochsPerSyncCommitteePeriod") - ret0, _ := ret[0].(uint64) + ret := m.ctrl.Call(m, "EpochStartTime", epoch) + ret0, _ := ret[0].(time.Time) return ret0 } -// EpochsPerSyncCommitteePeriod indicates an expected call of EpochsPerSyncCommitteePeriod. -func (mr *MockNetworkMockRecorder) EpochsPerSyncCommitteePeriod() *gomock.Call { +// EpochStartTime indicates an expected call of EpochStartTime. +func (mr *MockNetworkMockRecorder) EpochStartTime(epoch any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochsPerSyncCommitteePeriod", reflect.TypeOf((*MockNetwork)(nil).EpochsPerSyncCommitteePeriod)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EpochStartTime", reflect.TypeOf((*MockNetwork)(nil).EpochStartTime), epoch) } // EstimatedCurrentEpoch mocks base method. @@ -224,6 +224,20 @@ func (mr *MockNetworkMockRecorder) GetEpochFirstSlot(epoch any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEpochFirstSlot", reflect.TypeOf((*MockNetwork)(nil).GetEpochFirstSlot), epoch) } +// GetEpochsPerSyncCommitteePeriod mocks base method. +func (m *MockNetwork) GetEpochsPerSyncCommitteePeriod() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEpochsPerSyncCommitteePeriod") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// GetEpochsPerSyncCommitteePeriod indicates an expected call of GetEpochsPerSyncCommitteePeriod. +func (mr *MockNetworkMockRecorder) GetEpochsPerSyncCommitteePeriod() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEpochsPerSyncCommitteePeriod", reflect.TypeOf((*MockNetwork)(nil).GetEpochsPerSyncCommitteePeriod)) +} + // GetGenesisTime mocks base method. func (m *MockNetwork) GetGenesisTime() time.Time { m.ctrl.T.Helper() @@ -294,6 +308,34 @@ func (mr *MockNetworkMockRecorder) GetSlotsPerEpoch() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSlotsPerEpoch", reflect.TypeOf((*MockNetwork)(nil).GetSlotsPerEpoch)) } +// GetSyncCommitteeSize mocks base method. +func (m *MockNetwork) GetSyncCommitteeSize() uint64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSyncCommitteeSize") + ret0, _ := ret[0].(uint64) + return ret0 +} + +// GetSyncCommitteeSize indicates an expected call of GetSyncCommitteeSize. +func (mr *MockNetworkMockRecorder) GetSyncCommitteeSize() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSyncCommitteeSize", reflect.TypeOf((*MockNetwork)(nil).GetSyncCommitteeSize)) +} + +// IntervalDuration mocks base method. +func (m *MockNetwork) IntervalDuration() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IntervalDuration") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// IntervalDuration indicates an expected call of IntervalDuration. +func (mr *MockNetworkMockRecorder) IntervalDuration() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntervalDuration", reflect.TypeOf((*MockNetwork)(nil).IntervalDuration)) +} + // IsFirstSlotOfEpoch mocks base method. func (m *MockNetwork) IsFirstSlotOfEpoch(slot phase0.Slot) bool { m.ctrl.T.Helper() diff --git a/networkconfig/sepolia.go b/networkconfig/sepolia.go index 02ea111d2e..7a609a004c 100644 --- a/networkconfig/sepolia.go +++ b/networkconfig/sepolia.go @@ -11,11 +11,17 @@ import ( var Sepolia = NetworkConfig{ Name: "sepolia", BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.SepoliaNetwork), - SlotDuration: spectypes.SepoliaNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.SepoliaNetwork.SlotsPerEpoch(), - ForkVersion: spectypes.SepoliaNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.SepoliaNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + BeaconName: string(spectypes.SepoliaNetwork), + SlotDuration: spectypes.SepoliaNetwork.SlotDurationSec(), + SlotsPerEpoch: spectypes.SepoliaNetwork.SlotsPerEpoch(), + EpochsPerSyncCommitteePeriod: 256, + SyncCommitteeSize: 512, + SyncCommitteeSubnetCount: 4, + TargetAggregatorsPerSyncSubcommittee: 16, + TargetAggregatorsPerCommittee: 16, + IntervalsPerSlot: 3, + ForkVersion: spectypes.SepoliaNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.SepoliaNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x69}, @@ -26,5 +32,6 @@ var Sepolia = NetworkConfig{ // SSV Labs "enr:-Ja4QIE0Ml0a8Pq9zD-0g9KYGN3jAMPJ0CAP0i16fK-PSHfLeORl-Z5p8odoP1oS5S2E8IsF5jNG7gqTKhjVsHR-Z_CGAZXrnTJrgmlkgnY0gmlwhCOjXGWJc2VjcDI1NmsxoQKCRDQsIdFsJDmu_ZU2H6b2_HRJbuUneDXHLfFkSQH9O4Nzc3YBg3RjcIITioN1ZHCCD6I", }, + TotalEthereumValidators: 1781, // active_validators from https://sepolia.beaconcha.in/index/data on Mar 20, 2025 }, } diff --git a/networkconfig/ssv.go b/networkconfig/ssv.go index 61d3d18959..77f9db845b 100644 --- a/networkconfig/ssv.go +++ b/networkconfig/ssv.go @@ -36,11 +36,12 @@ type SSV interface { } type SSVConfig struct { - DomainType spectypes.DomainType - RegistrySyncOffset *big.Int - RegistryContractAddr ethcommon.Address - Bootnodes []string - DiscoveryProtocolID [6]byte + DomainType spectypes.DomainType + RegistrySyncOffset *big.Int + RegistryContractAddr ethcommon.Address + Bootnodes []string + DiscoveryProtocolID [6]byte + TotalEthereumValidators int // value needs to be maintained — consider getting it from external API with default or per-network value(s) as fallback } func (s SSVConfig) String() string { @@ -53,21 +54,23 @@ func (s SSVConfig) String() string { } type marshaledConfig struct { - DomainType hexutil.Bytes `json:"DomainType,omitempty" yaml:"DomainType,omitempty"` - RegistrySyncOffset *big.Int `json:"RegistrySyncOffset,omitempty" yaml:"RegistrySyncOffset,omitempty"` - RegistryContractAddr ethcommon.Address `json:"RegistryContractAddr,omitempty" yaml:"RegistryContractAddr,omitempty"` - Bootnodes []string `json:"Bootnodes,omitempty" yaml:"Bootnodes,omitempty"` - DiscoveryProtocolID hexutil.Bytes `json:"DiscoveryProtocolID,omitempty" yaml:"DiscoveryProtocolID,omitempty"` + DomainType hexutil.Bytes `json:"DomainType,omitempty" yaml:"DomainType,omitempty"` + RegistrySyncOffset *big.Int `json:"RegistrySyncOffset,omitempty" yaml:"RegistrySyncOffset,omitempty"` + RegistryContractAddr ethcommon.Address `json:"RegistryContractAddr,omitempty" yaml:"RegistryContractAddr,omitempty"` + Bootnodes []string `json:"Bootnodes,omitempty" yaml:"Bootnodes,omitempty"` + DiscoveryProtocolID hexutil.Bytes `json:"DiscoveryProtocolID,omitempty" yaml:"DiscoveryProtocolID,omitempty"` + TotalEthereumValidators int `json:"TotalEthereumValidators,omitempty" yaml:"TotalEthereumValidators,omitempty"` } // Helper method to avoid duplication between MarshalJSON and MarshalYAML func (s SSVConfig) marshal() marshaledConfig { aux := marshaledConfig{ - DomainType: s.DomainType[:], - RegistrySyncOffset: s.RegistrySyncOffset, - RegistryContractAddr: s.RegistryContractAddr, - Bootnodes: s.Bootnodes, - DiscoveryProtocolID: s.DiscoveryProtocolID[:], + DomainType: s.DomainType[:], + RegistrySyncOffset: s.RegistrySyncOffset, + RegistryContractAddr: s.RegistryContractAddr, + Bootnodes: s.Bootnodes, + DiscoveryProtocolID: s.DiscoveryProtocolID[:], + TotalEthereumValidators: s.TotalEthereumValidators, } return aux @@ -92,11 +95,12 @@ func (s *SSVConfig) unmarshalFromConfig(aux marshaledConfig) error { } *s = SSVConfig{ - DomainType: spectypes.DomainType(aux.DomainType), - RegistrySyncOffset: aux.RegistrySyncOffset, - RegistryContractAddr: aux.RegistryContractAddr, - Bootnodes: aux.Bootnodes, - DiscoveryProtocolID: [6]byte(aux.DiscoveryProtocolID), + DomainType: spectypes.DomainType(aux.DomainType), + RegistrySyncOffset: aux.RegistrySyncOffset, + RegistryContractAddr: aux.RegistryContractAddr, + Bootnodes: aux.Bootnodes, + DiscoveryProtocolID: [6]byte(aux.DiscoveryProtocolID), + TotalEthereumValidators: aux.TotalEthereumValidators, } return nil diff --git a/networkconfig/test-network.go b/networkconfig/test-network.go index 34e6e6fac2..aa9922026d 100644 --- a/networkconfig/test-network.go +++ b/networkconfig/test-network.go @@ -4,18 +4,27 @@ import ( "math/big" "time" + "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" spectypes "github.com/ssvlabs/ssv-spec/types" ) var TestNetwork = NetworkConfig{ Name: "testnet", BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.BeaconTestNetwork), - SlotDuration: spectypes.BeaconTestNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.BeaconTestNetwork.SlotsPerEpoch(), - ForkVersion: spectypes.BeaconTestNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.BeaconTestNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + BeaconName: string(spectypes.BeaconTestNetwork), + SlotDuration: spectypes.BeaconTestNetwork.SlotDurationSec(), + SlotsPerEpoch: spectypes.BeaconTestNetwork.SlotsPerEpoch(), + EpochsPerSyncCommitteePeriod: 256, + SyncCommitteeSize: 512, + SyncCommitteeSubnetCount: 4, + TargetAggregatorsPerSyncSubcommittee: 16, + TargetAggregatorsPerCommittee: 16, + IntervalsPerSlot: 3, + ForkVersion: spectypes.BeaconTestNetwork.ForkVersion(), + GenesisTime: time.Unix(int64(spectypes.BeaconTestNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb")), }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoNetworkID.Byte(), 0x2}, @@ -24,5 +33,6 @@ var TestNetwork = NetworkConfig{ Bootnodes: []string{ "enr:-Li4QFIQzamdvTxGJhvcXG_DFmCeyggSffDnllY5DiU47pd_K_1MRnSaJimWtfKJ-MD46jUX9TwgW5Jqe0t4pH41RYWGAYuFnlyth2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhCLdu_SJc2VjcDI1NmsxoQN4v-N9zFYwEqzGPBBX37q24QPFvAVUtokIo1fblIsmTIN0Y3CCE4uDdWRwgg-j", }, + TotalEthereumValidators: 1_000_000, // just some high enough value, so we never accidentally reach the message-limits derived from it while testing something with local testnet }, } diff --git a/operator/duties/committee_test.go b/operator/duties/committee_test.go index 537bdc14e0..238c1a5d6b 100644 --- a/operator/duties/committee_test.go +++ b/operator/duties/committee_test.go @@ -30,13 +30,13 @@ func setupCommitteeDutiesMock( s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedSyncCommitteePeriodAtEpoch(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) uint64 { - return uint64(epoch) / s.beaconConfig.EpochsPerSyncCommitteePeriod() + return uint64(epoch) / s.beaconConfig.GetEpochsPerSyncCommitteePeriod() }, ).AnyTimes() s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().FirstEpochOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Epoch { - return phase0.Epoch(period * s.beaconConfig.EpochsPerSyncCommitteePeriod()) + return phase0.Epoch(period * s.beaconConfig.GetEpochsPerSyncCommitteePeriod()) }, ).AnyTimes() @@ -55,6 +55,8 @@ func setupCommitteeDutiesMock( }, ).AnyTimes() + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().IntervalDuration().Return(s.beaconConfig.GetSlotDuration() / 3).AnyTimes() + s.beaconNode.(*MockBeaconNode).EXPECT().AttesterDuties(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( func(ctx context.Context, epoch phase0.Epoch, indices []phase0.ValidatorIndex) ([]*eth2apiv1.AttesterDuty, error) { if waitForDuties.Get() { diff --git a/operator/duties/scheduler.go b/operator/duties/scheduler.go index 883bb32e8f..c71a74420f 100644 --- a/operator/duties/scheduler.go +++ b/operator/duties/scheduler.go @@ -16,7 +16,6 @@ import ( spectypes "github.com/ssvlabs/ssv-spec/types" "go.uber.org/zap" - "github.com/ssvlabs/ssv/beacon/goclient" "github.com/ssvlabs/ssv/logging" "github.com/ssvlabs/ssv/logging/fields" "github.com/ssvlabs/ssv/network" @@ -24,7 +23,6 @@ import ( "github.com/ssvlabs/ssv/operator/duties/dutystore" "github.com/ssvlabs/ssv/operator/slotticker" "github.com/ssvlabs/ssv/protocol/v2/types" - "github.com/ssvlabs/ssv/utils/casts" ) //go:generate go tool -modfile=../../tool.mod mockgen -package=duties -destination=./scheduler_mock.go -source=./scheduler.go @@ -292,8 +290,8 @@ func (s *Scheduler) SlotTicker(ctx context.Context) { case <-s.ticker.Next(): slot := s.ticker.Slot() - delayThirdOfSlot := s.beaconConfig.GetSlotDuration() / casts.DurationFromUint64(goclient.IntervalsPerSlot) - finalTime := s.beaconConfig.GetSlotStartTime(slot).Add(delayThirdOfSlot) + delay := s.beaconConfig.IntervalDuration() + finalTime := s.beaconConfig.GetSlotStartTime(slot).Add(delay) waitDuration := time.Until(finalTime) if waitDuration > 0 { time.Sleep(waitDuration) @@ -368,7 +366,7 @@ func (s *Scheduler) HandleHeadEvent() func(event *eth2apiv1.HeadEvent) { s.currentDutyDependentRoot = event.CurrentDutyDependentRoot currentTime := time.Now() - delay := s.beaconConfig.GetSlotDuration() / casts.DurationFromUint64(goclient.IntervalsPerSlot) /* a third of the slot duration */ + delay := s.beaconConfig.IntervalDuration() slotStartTimeWithDelay := s.beaconConfig.GetSlotStartTime(event.Slot).Add(delay) if currentTime.Before(slotStartTimeWithDelay) { logger.Debug("🏁 Head event: Block arrived before 1/3 slot", zap.Duration("time_saved", slotStartTimeWithDelay.Sub(currentTime))) diff --git a/operator/duties/scheduler_test.go b/operator/duties/scheduler_test.go index ef5d1d53fc..60d22843b6 100644 --- a/operator/duties/scheduler_test.go +++ b/operator/duties/scheduler_test.go @@ -134,7 +134,9 @@ func setupSchedulerAndMocks(t *testing.T, handlers []dutyHandler, currentSlot *S }, ).AnyTimes() - s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EpochsPerSyncCommitteePeriod().Return(uint64(256)).AnyTimes() + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().GetEpochsPerSyncCommitteePeriod().Return(uint64(256)).AnyTimes() + + s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().IntervalDuration().Return(s.beaconConfig.GetSlotDuration() / 3).AnyTimes() // Create a pool to wait for the scheduler to finish. schedulerPool := pool.New().WithErrors().WithContext(ctx) diff --git a/operator/duties/sync_committee.go b/operator/duties/sync_committee.go index ec84d80c52..a6dbc06e12 100644 --- a/operator/duties/sync_committee.go +++ b/operator/duties/sync_committee.go @@ -324,5 +324,5 @@ func (h *SyncCommitteeHandler) shouldFetchNextPeriod(slot phase0.Slot) bool { } func (h *SyncCommitteeHandler) slotsPerPeriod() uint64 { - return h.beaconConfig.EpochsPerSyncCommitteePeriod() * h.beaconConfig.GetSlotsPerEpoch() + return h.beaconConfig.GetEpochsPerSyncCommitteePeriod() * h.beaconConfig.GetSlotsPerEpoch() } diff --git a/operator/duties/sync_committee_test.go b/operator/duties/sync_committee_test.go index 2cae5238fe..5d7af60c72 100644 --- a/operator/duties/sync_committee_test.go +++ b/operator/duties/sync_committee_test.go @@ -29,13 +29,13 @@ func setupSyncCommitteeDutiesMock( s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().EstimatedSyncCommitteePeriodAtEpoch(gomock.Any()).DoAndReturn( func(epoch phase0.Epoch) uint64 { - return uint64(epoch) / s.beaconConfig.EpochsPerSyncCommitteePeriod() + return uint64(epoch) / s.beaconConfig.GetEpochsPerSyncCommitteePeriod() }, ).AnyTimes() s.beaconConfig.(*networkconfig.MockBeacon).EXPECT().FirstEpochOfSyncPeriod(gomock.Any()).DoAndReturn( func(period uint64) phase0.Epoch { - return phase0.Epoch(period * s.beaconConfig.EpochsPerSyncCommitteePeriod()) + return phase0.Epoch(period * s.beaconConfig.GetEpochsPerSyncCommitteePeriod()) }, ).AnyTimes() diff --git a/operator/validator/controller.go b/operator/validator/controller.go index 02d8c6d5b5..58492a3dbe 100644 --- a/operator/validator/controller.go +++ b/operator/validator/controller.go @@ -233,7 +233,7 @@ func NewController(logger *zap.Logger, options ControllerOptions) Controller { } } - cacheTTL := options.NetworkConfig.GetSlotDuration() * time.Duration(options.NetworkConfig.GetSlotsPerEpoch()*2) // #nosec G115 + cacheTTL := 2 * options.NetworkConfig.EpochDuration() // #nosec G115 ctrl := controller{ logger: logger.Named(logging.NameController), diff --git a/utils/testutils.go b/utils/testutils.go index 312d3e9c34..e5c5f79b00 100644 --- a/utils/testutils.go +++ b/utils/testutils.go @@ -94,6 +94,10 @@ func SetupMockNetworkConfig(t *testing.T, domainType spectypes.DomainType, curre }, ).AnyTimes() + mockNetwork.EXPECT().EpochDuration().Return(time.Duration(mockNetwork.GetSlotsPerEpoch()) * mockNetwork.GetSlotDuration()).AnyTimes() // #nosec G115 + + mockNetwork.EXPECT().IntervalDuration().Return(mockNetwork.GetSlotDuration() / 3).AnyTimes() // #nosec G115 + mockNetwork.EXPECT().GetDomainType().Return(domainType).AnyTimes() mockNetwork.EXPECT().GetBeaconName().Return(string(beaconNetwork)).AnyTimes() From 6bfa93b239a120827970e16ecafa9762cdf86809 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 27 May 2025 18:05:07 +0400 Subject: [PATCH 26/34] networkconfig: narrow config usage (#2172) * use SSV/Beacon configs instead of NetworkConfig where possible * fix linter * fix a comment * fix issues after merging --- cli/operator/node.go | 6 +++--- doppelganger/doppelganger.go | 12 ++++++------ doppelganger/doppelganger_test.go | 2 +- exporter/api/decided/stream.go | 6 +++--- network/discovery/dv5_bootnode.go | 8 ++++---- network/discovery/dv5_service.go | 26 +++++++++++++------------- network/discovery/dv5_service_test.go | 9 +++------ network/discovery/service.go | 2 +- network/discovery/service_test.go | 10 +++++----- network/discovery/util_test.go | 12 ++++++------ network/p2p/config.go | 8 ++++---- network/p2p/p2p.go | 4 ++-- network/p2p/p2p_setup.go | 21 ++++++++++----------- network/p2p/test_utils.go | 4 ++-- network/topics/controller_test.go | 2 +- network/topics/msg_id.go | 25 +++++++++++-------------- network/topics/pubsub.go | 3 --- 17 files changed, 75 insertions(+), 85 deletions(-) diff --git a/cli/operator/node.go b/cli/operator/node.go index d42b4bb2ba..479daa5db4 100644 --- a/cli/operator/node.go +++ b/cli/operator/node.go @@ -354,7 +354,7 @@ var StartNodeCmd = &cobra.Command{ cfg.P2pNetworkConfig.OperatorPubKeyHash = format.OperatorID(operatorDataStore.GetOperatorData().PublicKey) cfg.P2pNetworkConfig.OperatorDataStore = operatorDataStore cfg.P2pNetworkConfig.FullNode = cfg.SSVOptions.ValidatorOptions.FullNode - cfg.P2pNetworkConfig.Network = networkConfig + cfg.P2pNetworkConfig.NetworkConfig = networkConfig validatorsMap := validators.New(cmd.Context()) @@ -400,7 +400,7 @@ var StartNodeCmd = &cobra.Command{ ws := exporterapi.NewWsServer(cmd.Context(), logger, nil, http.NewServeMux(), cfg.WithPing) cfg.SSVOptions.WS = ws cfg.SSVOptions.WsAPIPort = cfg.WsAPIPort - cfg.SSVOptions.ValidatorOptions.NewDecidedHandler = decided.NewStreamPublisher(networkConfig, logger, ws) + cfg.SSVOptions.ValidatorOptions.NewDecidedHandler = decided.NewStreamPublisher(logger, networkConfig.DomainType, ws) } cfg.SSVOptions.ValidatorOptions.DutyRoles = []spectypes.BeaconRole{spectypes.BNRoleAttester} // TODO could be better to set in other place @@ -461,7 +461,7 @@ var StartNodeCmd = &cobra.Command{ var doppelgangerHandler doppelganger.Provider if cfg.EnableDoppelgangerProtection { doppelgangerHandler = doppelganger.NewHandler(&doppelganger.Options{ - Network: networkConfig, + BeaconConfig: networkConfig.BeaconConfig, BeaconNode: consensusClient, ValidatorProvider: nodeStorage.ValidatorStore().WithOperatorID(operatorDataStore.GetOperatorID), SlotTickerProvider: slotTickerProvider, diff --git a/doppelganger/doppelganger.go b/doppelganger/doppelganger.go index d9ebab9654..276006b460 100644 --- a/doppelganger/doppelganger.go +++ b/doppelganger/doppelganger.go @@ -55,7 +55,7 @@ type BeaconNode interface { // Options contains the configuration options for the Doppelgänger protection. type Options struct { - Network networkconfig.NetworkConfig + BeaconConfig networkconfig.BeaconConfig BeaconNode BeaconNode ValidatorProvider ValidatorProvider SlotTickerProvider slotticker.Provider @@ -68,7 +68,7 @@ type handler struct { mu sync.RWMutex validatorsState map[phase0.ValidatorIndex]*doppelgangerState - network networkconfig.NetworkConfig + beaconConfig networkconfig.BeaconConfig beaconNode BeaconNode validatorProvider ValidatorProvider slotTickerProvider slotticker.Provider @@ -78,7 +78,7 @@ type handler struct { // NewHandler initializes a new instance of the Doppelgänger protection. func NewHandler(opts *Options) *handler { return &handler{ - network: opts.Network, + beaconConfig: opts.BeaconConfig, beaconNode: opts.BeaconNode, validatorProvider: opts.ValidatorProvider, slotTickerProvider: opts.SlotTickerProvider, @@ -176,7 +176,7 @@ func (h *handler) Start(ctx context.Context) error { var startEpoch, previousEpoch phase0.Epoch firstRun := true ticker := h.slotTickerProvider() - slotsPerEpoch := h.network.SlotsPerEpoch + slotsPerEpoch := h.beaconConfig.SlotsPerEpoch for { select { @@ -184,7 +184,7 @@ func (h *handler) Start(ctx context.Context) error { return ctx.Err() case <-ticker.Next(): currentSlot := ticker.Slot() - currentEpoch := h.network.EstimatedEpochAtSlot(currentSlot) + currentEpoch := h.beaconConfig.EstimatedEpochAtSlot(currentSlot) buildStr := fmt.Sprintf("e%v-s%v-#%v", currentEpoch, currentSlot, currentSlot%32+1) h.logger.Debug("🛠 ticker event", zap.String("epoch_slot_pos", buildStr)) @@ -233,7 +233,7 @@ func (h *handler) Start(ctx context.Context) error { func (h *handler) checkLiveness(ctx context.Context, slot phase0.Slot, epoch phase0.Epoch) { // Set a deadline until the start of the next slot, with a 100ms safety margin - ctx, cancel := context.WithDeadline(ctx, h.network.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) + ctx, cancel := context.WithDeadline(ctx, h.beaconConfig.GetSlotStartTime(slot+1).Add(100*time.Millisecond)) defer cancel() h.mu.RLock() diff --git a/doppelganger/doppelganger_test.go b/doppelganger/doppelganger_test.go index 9cc9a047d6..13d5766ba4 100644 --- a/doppelganger/doppelganger_test.go +++ b/doppelganger/doppelganger_test.go @@ -19,7 +19,7 @@ func newTestDoppelgangerHandler(t *testing.T) *handler { logger := logging.TestLogger(t) return NewHandler(&Options{ - Network: networkconfig.TestNetwork, + BeaconConfig: networkconfig.TestNetwork.BeaconConfig, BeaconNode: mockBeaconNode, ValidatorProvider: mockValidatorProvider, Logger: logger, diff --git a/exporter/api/decided/stream.go b/exporter/api/decided/stream.go index 52a02a6c7c..56fd00ef11 100644 --- a/exporter/api/decided/stream.go +++ b/exporter/api/decided/stream.go @@ -5,18 +5,18 @@ import ( "time" "github.com/patrickmn/go-cache" + spectypes "github.com/ssvlabs/ssv-spec/types" "go.uber.org/zap" "github.com/ssvlabs/ssv/exporter/api" "github.com/ssvlabs/ssv/logging/fields" - "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/qbft/controller" qbftstorage "github.com/ssvlabs/ssv/protocol/v2/qbft/storage" ) // NewStreamPublisher handles incoming newly decided messages. // it forward messages to websocket stream, where messages are cached (1m TTL) to avoid flooding -func NewStreamPublisher(domainTypeProvider networkconfig.NetworkConfig, logger *zap.Logger, ws api.WebSocketServer) controller.NewDecidedHandler { +func NewStreamPublisher(logger *zap.Logger, domainType spectypes.DomainType, ws api.WebSocketServer) controller.NewDecidedHandler { c := cache.New(time.Minute, time.Minute*3/2) feed := ws.BroadcastFeed() return func(msg qbftstorage.Participation) { @@ -28,6 +28,6 @@ func NewStreamPublisher(domainTypeProvider networkconfig.NetworkConfig, logger * c.SetDefault(key, true) logger.Debug("broadcast decided stream", fields.PubKey(msg.PubKey[:]), fields.Slot(msg.Slot)) - feed.Send(api.NewParticipantsAPIMsg(domainTypeProvider.DomainType, msg)) + feed.Send(api.NewParticipantsAPIMsg(domainType, msg)) } } diff --git a/network/discovery/dv5_bootnode.go b/network/discovery/dv5_bootnode.go index 3831b71299..cc58a03940 100644 --- a/network/discovery/dv5_bootnode.go +++ b/network/discovery/dv5_bootnode.go @@ -28,9 +28,9 @@ type Bootnode struct { } // NewBootnode creates a new bootnode -func NewBootnode(pctx context.Context, logger *zap.Logger, networkCfg networkconfig.NetworkConfig, opts *BootnodeOptions) (*Bootnode, error) { +func NewBootnode(pctx context.Context, logger *zap.Logger, ssvConfig networkconfig.SSVConfig, opts *BootnodeOptions) (*Bootnode, error) { ctx, cancel := context.WithCancel(pctx) - disc, err := createBootnodeDiscovery(ctx, logger, networkCfg, opts) + disc, err := createBootnodeDiscovery(ctx, logger, ssvConfig, opts) if err != nil { cancel() return nil, err @@ -52,13 +52,13 @@ func (b *Bootnode) Close() error { return nil } -func createBootnodeDiscovery(ctx context.Context, logger *zap.Logger, networkCfg networkconfig.NetworkConfig, opts *BootnodeOptions) (Service, error) { +func createBootnodeDiscovery(ctx context.Context, logger *zap.Logger, ssvConfig networkconfig.SSVConfig, opts *BootnodeOptions) (Service, error) { privKey, err := utils.ECDSAPrivateKey(logger.Named(logging.NameBootNode), opts.PrivateKey) if err != nil { return nil, err } discOpts := &Options{ - NetworkConfig: networkCfg, + SSVConfig: ssvConfig, DiscV5Opts: &DiscV5Options{ IP: opts.ExternalIP, BindIP: "", // net.IPv4zero.String() diff --git a/network/discovery/dv5_service.go b/network/discovery/dv5_service.go index 0b3685a1e8..3ff6f6552b 100644 --- a/network/discovery/dv5_service.go +++ b/network/discovery/dv5_service.go @@ -72,8 +72,8 @@ type DiscV5Service struct { conn *net.UDPConn sharedConn *SharedUDPConn - networkConfig networkconfig.NetworkConfig - subnets commons.Subnets + ssvConfig networkconfig.SSVConfig + subnets commons.Subnets publishLock chan struct{} } @@ -86,7 +86,7 @@ func newDiscV5Service(pctx context.Context, logger *zap.Logger, opts *Options) ( cancel: cancel, conns: opts.ConnIndex, subnetsIdx: opts.SubnetsIdx, - networkConfig: opts.NetworkConfig, + ssvConfig: opts.SSVConfig, subnets: opts.DiscV5Opts.Subnets, publishLock: make(chan struct{}, 1), discoveredPeersPool: opts.DiscoveredPeersPool, @@ -196,9 +196,9 @@ func (dvs *DiscV5Service) checkPeer(ctx context.Context, e PeerEvent) error { if err != nil { return errors.Wrap(err, "could not read domain type") } - if dvs.networkConfig.DomainType != nodeDomainType { + if dvs.ssvConfig.DomainType != nodeDomainType { recordPeerSkipped(ctx, skipReasonDomainTypeMismatch) - return fmt.Errorf("domain type %x doesn't match %x", nodeDomainType, dvs.networkConfig.DomainType) + return fmt.Errorf("domain type %x doesn't match %x", nodeDomainType, dvs.ssvConfig.DomainType) } // Get the peer's subnets, skipping if it has none. @@ -253,7 +253,7 @@ func (dvs *DiscV5Service) initDiscV5Listener(discOpts *Options) error { } // Get the protocol ID, or set to default if not provided - protocolID := dvs.networkConfig.DiscoveryProtocolID + protocolID := dvs.ssvConfig.DiscoveryProtocolID emptyProtocolID := [6]byte{} if protocolID == emptyProtocolID { protocolID = DefaultSSVProtocolID @@ -278,7 +278,7 @@ func (dvs *DiscV5Service) initDiscV5Listener(discOpts *Options) error { fields.BindIP(bindIP), zap.Uint16("UdpPort", opts.Port), fields.ENRLocalNode(localNode), - fields.Domain(discOpts.NetworkConfig.DomainType), + fields.Domain(discOpts.SSVConfig.DomainType), fields.ProtocolID(protocolID), ) @@ -297,7 +297,7 @@ func (dvs *DiscV5Service) initDiscV5Listener(discOpts *Options) error { fields.BindIP(bindIP), zap.Uint16("UdpPort", opts.Port), fields.ENRLocalNode(localNode), - fields.Domain(discOpts.NetworkConfig.DomainType), + fields.Domain(discOpts.SSVConfig.DomainType), ) dvs.dv5Listener = NewForkingDV5Listener(dvs.logger, dv5PreForkListener, dv5PostForkListener, 5*time.Second) @@ -388,12 +388,12 @@ func (dvs *DiscV5Service) DeregisterSubnets(subnets ...uint64) (updated bool, er // PublishENR publishes the ENR with the current domain type across the network func (dvs *DiscV5Service) PublishENR() { // Update own node record. - err := records.SetDomainTypeEntry(dvs.dv5Listener.LocalNode(), records.KeyDomainType, dvs.networkConfig.DomainType) + err := records.SetDomainTypeEntry(dvs.dv5Listener.LocalNode(), records.KeyDomainType, dvs.ssvConfig.DomainType) if err != nil { dvs.logger.Error("could not set domain type", zap.Error(err)) return } - err = records.SetDomainTypeEntry(dvs.dv5Listener.LocalNode(), records.KeyNextDomainType, dvs.networkConfig.DomainType) + err = records.SetDomainTypeEntry(dvs.dv5Listener.LocalNode(), records.KeyNextDomainType, dvs.ssvConfig.DomainType) if err != nil { dvs.logger.Error("could not set next domain type", zap.Error(err)) return @@ -458,8 +458,8 @@ func (dvs *DiscV5Service) createLocalNode(discOpts *Options, ipAddr net.IP) (*en localNode, // Satisfy decorations of forks supported by this node. - DecorateWithDomainType(records.KeyDomainType, dvs.networkConfig.DomainType), - DecorateWithDomainType(records.KeyNextDomainType, dvs.networkConfig.DomainType), + DecorateWithDomainType(records.KeyDomainType, dvs.ssvConfig.DomainType), + DecorateWithDomainType(records.KeyNextDomainType, dvs.ssvConfig.DomainType), DecorateWithSubnets(opts.Subnets), ) if err != nil { @@ -468,7 +468,7 @@ func (dvs *DiscV5Service) createLocalNode(discOpts *Options, ipAddr net.IP) (*en logFields := []zapcore.Field{ fields.ENRLocalNode(localNode), - fields.Domain(dvs.networkConfig.DomainType), + fields.Domain(dvs.ssvConfig.DomainType), } if opts.Subnets.HasActive() { diff --git a/network/discovery/dv5_service_test.go b/network/discovery/dv5_service_test.go index f9b1f5025c..f9992a8beb 100644 --- a/network/discovery/dv5_service_test.go +++ b/network/discovery/dv5_service_test.go @@ -82,11 +82,8 @@ func TestCheckPeer(t *testing.T) { } ) - var checkPeerTestNetwork = networkconfig.NetworkConfig{ - BeaconConfig: networkconfig.TestNetwork.BeaconConfig, - SSVConfig: networkconfig.SSVConfig{ - DomainType: spectypes.DomainType{0x1, 0x2, 0x3, 0x4}, - }, + var checkPeerTestSSVConfig = networkconfig.SSVConfig{ + DomainType: spectypes.DomainType{0x1, 0x2, 0x3, 0x4}, } // Create the LocalNode instances for the tests. @@ -122,7 +119,7 @@ func TestCheckPeer(t *testing.T) { ctx: ctx, conns: &mock.MockConnectionIndex{LimitValue: false}, subnetsIdx: subnetIndex, - networkConfig: checkPeerTestNetwork, + ssvConfig: checkPeerTestSSVConfig, subnets: mySubnets, discoveredPeersPool: ttl.New[peer.ID, DiscoveredPeer](time.Hour, time.Hour), trimmedRecently: ttl.New[peer.ID, struct{}](time.Hour, time.Hour), diff --git a/network/discovery/service.go b/network/discovery/service.go index be69188b4d..92ac437979 100644 --- a/network/discovery/service.go +++ b/network/discovery/service.go @@ -42,7 +42,7 @@ type Options struct { SubnetsIdx peers.SubnetsIndex HostAddress string HostDNS string - NetworkConfig networkconfig.NetworkConfig + SSVConfig networkconfig.SSVConfig DiscoveredPeersPool *ttl.Map[peer.ID, DiscoveredPeer] TrimmedRecently *ttl.Map[peer.ID, struct{}] } diff --git a/network/discovery/service_test.go b/network/discovery/service_test.go index 1f670291b0..c980f3f3ea 100644 --- a/network/discovery/service_test.go +++ b/network/discovery/service_test.go @@ -34,7 +34,7 @@ func TestNewDiscV5Service(t *testing.T) { assert.NotNil(t, dvs.dv5Listener) assert.NotNil(t, dvs.conns) assert.NotNil(t, dvs.subnetsIdx) - assert.NotNil(t, dvs.networkConfig) + assert.NotNil(t, dvs.ssvConfig) // Check bootnodes CheckBootnodes(t, dvs, testNetConfig) @@ -144,7 +144,7 @@ func TestDiscV5Service_PublishENR(t *testing.T) { ctx, cancel := context.WithTimeout(t.Context(), 2*time.Second) defer cancel() - opts := testingDiscoveryOptions(t, testNetConfig) + opts := testingDiscoveryOptions(t, testNetConfig.SSVConfig) dvs, err := newDiscV5Service(ctx, testLogger, opts) require.NoError(t, err) @@ -158,7 +158,7 @@ func TestDiscV5Service_PublishENR(t *testing.T) { checkLocalNodeDomainTypeAlignment(t, localNode, testNetConfig) // Change network config - dvs.networkConfig = networkconfig.HoleskyStage + dvs.ssvConfig = networkconfig.HoleskyStage.SSVConfig // Test PublishENR method dvs.PublishENR() @@ -170,7 +170,7 @@ func TestDiscV5Service_Bootstrap(t *testing.T) { ctx, cancel := context.WithTimeout(t.Context(), 2*time.Second) defer cancel() - opts := testingDiscoveryOptions(t, testNetConfig) + opts := testingDiscoveryOptions(t, testNetConfig.SSVConfig) dvs, err := newDiscV5Service(t.Context(), testLogger, opts) require.NoError(t, err) @@ -365,7 +365,7 @@ func TestServiceAddressConfiguration(t *testing.T) { defer cancel() // create options with unique ports for parallel testing - opts := testingDiscoveryOptions(t, testNetConfig) + opts := testingDiscoveryOptions(t, testNetConfig.SSVConfig) opts.DiscV5Opts.Port = uint16(13000 + i*10) opts.DiscV5Opts.TCPPort = uint16(14000 + i*10) opts.HostAddress = tc.hostAddress diff --git a/network/discovery/util_test.go b/network/discovery/util_test.go index b435207fcf..47237be3cf 100644 --- a/network/discovery/util_test.go +++ b/network/discovery/util_test.go @@ -40,7 +40,7 @@ var ( ) // Options for the discovery service -func testingDiscoveryOptions(t *testing.T, networkConfig networkconfig.NetworkConfig) *Options { +func testingDiscoveryOptions(t *testing.T, ssvConfig networkconfig.SSVConfig) *Options { // Generate key privKey, err := crypto.GenerateKey() require.NoError(t, err) @@ -54,7 +54,7 @@ func testingDiscoveryOptions(t *testing.T, networkConfig networkconfig.NetworkCo Port: testPort, TCPPort: testTCPPort, NetworkKey: privKey, - Bootnodes: networkConfig.Bootnodes, + Bootnodes: ssvConfig.Bootnodes, Subnets: mockSubnets(1), EnableLogging: false, } @@ -67,15 +67,15 @@ func testingDiscoveryOptions(t *testing.T, networkConfig networkconfig.NetworkCo DiscV5Opts: discV5Opts, ConnIndex: connectionIndex, SubnetsIdx: subnetsIndex, - NetworkConfig: networkConfig, + SSVConfig: ssvConfig, DiscoveredPeersPool: ttl.New[peer.ID, DiscoveredPeer](time.Hour, time.Hour), TrimmedRecently: ttl.New[peer.ID, struct{}](time.Hour, time.Hour), } } // Testing discovery with a given NetworkConfig -func testingDiscoveryWithNetworkConfig(t *testing.T, netConfig networkconfig.NetworkConfig) *DiscV5Service { - opts := testingDiscoveryOptions(t, netConfig) +func testingDiscoveryWithNetworkConfig(t *testing.T, ssvConfig networkconfig.SSVConfig) *DiscV5Service { + opts := testingDiscoveryOptions(t, ssvConfig) dvs, err := newDiscV5Service(t.Context(), testLogger, opts) require.NoError(t, err) require.NotNil(t, dvs) @@ -84,7 +84,7 @@ func testingDiscoveryWithNetworkConfig(t *testing.T, netConfig networkconfig.Net // Testing discovery service func testingDiscovery(t *testing.T) *DiscV5Service { - return testingDiscoveryWithNetworkConfig(t, testNetConfig) + return testingDiscoveryWithNetworkConfig(t, testNetConfig.SSVConfig) } // Testing LocalNode diff --git a/network/p2p/config.go b/network/p2p/config.go index a9c47f408b..0f6869431d 100644 --- a/network/p2p/config.go +++ b/network/p2p/config.go @@ -73,8 +73,8 @@ type Config struct { UserAgent string // NodeStorage is used to get operator metadata. NodeStorage storage.Storage - // Network defines a network configuration. - Network networkconfig.NetworkConfig + // NetworkConfig defines a network configuration. + NetworkConfig networkconfig.NetworkConfig // MessageValidator validates incoming messages. MessageValidator validation.MessageValidator @@ -183,12 +183,12 @@ func (c *Config) configureAddrs(logger *zap.Logger, opts []libp2p.Option) ([]lib func (c *Config) TransformBootnodes() []string { if c.Bootnodes == "" { - return c.Network.Bootnodes + return c.NetworkConfig.Bootnodes } // extend additional bootnodes from config extraBootnodes := strings.Split(c.Bootnodes, ";") - return append(extraBootnodes, c.Network.Bootnodes...) + return append(extraBootnodes, c.NetworkConfig.Bootnodes...) } func userAgent(fromCfg string) string { diff --git a/network/p2p/p2p.go b/network/p2p/p2p.go index ca334423cf..3cca377a18 100644 --- a/network/p2p/p2p.go +++ b/network/p2p/p2p.go @@ -555,9 +555,9 @@ func (n *p2pNetwork) UpdateScoreParams() { // function to get the starting time of the next epoch nextEpochStartingTime := func() time.Time { - currEpoch := n.cfg.Network.EstimatedCurrentEpoch() + currEpoch := n.cfg.NetworkConfig.EstimatedCurrentEpoch() nextEpoch := currEpoch + 1 - return n.cfg.Network.EpochStartTime(nextEpoch) + return n.cfg.NetworkConfig.EpochStartTime(nextEpoch) } // Create timer that triggers on the beginning of the next epoch diff --git a/network/p2p/p2p_setup.go b/network/p2p/p2p_setup.go index 1c1f527cf4..1a7877f277 100644 --- a/network/p2p/p2p_setup.go +++ b/network/p2p/p2p_setup.go @@ -186,7 +186,7 @@ func (n *p2pNetwork) setupPeerServices() error { if err != nil { return err } - d := n.cfg.Network.DomainType + d := n.cfg.NetworkConfig.DomainType domain := "0x" + hex.EncodeToString(d[:]) self := records.NewNodeInfo(domain) self.Metadata = &records.NodeMetadata{ @@ -215,7 +215,7 @@ func (n *p2pNetwork) setupPeerServices() error { // Handshake filters filters := func() []connections.HandshakeFilter { - newDomain := n.cfg.Network.DomainType + newDomain := n.cfg.NetworkConfig.DomainType newDomainString := "0x" + hex.EncodeToString(newDomain[:]) return []connections.HandshakeFilter{ connections.NetworkIDFilter(newDomainString), @@ -234,7 +234,7 @@ func (n *p2pNetwork) setupPeerServices() error { SubnetsIdx: n.idx, IDService: ids, Network: n.host.Network(), - DomainType: n.cfg.Network.DomainType, + DomainType: n.cfg.NetworkConfig.DomainType, SubnetsProvider: n.ActiveSubnets, }, filters) @@ -291,7 +291,7 @@ func (n *p2pNetwork) setupDiscovery() error { SubnetsIdx: n.idx, HostAddress: n.cfg.HostAddress, HostDNS: n.cfg.HostDNS, - NetworkConfig: n.cfg.Network, + SSVConfig: n.cfg.NetworkConfig.SSVConfig, DiscoveredPeersPool: n.discoveredPeersPool, TrimmedRecently: n.trimmedRecently, } @@ -308,12 +308,11 @@ func (n *p2pNetwork) setupDiscovery() error { func (n *p2pNetwork) setupPubsub() (topics.Controller, error) { cfg := &topics.PubSubConfig{ - NetworkConfig: n.cfg.Network, - Host: n.host, - TraceLog: n.cfg.PubSubTrace, - MsgValidator: n.msgValidator, - MsgHandler: n.handlePubsubMessages(), - ScoreIndex: n.idx, + Host: n.host, + TraceLog: n.cfg.PubSubTrace, + MsgValidator: n.msgValidator, + MsgHandler: n.handlePubsubMessages(), + ScoreIndex: n.idx, //Discovery: n.disc, OutboundQueueSize: n.cfg.PubsubOutQueueSize, ValidationQueueSize: n.cfg.PubsubValidationQueueSize, @@ -332,7 +331,7 @@ func (n *p2pNetwork) setupPubsub() (topics.Controller, error) { cfg.ScoreIndex = nil } - midHandler := topics.NewMsgIDHandler(n.ctx, n.cfg.Network, time.Minute*2) + midHandler := topics.NewMsgIDHandler(n.ctx, time.Minute*2) n.msgResolver = midHandler cfg.MsgIDHandler = midHandler go cfg.MsgIDHandler.Start() diff --git a/network/p2p/test_utils.go b/network/p2p/test_utils.go index 8fb6c3c5d0..adca8984c1 100644 --- a/network/p2p/test_utils.go +++ b/network/p2p/test_utils.go @@ -55,7 +55,7 @@ func (ln *LocalNet) WithBootnode(ctx context.Context, logger *zap.Logger) error if err != nil { return err } - bn, err := discovery.NewBootnode(ctx, logger, networkconfig.TestNetwork, &discovery.BootnodeOptions{ + bn, err := discovery.NewBootnode(ctx, logger, networkconfig.TestNetwork.SSVConfig, &discovery.BootnodeOptions{ PrivateKey: hex.EncodeToString(b), ExternalIP: "127.0.0.1", Port: ln.udpRand.Next(13001, 13999), @@ -185,7 +185,7 @@ func (ln *LocalNet) NewTestP2pNetwork(ctx context.Context, nodeIndex uint64, key signatureVerifier, phase0.Epoch(0), ) - cfg.Network = networkconfig.TestNetwork + cfg.NetworkConfig = networkconfig.TestNetwork if options.TotalValidators > 0 { cfg.GetValidatorStats = func() (uint64, uint64, uint64, error) { return options.TotalValidators, options.ActiveValidators, options.MyValidators, nil diff --git a/network/topics/controller_test.go b/network/topics/controller_test.go index 8e7a40b28b..6957bfa327 100644 --- a/network/topics/controller_test.go +++ b/network/topics/controller_test.go @@ -385,7 +385,7 @@ func newPeer(ctx context.Context, logger *zap.Logger, t *testing.T, msgValidator var p *P var midHandler topics.MsgIDHandler if msgID { - midHandler = topics.NewMsgIDHandler(ctx, networkconfig.TestNetwork, 2*time.Minute) + midHandler = topics.NewMsgIDHandler(ctx, 2*time.Minute) go midHandler.Start() } cfg := &topics.PubSubConfig{ diff --git a/network/topics/msg_id.go b/network/topics/msg_id.go index 0931d9cbf8..faa55fb499 100644 --- a/network/topics/msg_id.go +++ b/network/topics/msg_id.go @@ -13,7 +13,6 @@ import ( "go.uber.org/zap" "github.com/ssvlabs/ssv/logging/fields" - "github.com/ssvlabs/ssv/networkconfig" ) const ( @@ -55,23 +54,21 @@ type msgIDEntry struct { // msgIDHandler implements MsgIDHandler type msgIDHandler struct { - networkConfig networkconfig.NetworkConfig - ctx context.Context - added chan addedEvent - ids map[string]*msgIDEntry - locker sync.Locker - ttl time.Duration + ctx context.Context + added chan addedEvent + ids map[string]*msgIDEntry + locker sync.Locker + ttl time.Duration } // NewMsgIDHandler creates a new MsgIDHandler -func NewMsgIDHandler(ctx context.Context, networkConfig networkconfig.NetworkConfig, ttl time.Duration) MsgIDHandler { +func NewMsgIDHandler(ctx context.Context, ttl time.Duration) MsgIDHandler { handler := &msgIDHandler{ - networkConfig: networkConfig, - ctx: ctx, - added: make(chan addedEvent, msgIDHandlerBufferSize), - ids: make(map[string]*msgIDEntry), - locker: &sync.Mutex{}, - ttl: ttl, + ctx: ctx, + added: make(chan addedEvent, msgIDHandlerBufferSize), + ids: make(map[string]*msgIDEntry), + locker: &sync.Mutex{}, + ttl: ttl, } return handler } diff --git a/network/topics/pubsub.go b/network/topics/pubsub.go index 9576c9f0bc..a58c007d0c 100644 --- a/network/topics/pubsub.go +++ b/network/topics/pubsub.go @@ -18,7 +18,6 @@ import ( "github.com/ssvlabs/ssv/network/commons" "github.com/ssvlabs/ssv/network/peers" "github.com/ssvlabs/ssv/network/topics/params" - "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/registry/storage" ) @@ -46,8 +45,6 @@ const ( // PubSubConfig is the needed config to instantiate pubsub type PubSubConfig struct { - NetworkConfig networkconfig.NetworkConfig - Host host.Host TraceLog bool StaticPeers []peer.AddrInfo From 411a3a1cad8f8bc2c1171bb39bb82b7ed6288c3f Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 27 May 2025 11:21:17 -0300 Subject: [PATCH 27/34] fix issues after merging --- network/p2p/p2p_setup.go | 11 ++++++----- network/topics/pubsub.go | 10 ++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/network/p2p/p2p_setup.go b/network/p2p/p2p_setup.go index 1a7877f277..1db12a4aca 100644 --- a/network/p2p/p2p_setup.go +++ b/network/p2p/p2p_setup.go @@ -308,11 +308,12 @@ func (n *p2pNetwork) setupDiscovery() error { func (n *p2pNetwork) setupPubsub() (topics.Controller, error) { cfg := &topics.PubSubConfig{ - Host: n.host, - TraceLog: n.cfg.PubSubTrace, - MsgValidator: n.msgValidator, - MsgHandler: n.handlePubsubMessages(), - ScoreIndex: n.idx, + NetworkConfig: n.cfg.NetworkConfig, + Host: n.host, + TraceLog: n.cfg.PubSubTrace, + MsgValidator: n.msgValidator, + MsgHandler: n.handlePubsubMessages(), + ScoreIndex: n.idx, //Discovery: n.disc, OutboundQueueSize: n.cfg.PubsubOutQueueSize, ValidationQueueSize: n.cfg.PubsubValidationQueueSize, diff --git a/network/topics/pubsub.go b/network/topics/pubsub.go index a58c007d0c..d32c3e9b13 100644 --- a/network/topics/pubsub.go +++ b/network/topics/pubsub.go @@ -18,6 +18,7 @@ import ( "github.com/ssvlabs/ssv/network/commons" "github.com/ssvlabs/ssv/network/peers" "github.com/ssvlabs/ssv/network/topics/params" + "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/registry/storage" ) @@ -45,10 +46,11 @@ const ( // PubSubConfig is the needed config to instantiate pubsub type PubSubConfig struct { - Host host.Host - TraceLog bool - StaticPeers []peer.AddrInfo - MsgHandler PubsubMessageHandler + NetworkConfig networkconfig.NetworkConfig + Host host.Host + TraceLog bool + StaticPeers []peer.AddrInfo + MsgHandler PubsubMessageHandler // MsgValidator accepts the topic name and returns the corresponding msg validator // in case we need different validators for specific topics, // this should be the place to map a validator to topic From 2fdf4db5c464a81ca067b5a400efe9e74829b148 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 27 May 2025 19:22:54 +0400 Subject: [PATCH 28/34] beacon,networkconfig: move fork handling from beacon to networkconfig (#2178) * beacon/goclient: get beacon config from beacon node * use beacon config obtained from beacon node * log config as JSON * networkconfig: CLI for custom SSV config generation * implement JSON marshaling and YAML marshaling/unmarshaling * remove TotalEthereumValidators * simplify marshaling/unmarshaling logic * fix markdown formatting * use yaml@v3 * add tests * simplify unmarshaling * delete a comment * use Stringer to log node * guard beacon config reads with mutex * add a timeout log * delete hardcoded beacon configs * Revert "delete hardcoded beacon configs" This reverts commit c2e2f8f0124c0c65a088a3957fdeda4008f85bf2. * networkconfig: make hardcoded values configurable * fix issues after merging * code review comments * fix issues after merging * delete outer metrics for genesisForClient * rewrite modulo calculation * code review comments * unexport supportedSSVConfigs * revert the modulo calculation * add EpochDuration mock * G115 * fill missing fields in configs * add a comment about eth spec * fix error text * use genesis validators root from config in computeVoluntaryExitDomain * beacon,networkconfig: move forks from beacon to networkconfig * get rid of using Genesis method * use ForkAtEpoch instead of DataVersion * generate mocks * fix linter * fix beacon tests * beacon: delete ForkAtEpoch * fix ekm tests * update go.mod * fix some TODOs * fix linter * fix a typo * remove redundant comments * remove Spec method * delete a comment * uncomment config print * fix a context bug * fix issues after merging * pass network config name * update go.mod * fix issues after merging --- beacon/goclient/aggregator.go | 4 +- beacon/goclient/attest_test.go | 28 +- beacon/goclient/current_fork.go | 46 -- beacon/goclient/current_fork_test.go | 134 ----- beacon/goclient/dataversion.go | 92 ---- beacon/goclient/dataversion_test.go | 216 -------- beacon/goclient/genesis.go | 4 - beacon/goclient/genesis_test.go | 38 +- beacon/goclient/goclient.go | 49 +- beacon/goclient/signing.go | 31 +- beacon/goclient/signing_test.go | 2 +- beacon/goclient/spec.go | 169 +++++- beacon/goclient/spec_test.go | 4 +- cli/operator/node.go | 4 +- go.mod | 2 +- go.sum | 6 +- .../qbft/tests/temp_testing_beacon_network.go | 3 - network/topics/pubsub.go | 8 +- networkconfig/beacon.go | 82 ++- networkconfig/beacon_mock.go | 30 ++ networkconfig/beacon_test.go | 121 +++++ networkconfig/holesky.go | 41 +- networkconfig/hoodi.go | 41 +- networkconfig/local-testnet.go | 35 +- networkconfig/mainnet.go | 41 +- networkconfig/network_mock.go | 30 ++ networkconfig/sepolia.go | 42 +- networkconfig/test-network.go | 35 +- protocol/v2/blockchain/beacon/client.go | 7 - protocol/v2/blockchain/beacon/mock_client.go | 38 -- protocol/v2/ssv/runner/committee.go | 7 +- ssvsigner/ekm/mock.go | 21 - ssvsigner/ekm/remote_key_manager.go | 45 +- ssvsigner/ekm/remote_key_manager_test.go | 490 +----------------- ssvsigner/go.mod | 2 +- ssvsigner/go.sum | 9 +- 36 files changed, 743 insertions(+), 1214 deletions(-) delete mode 100644 beacon/goclient/current_fork.go delete mode 100644 beacon/goclient/current_fork_test.go delete mode 100644 beacon/goclient/dataversion.go delete mode 100644 beacon/goclient/dataversion_test.go create mode 100644 networkconfig/beacon_test.go diff --git a/beacon/goclient/aggregator.go b/beacon/goclient/aggregator.go index 077eed75d2..107cb4e024 100644 --- a/beacon/goclient/aggregator.go +++ b/beacon/goclient/aggregator.go @@ -39,7 +39,9 @@ func (gc *GoClient) SubmitAggregateSelectionProof( if err != nil { return nil, DataVersionNil, fmt.Errorf("failed to get attestation data: %w", err) } - if gc.DataVersion(gc.getBeaconConfig().EstimatedEpochAtSlot(attData.Slot)) < spec.DataVersionElectra { + + dataVersion, _ := gc.beaconConfig.ForkAtEpoch(gc.getBeaconConfig().EstimatedEpochAtSlot(attData.Slot)) + if dataVersion < spec.DataVersionElectra { attData.Index = committeeIndex } diff --git a/beacon/goclient/attest_test.go b/beacon/goclient/attest_test.go index 14d23a2ed1..b9f9d3e203 100644 --- a/beacon/goclient/attest_test.go +++ b/beacon/goclient/attest_test.go @@ -58,17 +58,28 @@ var ( }`), "/eth/v1/beacon/genesis": []byte(`{ "data": { - "genesis_time": "1695902400", - "genesis_validators_root": "0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1", + "genesis_time": "1606824023", + "genesis_validators_root": "0x4b363db94e28612020049ce3795b0252c16c4241df2bc9ef221abde47527c0d0", "genesis_fork_version": "0x00000000" } }`), "/eth/v1/config/spec": []byte(`{ "data": { - "CONFIG_NAME": "holesky", + "CONFIG_NAME": "mainnet", "GENESIS_FORK_VERSION": "0x00000000", - "CAPELLA_FORK_VERSION": "0x04017000", - "MIN_GENESIS_TIME": "1695902100", + "ALTAIR_FORK_VERSION": "0x01000000", + "ALTAIR_FORK_EPOCH": "74240", + "BELLATRIX_FORK_VERSION": "0x02000000", + "BELLATRIX_FORK_EPOCH": "144896", + "CAPELLA_FORK_VERSION": "0x03000000", + "CAPELLA_FORK_EPOCH": "194048", + "DENEB_FORK_VERSION": "0x04000000", + "DENEB_FORK_EPOCH": "269568", + "ELECTRA_FORK_VERSION": "0x05000000", + "ELECTRA_FORK_EPOCH": "364032", + "FULU_FORK_VERSION": "0x06000000", + "FULU_FORK_EPOCH": "18446744073709551615", + "MIN_GENESIS_TIME": "1606824000", "SECONDS_PER_SLOT": "12", "SLOTS_PER_EPOCH": "32", "EPOCHS_PER_SYNC_COMMITTEE_PERIOD": "256", @@ -76,12 +87,7 @@ var ( "SYNC_COMMITTEE_SUBNET_COUNT": "4", "TARGET_AGGREGATORS_PER_COMMITTEE": "16", "TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE": "16", - "INTERVALS_PER_SLOT": "3", - "ALTAIR_FORK_EPOCH": "74240", - "BELLATRIX_FORK_EPOCH": "144896", - "CAPELLA_FORK_EPOCH": "194048", - "DENEB_FORK_EPOCH": "269568", - "ELECTRA_FORK_EPOCH": "18446744073709551615" + "INTERVALS_PER_SLOT": "3" } }`), } diff --git a/beacon/goclient/current_fork.go b/beacon/goclient/current_fork.go deleted file mode 100644 index 813c25a9ea..0000000000 --- a/beacon/goclient/current_fork.go +++ /dev/null @@ -1,46 +0,0 @@ -package goclient - -import ( - "context" - "fmt" - "net/http" - "time" - - "github.com/attestantio/go-eth2-client/api" - "github.com/attestantio/go-eth2-client/spec/phase0" - "go.uber.org/zap" -) - -func (gc *GoClient) ForkAtEpoch(ctx context.Context, epoch phase0.Epoch) (*phase0.Fork, error) { - start := time.Now() - // ForkSchedule result is cached in the client and updated once in a while. - // So calling this method often shouldn't worsen the performance. - schedule, err := gc.multiClient.ForkSchedule(ctx, &api.ForkScheduleOpts{}) - recordRequestDuration(ctx, "ForkSchedule", gc.multiClient.Address(), http.MethodGet, time.Since(start), err) - if err != nil { - gc.log.Error(clResponseErrMsg, - zap.String("api", "ForkSchedule"), - zap.Error(err), - ) - return nil, err - } - if schedule.Data == nil { - gc.log.Error(clNilResponseForkDataErrMsg, - zap.String("api", "ForkSchedule"), - ) - return nil, fmt.Errorf("fork schedule response data is nil") - } - - var forkAtEpoch *phase0.Fork - for _, fork := range schedule.Data { - if fork.Epoch <= epoch && (forkAtEpoch == nil || fork.Epoch > forkAtEpoch.Epoch) { - forkAtEpoch = fork - } - } - - if forkAtEpoch == nil { - return nil, fmt.Errorf("could not find fork at epoch %d", epoch) - } - - return forkAtEpoch, nil -} diff --git a/beacon/goclient/current_fork_test.go b/beacon/goclient/current_fork_test.go deleted file mode 100644 index 70c8582c27..0000000000 --- a/beacon/goclient/current_fork_test.go +++ /dev/null @@ -1,134 +0,0 @@ -package goclient - -import ( - "encoding/json" - "net/http" - "testing" - "time" - - "github.com/attestantio/go-eth2-client/spec/phase0" - "github.com/stretchr/testify/require" - "go.uber.org/zap" - - "github.com/ssvlabs/ssv/beacon/goclient/tests" - "github.com/ssvlabs/ssv/networkconfig" -) - -const forkSchedulePath = "/eth/v1/config/fork_schedule" - -func TestCurrentFork(t *testing.T) { - beaconConfig := networkconfig.Mainnet.BeaconConfig - - t.Run("success", func(t *testing.T) { - mockServer := tests.MockServer(func(r *http.Request, resp json.RawMessage) (json.RawMessage, error) { - if r.URL.Path == forkSchedulePath { - return json.RawMessage(`{ - "data": [ - { - "previous_version": "0x00010203", - "current_version": "0x04050607", - "epoch": "100" - }, - { - "previous_version": "0x04050607", - "current_version": "0x08090a0b", - "epoch": "150" - }, - { - "previous_version": "0x08090a0b", - "current_version": "0x0c0d0e0f", - "epoch": "300" - } - ] - }`), nil - } - return resp, nil - }) - defer mockServer.Close() - - client, err := New( - t.Context(), - zap.NewNop(), - Options{ - BeaconConfig: beaconConfig, - BeaconNodeAddr: mockServer.URL, - CommonTimeout: 100 * time.Millisecond, - LongTimeout: 500 * time.Millisecond, - }, - ) - require.NoError(t, err) - - currentFork, err := client.ForkAtEpoch(t.Context(), 200) - require.NoError(t, err) - require.NotNil(t, currentFork) - - require.EqualValues(t, 150, currentFork.Epoch) - require.Equal(t, phase0.Version{0x04, 0x05, 0x06, 0x07}, currentFork.PreviousVersion) - require.Equal(t, phase0.Version{0x08, 0x09, 0x0a, 0x0b}, currentFork.CurrentVersion) - }) - - t.Run("nil_data", func(t *testing.T) { - mockServer := tests.MockServer(func(r *http.Request, resp json.RawMessage) (json.RawMessage, error) { - if r.URL.Path == forkSchedulePath { - return json.RawMessage(`{"data": null}`), nil - } - return resp, nil - }) - defer mockServer.Close() - - client, err := New( - t.Context(), - zap.NewNop(), - Options{ - BeaconConfig: beaconConfig, - BeaconNodeAddr: mockServer.URL, - CommonTimeout: 100 * time.Millisecond, - LongTimeout: 500 * time.Millisecond, - }, - ) - require.NoError(t, err) - - _, err = client.ForkAtEpoch(t.Context(), 1) - require.Error(t, err) - require.Contains(t, err.Error(), "fork schedule response data is nil") - }) - - t.Run("no_current_fork", func(t *testing.T) { - mockServer := tests.MockServer(func(r *http.Request, resp json.RawMessage) (json.RawMessage, error) { - if r.URL.Path == forkSchedulePath { - return json.RawMessage(`{ - "data": [ - { - "previous_version": "0x00010203", - "current_version": "0x04050607", - "epoch": "200" - }, - { - "previous_version": "0x04050607", - "current_version": "0x08090a0b", - "epoch": "300" - } - ] - }`), nil - } - return resp, nil - }) - defer mockServer.Close() - - client, err := New( - t.Context(), - zap.NewNop(), - Options{ - BeaconConfig: beaconConfig, - BeaconNodeAddr: mockServer.URL, - CommonTimeout: 100 * time.Millisecond, - LongTimeout: 500 * time.Millisecond, - }, - ) - require.NoError(t, err) - - _, err = client.ForkAtEpoch(t.Context(), 100) - require.Error(t, err) - require.Contains(t, err.Error(), "could not find fork at epoch 100") - }) -} diff --git a/beacon/goclient/dataversion.go b/beacon/goclient/dataversion.go deleted file mode 100644 index 78a1e0732a..0000000000 --- a/beacon/goclient/dataversion.go +++ /dev/null @@ -1,92 +0,0 @@ -package goclient - -import ( - "fmt" - - "github.com/attestantio/go-eth2-client/spec" - "github.com/attestantio/go-eth2-client/spec/phase0" -) - -func (gc *GoClient) DataVersion(epoch phase0.Epoch) spec.DataVersion { - gc.ForkLock.RLock() - defer gc.ForkLock.RUnlock() - if epoch < gc.ForkEpochAltair { - return spec.DataVersionPhase0 - } else if epoch < gc.ForkEpochBellatrix { - return spec.DataVersionAltair - } else if epoch < gc.ForkEpochCapella { - return spec.DataVersionBellatrix - } else if epoch < gc.ForkEpochDeneb { - return spec.DataVersionCapella - } else if epoch < gc.ForkEpochElectra { - return spec.DataVersionDeneb - } - return spec.DataVersionElectra -} - -func (gc *GoClient) checkForkValues(specResponse map[string]any) error { - // Validate the response. - if specResponse == nil { - return fmt.Errorf("spec response is nil") - } - - // Lock the fork values to ensure atomic read and update. - gc.ForkLock.Lock() - defer gc.ForkLock.Unlock() - - // We'll compute candidate new values first and update the fields only if all validations pass. - var newAltair, newBellatrix, newCapella, newDeneb, newElectra phase0.Epoch - - // processFork is a helper to handle required forks. - // It retrieves the candidate fork epoch from the response, - // and compares it with the current stored value. - // If the candidate is greater than the current value, that's an error. - // Otherwise, it returns the lower value (or the candidate if the current value is zero). - processFork := func(forkName, key string, current phase0.Epoch, required bool) (phase0.Epoch, error) { - raw, ok := specResponse[key] - if !ok { - if required { - return 0, fmt.Errorf("%s fork epoch not known by chain", forkName) - } - return FarFutureEpoch, nil - } - forkVal, ok := raw.(uint64) - if !ok { - return 0, fmt.Errorf("failed to decode %s fork epoch", forkName) - } - if current != FarFutureEpoch && current != phase0.Epoch(forkVal) { - // Reject if candidate is missing the fork epoch that we've already seen. - return 0, fmt.Errorf("new %s fork epoch (%d) doesn't match current value (%d)", forkName, phase0.Epoch(forkVal), current) - } - return phase0.Epoch(forkVal), nil - } - - var err error - // Process required forks. - if newAltair, err = processFork("ALTAIR", "ALTAIR_FORK_EPOCH", gc.ForkEpochAltair, true); err != nil { - return err - } - if newBellatrix, err = processFork("BELLATRIX", "BELLATRIX_FORK_EPOCH", gc.ForkEpochBellatrix, true); err != nil { - return err - } - if newCapella, err = processFork("CAPELLA", "CAPELLA_FORK_EPOCH", gc.ForkEpochCapella, true); err != nil { - return err - } - if newDeneb, err = processFork("DENEB", "DENEB_FORK_EPOCH", gc.ForkEpochDeneb, true); err != nil { - return err - } - alreadySeenElectra := gc.ForkEpochElectra != FarFutureEpoch - if newElectra, err = processFork("ELECTRA", "ELECTRA_FORK_EPOCH", gc.ForkEpochElectra, alreadySeenElectra); err != nil { - return err - } - - // At this point, no error was encountered. - // Update all fork values atomically. - gc.ForkEpochAltair = newAltair - gc.ForkEpochBellatrix = newBellatrix - gc.ForkEpochCapella = newCapella - gc.ForkEpochDeneb = newDeneb - gc.ForkEpochElectra = newElectra - - return nil -} diff --git a/beacon/goclient/dataversion_test.go b/beacon/goclient/dataversion_test.go deleted file mode 100644 index 1a579a16ad..0000000000 --- a/beacon/goclient/dataversion_test.go +++ /dev/null @@ -1,216 +0,0 @@ -package goclient - -import ( - "strings" - "testing" - - "github.com/attestantio/go-eth2-client/spec" - "github.com/attestantio/go-eth2-client/spec/phase0" -) - -// TestDataVersion verifies that DataVersion returns the correct version based on fork epochs. -func TestDataVersion(t *testing.T) { - // Create a client with preset fork epochs. - client := &GoClient{ - ForkEpochAltair: phase0.Epoch(10), - ForkEpochBellatrix: phase0.Epoch(20), - ForkEpochCapella: phase0.Epoch(30), - ForkEpochDeneb: phase0.Epoch(40), - ForkEpochElectra: phase0.Epoch(50), - } - - tests := []struct { - epoch phase0.Epoch - expected spec.DataVersion - }{ - {epoch: 0, expected: spec.DataVersionPhase0}, - {epoch: 9, expected: spec.DataVersionPhase0}, - {epoch: 10, expected: spec.DataVersionAltair}, - {epoch: 15, expected: spec.DataVersionAltair}, - {epoch: 20, expected: spec.DataVersionBellatrix}, - {epoch: 25, expected: spec.DataVersionBellatrix}, - {epoch: 30, expected: spec.DataVersionCapella}, - {epoch: 35, expected: spec.DataVersionCapella}, - {epoch: 40, expected: spec.DataVersionDeneb}, - {epoch: 45, expected: spec.DataVersionDeneb}, - {epoch: 50, expected: spec.DataVersionElectra}, - {epoch: 55, expected: spec.DataVersionElectra}, - } - - for _, tc := range tests { - got := client.DataVersion(tc.epoch) - if got != tc.expected { - t.Errorf("DataVersion(%d): expected %v, got %v", tc.epoch, tc.expected, got) - } - } -} - -// TestCheckForkValues verifies the checkForkValues function across various scenarios. -func TestCheckForkValues(t *testing.T) { - tests := []struct { - name string - // initial fork values - initialAltair, initialBellatrix, initialCapella, - initialDeneb, initialElectra phase0.Epoch - // input response and expected outcomes - response map[string]any - expectedErr string - expectedAltair, expectedBellatrix, expectedCapella, - expectedDeneb, expectedElectra phase0.Epoch - }{ - { - name: "nil response", - response: nil, - expectedErr: "spec response is nil", - }, - { - name: "missing ALTAIR", - initialAltair: FarFutureEpoch, - initialBellatrix: FarFutureEpoch, - initialCapella: FarFutureEpoch, - initialDeneb: FarFutureEpoch, - initialElectra: FarFutureEpoch, - response: map[string]any{ - "BELLATRIX_FORK_EPOCH": uint64(20), - "CAPELLA_FORK_EPOCH": uint64(30), - "DENEB_FORK_EPOCH": uint64(40), - }, - expectedErr: "ALTAIR fork epoch not known by chain", - }, - { - name: "invalid type for ALTAIR", - initialAltair: FarFutureEpoch, - initialBellatrix: FarFutureEpoch, - initialCapella: FarFutureEpoch, - initialDeneb: FarFutureEpoch, - initialElectra: FarFutureEpoch, - response: map[string]any{ - "ALTAIR_FORK_EPOCH": "not a uint", - "BELLATRIX_FORK_EPOCH": uint64(20), - "CAPELLA_FORK_EPOCH": uint64(30), - "DENEB_FORK_EPOCH": uint64(40), - }, - expectedErr: "failed to decode ALTAIR fork epoch", - }, - { - name: "valid update with initial zeros and electra provided", - initialAltair: FarFutureEpoch, - initialBellatrix: FarFutureEpoch, - initialCapella: FarFutureEpoch, - initialDeneb: FarFutureEpoch, - initialElectra: FarFutureEpoch, - response: map[string]any{ - "ALTAIR_FORK_EPOCH": uint64(10), - "BELLATRIX_FORK_EPOCH": uint64(20), - "CAPELLA_FORK_EPOCH": uint64(30), - "DENEB_FORK_EPOCH": uint64(40), - "ELECTRA_FORK_EPOCH": uint64(50), - }, - expectedAltair: phase0.Epoch(10), - expectedBellatrix: phase0.Epoch(20), - expectedCapella: phase0.Epoch(30), - expectedDeneb: phase0.Epoch(40), - expectedElectra: phase0.Epoch(50), - }, - { - name: "optional ELECTRA not provided, remains unchanged", - initialAltair: FarFutureEpoch, - initialBellatrix: FarFutureEpoch, - initialCapella: FarFutureEpoch, - initialDeneb: FarFutureEpoch, - initialElectra: FarFutureEpoch, - response: map[string]any{ - "ALTAIR_FORK_EPOCH": uint64(10), - "BELLATRIX_FORK_EPOCH": uint64(20), - "CAPELLA_FORK_EPOCH": uint64(30), - "DENEB_FORK_EPOCH": uint64(40), - }, - expectedAltair: phase0.Epoch(10), - expectedBellatrix: phase0.Epoch(20), - expectedCapella: phase0.Epoch(30), - expectedDeneb: phase0.Epoch(40), - expectedElectra: FarFutureEpoch, - }, - { - name: "optional ELECTRA provided and can't change", - initialAltair: 10, - initialBellatrix: 20, - initialCapella: 30, - initialDeneb: 40, - initialElectra: 99, - response: map[string]any{ - "ALTAIR_FORK_EPOCH": uint64(10), - "BELLATRIX_FORK_EPOCH": uint64(20), - "CAPELLA_FORK_EPOCH": uint64(30), - "DENEB_FORK_EPOCH": uint64(40), - "ELECTRA_FORK_EPOCH": uint64(50), - }, - expectedAltair: phase0.Epoch(10), - expectedBellatrix: phase0.Epoch(20), - expectedCapella: phase0.Epoch(30), - expectedDeneb: phase0.Epoch(40), - expectedElectra: phase0.Epoch(50), - expectedErr: "new ELECTRA fork epoch (50) doesn't match current value (99)", - }, - { - name: "optional ELECTRA provided, candidate greater than current", - initialAltair: 10, - initialBellatrix: 20, - initialCapella: 30, - initialDeneb: 40, - initialElectra: 50, - response: map[string]any{ - "ALTAIR_FORK_EPOCH": uint64(10), - "BELLATRIX_FORK_EPOCH": uint64(20), - "CAPELLA_FORK_EPOCH": uint64(30), - "DENEB_FORK_EPOCH": uint64(40), - "ELECTRA_FORK_EPOCH": uint64(60), - }, - expectedErr: "new ELECTRA fork epoch (60) doesn't match current value (50)", - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - // Create a client with initial fork values. - client := &GoClient{ - ForkEpochAltair: tc.initialAltair, - ForkEpochBellatrix: tc.initialBellatrix, - ForkEpochCapella: tc.initialCapella, - ForkEpochDeneb: tc.initialDeneb, - ForkEpochElectra: tc.initialElectra, - } - - err := client.checkForkValues(tc.response) - if tc.expectedErr != "" { - if err == nil { - t.Fatalf("expected error containing %q but got nil", tc.expectedErr) - } - if !strings.Contains(err.Error(), tc.expectedErr) { - t.Fatalf("expected error containing %q, got %q", tc.expectedErr, err.Error()) - } - return - } - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - // Verify that the fork epoch fields have been updated as expected. - if client.ForkEpochAltair != tc.expectedAltair { - t.Errorf("ForkEpochAltair: expected %d, got %d", tc.expectedAltair, client.ForkEpochAltair) - } - if client.ForkEpochBellatrix != tc.expectedBellatrix { - t.Errorf("ForkEpochBellatrix: expected %d, got %d", tc.expectedBellatrix, client.ForkEpochBellatrix) - } - if client.ForkEpochCapella != tc.expectedCapella { - t.Errorf("ForkEpochCapella: expected %d, got %d", tc.expectedCapella, client.ForkEpochCapella) - } - if client.ForkEpochDeneb != tc.expectedDeneb { - t.Errorf("ForkEpochDeneb: expected %d, got %d", tc.expectedDeneb, client.ForkEpochDeneb) - } - if client.ForkEpochElectra != tc.expectedElectra { - t.Errorf("ForkEpochElectra: expected %d, got %d", tc.expectedElectra, client.ForkEpochElectra) - } - }) - } -} diff --git a/beacon/goclient/genesis.go b/beacon/goclient/genesis.go index 254dedcaf3..07fa781316 100644 --- a/beacon/goclient/genesis.go +++ b/beacon/goclient/genesis.go @@ -12,10 +12,6 @@ import ( "go.uber.org/zap" ) -func (gc *GoClient) Genesis(ctx context.Context) (*apiv1.Genesis, error) { - return genesisForClient(ctx, gc.log, gc.multiClient) -} - // It's used in both Genesis and singleClientHooks, so we need some common implementation to avoid code repetition. func genesisForClient(ctx context.Context, log *zap.Logger, provider client.Service) (*apiv1.Genesis, error) { start := time.Now() diff --git a/beacon/goclient/genesis_test.go b/beacon/goclient/genesis_test.go index 85f2375d8c..4bf27fefb9 100644 --- a/beacon/goclient/genesis_test.go +++ b/beacon/goclient/genesis_test.go @@ -7,9 +7,9 @@ import ( "time" "github.com/stretchr/testify/require" - "go.uber.org/zap" "github.com/ssvlabs/ssv/beacon/goclient/tests" + "github.com/ssvlabs/ssv/logging" "github.com/ssvlabs/ssv/networkconfig" ) @@ -18,9 +18,11 @@ const ( specPath = "/eth/v1/config/spec" ) -func TestGenesis(t *testing.T) { +func Test_genesisForClient(t *testing.T) { ctx := t.Context() + logger := logging.TestLogger(t) + t.Run("success", func(t *testing.T) { mockServer := tests.MockServer(func(r *http.Request, resp json.RawMessage) (json.RawMessage, error) { if r.URL.Path == genesisPath { @@ -35,10 +37,21 @@ func TestGenesis(t *testing.T) { if r.URL.Path == specPath { return json.RawMessage(`{ "data": { - "CONFIG_NAME": "holesky", + "CONFIG_NAME": "mainnet", "GENESIS_FORK_VERSION": "0x00000000", - "CAPELLA_FORK_VERSION": "0x04017000", - "MIN_GENESIS_TIME": "1695902100", + "ALTAIR_FORK_VERSION": "0x01000000", + "ALTAIR_FORK_EPOCH": "74240", + "BELLATRIX_FORK_VERSION": "0x02000000", + "BELLATRIX_FORK_EPOCH": "144896", + "CAPELLA_FORK_VERSION": "0x03000000", + "CAPELLA_FORK_EPOCH": "194048", + "DENEB_FORK_VERSION": "0x04000000", + "DENEB_FORK_EPOCH": "269568", + "ELECTRA_FORK_VERSION": "0x05000000", + "ELECTRA_FORK_EPOCH": "364032", + "FULU_FORK_VERSION": "0x06000000", + "FULU_FORK_EPOCH": "18446744073709551615", + "MIN_GENESIS_TIME": "1606824000", "SECONDS_PER_SLOT": "12", "SLOTS_PER_EPOCH": "32", "EPOCHS_PER_SYNC_COMMITTEE_PERIOD": "256", @@ -46,12 +59,7 @@ func TestGenesis(t *testing.T) { "SYNC_COMMITTEE_SUBNET_COUNT": "4", "TARGET_AGGREGATORS_PER_COMMITTEE": "16", "TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE": "16", - "INTERVALS_PER_SLOT": "3", - "ALTAIR_FORK_EPOCH": "74240", - "BELLATRIX_FORK_EPOCH": "144896", - "CAPELLA_FORK_EPOCH": "194048", - "DENEB_FORK_EPOCH": "269568", - "ELECTRA_FORK_EPOCH": "18446744073709551615" + "INTERVALS_PER_SLOT": "3" } }`), nil } @@ -61,7 +69,7 @@ func TestGenesis(t *testing.T) { client, err := New( ctx, - zap.NewNop(), + logger, Options{ BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: mockServer.URL, @@ -71,7 +79,7 @@ func TestGenesis(t *testing.T) { ) require.NoError(t, err) - genesis, err := client.Genesis(ctx) + genesis, err := genesisForClient(ctx, logger, client.multiClient) require.NoError(t, err) require.NotNil(t, genesis) @@ -90,7 +98,7 @@ func TestGenesis(t *testing.T) { client, err := New( ctx, - zap.NewNop(), + logger, Options{ BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: mockServer.URL, @@ -114,7 +122,7 @@ func TestGenesis(t *testing.T) { client, err := New( ctx, - zap.NewNop(), + logger, Options{ BeaconConfig: networkconfig.Mainnet.BeaconConfig, BeaconNodeAddr: mockServer.URL, diff --git a/beacon/goclient/goclient.go b/beacon/goclient/goclient.go index 0bd2a40347..5c9166900a 100644 --- a/beacon/goclient/goclient.go +++ b/beacon/goclient/goclient.go @@ -168,13 +168,6 @@ type GoClient struct { lastProcessedEventSlotLock sync.Mutex lastProcessedEventSlot phase0.Slot - ForkLock sync.RWMutex - ForkEpochElectra phase0.Epoch - ForkEpochDeneb phase0.Epoch - ForkEpochCapella phase0.Epoch - ForkEpochBellatrix phase0.Epoch - ForkEpochAltair phase0.Epoch - // voluntaryExitDomainCached is voluntary exit domain value calculated lazily and re-used // since it doesn't change over time voluntaryExitDomainCached atomic.Pointer[phase0.Domain] @@ -209,12 +202,6 @@ func New( weightedAttestationDataSoftTimeout: time.Duration(float64(commonTimeout) / 2.5), weightedAttestationDataHardTimeout: commonTimeout, supportedTopics: []EventTopic{EventTopicHead, EventTopicBlock}, - // Initialize forks with FAR_FUTURE_EPOCH. - ForkEpochAltair: math.MaxUint64, - ForkEpochBellatrix: math.MaxUint64, - ForkEpochCapella: math.MaxUint64, - ForkEpochDeneb: math.MaxUint64, - ForkEpochElectra: math.MaxUint64, } if opt.BeaconNodeAddr == "" { @@ -374,38 +361,20 @@ func (gc *GoClient) singleClientHooks() *eth2clienthttp.Hooks { currentConfig, err := gc.applyBeaconConfig(s.Address(), beaconConfig) if err != nil { logger.Fatal("client returned unexpected beacon config, make sure all clients use the same Ethereum network", + zap.Error(err), + zap.Any("current_forks", currentConfig.Forks), + zap.Any("got_forks", beaconConfig.Forks), zap.Stringer("client_config", beaconConfig), zap.Stringer("expected_config", currentConfig), ) return // Tests may override Fatal's behavior } - spec, err := specForClient(ctx, logger, s) - if err != nil { - logger.Error(clResponseErrMsg, - zap.String("api", "Spec"), - zap.Error(err), - ) - return - } - - if err := gc.checkForkValues(spec); err != nil { - logger.Error("failed to check fork values", - zap.Error(err), - ) - return - } - gc.ForkLock.RLock() - config := gc.getBeaconConfig() - logger.Info("retrieved fork epochs", - zap.Uint64("current_data_version", uint64(gc.DataVersion(config.EstimatedCurrentEpoch()))), - zap.Uint64("altair", uint64(gc.ForkEpochAltair)), - zap.Uint64("bellatrix", uint64(gc.ForkEpochBellatrix)), - zap.Uint64("capella", uint64(gc.ForkEpochCapella)), - zap.Uint64("deneb", uint64(gc.ForkEpochDeneb)), - zap.Uint64("electra", uint64(gc.ForkEpochElectra)), + dataVersion, _ := currentConfig.ForkAtEpoch(currentConfig.EstimatedCurrentEpoch()) + logger.Info("retrieved beacon config", + zap.Uint64("data_version", uint64(dataVersion)), + zap.Stringer("config", currentConfig), ) - gc.ForkLock.RUnlock() }, OnInactive: func(ctx context.Context, s *eth2clienthttp.Service) { gc.log.Warn("consensus client disconnected", @@ -443,8 +412,8 @@ func (gc *GoClient) applyBeaconConfig(nodeAddress string, beaconConfig networkco return beaconConfig, nil } - if *gc.beaconConfig != beaconConfig { - return *gc.beaconConfig, fmt.Errorf("beacon config misalign, current %v, got %v", gc.beaconConfig, beaconConfig) + if err := gc.beaconConfig.AssertSame(beaconConfig); err != nil { + return *gc.beaconConfig, fmt.Errorf("beacon config misalign: %w", err) } return *gc.beaconConfig, nil diff --git a/beacon/goclient/signing.go b/beacon/goclient/signing.go index 5c00ce6828..4cc990caa8 100644 --- a/beacon/goclient/signing.go +++ b/beacon/goclient/signing.go @@ -9,6 +9,7 @@ import ( "sync" "time" + "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" ssz "github.com/ferranbt/fastssz" "github.com/pkg/errors" @@ -16,13 +17,13 @@ import ( "go.uber.org/zap" ) -func (gc *GoClient) voluntaryExitDomain(ctx context.Context) (phase0.Domain, error) { +func (gc *GoClient) voluntaryExitDomain() (phase0.Domain, error) { value := gc.voluntaryExitDomainCached.Load() if value != nil { return *value, nil } - v, err := gc.computeVoluntaryExitDomain(ctx) + v, err := gc.computeVoluntaryExitDomain() if err != nil { return phase0.Domain{}, fmt.Errorf("compute voluntary exit domain: %w", err) } @@ -30,26 +31,12 @@ func (gc *GoClient) voluntaryExitDomain(ctx context.Context) (phase0.Domain, err return v, nil } -func (gc *GoClient) computeVoluntaryExitDomain(ctx context.Context) (phase0.Domain, error) { - // TODO: pull from beacon node - specResponse, err := gc.Spec(ctx) - if err != nil { - return phase0.Domain{}, fmt.Errorf("fetch spec: %w", err) - } - - // EIP-7044 requires using CAPELLA_FORK_VERSION for DomainVoluntaryExit: https://eips.ethereum.org/EIPS/eip-7044 - forkVersionRaw, ok := specResponse["CAPELLA_FORK_VERSION"] - if !ok { - return phase0.Domain{}, fmt.Errorf("capella fork version not known by chain") - } - forkVersion, ok := forkVersionRaw.(phase0.Version) - if !ok { - return phase0.Domain{}, fmt.Errorf("failed to decode capella fork version") - } +func (gc *GoClient) computeVoluntaryExitDomain() (phase0.Domain, error) { + beaconConfig := gc.getBeaconConfig() forkData := &phase0.ForkData{ - CurrentVersion: forkVersion, - GenesisValidatorsRoot: gc.getBeaconConfig().GenesisValidatorsRoot, + CurrentVersion: beaconConfig.Forks[spec.DataVersionCapella].CurrentVersion, + GenesisValidatorsRoot: beaconConfig.GenesisValidatorsRoot, } root, err := forkData.HashTreeRoot() @@ -75,7 +62,7 @@ func (gc *GoClient) DomainData( // to (Mainnet, Hoodi, etc.) var appDomain phase0.Domain forkData := phase0.ForkData{ - CurrentVersion: gc.getBeaconConfig().ForkVersion, + CurrentVersion: gc.getBeaconConfig().GenesisForkVersion, GenesisValidatorsRoot: phase0.Root{}, } root, err := forkData.HashTreeRoot() @@ -88,7 +75,7 @@ func (gc *GoClient) DomainData( case spectypes.DomainVoluntaryExit: // Deneb upgrade introduced https://eips.ethereum.org/EIPS/eip-7044 that requires special // handling for DomainVoluntaryExit - return gc.voluntaryExitDomain(ctx) + return gc.voluntaryExitDomain() } start := time.Now() diff --git a/beacon/goclient/signing_test.go b/beacon/goclient/signing_test.go index d4e503785e..dce8a8751b 100644 --- a/beacon/goclient/signing_test.go +++ b/beacon/goclient/signing_test.go @@ -33,7 +33,7 @@ func Test_computeVoluntaryExitDomain(t *testing.T) { ) require.NoError(t, err) - domain, err := client.computeVoluntaryExitDomain(ctx) + domain, err := client.computeVoluntaryExitDomain() require.NoError(t, err) require.NotNil(t, domain) diff --git a/beacon/goclient/spec.go b/beacon/goclient/spec.go index 02f3809edd..5637bab084 100644 --- a/beacon/goclient/spec.go +++ b/beacon/goclient/spec.go @@ -9,6 +9,8 @@ import ( client "github.com/attestantio/go-eth2-client" "github.com/attestantio/go-eth2-client/api" eth2clienthttp "github.com/attestantio/go-eth2-client/http" + "github.com/attestantio/go-eth2-client/spec" + "github.com/attestantio/go-eth2-client/spec/phase0" "go.uber.org/zap" "github.com/ssvlabs/ssv/networkconfig" @@ -33,6 +35,33 @@ func (gc *GoClient) BeaconConfig() networkconfig.BeaconConfig { return *config } +func specForClient(ctx context.Context, log *zap.Logger, provider client.Service) (map[string]any, error) { + start := time.Now() + specResponse, err := provider.(client.SpecProvider).Spec(ctx, &api.SpecOpts{}) + recordRequestDuration(ctx, "Spec", provider.Address(), http.MethodGet, time.Since(start), err) + if err != nil { + log.Error(clResponseErrMsg, + zap.String("api", "Spec"), + zap.Error(err), + ) + return nil, fmt.Errorf("failed to obtain spec response: %w", err) + } + if specResponse == nil { + log.Error(clNilResponseErrMsg, + zap.String("api", "Spec"), + ) + return nil, fmt.Errorf("spec response is nil") + } + if specResponse.Data == nil { + log.Error(clNilResponseDataErrMsg, + zap.String("api", "Spec"), + ) + return nil, fmt.Errorf("spec response data is nil") + } + + return specResponse.Data, nil +} + // fetchBeaconConfig must be called once on GoClient's initialization func (gc *GoClient) fetchBeaconConfig(ctx context.Context, client *eth2clienthttp.Service) (networkconfig.BeaconConfig, error) { specResponse, err := specForClient(ctx, gc.log, client) @@ -133,6 +162,12 @@ func (gc *GoClient) fetchBeaconConfig(ctx context.Context, client *eth2clienthtt } } + forkData, err := gc.getForkData(specResponse) + if err != nil { + gc.log.Error(clResponseErrMsg, zap.String("api", "Spec"), zap.Error(err)) + return networkconfig.BeaconConfig{}, fmt.Errorf("failed to extract fork data: %w", err) + } + genesisResponse, err := genesisForClient(ctx, gc.log, client) if err != nil { gc.log.Error(clResponseErrMsg, zap.String("api", "Genesis"), zap.Error(err)) @@ -149,41 +184,127 @@ func (gc *GoClient) fetchBeaconConfig(ctx context.Context, client *eth2clienthtt TargetAggregatorsPerSyncSubcommittee: targetAggregatorsPerSyncSubcommittee, TargetAggregatorsPerCommittee: targetAggregatorsPerCommittee, IntervalsPerSlot: intervalsPerSlot, - ForkVersion: genesisResponse.GenesisForkVersion, + GenesisForkVersion: genesisResponse.GenesisForkVersion, GenesisTime: genesisResponse.GenesisTime, GenesisValidatorsRoot: genesisResponse.GenesisValidatorsRoot, + Forks: forkData, } return beaconConfig, nil } -func (gc *GoClient) Spec(ctx context.Context) (map[string]any, error) { - return specForClient(ctx, gc.log, gc.multiClient) -} +func (gc *GoClient) getForkData(specResponse map[string]any) (map[spec.DataVersion]phase0.Fork, error) { + if specResponse == nil { + return nil, fmt.Errorf("spec response is nil") + } -func specForClient(ctx context.Context, log *zap.Logger, provider client.Service) (map[string]any, error) { - start := time.Now() - specResponse, err := provider.(client.SpecProvider).Spec(ctx, &api.SpecOpts{}) - recordRequestDuration(ctx, "Spec", provider.Address(), http.MethodGet, time.Since(start), err) + getForkEpoch := func(key string, required bool) (phase0.Epoch, error) { + raw, ok := specResponse[key] + if !ok { + if required { + return 0, fmt.Errorf("%s is not known by chain", key) + } + return FarFutureEpoch, nil + } + forkVal, ok := raw.(uint64) + if !ok { + return 0, fmt.Errorf("failed to decode %s", key) + } + return phase0.Epoch(forkVal), nil + } + + getForkVersion := func(key string) (phase0.Version, error) { + raw, ok := specResponse[key] + if !ok { + return phase0.Version{}, fmt.Errorf("%s is not known by chain", key) + } + versionVal, ok := raw.(phase0.Version) + if !ok { + return phase0.Version{}, fmt.Errorf("failed to decode %s", key) + } + return versionVal, nil + } + + genesisForkVersion, err := getForkVersion("GENESIS_FORK_VERSION") if err != nil { - log.Error(clResponseErrMsg, - zap.String("api", "Spec"), - zap.Error(err), - ) - return nil, fmt.Errorf("failed to obtain spec response: %w", err) + return nil, err } - if specResponse == nil { - log.Error(clNilResponseErrMsg, - zap.String("api", "Spec"), - ) - return nil, fmt.Errorf("spec response is nil") + altairEpoch, err := getForkEpoch("ALTAIR_FORK_EPOCH", true) + if err != nil { + return nil, err } - if specResponse.Data == nil { - log.Error(clNilResponseDataErrMsg, - zap.String("api", "Spec"), - ) - return nil, fmt.Errorf("spec response data is nil") + altairForkVersion, err := getForkVersion("ALTAIR_FORK_VERSION") + if err != nil { + return nil, err + } + bellatrixEpoch, err := getForkEpoch("BELLATRIX_FORK_EPOCH", true) + if err != nil { + return nil, err + } + bellatrixForkVersion, err := getForkVersion("BELLATRIX_FORK_VERSION") + if err != nil { + return nil, err + } + capellaEpoch, err := getForkEpoch("CAPELLA_FORK_EPOCH", true) + if err != nil { + return nil, err + } + capellaForkVersion, err := getForkVersion("CAPELLA_FORK_VERSION") + if err != nil { + return nil, err + } + denebEpoch, err := getForkEpoch("DENEB_FORK_EPOCH", true) + if err != nil { + return nil, err + } + denebForkVersion, err := getForkVersion("DENEB_FORK_VERSION") + if err != nil { + return nil, err + } + // After Electra fork happens on all networks, + // - Electra check should become required + // - Fulu check might be added as non-required + electraEpoch, err := getForkEpoch("ELECTRA_FORK_EPOCH", false) + if err != nil { + return nil, err + } + electraForkVersion, err := getForkVersion("ELECTRA_FORK_VERSION") + if err != nil { + return nil, err } - return specResponse.Data, nil + forkEpochs := map[spec.DataVersion]phase0.Fork{ + spec.DataVersionPhase0: { + PreviousVersion: genesisForkVersion, + CurrentVersion: genesisForkVersion, + Epoch: 0, + }, + spec.DataVersionAltair: { + PreviousVersion: genesisForkVersion, + CurrentVersion: altairForkVersion, + Epoch: altairEpoch, + }, + spec.DataVersionBellatrix: { + PreviousVersion: altairForkVersion, + CurrentVersion: bellatrixForkVersion, + Epoch: bellatrixEpoch, + }, + spec.DataVersionCapella: { + PreviousVersion: bellatrixForkVersion, + CurrentVersion: capellaForkVersion, + Epoch: capellaEpoch, + }, + spec.DataVersionDeneb: { + PreviousVersion: capellaForkVersion, + CurrentVersion: denebForkVersion, + Epoch: denebEpoch, + }, + spec.DataVersionElectra: { + PreviousVersion: denebForkVersion, + CurrentVersion: electraForkVersion, + Epoch: electraEpoch, + }, + } + + return forkEpochs, nil } diff --git a/beacon/goclient/spec_test.go b/beacon/goclient/spec_test.go index 17ee95bd76..3d3a076057 100644 --- a/beacon/goclient/spec_test.go +++ b/beacon/goclient/spec_test.go @@ -11,7 +11,7 @@ import ( "github.com/ssvlabs/ssv/networkconfig" ) -func TestSpec(t *testing.T) { +func Test_specForClient(t *testing.T) { ctx := t.Context() t.Run("success", func(t *testing.T) { @@ -30,7 +30,7 @@ func TestSpec(t *testing.T) { ) require.NoError(t, err) - spec, err := client.Spec(ctx) + spec, err := specForClient(ctx, client.log, client.multiClient) require.NoError(t, err) require.NotNil(t, spec) diff --git a/cli/operator/node.go b/cli/operator/node.go index 479daa5db4..c85f5bfe72 100644 --- a/cli/operator/node.go +++ b/cli/operator/node.go @@ -15,6 +15,7 @@ import ( "sync" "time" + "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/ilyakaznacheev/cleanenv" "github.com/pkg/errors" @@ -328,7 +329,6 @@ var StartNodeCmd = &cobra.Command{ logger, networkConfig, ssvSignerClient, - consensusClient, db, operatorDataStore.GetOperatorID, ) @@ -369,7 +369,7 @@ var StartNodeCmd = &cobra.Command{ nodeStorage, dutyStore, signatureVerifier, - consensusClient.ForkEpochElectra, + networkConfig.Forks[spec.DataVersionElectra].Epoch, validation.WithLogger(logger), ) diff --git a/go.mod b/go.mod index 0a50b7a2cc..4c8d66a908 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/spf13/cobra v1.8.1 github.com/ssvlabs/eth2-key-manager v1.5.5 github.com/ssvlabs/ssv-spec v1.1.3 - github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527132358-45464863718a + github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527135742-46517c804400 github.com/status-im/keycard-go v0.2.0 github.com/stretchr/testify v1.9.0 github.com/wealdtech/go-eth2-types/v2 v2.8.1 diff --git a/go.sum b/go.sum index d1ff79c833..7c4c41339a 100644 --- a/go.sum +++ b/go.sum @@ -756,10 +756,8 @@ github.com/ssvlabs/go-eth2-client v0.6.31-0.20250417062221-9cd9b891d4d6 h1:26sqP github.com/ssvlabs/go-eth2-client v0.6.31-0.20250417062221-9cd9b891d4d6/go.mod h1:fvULSL9WtNskkOB4i+Yyr6BKpNHXvmpGZj9969fCrfY= github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo8= github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250512164336-eaf440d63581 h1:BTh8A1s2HNIHrussld4QZTguuRO1tuqqkyvT+0kThpE= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250512164336-eaf440d63581/go.mod h1:HkcbtVHpGBPnJjdWWd08Z3lv7l0VWejJU80yUUqY5Go= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527132358-45464863718a h1:3ITXI8KXYlhjrmxDgJlXV/NPp2lAXWXfVjj5Qt8dG7o= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527132358-45464863718a/go.mod h1:/Emoj7oqjC+r1rr5UYI4+XCqfw2/LXlutZCPInXpkx0= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527135742-46517c804400 h1:s0obHG5dvNM3HsXwbbHaj0j0e8mIMWMSPATpxCPey7k= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527135742-46517c804400/go.mod h1:SoeLhAtnyvAvhiHg0gQctkruAXAOPRh2sZzN4h8Jdic= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/integration/qbft/tests/temp_testing_beacon_network.go b/integration/qbft/tests/temp_testing_beacon_network.go index ca96d705c3..5eb3b5fc90 100644 --- a/integration/qbft/tests/temp_testing_beacon_network.go +++ b/integration/qbft/tests/temp_testing_beacon_network.go @@ -34,9 +34,6 @@ func (bn *TestingBeaconNodeWrapped) GetBeaconNode() *spectestingutils.TestingBea func (bn *TestingBeaconNodeWrapped) GetAttestationData(ctx context.Context, slot phase0.Slot) (*phase0.AttestationData, spec.DataVersion, error) { return bn.Bn.GetAttestationData(slot) } -func (bn *TestingBeaconNodeWrapped) DataVersion(epoch phase0.Epoch) spec.DataVersion { - return bn.Bn.DataVersion(epoch) -} func (bn *TestingBeaconNodeWrapped) DomainData(ctx context.Context, epoch phase0.Epoch, domain phase0.DomainType) (phase0.Domain, error) { return bn.Bn.DomainData(epoch, domain) } diff --git a/network/topics/pubsub.go b/network/topics/pubsub.go index d32c3e9b13..7fc8c9a271 100644 --- a/network/topics/pubsub.go +++ b/network/topics/pubsub.go @@ -115,7 +115,13 @@ type CommitteesProvider interface { } // NewPubSub creates a new pubsub router and the necessary components -func NewPubSub(ctx context.Context, logger *zap.Logger, cfg *PubSubConfig, committeesProvider CommitteesProvider, gossipScoreIndex peers.GossipScoreIndex) (*pubsub.PubSub, Controller, error) { +func NewPubSub( + ctx context.Context, + logger *zap.Logger, + cfg *PubSubConfig, + committeesProvider CommitteesProvider, + gossipScoreIndex peers.GossipScoreIndex, +) (*pubsub.PubSub, Controller, error) { if err := cfg.init(); err != nil { return nil, nil, err } diff --git a/networkconfig/beacon.go b/networkconfig/beacon.go index 94114ca754..e902a41b1f 100644 --- a/networkconfig/beacon.go +++ b/networkconfig/beacon.go @@ -3,9 +3,11 @@ package networkconfig import ( "encoding/json" "fmt" + "maps" "math" "time" + "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" ) @@ -33,7 +35,9 @@ type Beacon interface { GetSlotsPerEpoch() uint64 GetGenesisTime() time.Time GetSyncCommitteeSize() uint64 + GetGenesisValidatorsRoot() phase0.Root GetBeaconName() string + ForkAtEpoch(epoch phase0.Epoch) (spec.DataVersion, *phase0.Fork) } type BeaconConfig struct { @@ -46,9 +50,10 @@ type BeaconConfig struct { TargetAggregatorsPerSyncSubcommittee uint64 TargetAggregatorsPerCommittee uint64 IntervalsPerSlot uint64 - ForkVersion phase0.Version + GenesisForkVersion phase0.Version GenesisTime time.Time GenesisValidatorsRoot phase0.Root + Forks map[spec.DataVersion]phase0.Fork } func (b BeaconConfig) String() string { @@ -181,6 +186,81 @@ func (b BeaconConfig) GetSyncCommitteeSize() uint64 { return b.SyncCommitteeSize } +func (b BeaconConfig) GetGenesisValidatorsRoot() phase0.Root { + return b.GenesisValidatorsRoot +} + func (b BeaconConfig) GetBeaconName() string { return b.BeaconName } + +func (b BeaconConfig) ForkAtEpoch(epoch phase0.Epoch) (spec.DataVersion, *phase0.Fork) { + versions := []spec.DataVersion{ + spec.DataVersionPhase0, + spec.DataVersionAltair, + spec.DataVersionBellatrix, + spec.DataVersionCapella, + spec.DataVersionDeneb, + spec.DataVersionElectra, + } + + for i, v := range versions { + if epoch < b.Forks[v].Epoch { + if i == 0 { + panic("epoch before genesis") + } + + version := versions[i-1] + fork := b.Forks[version] + return version, &fork + } + } + + version := versions[len(versions)-1] + fork := b.Forks[version] + return version, &fork +} + +func (b BeaconConfig) AssertSame(other BeaconConfig) error { + if b.BeaconName != other.BeaconName { + return fmt.Errorf("different BeaconName") + } + if b.SlotDuration != other.SlotDuration { + return fmt.Errorf("different SlotDuration") + } + if b.SlotsPerEpoch != other.SlotsPerEpoch { + return fmt.Errorf("different SlotsPerEpoch") + } + if b.EpochsPerSyncCommitteePeriod != other.EpochsPerSyncCommitteePeriod { + return fmt.Errorf("different EpochsPerSyncCommitteePeriod") + } + if b.SyncCommitteeSize != other.SyncCommitteeSize { + return fmt.Errorf("different SyncCommitteeSize") + } + if b.SyncCommitteeSubnetCount != other.SyncCommitteeSubnetCount { + return fmt.Errorf("different SyncCommitteeSubnetCount") + } + if b.TargetAggregatorsPerSyncSubcommittee != other.TargetAggregatorsPerSyncSubcommittee { + return fmt.Errorf("different TargetAggregatorsPerSyncSubcommittee") + } + if b.TargetAggregatorsPerCommittee != other.TargetAggregatorsPerCommittee { + return fmt.Errorf("different TargetAggregatorsPerCommittee") + } + if b.IntervalsPerSlot != other.IntervalsPerSlot { + return fmt.Errorf("different IntervalsPerSlot") + } + if b.GenesisForkVersion != other.GenesisForkVersion { + return fmt.Errorf("different GenesisForkVersion") + } + if b.GenesisTime != other.GenesisTime { + return fmt.Errorf("different GenesisTime") + } + if b.GenesisValidatorsRoot != other.GenesisValidatorsRoot { + return fmt.Errorf("different GenesisValidatorsRoot") + } + + if !maps.Equal(b.Forks, other.Forks) { + return fmt.Errorf("different Forks") + } + return nil +} diff --git a/networkconfig/beacon_mock.go b/networkconfig/beacon_mock.go index b889e605cc..89f809c62b 100644 --- a/networkconfig/beacon_mock.go +++ b/networkconfig/beacon_mock.go @@ -13,6 +13,7 @@ import ( reflect "reflect" time "time" + spec "github.com/attestantio/go-eth2-client/spec" phase0 "github.com/attestantio/go-eth2-client/spec/phase0" gomock "go.uber.org/mock/gomock" ) @@ -181,6 +182,21 @@ func (mr *MockBeaconMockRecorder) FirstSlotAtEpoch(epoch any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FirstSlotAtEpoch", reflect.TypeOf((*MockBeacon)(nil).FirstSlotAtEpoch), epoch) } +// ForkAtEpoch mocks base method. +func (m *MockBeacon) ForkAtEpoch(epoch phase0.Epoch) (spec.DataVersion, *phase0.Fork) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ForkAtEpoch", epoch) + ret0, _ := ret[0].(spec.DataVersion) + ret1, _ := ret[1].(*phase0.Fork) + return ret0, ret1 +} + +// ForkAtEpoch indicates an expected call of ForkAtEpoch. +func (mr *MockBeaconMockRecorder) ForkAtEpoch(epoch any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForkAtEpoch", reflect.TypeOf((*MockBeacon)(nil).ForkAtEpoch), epoch) +} + // GetBeaconName mocks base method. func (m *MockBeacon) GetBeaconName() string { m.ctrl.T.Helper() @@ -237,6 +253,20 @@ func (mr *MockBeaconMockRecorder) GetGenesisTime() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGenesisTime", reflect.TypeOf((*MockBeacon)(nil).GetGenesisTime)) } +// GetGenesisValidatorsRoot mocks base method. +func (m *MockBeacon) GetGenesisValidatorsRoot() phase0.Root { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGenesisValidatorsRoot") + ret0, _ := ret[0].(phase0.Root) + return ret0 +} + +// GetGenesisValidatorsRoot indicates an expected call of GetGenesisValidatorsRoot. +func (mr *MockBeaconMockRecorder) GetGenesisValidatorsRoot() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGenesisValidatorsRoot", reflect.TypeOf((*MockBeacon)(nil).GetGenesisValidatorsRoot)) +} + // GetSlotDuration mocks base method. func (m *MockBeacon) GetSlotDuration() time.Duration { m.ctrl.T.Helper() diff --git a/networkconfig/beacon_test.go b/networkconfig/beacon_test.go new file mode 100644 index 0000000000..d15469b15b --- /dev/null +++ b/networkconfig/beacon_test.go @@ -0,0 +1,121 @@ +package networkconfig + +import ( + "testing" + + "github.com/attestantio/go-eth2-client/spec" + "github.com/attestantio/go-eth2-client/spec/phase0" + "github.com/stretchr/testify/require" +) + +// TestForkAtEpoch verifies that ForkAtEpoch returns the correct version and fork data based on fork epochs. +func TestForkAtEpoch(t *testing.T) { + config := &BeaconConfig{ + Forks: map[spec.DataVersion]phase0.Fork{ + spec.DataVersionPhase0: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0}, + CurrentVersion: phase0.Version{0}, + }, + spec.DataVersionAltair: { + Epoch: phase0.Epoch(10), + PreviousVersion: phase0.Version{0}, + CurrentVersion: phase0.Version{1}, + }, + spec.DataVersionBellatrix: { + Epoch: phase0.Epoch(20), + PreviousVersion: phase0.Version{1}, + CurrentVersion: phase0.Version{2}, + }, + spec.DataVersionCapella: { + Epoch: phase0.Epoch(30), + PreviousVersion: phase0.Version{2}, + CurrentVersion: phase0.Version{3}, + }, + spec.DataVersionDeneb: { + Epoch: phase0.Epoch(40), + PreviousVersion: phase0.Version{3}, + CurrentVersion: phase0.Version{4}, + }, + spec.DataVersionElectra: { + Epoch: phase0.Epoch(50), + PreviousVersion: phase0.Version{4}, + CurrentVersion: phase0.Version{5}, + }, + }, + } + + tests := []struct { + epoch phase0.Epoch + version spec.DataVersion + fork phase0.Fork + }{ + {epoch: 0, version: spec.DataVersionPhase0, fork: phase0.Fork{ + PreviousVersion: phase0.Version{0}, + CurrentVersion: phase0.Version{0}, + Epoch: 0, + }}, + {epoch: 9, version: spec.DataVersionPhase0, fork: phase0.Fork{ + PreviousVersion: phase0.Version{0}, + CurrentVersion: phase0.Version{0}, + Epoch: 0, + }}, + {epoch: 10, version: spec.DataVersionAltair, fork: phase0.Fork{ + Epoch: phase0.Epoch(10), + PreviousVersion: phase0.Version{0}, + CurrentVersion: phase0.Version{1}, + }}, + {epoch: 15, version: spec.DataVersionAltair, fork: phase0.Fork{ + Epoch: phase0.Epoch(10), + PreviousVersion: phase0.Version{0}, + CurrentVersion: phase0.Version{1}, + }}, + {epoch: 20, version: spec.DataVersionBellatrix, fork: phase0.Fork{ + Epoch: phase0.Epoch(20), + PreviousVersion: phase0.Version{1}, + CurrentVersion: phase0.Version{2}, + }}, + {epoch: 25, version: spec.DataVersionBellatrix, fork: phase0.Fork{ + Epoch: phase0.Epoch(20), + PreviousVersion: phase0.Version{1}, + CurrentVersion: phase0.Version{2}, + }}, + {epoch: 30, version: spec.DataVersionCapella, fork: phase0.Fork{ + Epoch: phase0.Epoch(30), + PreviousVersion: phase0.Version{2}, + CurrentVersion: phase0.Version{3}, + }}, + {epoch: 35, version: spec.DataVersionCapella, fork: phase0.Fork{ + Epoch: phase0.Epoch(30), + PreviousVersion: phase0.Version{2}, + CurrentVersion: phase0.Version{3}, + }}, + {epoch: 40, version: spec.DataVersionDeneb, fork: phase0.Fork{ + Epoch: phase0.Epoch(40), + PreviousVersion: phase0.Version{3}, + CurrentVersion: phase0.Version{4}, + }}, + {epoch: 45, version: spec.DataVersionDeneb, fork: phase0.Fork{ + Epoch: phase0.Epoch(40), + PreviousVersion: phase0.Version{3}, + CurrentVersion: phase0.Version{4}, + }}, + {epoch: 50, version: spec.DataVersionElectra, fork: phase0.Fork{ + Epoch: phase0.Epoch(50), + PreviousVersion: phase0.Version{4}, + CurrentVersion: phase0.Version{5}, + }}, + {epoch: 55, version: spec.DataVersionElectra, fork: phase0.Fork{ + Epoch: phase0.Epoch(50), + PreviousVersion: phase0.Version{4}, + CurrentVersion: phase0.Version{5}, + }}, + } + + for _, tc := range tests { + version, fork := config.ForkAtEpoch(tc.epoch) + require.Equal(t, tc.version, version, "Wrong version") + require.NotNil(t, tc.fork, fork, "Nil fork") + require.Equal(t, tc.fork, *fork, "Wrong fork") + } +} diff --git a/networkconfig/holesky.go b/networkconfig/holesky.go index 2aa8a9bc30..5768389e9b 100644 --- a/networkconfig/holesky.go +++ b/networkconfig/holesky.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -22,9 +23,47 @@ var Holesky = NetworkConfig{ TargetAggregatorsPerSyncSubcommittee: 16, TargetAggregatorsPerCommittee: 16, IntervalsPerSlot: 3, - ForkVersion: spectypes.HoleskyNetwork.ForkVersion(), + GenesisForkVersion: spectypes.HoleskyNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1")), + Forks: map[spec.DataVersion]phase0.Fork{ + // Phase0 + spec.DataVersionPhase0: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0x00, 0x01, 0x70, 0x00}, // GENESIS_FORK_VERSION: 0x01017000 + CurrentVersion: phase0.Version{0x00, 0x01, 0x70, 0x00}, + }, + // Altair @ epoch 0 + spec.DataVersionAltair: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0x00, 0x01, 0x70, 0x00}, + CurrentVersion: phase0.Version{0x02, 0x01, 0x70, 0x00}, // ALTAIR_FORK_VERSION: 0x02017000 + }, + // Bellatrix @ epoch 0 + spec.DataVersionBellatrix: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0x02, 0x01, 0x70, 0x00}, + CurrentVersion: phase0.Version{0x03, 0x01, 0x70, 0x00}, // BELLATRIX_FORK_VERSION: 0x03017000 + }, + // Capella @ epoch 256 + spec.DataVersionCapella: { + Epoch: phase0.Epoch(256), + PreviousVersion: phase0.Version{0x03, 0x01, 0x70, 0x00}, + CurrentVersion: phase0.Version{0x04, 0x01, 0x70, 0x00}, // CAPELLA_FORK_VERSION: 0x04017000 + }, + // Deneb @ epoch 29 696 + spec.DataVersionDeneb: { + Epoch: phase0.Epoch(29696), + PreviousVersion: phase0.Version{0x04, 0x01, 0x70, 0x00}, + CurrentVersion: phase0.Version{0x05, 0x01, 0x70, 0x00}, // DENEB_FORK_VERSION: 0x05017000 + }, + // Electra @ epoch 115 968 + spec.DataVersionElectra: { + Epoch: phase0.Epoch(115968), + PreviousVersion: phase0.Version{0x05, 0x01, 0x70, 0x00}, + CurrentVersion: phase0.Version{0x06, 0x01, 0x70, 0x00}, // ELECTRA_FORK_VERSION: 0x06017000 + }, + }, }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x2}, diff --git a/networkconfig/hoodi.go b/networkconfig/hoodi.go index 31af8e0c95..562890c354 100644 --- a/networkconfig/hoodi.go +++ b/networkconfig/hoodi.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -22,9 +23,47 @@ var Hoodi = NetworkConfig{ TargetAggregatorsPerSyncSubcommittee: 16, TargetAggregatorsPerCommittee: 16, IntervalsPerSlot: 3, - ForkVersion: spectypes.HoodiNetwork.ForkVersion(), + GenesisForkVersion: spectypes.HoodiNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.HoodiNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x212f13fc4df078b6cb7db228f1c8307566dcecf900867401a92023d7ba99cb5f")), + Forks: map[spec.DataVersion]phase0.Fork{ + // Phase0 (genesis) + spec.DataVersionPhase0: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0x10, 0x00, 0x09, 0x10}, // GENESIS_FORK_VERSION + CurrentVersion: phase0.Version{0x10, 0x00, 0x09, 0x10}, + }, + // Altair @ epoch 0 + spec.DataVersionAltair: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0x10, 0x00, 0x09, 0x10}, + CurrentVersion: phase0.Version{0x20, 0x00, 0x09, 0x10}, // ALTAIR_FORK_VERSION + }, + // Bellatrix (Merge) @ epoch 0 + spec.DataVersionBellatrix: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0x20, 0x00, 0x09, 0x10}, + CurrentVersion: phase0.Version{0x30, 0x00, 0x09, 0x10}, // BELLATRIX_FORK_VERSION + }, + // Capella @ epoch 0 + spec.DataVersionCapella: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0x30, 0x00, 0x09, 0x10}, + CurrentVersion: phase0.Version{0x40, 0x00, 0x09, 0x10}, // CAPELLA_FORK_VERSION + }, + // Deneb @ epoch 0 + spec.DataVersionDeneb: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0x40, 0x00, 0x09, 0x10}, + CurrentVersion: phase0.Version{0x50, 0x00, 0x09, 0x10}, // DENEB_FORK_VERSION + }, + // Electra @ epoch 2048 + spec.DataVersionElectra: { + Epoch: phase0.Epoch(2048), + PreviousVersion: phase0.Version{0x50, 0x00, 0x09, 0x10}, + CurrentVersion: phase0.Version{0x60, 0x00, 0x09, 0x10}, // ELECTRA_FORK_VERSION + }, + }, }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x3}, diff --git a/networkconfig/local-testnet.go b/networkconfig/local-testnet.go index 5a40e88b0c..600911f8f6 100644 --- a/networkconfig/local-testnet.go +++ b/networkconfig/local-testnet.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -22,9 +23,41 @@ var LocalTestnet = NetworkConfig{ TargetAggregatorsPerSyncSubcommittee: 16, TargetAggregatorsPerCommittee: 16, IntervalsPerSlot: 3, - ForkVersion: spectypes.PraterNetwork.ForkVersion(), + GenesisForkVersion: spectypes.PraterNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.PraterNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb")), + Forks: map[spec.DataVersion]phase0.Fork{ + spec.DataVersionPhase0: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0, 0, 0, 0}, + CurrentVersion: phase0.Version{0, 0, 0, 0}, + }, + spec.DataVersionAltair: { + Epoch: phase0.Epoch(1), + PreviousVersion: phase0.Version{0, 0, 0, 0}, + CurrentVersion: phase0.Version{1, 0, 0, 0}, + }, + spec.DataVersionBellatrix: { + Epoch: phase0.Epoch(2), + PreviousVersion: phase0.Version{1, 0, 0, 0}, + CurrentVersion: phase0.Version{2, 0, 0, 0}, + }, + spec.DataVersionCapella: { + Epoch: phase0.Epoch(3), + PreviousVersion: phase0.Version{2, 0, 0, 0}, + CurrentVersion: phase0.Version{3, 0, 0, 0}, + }, + spec.DataVersionDeneb: { + Epoch: phase0.Epoch(4), + PreviousVersion: phase0.Version{3, 0, 0, 0}, + CurrentVersion: phase0.Version{4, 0, 0, 0}, + }, + spec.DataVersionElectra: { + Epoch: phase0.Epoch(5), + PreviousVersion: phase0.Version{4, 0, 0, 0}, + CurrentVersion: phase0.Version{5, 0, 0, 0}, + }, + }, }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoV2NetworkID.Byte(), 0x2}, diff --git a/networkconfig/mainnet.go b/networkconfig/mainnet.go index 995ff156d2..2e4dc7c581 100644 --- a/networkconfig/mainnet.go +++ b/networkconfig/mainnet.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -22,9 +23,47 @@ var Mainnet = NetworkConfig{ TargetAggregatorsPerSyncSubcommittee: 16, TargetAggregatorsPerCommittee: 16, IntervalsPerSlot: 3, - ForkVersion: spectypes.MainNetwork.ForkVersion(), + GenesisForkVersion: spectypes.MainNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.MainNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95")), + Forks: map[spec.DataVersion]phase0.Fork{ + // Phase0 (genesis) + spec.DataVersionPhase0: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0x00, 0x00, 0x00, 0x00}, // GENESIS_FORK_VERSION + CurrentVersion: phase0.Version{0x00, 0x00, 0x00, 0x00}, + }, + // Altair @ epoch 74240 + spec.DataVersionAltair: { + Epoch: phase0.Epoch(74240), + PreviousVersion: phase0.Version{0x00, 0x00, 0x00, 0x00}, + CurrentVersion: phase0.Version{0x01, 0x00, 0x00, 0x00}, // ALTAIR_FORK_VERSION + }, + // Bellatrix (Merge) @ epoch 144896 + spec.DataVersionBellatrix: { + Epoch: phase0.Epoch(144896), + PreviousVersion: phase0.Version{0x01, 0x00, 0x00, 0x00}, + CurrentVersion: phase0.Version{0x02, 0x00, 0x00, 0x00}, // BELLATRIX_FORK_VERSION + }, + // Capella @ epoch 194048 + spec.DataVersionCapella: { + Epoch: phase0.Epoch(194048), + PreviousVersion: phase0.Version{0x02, 0x00, 0x00, 0x00}, + CurrentVersion: phase0.Version{0x03, 0x00, 0x00, 0x00}, // CAPELLA_FORK_VERSION + }, + // Deneb @ epoch 269568 + spec.DataVersionDeneb: { + Epoch: phase0.Epoch(269568), + PreviousVersion: phase0.Version{0x03, 0x00, 0x00, 0x00}, + CurrentVersion: phase0.Version{0x04, 0x00, 0x00, 0x00}, // DENEB_FORK_VERSION + }, + // Electra @ epoch 364032 + spec.DataVersionElectra: { + Epoch: phase0.Epoch(364032), + PreviousVersion: phase0.Version{0x04, 0x00, 0x00, 0x00}, + CurrentVersion: phase0.Version{0x05, 0x00, 0x00, 0x00}, // ELECTRA_FORK_VERSION + }, + }, }, SSVConfig: SSVConfig{ DomainType: spectypes.AlanMainnet, diff --git a/networkconfig/network_mock.go b/networkconfig/network_mock.go index 85e12572dc..f6448d21e5 100644 --- a/networkconfig/network_mock.go +++ b/networkconfig/network_mock.go @@ -13,6 +13,7 @@ import ( reflect "reflect" time "time" + spec "github.com/attestantio/go-eth2-client/spec" phase0 "github.com/attestantio/go-eth2-client/spec/phase0" types "github.com/ssvlabs/ssv-spec/types" gomock "go.uber.org/mock/gomock" @@ -182,6 +183,21 @@ func (mr *MockNetworkMockRecorder) FirstSlotAtEpoch(epoch any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FirstSlotAtEpoch", reflect.TypeOf((*MockNetwork)(nil).FirstSlotAtEpoch), epoch) } +// ForkAtEpoch mocks base method. +func (m *MockNetwork) ForkAtEpoch(epoch phase0.Epoch) (spec.DataVersion, *phase0.Fork) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ForkAtEpoch", epoch) + ret0, _ := ret[0].(spec.DataVersion) + ret1, _ := ret[1].(*phase0.Fork) + return ret0, ret1 +} + +// ForkAtEpoch indicates an expected call of ForkAtEpoch. +func (mr *MockNetworkMockRecorder) ForkAtEpoch(epoch any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForkAtEpoch", reflect.TypeOf((*MockNetwork)(nil).ForkAtEpoch), epoch) +} + // GetBeaconName mocks base method. func (m *MockNetwork) GetBeaconName() string { m.ctrl.T.Helper() @@ -252,6 +268,20 @@ func (mr *MockNetworkMockRecorder) GetGenesisTime() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGenesisTime", reflect.TypeOf((*MockNetwork)(nil).GetGenesisTime)) } +// GetGenesisValidatorsRoot mocks base method. +func (m *MockNetwork) GetGenesisValidatorsRoot() phase0.Root { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGenesisValidatorsRoot") + ret0, _ := ret[0].(phase0.Root) + return ret0 +} + +// GetGenesisValidatorsRoot indicates an expected call of GetGenesisValidatorsRoot. +func (mr *MockNetworkMockRecorder) GetGenesisValidatorsRoot() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGenesisValidatorsRoot", reflect.TypeOf((*MockNetwork)(nil).GetGenesisValidatorsRoot)) +} + // GetSlotDuration mocks base method. func (m *MockNetwork) GetSlotDuration() time.Duration { m.ctrl.T.Helper() diff --git a/networkconfig/sepolia.go b/networkconfig/sepolia.go index 7a609a004c..43052457b8 100644 --- a/networkconfig/sepolia.go +++ b/networkconfig/sepolia.go @@ -4,6 +4,8 @@ import ( "math/big" "time" + "github.com/attestantio/go-eth2-client/spec" + "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) @@ -20,8 +22,46 @@ var Sepolia = NetworkConfig{ TargetAggregatorsPerSyncSubcommittee: 16, TargetAggregatorsPerCommittee: 16, IntervalsPerSlot: 3, - ForkVersion: spectypes.SepoliaNetwork.ForkVersion(), + GenesisForkVersion: spectypes.SepoliaNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.SepoliaNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 + Forks: map[spec.DataVersion]phase0.Fork{ + // Phase0 (genesis) + spec.DataVersionPhase0: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x69}, // GENESIS_FORK_VERSION + CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x69}, + }, + // Altair @ epoch 50 + spec.DataVersionAltair: { + Epoch: phase0.Epoch(50), + PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x69}, + CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x70}, // ALTAIR_FORK_VERSION + }, + // Bellatrix (Merge) @ epoch 100 + spec.DataVersionBellatrix: { + Epoch: phase0.Epoch(100), + PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x70}, + CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x71}, // BELLATRIX_FORK_VERSION + }, + // Capella @ epoch 56832 + spec.DataVersionCapella: { + Epoch: phase0.Epoch(56832), + PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x71}, + CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x72}, // CAPELLA_FORK_VERSION + }, + // Deneb @ epoch 132608 + spec.DataVersionDeneb: { + Epoch: phase0.Epoch(132608), + PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x72}, + CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x73}, // DENEB_FORK_VERSION + }, + // Electra @ epoch 222464 + spec.DataVersionElectra: { + Epoch: phase0.Epoch(222464), + PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x73}, + CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x74}, // ELECTRA_FORK_VERSION + }, + }, }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x69}, diff --git a/networkconfig/test-network.go b/networkconfig/test-network.go index aa9922026d..6cfbfb975f 100644 --- a/networkconfig/test-network.go +++ b/networkconfig/test-network.go @@ -4,6 +4,7 @@ import ( "math/big" "time" + "github.com/attestantio/go-eth2-client/spec" "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -22,9 +23,41 @@ var TestNetwork = NetworkConfig{ TargetAggregatorsPerSyncSubcommittee: 16, TargetAggregatorsPerCommittee: 16, IntervalsPerSlot: 3, - ForkVersion: spectypes.BeaconTestNetwork.ForkVersion(), + GenesisForkVersion: spectypes.BeaconTestNetwork.ForkVersion(), GenesisTime: time.Unix(int64(spectypes.BeaconTestNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb")), + Forks: map[spec.DataVersion]phase0.Fork{ + spec.DataVersionPhase0: { + Epoch: phase0.Epoch(0), + PreviousVersion: phase0.Version{0, 0, 0, 0}, + CurrentVersion: phase0.Version{0, 0, 0, 0}, + }, + spec.DataVersionAltair: { + Epoch: phase0.Epoch(1), + PreviousVersion: phase0.Version{0, 0, 0, 0}, + CurrentVersion: phase0.Version{1, 0, 0, 0}, + }, + spec.DataVersionBellatrix: { + Epoch: phase0.Epoch(2), + PreviousVersion: phase0.Version{1, 0, 0, 0}, + CurrentVersion: phase0.Version{2, 0, 0, 0}, + }, + spec.DataVersionCapella: { + Epoch: phase0.Epoch(3), + PreviousVersion: phase0.Version{2, 0, 0, 0}, + CurrentVersion: phase0.Version{3, 0, 0, 0}, + }, + spec.DataVersionDeneb: { + Epoch: phase0.Epoch(4), + PreviousVersion: phase0.Version{3, 0, 0, 0}, + CurrentVersion: phase0.Version{4, 0, 0, 0}, + }, + spec.DataVersionElectra: { + Epoch: phase0.Epoch(5), + PreviousVersion: phase0.Version{4, 0, 0, 0}, + CurrentVersion: phase0.Version{5, 0, 0, 0}, + }, + }, }, SSVConfig: SSVConfig{ DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoNetworkID.Byte(), 0x2}, diff --git a/protocol/v2/blockchain/beacon/client.go b/protocol/v2/blockchain/beacon/client.go index 18dd29a6f4..4ab619d44b 100644 --- a/protocol/v2/blockchain/beacon/client.go +++ b/protocol/v2/blockchain/beacon/client.go @@ -79,12 +79,6 @@ type DomainCalls interface { DomainData(ctx context.Context, epoch phase0.Epoch, domain phase0.DomainType) (phase0.Domain, error) } -type VersionCalls interface { - // DataVersion returns a data version for the given epoch. - // In practice, for performance, responses can be cached in order not to always trigger an API call. - DataVersion(epoch phase0.Epoch) spec.DataVersion -} - // beaconDuties interface serves all duty related calls type beaconDuties interface { AttesterDuties(ctx context.Context, epoch phase0.Epoch, validatorIndices []phase0.ValidatorIndex) ([]*eth2apiv1.AttesterDuty, error) @@ -128,7 +122,6 @@ type BeaconNode interface { ValidatorRegistrationCalls VoluntaryExitCalls DomainCalls - VersionCalls beaconDuties beaconSubscriber diff --git a/protocol/v2/blockchain/beacon/mock_client.go b/protocol/v2/blockchain/beacon/mock_client.go index 7334b575a9..5742f52083 100644 --- a/protocol/v2/blockchain/beacon/mock_client.go +++ b/protocol/v2/blockchain/beacon/mock_client.go @@ -450,44 +450,6 @@ func (mr *MockDomainCallsMockRecorder) DomainData(ctx, epoch, domain any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DomainData", reflect.TypeOf((*MockDomainCalls)(nil).DomainData), ctx, epoch, domain) } -// MockVersionCalls is a mock of VersionCalls interface. -type MockVersionCalls struct { - ctrl *gomock.Controller - recorder *MockVersionCallsMockRecorder - isgomock struct{} -} - -// MockVersionCallsMockRecorder is the mock recorder for MockVersionCalls. -type MockVersionCallsMockRecorder struct { - mock *MockVersionCalls -} - -// NewMockVersionCalls creates a new mock instance. -func NewMockVersionCalls(ctrl *gomock.Controller) *MockVersionCalls { - mock := &MockVersionCalls{ctrl: ctrl} - mock.recorder = &MockVersionCallsMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockVersionCalls) EXPECT() *MockVersionCallsMockRecorder { - return m.recorder -} - -// DataVersion mocks base method. -func (m *MockVersionCalls) DataVersion(epoch phase0.Epoch) spec.DataVersion { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DataVersion", epoch) - ret0, _ := ret[0].(spec.DataVersion) - return ret0 -} - -// DataVersion indicates an expected call of DataVersion. -func (mr *MockVersionCallsMockRecorder) DataVersion(epoch any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DataVersion", reflect.TypeOf((*MockVersionCalls)(nil).DataVersion), epoch) -} - // MockbeaconDuties is a mock of beaconDuties interface. type MockbeaconDuties struct { ctrl *gomock.Controller diff --git a/protocol/v2/ssv/runner/committee.go b/protocol/v2/ssv/runner/committee.go index 85843e4a72..d87a90dbf8 100644 --- a/protocol/v2/ssv/runner/committee.go +++ b/protocol/v2/ssv/runner/committee.go @@ -19,12 +19,13 @@ import ( spectypes "github.com/ssvlabs/ssv-spec/types" "go.uber.org/zap" + "github.com/ssvlabs/ssv/ssvsigner/ekm" + "github.com/ssvlabs/ssv/logging/fields" "github.com/ssvlabs/ssv/networkconfig" "github.com/ssvlabs/ssv/protocol/v2/blockchain/beacon" "github.com/ssvlabs/ssv/protocol/v2/qbft/controller" ssvtypes "github.com/ssvlabs/ssv/protocol/v2/types" - "github.com/ssvlabs/ssv/ssvsigner/ekm" ) var ( @@ -231,7 +232,7 @@ func (cr *CommitteeRunner) ProcessConsensus(ctx context.Context, logger *zap.Log blockedAttesterDuties := 0 epoch := cr.BaseRunner.NetworkConfig.EstimatedEpochAtSlot(duty.DutySlot()) - version := cr.beacon.DataVersion(epoch) + version, _ := cr.BaseRunner.NetworkConfig.ForkAtEpoch(epoch) for _, validatorDuty := range duty.(*spectypes.CommitteeDuty).ValidatorDuties { if err := cr.DutyGuard.ValidDuty(validatorDuty.Type, spectypes.ValidatorPK(validatorDuty.PubKey), validatorDuty.DutySlot()); err != nil { @@ -688,7 +689,7 @@ func (cr *CommitteeRunner) expectedPostConsensusRootsAndBeaconObjects(ctx contex slot := duty.DutySlot() epoch := cr.GetBaseRunner().NetworkConfig.EstimatedEpochAtSlot(slot) - dataVersion := cr.beacon.DataVersion(epoch) + dataVersion, _ := cr.GetBaseRunner().NetworkConfig.ForkAtEpoch(epoch) for _, validatorDuty := range duty.(*spectypes.CommitteeDuty).ValidatorDuties { if validatorDuty == nil { diff --git a/ssvsigner/ekm/mock.go b/ssvsigner/ekm/mock.go index 6ca37fed95..5351761ded 100644 --- a/ssvsigner/ekm/mock.go +++ b/ssvsigner/ekm/mock.go @@ -3,7 +3,6 @@ package ekm import ( "context" - eth2api "github.com/attestantio/go-eth2-client/api/v1" "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/ssvlabs/eth2-key-manager/core" "github.com/stretchr/testify/mock" @@ -53,26 +52,6 @@ func (m *MockRemoteSigner) OperatorSign(ctx context.Context, payload []byte) ([] return args.Get(0).([]byte), args.Error(1) } -type MockConsensusClient struct { - mock.Mock -} - -func (m *MockConsensusClient) ForkAtEpoch(ctx context.Context, epoch phase0.Epoch) (*phase0.Fork, error) { - args := m.Called(ctx, epoch) - if args.Get(0) == nil { - return nil, args.Error(1) - } - return args.Get(0).(*phase0.Fork), args.Error(1) -} - -func (m *MockConsensusClient) Genesis(ctx context.Context) (*eth2api.Genesis, error) { - args := m.Called(ctx) - if args.Get(0) == nil { - return nil, args.Error(1) - } - return args.Get(0).(*eth2api.Genesis), args.Error(1) -} - type MockBeaconNetwork struct { mock.Mock } diff --git a/ssvsigner/ekm/remote_key_manager.go b/ssvsigner/ekm/remote_key_manager.go index 25e0c4c664..cc2df5112e 100644 --- a/ssvsigner/ekm/remote_key_manager.go +++ b/ssvsigner/ekm/remote_key_manager.go @@ -39,14 +39,13 @@ import ( // // RemoteKeyManager doesn't use operator private key as it's stored externally in the remote signer. type RemoteKeyManager struct { - logger *zap.Logger - beaconConfig networkconfig.Beacon - signerClient signerClient - consensusClient consensusClient - getOperatorId func() spectypes.OperatorID - operatorPubKey keys.OperatorPublicKey - signLocksMu sync.RWMutex - signLocks map[signKey]*sync.RWMutex + logger *zap.Logger + beaconConfig networkconfig.Beacon + signerClient signerClient + getOperatorId func() spectypes.OperatorID + operatorPubKey keys.OperatorPublicKey + signLocksMu sync.RWMutex + signLocks map[signKey]*sync.RWMutex slashingProtector } @@ -58,11 +57,6 @@ type signerClient interface { OperatorSign(ctx context.Context, payload []byte) ([]byte, error) } -type consensusClient interface { - ForkAtEpoch(ctx context.Context, epoch phase0.Epoch) (*phase0.Fork, error) - Genesis(ctx context.Context) (*eth2apiv1.Genesis, error) -} - // NewRemoteKeyManager returns a RemoteKeyManager that fetches the operator's public // identity from the signerClient, sets up local slashing protection, and uses // the provided consensusClient to get the current fork/genesis for sign requests. @@ -71,7 +65,6 @@ func NewRemoteKeyManager( logger *zap.Logger, beaconConfig networkconfig.Beacon, signerClient signerClient, - consensusClient consensusClient, db basedb.Database, getOperatorId func() spectypes.OperatorID, ) (*RemoteKeyManager, error) { @@ -92,7 +85,6 @@ func NewRemoteKeyManager( logger: logger, beaconConfig: beaconConfig, signerClient: signerClient, - consensusClient: consensusClient, slashingProtector: NewSlashingProtector(logger, beaconConfig, signerStore, protection), getOperatorId: getOperatorId, operatorPubKey: operatorPubKey, @@ -156,13 +148,8 @@ func (km *RemoteKeyManager) SignBeaconObject( ) (spectypes.Signature, phase0.Root, error) { epoch := km.beaconConfig.EstimatedEpochAtSlot(slot) - forkInfo, err := km.getForkInfo(ctx, epoch) - if err != nil { - return spectypes.Signature{}, phase0.Root{}, fmt.Errorf("get fork info: %w", err) - } - req := web3signer.SignRequest{ - ForkInfo: forkInfo, + ForkInfo: km.getForkInfo(epoch), } switch signatureDomain { @@ -465,21 +452,13 @@ func (km *RemoteKeyManager) handleDomainProposer( return ret, nil } -func (km *RemoteKeyManager) getForkInfo(ctx context.Context, epoch phase0.Epoch) (web3signer.ForkInfo, error) { - currentFork, err := km.consensusClient.ForkAtEpoch(ctx, epoch) - if err != nil { - return web3signer.ForkInfo{}, fmt.Errorf("get current fork: %w", err) - } - - genesis, err := km.consensusClient.Genesis(ctx) - if err != nil { - return web3signer.ForkInfo{}, fmt.Errorf("get genesis: %w", err) - } +func (km *RemoteKeyManager) getForkInfo(epoch phase0.Epoch) web3signer.ForkInfo { + _, currentFork := km.beaconConfig.ForkAtEpoch(epoch) return web3signer.ForkInfo{ Fork: currentFork, - GenesisValidatorsRoot: genesis.GenesisValidatorsRoot, - }, nil + GenesisValidatorsRoot: km.beaconConfig.GetGenesisValidatorsRoot(), + } } func (km *RemoteKeyManager) Sign(payload []byte) ([]byte, error) { diff --git a/ssvsigner/ekm/remote_key_manager_test.go b/ssvsigner/ekm/remote_key_manager_test.go index 426b88349f..5028712e6c 100644 --- a/ssvsigner/ekm/remote_key_manager_test.go +++ b/ssvsigner/ekm/remote_key_manager_test.go @@ -29,21 +29,19 @@ import ( "github.com/ssvlabs/ssv/ssvsigner" ) -var testNetCfg = networkconfig.HoodiStage // using a real network config because https://github.com/ssvlabs/eth2-key-manager doesn't support min genesis time for networkconfig.TestNetwork +var testNetCfg = networkconfig.HoodiStage.BeaconConfig // using a real network config because https://github.com/ssvlabs/eth2-key-manager doesn't support min genesis time for networkconfig.TestNetwork type RemoteKeyManagerTestSuite struct { suite.Suite - client *MockRemoteSigner - consensusClient *MockConsensusClient - db *MockDatabase - txn *MockTxn - readTxn *MockReadTxn - logger *zap.Logger + client *MockRemoteSigner + db *MockDatabase + txn *MockTxn + readTxn *MockReadTxn + logger *zap.Logger } func (s *RemoteKeyManagerTestSuite) SetupTest() { s.client = &MockRemoteSigner{} - s.consensusClient = &MockConsensusClient{} s.db = &MockDatabase{} s.txn = &MockTxn{} s.readTxn = &MockReadTxn{} @@ -59,7 +57,6 @@ func (s *RemoteKeyManagerTestSuite) TestRemoteKeyManagerWithMockedOperatorKey() logger: s.logger, beaconConfig: testNetCfg, signerClient: s.client, - consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: mockSlashingProtector, @@ -90,7 +87,6 @@ func (s *RemoteKeyManagerTestSuite) TestRemoveShareWithMockedOperatorKey() { logger: s.logger, beaconConfig: testNetCfg, signerClient: s.client, - consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: mockSlashingProtector, @@ -113,12 +109,11 @@ func (s *RemoteKeyManagerTestSuite) TestRemoveShareWithMockedOperatorKey() { func (s *RemoteKeyManagerTestSuite) TestSignWithMockedOperatorKey() { rm := &RemoteKeyManager{ - logger: s.logger, - signerClient: s.client, - consensusClient: s.consensusClient, - getOperatorId: func() spectypes.OperatorID { return 1 }, - operatorPubKey: &MockOperatorPublicKey{}, - signLocks: map[signKey]*sync.RWMutex{}, + logger: s.logger, + signerClient: s.client, + getOperatorId: func() spectypes.OperatorID { return 1 }, + operatorPubKey: &MockOperatorPublicKey{}, + signLocks: map[signKey]*sync.RWMutex{}, } payload := []byte("message_to_sign") @@ -170,7 +165,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() logger: s.logger, beaconConfig: testNetCfg, signerClient: s.client, - consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: mockSlashingProtector, @@ -199,21 +193,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() mockSlashingProtector.On("IsAttestationSlashable", mock.Anything, attestationData).Return(nil) mockSlashingProtector.On("UpdateHighestAttestation", pubKey, attestationData).Return(nil) - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - - genesis := ð2api.Genesis{ - GenesisTime: time.Unix(12345, 0), - GenesisValidatorsRoot: phase0.Root{9, 8, 7}, - GenesisForkVersion: phase0.Version{1, 2, 3, 4}, - } - - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil) - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil) - expectedSignature := phase0.BLSSignature{5, 6, 7} s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil) @@ -224,7 +203,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() s.NotEqual([32]byte{}, root) mockSlashingProtector.AssertExpectations(s.T()) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignBeaconBlock (capella)", func() { @@ -266,21 +244,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() mockSlashingProtector.On("IsBeaconBlockSlashable", mock.Anything, blindedBlock.Slot).Return(nil) mockSlashingProtector.On("UpdateHighestProposal", pubKey, blindedBlock.Slot).Return(nil) - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - - genesis := ð2api.Genesis{ - GenesisTime: time.Unix(12345, 0), - GenesisValidatorsRoot: phase0.Root{9, 8, 7}, - GenesisForkVersion: phase0.Version{1, 2, 3, 4}, - } - - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil) - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil) - expectedSignature := phase0.BLSSignature{5, 6, 7} s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil) @@ -291,7 +254,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() s.NotEqual([32]byte{}, root) mockSlashingProtector.AssertExpectations(s.T()) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignBeaconBlock (deneb)", func() { @@ -335,21 +297,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() mockSlashingProtector.On("IsBeaconBlockSlashable", mock.Anything, blindedBlock.Slot).Return(nil) mockSlashingProtector.On("UpdateHighestProposal", pubKey, blindedBlock.Slot).Return(nil) - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - - genesis := ð2api.Genesis{ - GenesisTime: time.Unix(12345, 0), - GenesisValidatorsRoot: phase0.Root{9, 8, 7}, - GenesisForkVersion: phase0.Version{1, 2, 3, 4}, - } - - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil) - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil) - expectedSignature := phase0.BLSSignature{5, 6, 7} s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil) @@ -360,7 +307,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() s.NotEqual([32]byte{}, root) mockSlashingProtector.AssertExpectations(s.T()) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignBeaconBlock (electra)", func() { @@ -430,21 +376,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() mockSlashingProtector.On("IsBeaconBlockSlashable", mock.Anything, blindedBlock.Slot).Return(nil) mockSlashingProtector.On("UpdateHighestProposal", pubKey, blindedBlock.Slot).Return(nil) - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - - genesis := ð2api.Genesis{ - GenesisTime: time.Unix(12345, 0), - GenesisValidatorsRoot: phase0.Root{9, 8, 7}, - GenesisForkVersion: phase0.Version{1, 2, 3, 4}, - } - - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil) - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil) - expectedSignature := phase0.BLSSignature{5, 6, 7} s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil) @@ -455,7 +386,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() s.NotEqual([32]byte{}, root) mockSlashingProtector.AssertExpectations(s.T()) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignBlindedBeaconBlock (capella)", func() { @@ -499,21 +429,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() mockSlashingProtector.On("IsBeaconBlockSlashable", mock.Anything, blindedBlock.Slot).Return(nil) mockSlashingProtector.On("UpdateHighestProposal", pubKey, blindedBlock.Slot).Return(nil) - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - - genesis := ð2api.Genesis{ - GenesisTime: time.Unix(12345, 0), - GenesisValidatorsRoot: phase0.Root{9, 8, 7}, - GenesisForkVersion: phase0.Version{1, 2, 3, 4}, - } - - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil) - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil) - expectedSignature := phase0.BLSSignature{5, 6, 7} s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil) @@ -524,7 +439,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() s.NotEqual([32]byte{}, root) mockSlashingProtector.AssertExpectations(s.T()) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignBlindedBeaconBlock (deneb)", func() { @@ -570,21 +484,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() mockSlashingProtector.On("IsBeaconBlockSlashable", mock.Anything, blindedBlock.Slot).Return(nil) mockSlashingProtector.On("UpdateHighestProposal", pubKey, blindedBlock.Slot).Return(nil) - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - - genesis := ð2api.Genesis{ - GenesisTime: time.Unix(12345, 0), - GenesisValidatorsRoot: phase0.Root{9, 8, 7}, - GenesisForkVersion: phase0.Version{1, 2, 3, 4}, - } - - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil) - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil) - expectedSignature := phase0.BLSSignature{5, 6, 7} s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil) @@ -595,7 +494,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() s.NotEqual([32]byte{}, root) mockSlashingProtector.AssertExpectations(s.T()) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignBlindedBeaconBlock (electra)", func() { @@ -667,21 +565,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() mockSlashingProtector.On("IsBeaconBlockSlashable", mock.Anything, blindedBlock.Slot).Return(nil) mockSlashingProtector.On("UpdateHighestProposal", pubKey, blindedBlock.Slot).Return(nil) - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - - genesis := ð2api.Genesis{ - GenesisTime: time.Unix(12345, 0), - GenesisValidatorsRoot: phase0.Root{9, 8, 7}, - GenesisForkVersion: phase0.Version{1, 2, 3, 4}, - } - - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil) - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil) - expectedSignature := phase0.BLSSignature{5, 6, 7} s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil) @@ -692,113 +575,22 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectWithMockedOperatorKey() s.NotEqual([32]byte{}, root) mockSlashingProtector.AssertExpectations(s.T()) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) } func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { ctx := s.T().Context() - mockSlashingProtector := &MockSlashingProtector{} - - rm := &RemoteKeyManager{ - logger: s.logger, - beaconConfig: testNetCfg, - signerClient: s.client, - consensusClient: s.consensusClient, - getOperatorId: func() spectypes.OperatorID { return 1 }, - operatorPubKey: &MockOperatorPublicKey{}, - slashingProtector: mockSlashingProtector, - signLocks: map[signKey]*sync.RWMutex{}, - } - slot := phase0.Slot(123) - s.Run("ForkInfoError", func() { - pubKey := phase0.BLSPubKey{1, 2, 3} - domain := phase0.Domain{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32} - attestationData := &phase0.AttestationData{ - Slot: 123, - Index: 1, - BeaconBlockRoot: phase0.Root{1, 2, 3}, - Source: &phase0.Checkpoint{ - Epoch: 10, - Root: phase0.Root{4, 5, 6}, - }, - Target: &phase0.Checkpoint{ - Epoch: 11, - Root: phase0.Root{7, 8, 9}, - }, - } - - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(nil, errors.New("fork info error")) - - signature, root, err := rm.SignBeaconObject(ctx, attestationData, domain, pubKey, slot, spectypes.DomainAttester) - - s.ErrorContains(err, "get fork info") - s.Equal(spectypes.Signature{}, signature) - s.Equal(phase0.Root{}, root) - s.consensusClient.AssertExpectations(s.T()) - }) - - s.Run("SlashingProtectionError", func() { - clientMock := new(MockRemoteSigner) - consensusMock := new(MockConsensusClient) - slashingMock := new(MockSlashingProtector) - - rmTest := &RemoteKeyManager{ - logger: s.logger, - beaconConfig: testNetCfg, - signerClient: clientMock, - consensusClient: consensusMock, - getOperatorId: func() spectypes.OperatorID { return 1 }, - operatorPubKey: &MockOperatorPublicKey{}, - slashingProtector: slashingMock, - signLocks: map[signKey]*sync.RWMutex{}, - } - - pubKey := phase0.BLSPubKey{1, 2, 3} - domain := phase0.Domain{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32} - attestationData := &phase0.AttestationData{ - Slot: 123, - Index: 1, - BeaconBlockRoot: phase0.Root{1, 2, 3}, - Source: &phase0.Checkpoint{ - Epoch: 10, - Root: phase0.Root{4, 5, 6}, - }, - Target: &phase0.Checkpoint{ - Epoch: 11, - Root: phase0.Root{7, 8, 9}, - }, - } - - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - consensusMock.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - consensusMock.On("Genesis", mock.Anything).Return(nil, errors.New("genesis error")).Once() - - signature, root, err := rmTest.SignBeaconObject(ctx, attestationData, domain, pubKey, slot, spectypes.DomainAttester) - - s.ErrorContains(err, "get fork info: get genesis") - s.Equal(spectypes.Signature{}, signature) - s.Equal(phase0.Root{}, root) - consensusMock.AssertExpectations(s.T()) - }) - s.Run("RemoteSignerError", func() { clientMock := new(MockRemoteSigner) - consensusMock := new(MockConsensusClient) slashingMock := new(MockSlashingProtector) rmTest := &RemoteKeyManager{ logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -821,19 +613,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { }, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - genesis := ð2api.Genesis{ - GenesisTime: time.Time{}, - GenesisValidatorsRoot: phase0.Root{}, - GenesisForkVersion: phase0.Version{}, - } - - consensusMock.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - consensusMock.On("Genesis", mock.Anything).Return(genesis, nil).Once() slashingMock.On("IsAttestationSlashable", mock.Anything, mock.Anything).Return(nil).Once() slashingMock.On("UpdateHighestAttestation", mock.Anything, mock.Anything).Return(nil).Once() clientMock.On("Sign", mock.Anything, mock.Anything, mock.Anything).Return(phase0.BLSSignature{}, errors.New("sign error")).Once() @@ -843,19 +622,16 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { s.ErrorContains(err, "remote signer") s.Equal(spectypes.Signature{}, signature) s.Equal(phase0.Root{}, root) - consensusMock.AssertExpectations(s.T()) }) s.Run("IsAttestationSlashableError", func() { clientMock := new(MockRemoteSigner) - consensusMock := new(MockConsensusClient) slashingMock := new(MockSlashingProtector) rmTest := &RemoteKeyManager{ logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -878,19 +654,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { }, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - genesis := ð2api.Genesis{ - GenesisTime: time.Time{}, - GenesisValidatorsRoot: phase0.Root{}, - GenesisForkVersion: phase0.Version{}, - } - - consensusMock.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - consensusMock.On("Genesis", mock.Anything).Return(genesis, nil).Once() slashingMock.On("IsAttestationSlashable", mock.Anything, mock.Anything).Return(errors.New("test error (IsAttestationSlashable)")).Once() slashingMock.On("UpdateHighestAttestation", mock.Anything, mock.Anything).Return(nil).Once() clientMock.On("Sign", mock.Anything, mock.Anything, mock.Anything).Return([]byte{1, 2, 3}, nil).Once() @@ -900,19 +663,16 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { s.ErrorContains(err, "test error (IsAttestationSlashable)") s.Empty(signature) s.Equal(phase0.Root{}, root) - consensusMock.AssertExpectations(s.T()) }) s.Run("UpdateHighestAttestationError", func() { clientMock := new(MockRemoteSigner) - consensusMock := new(MockConsensusClient) slashingMock := new(MockSlashingProtector) rmTest := &RemoteKeyManager{ logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -935,19 +695,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { }, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - genesis := ð2api.Genesis{ - GenesisTime: time.Time{}, - GenesisValidatorsRoot: phase0.Root{}, - GenesisForkVersion: phase0.Version{}, - } - - consensusMock.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - consensusMock.On("Genesis", mock.Anything).Return(genesis, nil).Once() slashingMock.On("IsAttestationSlashable", mock.Anything, mock.Anything).Return(nil).Once() slashingMock.On("UpdateHighestAttestation", mock.Anything, mock.Anything).Return(errors.New("test error (UpdateHighestAttestation)")).Once() clientMock.On("Sign", mock.Anything, mock.Anything, mock.Anything).Return([]byte{1, 2, 3}, nil).Once() @@ -957,19 +704,16 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { s.ErrorContains(err, "test error (UpdateHighestAttestation)") s.Empty(signature) s.Equal(phase0.Root{}, root) - consensusMock.AssertExpectations(s.T()) }) s.Run("IsBeaconBlockSlashable_Capella", func() { clientMock := new(MockRemoteSigner) - consensusMock := new(MockConsensusClient) slashingMock := new(MockSlashingProtector) rmTest := &RemoteKeyManager{ logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -1013,19 +757,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { }, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - genesis := ð2api.Genesis{ - GenesisTime: time.Time{}, - GenesisValidatorsRoot: phase0.Root{}, - GenesisForkVersion: phase0.Version{}, - } - - consensusMock.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - consensusMock.On("Genesis", mock.Anything).Return(genesis, nil).Once() slashingMock.On("IsBeaconBlockSlashable", mock.Anything, mock.Anything).Return(errors.New("test error (IsBeaconBlockSlashable)")).Once() slashingMock.On("UpdateHighestProposal", mock.Anything, mock.Anything).Return(nil).Once() clientMock.On("Sign", mock.Anything, mock.Anything, mock.Anything).Return([]byte{1, 2, 3}, nil).Once() @@ -1035,19 +766,16 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { s.ErrorContains(err, "test error (IsBeaconBlockSlashable)") s.Empty(signature) s.Equal(phase0.Root{}, root) - consensusMock.AssertExpectations(s.T()) }) s.Run("UpdateHighestProposal_Capella", func() { clientMock := new(MockRemoteSigner) - consensusMock := new(MockConsensusClient) slashingMock := new(MockSlashingProtector) rmTest := &RemoteKeyManager{ logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -1091,19 +819,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { }, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - genesis := ð2api.Genesis{ - GenesisTime: time.Time{}, - GenesisValidatorsRoot: phase0.Root{}, - GenesisForkVersion: phase0.Version{}, - } - - consensusMock.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - consensusMock.On("Genesis", mock.Anything).Return(genesis, nil).Once() slashingMock.On("IsBeaconBlockSlashable", mock.Anything, mock.Anything).Return(nil).Once() slashingMock.On("UpdateHighestProposal", mock.Anything, mock.Anything).Return(errors.New("test error (UpdateHighestProposal)")).Once() clientMock.On("Sign", mock.Anything, mock.Anything, mock.Anything).Return([]byte{1, 2, 3}, nil).Once() @@ -1113,19 +828,16 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { s.ErrorContains(err, "test error (UpdateHighestProposal)") s.Empty(signature) s.Equal(phase0.Root{}, root) - consensusMock.AssertExpectations(s.T()) }) s.Run("IsBeaconBlockSlashable_Deneb", func() { clientMock := new(MockRemoteSigner) - consensusMock := new(MockConsensusClient) slashingMock := new(MockSlashingProtector) rmTest := &RemoteKeyManager{ logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -1171,19 +883,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { }, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - genesis := ð2api.Genesis{ - GenesisTime: time.Time{}, - GenesisValidatorsRoot: phase0.Root{}, - GenesisForkVersion: phase0.Version{}, - } - - consensusMock.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - consensusMock.On("Genesis", mock.Anything).Return(genesis, nil).Once() slashingMock.On("IsBeaconBlockSlashable", mock.Anything, mock.Anything).Return(errors.New("test error (IsBeaconBlockSlashable)")).Once() slashingMock.On("UpdateHighestProposal", mock.Anything, mock.Anything).Return(nil).Once() clientMock.On("Sign", mock.Anything, mock.Anything, mock.Anything).Return([]byte{1, 2, 3}, nil).Once() @@ -1193,19 +892,16 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { s.ErrorContains(err, "test error (IsBeaconBlockSlashable)") s.Empty(signature) s.Equal(phase0.Root{}, root) - consensusMock.AssertExpectations(s.T()) }) s.Run("UpdateHighestProposal_Deneb", func() { clientMock := new(MockRemoteSigner) - consensusMock := new(MockConsensusClient) slashingMock := new(MockSlashingProtector) rmTest := &RemoteKeyManager{ logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -1251,19 +947,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { }, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - genesis := ð2api.Genesis{ - GenesisTime: time.Time{}, - GenesisValidatorsRoot: phase0.Root{}, - GenesisForkVersion: phase0.Version{}, - } - - consensusMock.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - consensusMock.On("Genesis", mock.Anything).Return(genesis, nil).Once() slashingMock.On("IsBeaconBlockSlashable", mock.Anything, mock.Anything).Return(nil).Once() slashingMock.On("UpdateHighestProposal", mock.Anything, mock.Anything).Return(errors.New("test error (UpdateHighestProposal)")).Once() clientMock.On("Sign", mock.Anything, mock.Anything, mock.Anything).Return([]byte{1, 2, 3}, nil).Once() @@ -1273,19 +956,16 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { s.ErrorContains(err, "test error (UpdateHighestProposal)") s.Empty(signature) s.Equal(phase0.Root{}, root) - consensusMock.AssertExpectations(s.T()) }) s.Run("IsBeaconBlockSlashable_Electra", func() { clientMock := new(MockRemoteSigner) - consensusMock := new(MockConsensusClient) slashingMock := new(MockSlashingProtector) rmTest := &RemoteKeyManager{ logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -1356,19 +1036,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { }, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - genesis := ð2api.Genesis{ - GenesisTime: time.Time{}, - GenesisValidatorsRoot: phase0.Root{}, - GenesisForkVersion: phase0.Version{}, - } - - consensusMock.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - consensusMock.On("Genesis", mock.Anything).Return(genesis, nil).Once() slashingMock.On("IsBeaconBlockSlashable", mock.Anything, mock.Anything).Return(errors.New("test error (IsBeaconBlockSlashable)")).Once() slashingMock.On("UpdateHighestProposal", mock.Anything, mock.Anything).Return(nil).Once() clientMock.On("Sign", mock.Anything, mock.Anything, mock.Anything).Return([]byte{1, 2, 3}, nil).Once() @@ -1378,19 +1045,16 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { s.ErrorContains(err, "test error (IsBeaconBlockSlashable)") s.Empty(signature) s.Equal(phase0.Root{}, root) - consensusMock.AssertExpectations(s.T()) }) s.Run("UpdateHighestProposal_Electra", func() { clientMock := new(MockRemoteSigner) - consensusMock := new(MockConsensusClient) slashingMock := new(MockSlashingProtector) rmTest := &RemoteKeyManager{ logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: consensusMock, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -1461,19 +1125,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { }, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - genesis := ð2api.Genesis{ - GenesisTime: time.Time{}, - GenesisValidatorsRoot: phase0.Root{}, - GenesisForkVersion: phase0.Version{}, - } - - consensusMock.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - consensusMock.On("Genesis", mock.Anything).Return(genesis, nil).Once() slashingMock.On("IsBeaconBlockSlashable", mock.Anything, mock.Anything).Return(nil).Once() slashingMock.On("UpdateHighestProposal", mock.Anything, mock.Anything).Return(errors.New("test error (UpdateHighestProposal)")).Once() clientMock.On("Sign", mock.Anything, mock.Anything, mock.Anything).Return([]byte{1, 2, 3}, nil).Once() @@ -1483,7 +1134,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectErrorCases() { s.ErrorContains(err, "test error (UpdateHighestProposal)") s.Empty(signature) s.Equal(phase0.Root{}, root) - consensusMock.AssertExpectations(s.T()) }) } @@ -1497,7 +1147,6 @@ func (s *RemoteKeyManagerTestSuite) TestAddShareErrorCases() { logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: mockSlashingProtector, @@ -1526,7 +1175,6 @@ func (s *RemoteKeyManagerTestSuite) TestAddShareErrorCases() { logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -1558,7 +1206,6 @@ func (s *RemoteKeyManagerTestSuite) TestRemoveShareErrorCases() { logger: s.logger, beaconConfig: testNetCfg, signerClient: s.client, - consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: mockSlashingProtector, @@ -1583,7 +1230,6 @@ func (s *RemoteKeyManagerTestSuite) TestRemoveShareErrorCases() { logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -1611,7 +1257,6 @@ func (s *RemoteKeyManagerTestSuite) TestRemoveShareErrorCases() { logger: s.logger, beaconConfig: testNetCfg, signerClient: clientMock, - consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: slashingMock, @@ -1718,25 +1363,12 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectAdditionalDomains() { logger: s.logger, beaconConfig: testNetCfg, signerClient: s.client, - consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: mockSlashingProtector, signLocks: map[signKey]*sync.RWMutex{}, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - - genesis := ð2api.Genesis{ - GenesisTime: time.Unix(12345, 0), - GenesisValidatorsRoot: phase0.Root{9, 8, 7}, - GenesisForkVersion: phase0.Version{1, 2, 3, 4}, - } - pubKey := phase0.BLSPubKey{1, 2, 3} domain := phase0.Domain{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32} expectedSignature := phase0.BLSSignature{5, 6, 7} @@ -1748,8 +1380,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectAdditionalDomains() { ValidatorIndex: 456, } - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil).Once() signature, root, err := rm.SignBeaconObject(ctx, voluntaryExit, domain, pubKey, slot, spectypes.DomainVoluntaryExit) @@ -1758,14 +1388,11 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectAdditionalDomains() { s.EqualValues(expectedSignature[:], signature) s.NotEqual([32]byte{}, root) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignSelectionProof", func() { signedSlot := spectypes.SSZUint64(123) - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil).Once() signature, root, err := rm.SignBeaconObject(ctx, signedSlot, domain, pubKey, slot, spectypes.DomainSelectionProof) @@ -1774,14 +1401,11 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectAdditionalDomains() { s.EqualValues(expectedSignature[:], signature) s.NotEqual([32]byte{}, root) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignSyncCommittee", func() { blockRoot := phase0.Root{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32} - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil).Once() signature, root, err := rm.SignBeaconObject(ctx, spectypes.SSZBytes(blockRoot[:]), domain, pubKey, slot, spectypes.DomainSyncCommittee) @@ -1790,7 +1414,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectAdditionalDomains() { s.EqualValues(expectedSignature[:], signature) s.NotEqual([32]byte{}, root) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignSyncCommitteeSelectionProof", func() { @@ -1799,8 +1422,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectAdditionalDomains() { SubcommitteeIndex: 456, } - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil).Once() signature, root, err := rm.SignBeaconObject(ctx, selectionData, domain, pubKey, slot, spectypes.DomainSyncCommitteeSelectionProof) @@ -1809,22 +1430,17 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectAdditionalDomains() { s.EqualValues(expectedSignature[:], signature) s.NotEqual([32]byte{}, root) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("InvalidDomainType", func() { signedSlot := spectypes.SSZUint64(123) unknownDomain := phase0.DomainType{255, 255, 255, 255} - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() - signature, root, err := rm.SignBeaconObject(ctx, signedSlot, domain, pubKey, slot, unknownDomain) s.ErrorContains(err, "domain unknown") s.Nil(signature) s.Equal(phase0.Root{}, root) - s.consensusClient.AssertExpectations(s.T()) }) } @@ -1837,25 +1453,12 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectMoreDomains() { logger: s.logger, beaconConfig: testNetCfg, signerClient: s.client, - consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: mockSlashingProtector, signLocks: map[signKey]*sync.RWMutex{}, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - - genesis := ð2api.Genesis{ - GenesisTime: time.Unix(12345, 0), - GenesisValidatorsRoot: phase0.Root{9, 8, 7}, - GenesisForkVersion: phase0.Version{1, 2, 3, 4}, - } - pubKey := phase0.BLSPubKey{1, 2, 3} domain := phase0.Domain{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32} expectedSignature := phase0.BLSSignature{5, 6, 7} @@ -1888,8 +1491,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectMoreDomains() { Aggregate: attestation, } - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil).Once() signature, root, err := rm.SignBeaconObject(ctx, aggregateAndProof, domain, pubKey, slot, spectypes.DomainAggregateAndProof) @@ -1898,7 +1499,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectMoreDomains() { s.EqualValues(expectedSignature[:], signature) s.NotEqual([32]byte{}, root) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignAggregateAndProofElectra", func() { @@ -1929,8 +1529,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectMoreDomains() { Aggregate: attestation, } - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil).Once() signature, root, err := rm.SignBeaconObject(ctx, aggregateAndProof, domain, pubKey, slot, spectypes.DomainAggregateAndProof) @@ -1939,14 +1537,11 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectMoreDomains() { s.EqualValues(expectedSignature[:], signature) s.NotEqual([32]byte{}, root) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignRandao", func() { epoch := spectypes.SSZUint64(42) - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil).Once() signature, root, err := rm.SignBeaconObject(ctx, epoch, domain, pubKey, slot, spectypes.DomainRandao) @@ -1955,7 +1550,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectMoreDomains() { s.EqualValues(expectedSignature[:], signature) s.NotEqual([32]byte{}, root) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignApplicationBuilder", func() { @@ -1966,8 +1560,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectMoreDomains() { Pubkey: phase0.BLSPubKey{1, 2, 3, 4, 5}, } - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil).Once() signature, root, err := rm.SignBeaconObject(ctx, validatorReg, domain, pubKey, slot, spectypes.DomainApplicationBuilder) @@ -1976,7 +1568,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectMoreDomains() { s.EqualValues(expectedSignature[:], signature) s.NotEqual([32]byte{}, root) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignContributionAndProof", func() { @@ -1992,8 +1583,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectMoreDomains() { SelectionProof: phase0.BLSSignature{1, 2, 3, 4, 5}, } - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() s.client.On("Sign", mock.Anything, pubKey, mock.Anything).Return(expectedSignature, nil).Once() signature, root, err := rm.SignBeaconObject(ctx, contributionAndProof, domain, pubKey, slot, spectypes.DomainContributionAndProof) @@ -2002,7 +1591,6 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectMoreDomains() { s.EqualValues(expectedSignature[:], signature) s.NotEqual([32]byte{}, root) s.client.AssertExpectations(s.T()) - s.consensusClient.AssertExpectations(s.T()) }) } @@ -2015,25 +1603,12 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectTypeCastErrors() { logger: s.logger, beaconConfig: testNetCfg, signerClient: s.client, - consensusClient: s.consensusClient, getOperatorId: func() spectypes.OperatorID { return 1 }, operatorPubKey: &MockOperatorPublicKey{}, slashingProtector: mockSlashingProtector, signLocks: map[signKey]*sync.RWMutex{}, } - mockFork := &phase0.Fork{ - PreviousVersion: phase0.Version{1, 2, 3, 4}, - CurrentVersion: phase0.Version{5, 6, 7, 8}, - Epoch: 10, - } - - genesis := ð2api.Genesis{ - GenesisTime: time.Unix(12345, 0), - GenesisValidatorsRoot: phase0.Root{9, 8, 7}, - GenesisForkVersion: phase0.Version{1, 2, 3, 4}, - } - pubKey := phase0.BLSPubKey{1, 2, 3} domain := phase0.Domain{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32} slot := phase0.Slot(123) @@ -2041,121 +1616,81 @@ func (s *RemoteKeyManagerTestSuite) TestSignBeaconObjectTypeCastErrors() { s.Run("AttesterTypeCastError", func() { wrongType := &phase0.VoluntaryExit{} - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() - _, _, err := rm.SignBeaconObject(ctx, wrongType, domain, pubKey, slot, spectypes.DomainAttester) s.ErrorContains(err, "could not cast obj to AttestationData") - s.consensusClient.AssertExpectations(s.T()) }) s.Run("AggregateAndProofTypeCastError", func() { wrongType := &phase0.VoluntaryExit{} - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() - _, _, err := rm.SignBeaconObject(ctx, wrongType, domain, pubKey, slot, spectypes.DomainAggregateAndProof) s.ErrorContains(err, "obj type is unknown") - s.consensusClient.AssertExpectations(s.T()) }) s.Run("RandaoTypeCastError", func() { wrongType := &phase0.VoluntaryExit{} - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() - _, _, err := rm.SignBeaconObject(ctx, wrongType, domain, pubKey, slot, spectypes.DomainRandao) s.ErrorContains(err, "could not cast obj to SSZUint64") - s.consensusClient.AssertExpectations(s.T()) }) s.Run("ApplicationBuilderTypeCastError", func() { wrongType := &phase0.VoluntaryExit{} - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() - _, _, err := rm.SignBeaconObject(ctx, wrongType, domain, pubKey, slot, spectypes.DomainApplicationBuilder) s.ErrorContains(err, "could not cast obj to ValidatorRegistration") - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignContributionAndProofTypeCastError", func() { wrongType := &phase0.VoluntaryExit{} - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() - _, _, err := rm.SignBeaconObject(ctx, wrongType, domain, pubKey, slot, spectypes.DomainContributionAndProof) s.ErrorContains(err, "could not cast obj to ContributionAndProof") - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignSyncCommitteeSelectionProofTypeCastError", func() { wrongType := &phase0.VoluntaryExit{} - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() - _, _, err := rm.SignBeaconObject(ctx, wrongType, domain, pubKey, slot, spectypes.DomainSyncCommitteeSelectionProof) s.ErrorContains(err, "could not cast obj to SyncAggregatorSelectionData") - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignVoluntaryExitTypeCastError", func() { wrongType := spectypes.SSZUint64(1) - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() - _, _, err := rm.SignBeaconObject(ctx, wrongType, domain, pubKey, slot, spectypes.DomainVoluntaryExit) s.ErrorContains(err, "could not cast obj to VoluntaryExit") - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignSyncCommitteeTypeCastError", func() { wrongType := spectypes.SSZUint64(1) - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() - _, _, err := rm.SignBeaconObject(ctx, wrongType, domain, pubKey, slot, spectypes.DomainSyncCommittee) s.ErrorContains(err, "could not cast obj to SSZBytes") - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignSelectionProofTypeCastError", func() { wrongType := &phase0.VoluntaryExit{} - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil).Once() - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil).Once() - _, _, err := rm.SignBeaconObject(ctx, wrongType, domain, pubKey, slot, spectypes.DomainSelectionProof) s.ErrorContains(err, "could not cast obj to SSZUint64") - s.consensusClient.AssertExpectations(s.T()) }) s.Run("SignProposerTypeCastError", func() { wrongType := &phase0.VoluntaryExit{} - s.consensusClient.On("ForkAtEpoch", mock.Anything, mock.Anything).Return(mockFork, nil) - s.consensusClient.On("Genesis", mock.Anything).Return(genesis, nil) - _, _, err := rm.SignBeaconObject(ctx, wrongType, domain, pubKey, slot, spectypes.DomainProposer) s.ErrorContains(err, "obj type is unknown") - s.consensusClient.AssertExpectations(s.T()) }) } @@ -2190,7 +1725,6 @@ QwIDAQAB logger, testNetCfg, s.client, - s.consensusClient, s.db, getOperatorId, ) @@ -2219,7 +1753,6 @@ func (s *RemoteKeyManagerTestSuite) TestNewRemoteKeyManager_OperatorIdentity_Wro logger, testNetCfg, s.client, - s.consensusClient, s.db, getOperatorId, ) @@ -2247,7 +1780,6 @@ func (s *RemoteKeyManagerTestSuite) TestNewRemoteKeyManager_OperatorIdentity_Err logger, testNetCfg, s.client, - s.consensusClient, s.db, getOperatorId, ) diff --git a/ssvsigner/go.mod b/ssvsigner/go.mod index 58a821de4a..04977e6ccd 100644 --- a/ssvsigner/go.mod +++ b/ssvsigner/go.mod @@ -26,7 +26,7 @@ require ( github.com/microsoft/go-crypto-openssl v0.2.9 github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 github.com/ssvlabs/eth2-key-manager v1.5.5 - github.com/ssvlabs/ssv v1.2.1-0.20250527132358-45464863718a + github.com/ssvlabs/ssv v1.2.1-0.20250527135742-46517c804400 github.com/ssvlabs/ssv-spec v1.1.3 github.com/stretchr/testify v1.9.0 github.com/valyala/fasthttp v1.58.0 diff --git a/ssvsigner/go.sum b/ssvsigner/go.sum index 49e5bdbaed..9a51a1f182 100644 --- a/ssvsigner/go.sum +++ b/ssvsigner/go.sum @@ -320,13 +320,10 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/ssvlabs/eth2-key-manager v1.5.2 h1:gF+8FJkoV1VXpVCPspyVW/Jdky0kt9Pndk88W8ePqx8= -github.com/ssvlabs/eth2-key-manager v1.5.2/go.mod h1:yeUzAP+SBJXgeXPiGBrLeLuHIQCpeJZV7Jz3Fwzm/zk= +github.com/ssvlabs/eth2-key-manager v1.5.5 h1:AzwNowGvcmVpRCVHq10FVnpkVIUpoDo5YbJWNMnYA8Q= github.com/ssvlabs/eth2-key-manager v1.5.5/go.mod h1:yeUzAP+SBJXgeXPiGBrLeLuHIQCpeJZV7Jz3Fwzm/zk= -github.com/ssvlabs/ssv v1.2.1-0.20250512164336-eaf440d63581 h1:Tp0RSFcC70HFzCikFvLdnx8+xBTl2muZLERX9TGvmT8= -github.com/ssvlabs/ssv v1.2.1-0.20250512164336-eaf440d63581/go.mod h1:BbVBaDhZhJqqeXYM18RUxebPVcdMTtxLVEs21uktSpg= -github.com/ssvlabs/ssv v1.2.1-0.20250527132358-45464863718a h1:quMN/FOHKACUsWZhuCfGSRuccak5dw/Nw9ZpI69mY+4= -github.com/ssvlabs/ssv v1.2.1-0.20250527132358-45464863718a/go.mod h1:/6NNYfzIHtxMQpmTRRQw2q0ej1NhVSf5Ds+JALkggAw= +github.com/ssvlabs/ssv v1.2.1-0.20250527135742-46517c804400 h1:ozh2bK3MVRSrK5N4nS5zd1LfCdGSdN9eLECtrH6UzR8= +github.com/ssvlabs/ssv v1.2.1-0.20250527135742-46517c804400/go.mod h1:wRnyLfbDrPEJeyZiGzgobXP5IqcFG6SPyrA7jOrpJ9Y= github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo8= github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= From 15278de937448598328d1034aeffbc479f880158 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 27 May 2025 19:27:59 +0400 Subject: [PATCH 29/34] networkconfig: delete hardcoded beacon configs (#2183) * beacon/goclient: get beacon config from beacon node * use beacon config obtained from beacon node * log config as JSON * networkconfig: CLI for custom SSV config generation * implement JSON marshaling and YAML marshaling/unmarshaling * remove TotalEthereumValidators * simplify marshaling/unmarshaling logic * fix markdown formatting * use yaml@v3 * add tests * simplify unmarshaling * delete a comment * use Stringer to log node * guard beacon config reads with mutex * add a timeout log * delete hardcoded beacon configs * Revert "delete hardcoded beacon configs" This reverts commit c2e2f8f0124c0c65a088a3957fdeda4008f85bf2. * networkconfig: make hardcoded values configurable * fix issues after merging * code review comments * fix issues after merging * delete outer metrics for genesisForClient * rewrite modulo calculation * code review comments * unexport supportedSSVConfigs * revert the modulo calculation * add EpochDuration mock * G115 * fill missing fields in configs * add a comment about eth spec * fix error text * use genesis validators root from config in computeVoluntaryExitDomain * beacon,networkconfig: move forks from beacon to networkconfig * get rid of using Genesis method * use ForkAtEpoch instead of DataVersion * generate mocks * fix linter * fix beacon tests * beacon: delete ForkAtEpoch * fix ekm tests * update go.mod * fix some TODOs * networkconfig: delete mainnet beacon config * networkconfig: delete rest of configs * replace TestRealNetwork with TestNetwork * fix linter * fix a typo * remove redundant comments * remove Spec method * delete a comment * uncomment config print * fix a context bug * fix issues after merging * delete TestRealNetwork * pass network config name * update go.mod * fix issues after merging * fix issues after merging --- beacon/goclient/genesis_test.go | 6 +- beacon/goclient/signing_test.go | 2 +- beacon/goclient/spec_test.go | 2 +- cli/flags/export_keys_from_mnemonic.go | 2 +- cli/generate_config.go | 2 +- exporter/api/query_handlers_test.go | 3 +- network/discovery/service_test.go | 4 +- networkconfig/holesky-e2e.go | 18 +++-- networkconfig/holesky-stage.go | 28 ++++---- networkconfig/holesky.go | 79 +++----------------- networkconfig/hoodi-stage.go | 24 +++---- networkconfig/hoodi.go | 79 +++----------------- networkconfig/local-testnet.go | 71 +++--------------- networkconfig/mainnet.go | 91 +++++------------------- networkconfig/sepolia.go | 77 +++----------------- networkconfig/ssv.go | 16 ++--- networkconfig/test-network.go | 2 + protocol/v2/types/ssvshare_test.go | 2 +- ssvsigner/ekm/remote_key_manager_test.go | 2 +- 19 files changed, 113 insertions(+), 397 deletions(-) diff --git a/beacon/goclient/genesis_test.go b/beacon/goclient/genesis_test.go index 4bf27fefb9..b1f009c0c7 100644 --- a/beacon/goclient/genesis_test.go +++ b/beacon/goclient/genesis_test.go @@ -71,7 +71,7 @@ func Test_genesisForClient(t *testing.T) { ctx, logger, Options{ - BeaconConfig: networkconfig.Mainnet.BeaconConfig, + BeaconConfig: networkconfig.TestNetwork.BeaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, @@ -100,7 +100,7 @@ func Test_genesisForClient(t *testing.T) { ctx, logger, Options{ - BeaconConfig: networkconfig.Mainnet.BeaconConfig, + BeaconConfig: networkconfig.TestNetwork.BeaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, @@ -124,7 +124,7 @@ func Test_genesisForClient(t *testing.T) { ctx, logger, Options{ - BeaconConfig: networkconfig.Mainnet.BeaconConfig, + BeaconConfig: networkconfig.TestNetwork.BeaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, diff --git a/beacon/goclient/signing_test.go b/beacon/goclient/signing_test.go index dce8a8751b..dc406fef8b 100644 --- a/beacon/goclient/signing_test.go +++ b/beacon/goclient/signing_test.go @@ -25,7 +25,7 @@ func Test_computeVoluntaryExitDomain(t *testing.T) { ctx, zap.NewNop(), Options{ - BeaconConfig: networkconfig.Mainnet.BeaconConfig, + BeaconConfig: networkconfig.TestNetwork.BeaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, diff --git a/beacon/goclient/spec_test.go b/beacon/goclient/spec_test.go index 3d3a076057..0c99cea966 100644 --- a/beacon/goclient/spec_test.go +++ b/beacon/goclient/spec_test.go @@ -22,7 +22,7 @@ func Test_specForClient(t *testing.T) { ctx, zap.NewNop(), Options{ - BeaconConfig: networkconfig.Mainnet.BeaconConfig, + BeaconConfig: networkconfig.TestNetwork.BeaconConfig, BeaconNodeAddr: mockServer.URL, CommonTimeout: 100 * time.Millisecond, LongTimeout: 500 * time.Millisecond, diff --git a/cli/flags/export_keys_from_mnemonic.go b/cli/flags/export_keys_from_mnemonic.go index 8219d925b3..b2ef32c3f9 100644 --- a/cli/flags/export_keys_from_mnemonic.go +++ b/cli/flags/export_keys_from_mnemonic.go @@ -36,7 +36,7 @@ func GetKeyIndexFlagValue(c *cobra.Command) (uint64, error) { // AddNetworkFlag adds the network key flag to the command func AddNetworkFlag(c *cobra.Command) { - cliflag.AddPersistentStringFlag(c, networkFlag, networkconfig.Mainnet.GetBeaconName(), "network", false) + cliflag.AddPersistentStringFlag(c, networkFlag, networkconfig.MainnetName, "network", false) } // GetNetworkFlag gets the network key flag from the command diff --git a/cli/generate_config.go b/cli/generate_config.go index 41de6e6d58..32fb2a9ab7 100644 --- a/cli/generate_config.go +++ b/cli/generate_config.go @@ -26,7 +26,7 @@ const ( ) var ( - defaultNetwork = networkconfig.LocalTestnet + defaultNetwork = networkconfig.LocalTestnetSSV ) var ( diff --git a/exporter/api/query_handlers_test.go b/exporter/api/query_handlers_test.go index e86cd246fd..2f67164ef2 100644 --- a/exporter/api/query_handlers_test.go +++ b/exporter/api/query_handlers_test.go @@ -105,8 +105,7 @@ func TestHandleDecidedQuery(t *testing.T) { for _, role := range roles { pk := sks[1].GetPublicKey() - ssvConfig, err := networkconfig.GetSSVConfigByName(networkconfig.HoleskyStage.Name) - require.NoError(t, err) + ssvConfig := networkconfig.TestNetwork.SSVConfig decided250Seq, err := protocoltesting.CreateMultipleStoredInstances(rsaKeys, specqbft.Height(0), specqbft.Height(250), func(height specqbft.Height) ([]spectypes.OperatorID, *specqbft.Message) { return oids, &specqbft.Message{ MsgType: specqbft.CommitMsgType, diff --git a/network/discovery/service_test.go b/network/discovery/service_test.go index c980f3f3ea..4249e342bb 100644 --- a/network/discovery/service_test.go +++ b/network/discovery/service_test.go @@ -158,12 +158,12 @@ func TestDiscV5Service_PublishENR(t *testing.T) { checkLocalNodeDomainTypeAlignment(t, localNode, testNetConfig) // Change network config - dvs.ssvConfig = networkconfig.HoleskyStage.SSVConfig + dvs.ssvConfig = networkconfig.TestNetwork.SSVConfig // Test PublishENR method dvs.PublishENR() // Check LocalNode has been updated - checkLocalNodeDomainTypeAlignment(t, localNode, networkconfig.HoleskyStage) + checkLocalNodeDomainTypeAlignment(t, localNode, networkconfig.TestNetwork) } func TestDiscV5Service_Bootstrap(t *testing.T) { diff --git a/networkconfig/holesky-e2e.go b/networkconfig/holesky-e2e.go index efa627fe98..32efa10ce7 100644 --- a/networkconfig/holesky-e2e.go +++ b/networkconfig/holesky-e2e.go @@ -7,14 +7,12 @@ import ( spectypes "github.com/ssvlabs/ssv-spec/types" ) -var HoleskyE2E = NetworkConfig{ - Name: "holesky-e2e", - BeaconConfig: Holesky.BeaconConfig, - SSVConfig: SSVConfig{ - DomainType: spectypes.DomainType{0x0, 0x0, 0xee, 0x1}, - RegistryContractAddr: ethcommon.HexToAddress("0x58410bef803ecd7e63b23664c586a6db72daf59c"), - RegistrySyncOffset: big.NewInt(405579), - Bootnodes: []string{}, - TotalEthereumValidators: Holesky.TotalEthereumValidators, - }, +const HoleskyE2EName = "holesky-e2e" + +var HoleskyE2ESSV = SSVConfig{ + DomainType: spectypes.DomainType{0x0, 0x0, 0xee, 0x1}, + RegistryContractAddr: ethcommon.HexToAddress("0x58410bef803ecd7e63b23664c586a6db72daf59c"), + RegistrySyncOffset: big.NewInt(405579), + Bootnodes: []string{}, + TotalEthereumValidators: HoleskySSV.TotalEthereumValidators, } diff --git a/networkconfig/holesky-stage.go b/networkconfig/holesky-stage.go index 219aef756a..e15185afee 100644 --- a/networkconfig/holesky-stage.go +++ b/networkconfig/holesky-stage.go @@ -6,21 +6,19 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ) -var HoleskyStage = NetworkConfig{ - Name: "holesky-stage", - BeaconConfig: Holesky.BeaconConfig, - SSVConfig: SSVConfig{ - DomainType: [4]byte{0x00, 0x00, 0x31, 0x13}, - RegistrySyncOffset: new(big.Int).SetInt64(84599), - RegistryContractAddr: ethcommon.HexToAddress("0x0d33801785340072C452b994496B19f196b7eE15"), - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // Public bootnode: - // "enr:-Ja4QDYHVgUs9NvlMqq93ot6VNqbmrIlMrwKnq4X3DPRgyUNB4ospDp8ubMvsf-KsgqY8rzpZKy4GbE1DLphabpRBc-GAY_diLjngmlkgnY0gmlwhDQrLYqJc2VjcDI1NmsxoQKnAiuSlgSR8asjCH0aYoVKM8uPbi4noFuFHZHaAHqknYNzc3YBg3RjcIITiYN1ZHCCD6E", +const HoleskyStageName = "holesky-stage" - // Private bootnode: - "enr:-Ja4QDRUBjWOvVfGxpxvv3FqaCy3psm7IsKu5ETb1GXiexGYDFppD33t7AHRfmQddoAkBiyb7pt4t7ZN0sNB9CsW4I-GAZGOmChMgmlkgnY0gmlwhAorXxuJc2VjcDI1NmsxoQP_bBE-ZYvaXKBR3dRYMN5K_lZP-q-YsBzDZEtxH_4T_YNzc3YBg3RjcIITioN1ZHCCD6I", - }, - TotalEthereumValidators: Holesky.TotalEthereumValidators, +var HoleskyStageSSV = SSVConfig{ + DomainType: [4]byte{0x00, 0x00, 0x31, 0x13}, + RegistrySyncOffset: new(big.Int).SetInt64(84599), + RegistryContractAddr: ethcommon.HexToAddress("0x0d33801785340072C452b994496B19f196b7eE15"), + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // Public bootnode: + // "enr:-Ja4QDYHVgUs9NvlMqq93ot6VNqbmrIlMrwKnq4X3DPRgyUNB4ospDp8ubMvsf-KsgqY8rzpZKy4GbE1DLphabpRBc-GAY_diLjngmlkgnY0gmlwhDQrLYqJc2VjcDI1NmsxoQKnAiuSlgSR8asjCH0aYoVKM8uPbi4noFuFHZHaAHqknYNzc3YBg3RjcIITiYN1ZHCCD6E", + + // Private bootnode: + "enr:-Ja4QDRUBjWOvVfGxpxvv3FqaCy3psm7IsKu5ETb1GXiexGYDFppD33t7AHRfmQddoAkBiyb7pt4t7ZN0sNB9CsW4I-GAZGOmChMgmlkgnY0gmlwhAorXxuJc2VjcDI1NmsxoQP_bBE-ZYvaXKBR3dRYMN5K_lZP-q-YsBzDZEtxH_4T_YNzc3YBg3RjcIITioN1ZHCCD6I", }, + TotalEthereumValidators: HoleskySSV.TotalEthereumValidators, } diff --git a/networkconfig/holesky.go b/networkconfig/holesky.go index 5768389e9b..5cabf6562a 100644 --- a/networkconfig/holesky.go +++ b/networkconfig/holesky.go @@ -2,78 +2,21 @@ package networkconfig import ( "math/big" - "time" - "github.com/attestantio/go-eth2-client/spec" - "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" spectypes "github.com/ssvlabs/ssv-spec/types" ) -var Holesky = NetworkConfig{ - Name: "holesky", - BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.HoleskyNetwork), - SlotDuration: spectypes.HoleskyNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.HoleskyNetwork.SlotsPerEpoch(), - EpochsPerSyncCommitteePeriod: 256, - SyncCommitteeSize: 512, - SyncCommitteeSubnetCount: 4, - TargetAggregatorsPerSyncSubcommittee: 16, - TargetAggregatorsPerCommittee: 16, - IntervalsPerSlot: 3, - GenesisForkVersion: spectypes.HoleskyNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.HoleskyNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 - GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1")), - Forks: map[spec.DataVersion]phase0.Fork{ - // Phase0 - spec.DataVersionPhase0: { - Epoch: phase0.Epoch(0), - PreviousVersion: phase0.Version{0x00, 0x01, 0x70, 0x00}, // GENESIS_FORK_VERSION: 0x01017000 - CurrentVersion: phase0.Version{0x00, 0x01, 0x70, 0x00}, - }, - // Altair @ epoch 0 - spec.DataVersionAltair: { - Epoch: phase0.Epoch(0), - PreviousVersion: phase0.Version{0x00, 0x01, 0x70, 0x00}, - CurrentVersion: phase0.Version{0x02, 0x01, 0x70, 0x00}, // ALTAIR_FORK_VERSION: 0x02017000 - }, - // Bellatrix @ epoch 0 - spec.DataVersionBellatrix: { - Epoch: phase0.Epoch(0), - PreviousVersion: phase0.Version{0x02, 0x01, 0x70, 0x00}, - CurrentVersion: phase0.Version{0x03, 0x01, 0x70, 0x00}, // BELLATRIX_FORK_VERSION: 0x03017000 - }, - // Capella @ epoch 256 - spec.DataVersionCapella: { - Epoch: phase0.Epoch(256), - PreviousVersion: phase0.Version{0x03, 0x01, 0x70, 0x00}, - CurrentVersion: phase0.Version{0x04, 0x01, 0x70, 0x00}, // CAPELLA_FORK_VERSION: 0x04017000 - }, - // Deneb @ epoch 29 696 - spec.DataVersionDeneb: { - Epoch: phase0.Epoch(29696), - PreviousVersion: phase0.Version{0x04, 0x01, 0x70, 0x00}, - CurrentVersion: phase0.Version{0x05, 0x01, 0x70, 0x00}, // DENEB_FORK_VERSION: 0x05017000 - }, - // Electra @ epoch 115 968 - spec.DataVersionElectra: { - Epoch: phase0.Epoch(115968), - PreviousVersion: phase0.Version{0x05, 0x01, 0x70, 0x00}, - CurrentVersion: phase0.Version{0x06, 0x01, 0x70, 0x00}, // ELECTRA_FORK_VERSION: 0x06017000 - }, - }, - }, - SSVConfig: SSVConfig{ - DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x2}, - RegistrySyncOffset: new(big.Int).SetInt64(181612), - RegistryContractAddr: ethcommon.HexToAddress("0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA"), - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // SSV Labs - "enr:-Ja4QKFD3u5tZob7xukp-JKX9QJMFqqI68cItsE4tBbhsOyDR0M_1UUjb35hbrqvTP3bnXO_LnKh-jNLTeaUqN4xiduGAZKaP_sagmlkgnY0gmlwhDb0fh6Jc2VjcDI1NmsxoQMw_H2anuiqP9NmEaZwbUfdvPFog7PvcKmoVByDa576SINzc3YBg3RjcIITioN1ZHCCD6I", - }, - TotalEthereumValidators: 1757795, // active_validators from https://holesky.beaconcha.in/index/data on Nov 20, 2024 +const HoleskyName = "holesky" + +var HoleskySSV = SSVConfig{ + DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x2}, + RegistrySyncOffset: new(big.Int).SetInt64(181612), + RegistryContractAddr: ethcommon.HexToAddress("0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA"), + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // SSV Labs + "enr:-Ja4QKFD3u5tZob7xukp-JKX9QJMFqqI68cItsE4tBbhsOyDR0M_1UUjb35hbrqvTP3bnXO_LnKh-jNLTeaUqN4xiduGAZKaP_sagmlkgnY0gmlwhDb0fh6Jc2VjcDI1NmsxoQMw_H2anuiqP9NmEaZwbUfdvPFog7PvcKmoVByDa576SINzc3YBg3RjcIITioN1ZHCCD6I", }, + TotalEthereumValidators: 1757795, // active_validators from https://holesky.beaconcha.in/index/data on Nov 20, 2024 } diff --git a/networkconfig/hoodi-stage.go b/networkconfig/hoodi-stage.go index 36ee870d92..b78942dc05 100644 --- a/networkconfig/hoodi-stage.go +++ b/networkconfig/hoodi-stage.go @@ -6,18 +6,16 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ) -var HoodiStage = NetworkConfig{ - Name: "hoodi-stage", - BeaconConfig: Hoodi.BeaconConfig, - SSVConfig: SSVConfig{ - DomainType: [4]byte{0x00, 0x00, 0x31, 0x14}, - RegistrySyncOffset: new(big.Int).SetInt64(1004), - RegistryContractAddr: ethcommon.HexToAddress("0x0aaace4e8affc47c6834171c88d342a4abd8f105"), - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // SSV Labs - "enr:-Ja4QJZcaYfS0GpX-5xREVBa26a-E-QHMFek-EndsJdgM6loIM7pfbJwPDCNK1VzPkUhMjwcTTuNASiHU6X-sjsrxFmGAZWjNu06gmlkgnY0gmlwhErcGnyJc2VjcDI1NmsxoQP_bBE-ZYvaXKBR3dRYMN5K_lZP-q-YsBzDZEtxH_4T_YNzc3YBg3RjcIITioN1ZHCCD6I", - }, - TotalEthereumValidators: Hoodi.TotalEthereumValidators, +const HoodiStageName = "hoodi-stage" + +var HoodiStageSSV = SSVConfig{ + DomainType: [4]byte{0x00, 0x00, 0x31, 0x14}, + RegistrySyncOffset: new(big.Int).SetInt64(1004), + RegistryContractAddr: ethcommon.HexToAddress("0x0aaace4e8affc47c6834171c88d342a4abd8f105"), + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // SSV Labs + "enr:-Ja4QJZcaYfS0GpX-5xREVBa26a-E-QHMFek-EndsJdgM6loIM7pfbJwPDCNK1VzPkUhMjwcTTuNASiHU6X-sjsrxFmGAZWjNu06gmlkgnY0gmlwhErcGnyJc2VjcDI1NmsxoQP_bBE-ZYvaXKBR3dRYMN5K_lZP-q-YsBzDZEtxH_4T_YNzc3YBg3RjcIITioN1ZHCCD6I", }, + TotalEthereumValidators: HoodiSSV.TotalEthereumValidators, } diff --git a/networkconfig/hoodi.go b/networkconfig/hoodi.go index 562890c354..67a50e834c 100644 --- a/networkconfig/hoodi.go +++ b/networkconfig/hoodi.go @@ -2,78 +2,21 @@ package networkconfig import ( "math/big" - "time" - "github.com/attestantio/go-eth2-client/spec" - "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" spectypes "github.com/ssvlabs/ssv-spec/types" ) -var Hoodi = NetworkConfig{ - Name: "hoodi", - BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.HoodiNetwork), - SlotDuration: spectypes.HoodiNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.HoodiNetwork.SlotsPerEpoch(), - EpochsPerSyncCommitteePeriod: 256, - SyncCommitteeSize: 512, - SyncCommitteeSubnetCount: 4, - TargetAggregatorsPerSyncSubcommittee: 16, - TargetAggregatorsPerCommittee: 16, - IntervalsPerSlot: 3, - GenesisForkVersion: spectypes.HoodiNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.HoodiNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 - GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x212f13fc4df078b6cb7db228f1c8307566dcecf900867401a92023d7ba99cb5f")), - Forks: map[spec.DataVersion]phase0.Fork{ - // Phase0 (genesis) - spec.DataVersionPhase0: { - Epoch: phase0.Epoch(0), - PreviousVersion: phase0.Version{0x10, 0x00, 0x09, 0x10}, // GENESIS_FORK_VERSION - CurrentVersion: phase0.Version{0x10, 0x00, 0x09, 0x10}, - }, - // Altair @ epoch 0 - spec.DataVersionAltair: { - Epoch: phase0.Epoch(0), - PreviousVersion: phase0.Version{0x10, 0x00, 0x09, 0x10}, - CurrentVersion: phase0.Version{0x20, 0x00, 0x09, 0x10}, // ALTAIR_FORK_VERSION - }, - // Bellatrix (Merge) @ epoch 0 - spec.DataVersionBellatrix: { - Epoch: phase0.Epoch(0), - PreviousVersion: phase0.Version{0x20, 0x00, 0x09, 0x10}, - CurrentVersion: phase0.Version{0x30, 0x00, 0x09, 0x10}, // BELLATRIX_FORK_VERSION - }, - // Capella @ epoch 0 - spec.DataVersionCapella: { - Epoch: phase0.Epoch(0), - PreviousVersion: phase0.Version{0x30, 0x00, 0x09, 0x10}, - CurrentVersion: phase0.Version{0x40, 0x00, 0x09, 0x10}, // CAPELLA_FORK_VERSION - }, - // Deneb @ epoch 0 - spec.DataVersionDeneb: { - Epoch: phase0.Epoch(0), - PreviousVersion: phase0.Version{0x40, 0x00, 0x09, 0x10}, - CurrentVersion: phase0.Version{0x50, 0x00, 0x09, 0x10}, // DENEB_FORK_VERSION - }, - // Electra @ epoch 2048 - spec.DataVersionElectra: { - Epoch: phase0.Epoch(2048), - PreviousVersion: phase0.Version{0x50, 0x00, 0x09, 0x10}, - CurrentVersion: phase0.Version{0x60, 0x00, 0x09, 0x10}, // ELECTRA_FORK_VERSION - }, - }, - }, - SSVConfig: SSVConfig{ - DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x3}, - RegistrySyncOffset: new(big.Int).SetInt64(1065), - RegistryContractAddr: ethcommon.HexToAddress("0x58410Bef803ECd7E63B23664C586A6DB72DAf59c"), - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // SSV Labs - "enr:-Ja4QIKlyNFuFtTOnVoavqwmpgSJXfhSmhpdSDOUhf5-FBr7bBxQRvG6VrpUvlkr8MtpNNuMAkM33AseduSaOhd9IeWGAZWjRbnvgmlkgnY0gmlwhCNVVTCJc2VjcDI1NmsxoQNTTyiJPoZh502xOZpHSHAfR-94NaXLvi5J4CNHMh2tjoNzc3YBg3RjcIITioN1ZHCCD6I", - }, - TotalEthereumValidators: 1107955, // active_validators from https://hoodi.beaconcha.in/index/data on Apr 18, 2025 +const HoodiName = "hoodi" + +var HoodiSSV = SSVConfig{ + DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x3}, + RegistrySyncOffset: new(big.Int).SetInt64(1065), + RegistryContractAddr: ethcommon.HexToAddress("0x58410Bef803ECd7E63B23664C586A6DB72DAf59c"), + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // SSV Labs + "enr:-Ja4QIKlyNFuFtTOnVoavqwmpgSJXfhSmhpdSDOUhf5-FBr7bBxQRvG6VrpUvlkr8MtpNNuMAkM33AseduSaOhd9IeWGAZWjRbnvgmlkgnY0gmlwhCNVVTCJc2VjcDI1NmsxoQNTTyiJPoZh502xOZpHSHAfR-94NaXLvi5J4CNHMh2tjoNzc3YBg3RjcIITioN1ZHCCD6I", }, + TotalEthereumValidators: 1107955, // active_validators from https://hoodi.beaconcha.in/index/data on Apr 18, 2025 } diff --git a/networkconfig/local-testnet.go b/networkconfig/local-testnet.go index 600911f8f6..8372ca1c5c 100644 --- a/networkconfig/local-testnet.go +++ b/networkconfig/local-testnet.go @@ -2,71 +2,18 @@ package networkconfig import ( "math/big" - "time" - "github.com/attestantio/go-eth2-client/spec" - "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" spectypes "github.com/ssvlabs/ssv-spec/types" ) -var LocalTestnet = NetworkConfig{ - Name: "local-testnet", - BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.PraterNetwork), - SlotDuration: spectypes.PraterNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.PraterNetwork.SlotsPerEpoch(), - EpochsPerSyncCommitteePeriod: 256, - SyncCommitteeSize: 512, - SyncCommitteeSubnetCount: 4, - TargetAggregatorsPerSyncSubcommittee: 16, - TargetAggregatorsPerCommittee: 16, - IntervalsPerSlot: 3, - GenesisForkVersion: spectypes.PraterNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.PraterNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 - GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb")), - Forks: map[spec.DataVersion]phase0.Fork{ - spec.DataVersionPhase0: { - Epoch: phase0.Epoch(0), - PreviousVersion: phase0.Version{0, 0, 0, 0}, - CurrentVersion: phase0.Version{0, 0, 0, 0}, - }, - spec.DataVersionAltair: { - Epoch: phase0.Epoch(1), - PreviousVersion: phase0.Version{0, 0, 0, 0}, - CurrentVersion: phase0.Version{1, 0, 0, 0}, - }, - spec.DataVersionBellatrix: { - Epoch: phase0.Epoch(2), - PreviousVersion: phase0.Version{1, 0, 0, 0}, - CurrentVersion: phase0.Version{2, 0, 0, 0}, - }, - spec.DataVersionCapella: { - Epoch: phase0.Epoch(3), - PreviousVersion: phase0.Version{2, 0, 0, 0}, - CurrentVersion: phase0.Version{3, 0, 0, 0}, - }, - spec.DataVersionDeneb: { - Epoch: phase0.Epoch(4), - PreviousVersion: phase0.Version{3, 0, 0, 0}, - CurrentVersion: phase0.Version{4, 0, 0, 0}, - }, - spec.DataVersionElectra: { - Epoch: phase0.Epoch(5), - PreviousVersion: phase0.Version{4, 0, 0, 0}, - CurrentVersion: phase0.Version{5, 0, 0, 0}, - }, - }, - }, - SSVConfig: SSVConfig{ - DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoV2NetworkID.Byte(), 0x2}, - RegistrySyncOffset: new(big.Int).SetInt64(0), - RegistryContractAddr: ethcommon.HexToAddress("0xC3CD9A0aE89Fff83b71b58b6512D43F8a41f363D"), - Bootnodes: []string{ - "enr:-Li4QLR4Y1VbwiqFYKy6m-WFHRNDjhMDZ_qJwIABu2PY9BHjIYwCKpTvvkVmZhu43Q6zVA29sEUhtz10rQjDJkK3Hd-GAYiGrW2Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhCLdu_SJc2VjcDI1NmsxoQJTcI7GHPw-ZqIflPZYYDK_guurp_gsAFF5Erns3-PAvIN0Y3CCE4mDdWRwgg-h", - }, - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - TotalEthereumValidators: TestNetwork.TotalEthereumValidators, - }, +const LocalTestnetName = "local-testnet" + +var LocalTestnetSSV = SSVConfig{ + DomainType: spectypes.DomainType{0x0, 0x0, spectypes.JatoV2NetworkID.Byte(), 0x2}, + RegistrySyncOffset: new(big.Int).SetInt64(0), RegistryContractAddr: ethcommon.HexToAddress("0xC3CD9A0aE89Fff83b71b58b6512D43F8a41f363D"), + Bootnodes: []string{ + "enr:-Li4QLR4Y1VbwiqFYKy6m-WFHRNDjhMDZ_qJwIABu2PY9BHjIYwCKpTvvkVmZhu43Q6zVA29sEUhtz10rQjDJkK3Hd-GAYiGrW2Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhCLdu_SJc2VjcDI1NmsxoQJTcI7GHPw-ZqIflPZYYDK_guurp_gsAFF5Erns3-PAvIN0Y3CCE4mDdWRwgg-h", + }, DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + TotalEthereumValidators: TestNetwork.TotalEthereumValidators, } diff --git a/networkconfig/mainnet.go b/networkconfig/mainnet.go index 2e4dc7c581..c96426d8c4 100644 --- a/networkconfig/mainnet.go +++ b/networkconfig/mainnet.go @@ -2,87 +2,30 @@ package networkconfig import ( "math/big" - "time" - "github.com/attestantio/go-eth2-client/spec" - "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" spectypes "github.com/ssvlabs/ssv-spec/types" ) -var Mainnet = NetworkConfig{ - Name: "mainnet", - BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.MainNetwork), - SlotDuration: spectypes.MainNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.MainNetwork.SlotsPerEpoch(), - EpochsPerSyncCommitteePeriod: 256, - SyncCommitteeSize: 512, - SyncCommitteeSubnetCount: 4, - TargetAggregatorsPerSyncSubcommittee: 16, - TargetAggregatorsPerCommittee: 16, - IntervalsPerSlot: 3, - GenesisForkVersion: spectypes.MainNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.MainNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 - GenesisValidatorsRoot: phase0.Root(hexutil.MustDecode("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95")), - Forks: map[spec.DataVersion]phase0.Fork{ - // Phase0 (genesis) - spec.DataVersionPhase0: { - Epoch: phase0.Epoch(0), - PreviousVersion: phase0.Version{0x00, 0x00, 0x00, 0x00}, // GENESIS_FORK_VERSION - CurrentVersion: phase0.Version{0x00, 0x00, 0x00, 0x00}, - }, - // Altair @ epoch 74240 - spec.DataVersionAltair: { - Epoch: phase0.Epoch(74240), - PreviousVersion: phase0.Version{0x00, 0x00, 0x00, 0x00}, - CurrentVersion: phase0.Version{0x01, 0x00, 0x00, 0x00}, // ALTAIR_FORK_VERSION - }, - // Bellatrix (Merge) @ epoch 144896 - spec.DataVersionBellatrix: { - Epoch: phase0.Epoch(144896), - PreviousVersion: phase0.Version{0x01, 0x00, 0x00, 0x00}, - CurrentVersion: phase0.Version{0x02, 0x00, 0x00, 0x00}, // BELLATRIX_FORK_VERSION - }, - // Capella @ epoch 194048 - spec.DataVersionCapella: { - Epoch: phase0.Epoch(194048), - PreviousVersion: phase0.Version{0x02, 0x00, 0x00, 0x00}, - CurrentVersion: phase0.Version{0x03, 0x00, 0x00, 0x00}, // CAPELLA_FORK_VERSION - }, - // Deneb @ epoch 269568 - spec.DataVersionDeneb: { - Epoch: phase0.Epoch(269568), - PreviousVersion: phase0.Version{0x03, 0x00, 0x00, 0x00}, - CurrentVersion: phase0.Version{0x04, 0x00, 0x00, 0x00}, // DENEB_FORK_VERSION - }, - // Electra @ epoch 364032 - spec.DataVersionElectra: { - Epoch: phase0.Epoch(364032), - PreviousVersion: phase0.Version{0x04, 0x00, 0x00, 0x00}, - CurrentVersion: phase0.Version{0x05, 0x00, 0x00, 0x00}, // ELECTRA_FORK_VERSION - }, - }, - }, - SSVConfig: SSVConfig{ - DomainType: spectypes.AlanMainnet, - RegistrySyncOffset: new(big.Int).SetInt64(17507487), - RegistryContractAddr: ethcommon.HexToAddress("0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1"), - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // SSV Labs - "enr:-Ja4QAbDe5XANqJUDyJU1GmtS01qqMwDYx9JNZgymjBb55fMaha80E2HznRYoUGy6NFVSvs1u1cFqSM0MgJI-h1QKLeGAZKaTo7LgmlkgnY0gmlwhDQrfraJc2VjcDI1NmsxoQNEj0Pgq9-VxfeX83LPDOUPyWiTVzdI-DnfMdO1n468u4Nzc3YBg3RjcIITioN1ZHCCD6I", +const MainnetName = "mainnet" + +var MainnetSSV = SSVConfig{ + DomainType: spectypes.AlanMainnet, + RegistrySyncOffset: new(big.Int).SetInt64(17507487), + RegistryContractAddr: ethcommon.HexToAddress("0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1"), + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // SSV Labs + "enr:-Ja4QAbDe5XANqJUDyJU1GmtS01qqMwDYx9JNZgymjBb55fMaha80E2HznRYoUGy6NFVSvs1u1cFqSM0MgJI-h1QKLeGAZKaTo7LgmlkgnY0gmlwhDQrfraJc2VjcDI1NmsxoQNEj0Pgq9-VxfeX83LPDOUPyWiTVzdI-DnfMdO1n468u4Nzc3YBg3RjcIITioN1ZHCCD6I", - // 0NEinfra bootnode - "enr:-Li4QDwrOuhEq5gBJBzFUPkezoYiy56SXZUwkSD7bxYo8RAhPnHyS0de0nOQrzl-cL47RY9Jg8k6Y_MgaUd9a5baYXeGAYnfZE76h2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhDaTS0mJc2VjcDI1NmsxoQMZzUHaN3eClRgF9NAqRNc-ilGpJDDJxdenfo4j-zWKKYN0Y3CCE4iDdWRwgg-g", + // 0NEinfra bootnode + "enr:-Li4QDwrOuhEq5gBJBzFUPkezoYiy56SXZUwkSD7bxYo8RAhPnHyS0de0nOQrzl-cL47RY9Jg8k6Y_MgaUd9a5baYXeGAYnfZE76h2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhDaTS0mJc2VjcDI1NmsxoQMZzUHaN3eClRgF9NAqRNc-ilGpJDDJxdenfo4j-zWKKYN0Y3CCE4iDdWRwgg-g", - // Eridian (eridianalpha.com) - "enr:-Li4QIzHQ2H82twhvsu8EePZ6CA1gl0_B0WWsKaT07245TkHUqXay-MXEgObJB7BxMFl8TylFxfnKNxQyGTXh-2nAlOGAYuraxUEh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBKCzUSJc2VjcDI1NmsxoQNKskkQ6-mBdBWr_ORJfyHai5uD0vL6Fuw90X0sPwmRsoN0Y3CCE4iDdWRwgg-g", + // Eridian (eridianalpha.com) + "enr:-Li4QIzHQ2H82twhvsu8EePZ6CA1gl0_B0WWsKaT07245TkHUqXay-MXEgObJB7BxMFl8TylFxfnKNxQyGTXh-2nAlOGAYuraxUEh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBKCzUSJc2VjcDI1NmsxoQNKskkQ6-mBdBWr_ORJfyHai5uD0vL6Fuw90X0sPwmRsoN0Y3CCE4iDdWRwgg-g", - // CryptoManufaktur - "enr:-Li4QH7FwJcL8gJj0zHAITXqghMkG-A5bfWh2-3Q7vosy9D1BS8HZk-1ITuhK_rfzG3v_UtBDI6uNJZWpdcWfrQFCxKGAYnQ1DRCh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLb3g2Jc2VjcDI1NmsxoQKeSDcZWSaY9FC723E9yYX1Li18bswhLNlxBZdLfgOKp4N0Y3CCE4mDdWRwgg-h", - }, - TotalEthereumValidators: 1064860, // active_validators from https://mainnet.beaconcha.in/index/data on Apr 18, 2025 + // CryptoManufaktur + "enr:-Li4QH7FwJcL8gJj0zHAITXqghMkG-A5bfWh2-3Q7vosy9D1BS8HZk-1ITuhK_rfzG3v_UtBDI6uNJZWpdcWfrQFCxKGAYnQ1DRCh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLb3g2Jc2VjcDI1NmsxoQKeSDcZWSaY9FC723E9yYX1Li18bswhLNlxBZdLfgOKp4N0Y3CCE4mDdWRwgg-h", }, + TotalEthereumValidators: 1064860, // active_validators from https://mainnet.beaconcha.in/index/data on Apr 18, 2025 } diff --git a/networkconfig/sepolia.go b/networkconfig/sepolia.go index 43052457b8..8ec1899e81 100644 --- a/networkconfig/sepolia.go +++ b/networkconfig/sepolia.go @@ -2,76 +2,21 @@ package networkconfig import ( "math/big" - "time" - "github.com/attestantio/go-eth2-client/spec" - "github.com/attestantio/go-eth2-client/spec/phase0" ethcommon "github.com/ethereum/go-ethereum/common" spectypes "github.com/ssvlabs/ssv-spec/types" ) -var Sepolia = NetworkConfig{ - Name: "sepolia", - BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.SepoliaNetwork), - SlotDuration: spectypes.SepoliaNetwork.SlotDurationSec(), - SlotsPerEpoch: spectypes.SepoliaNetwork.SlotsPerEpoch(), - EpochsPerSyncCommitteePeriod: 256, - SyncCommitteeSize: 512, - SyncCommitteeSubnetCount: 4, - TargetAggregatorsPerSyncSubcommittee: 16, - TargetAggregatorsPerCommittee: 16, - IntervalsPerSlot: 3, - GenesisForkVersion: spectypes.SepoliaNetwork.ForkVersion(), - GenesisTime: time.Unix(int64(spectypes.SepoliaNetwork.MinGenesisTime()), 0), // #nosec G115 -- time should not exceed int64 - Forks: map[spec.DataVersion]phase0.Fork{ - // Phase0 (genesis) - spec.DataVersionPhase0: { - Epoch: phase0.Epoch(0), - PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x69}, // GENESIS_FORK_VERSION - CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x69}, - }, - // Altair @ epoch 50 - spec.DataVersionAltair: { - Epoch: phase0.Epoch(50), - PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x69}, - CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x70}, // ALTAIR_FORK_VERSION - }, - // Bellatrix (Merge) @ epoch 100 - spec.DataVersionBellatrix: { - Epoch: phase0.Epoch(100), - PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x70}, - CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x71}, // BELLATRIX_FORK_VERSION - }, - // Capella @ epoch 56832 - spec.DataVersionCapella: { - Epoch: phase0.Epoch(56832), - PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x71}, - CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x72}, // CAPELLA_FORK_VERSION - }, - // Deneb @ epoch 132608 - spec.DataVersionDeneb: { - Epoch: phase0.Epoch(132608), - PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x72}, - CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x73}, // DENEB_FORK_VERSION - }, - // Electra @ epoch 222464 - spec.DataVersionElectra: { - Epoch: phase0.Epoch(222464), - PreviousVersion: phase0.Version{0x90, 0x00, 0x00, 0x73}, - CurrentVersion: phase0.Version{0x90, 0x00, 0x00, 0x74}, // ELECTRA_FORK_VERSION - }, - }, - }, - SSVConfig: SSVConfig{ - DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x69}, - RegistrySyncOffset: new(big.Int).SetInt64(7795814), - RegistryContractAddr: ethcommon.HexToAddress("0x261419B48F36EdF420743E9f91bABF4856e76f99"), - DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, - Bootnodes: []string{ - // SSV Labs - "enr:-Ja4QIE0Ml0a8Pq9zD-0g9KYGN3jAMPJ0CAP0i16fK-PSHfLeORl-Z5p8odoP1oS5S2E8IsF5jNG7gqTKhjVsHR-Z_CGAZXrnTJrgmlkgnY0gmlwhCOjXGWJc2VjcDI1NmsxoQKCRDQsIdFsJDmu_ZU2H6b2_HRJbuUneDXHLfFkSQH9O4Nzc3YBg3RjcIITioN1ZHCCD6I", - }, - TotalEthereumValidators: 1781, // active_validators from https://sepolia.beaconcha.in/index/data on Mar 20, 2025 +const SepoliaName = "sepolia" + +var SepoliaSSV = SSVConfig{ + DomainType: spectypes.DomainType{0x0, 0x0, 0x5, 0x69}, + RegistrySyncOffset: new(big.Int).SetInt64(7795814), + RegistryContractAddr: ethcommon.HexToAddress("0x261419B48F36EdF420743E9f91bABF4856e76f99"), + DiscoveryProtocolID: [6]byte{'s', 's', 'v', 'd', 'v', '5'}, + Bootnodes: []string{ + // SSV Labs + "enr:-Ja4QIE0Ml0a8Pq9zD-0g9KYGN3jAMPJ0CAP0i16fK-PSHfLeORl-Z5p8odoP1oS5S2E8IsF5jNG7gqTKhjVsHR-Z_CGAZXrnTJrgmlkgnY0gmlwhCOjXGWJc2VjcDI1NmsxoQKCRDQsIdFsJDmu_ZU2H6b2_HRJbuUneDXHLfFkSQH9O4Nzc3YBg3RjcIITioN1ZHCCD6I", }, + TotalEthereumValidators: 1781, // active_validators from https://sepolia.beaconcha.in/index/data on Mar 20, 2025 } diff --git a/networkconfig/ssv.go b/networkconfig/ssv.go index 77f9db845b..5547c60587 100644 --- a/networkconfig/ssv.go +++ b/networkconfig/ssv.go @@ -13,14 +13,14 @@ import ( //go:generate go tool -modfile=../tool.mod mockgen -package=networkconfig -destination=./ssv_mock.go -source=./ssv.go var supportedSSVConfigs = map[string]SSVConfig{ - Mainnet.Name: Mainnet.SSVConfig, - Holesky.Name: Holesky.SSVConfig, - HoleskyStage.Name: HoleskyStage.SSVConfig, - LocalTestnet.Name: LocalTestnet.SSVConfig, - HoleskyE2E.Name: HoleskyE2E.SSVConfig, - Hoodi.Name: Hoodi.SSVConfig, - HoodiStage.Name: HoodiStage.SSVConfig, - Sepolia.Name: Sepolia.SSVConfig, + MainnetName: MainnetSSV, + HoleskyName: HoleskySSV, + HoleskyStageName: HoleskyStageSSV, + LocalTestnetName: LocalTestnetSSV, + HoleskyE2EName: HoleskyE2ESSV, + HoodiName: HoodiSSV, + HoodiStageName: HoodiStageSSV, + SepoliaName: SepoliaSSV, } func GetSSVConfigByName(name string) (SSVConfig, error) { diff --git a/networkconfig/test-network.go b/networkconfig/test-network.go index 6cfbfb975f..d4f9efe391 100644 --- a/networkconfig/test-network.go +++ b/networkconfig/test-network.go @@ -11,6 +11,8 @@ import ( spectypes "github.com/ssvlabs/ssv-spec/types" ) +// Not exporting any name as it's used for tests and not supposed to be passed in a config. + var TestNetwork = NetworkConfig{ Name: "testnet", BeaconConfig: BeaconConfig{ diff --git a/protocol/v2/types/ssvshare_test.go b/protocol/v2/types/ssvshare_test.go index 89b967e0cf..f3d4dc8979 100644 --- a/protocol/v2/types/ssvshare_test.go +++ b/protocol/v2/types/ssvshare_test.go @@ -209,7 +209,7 @@ func TestSSVShare_IsParticipating(t *testing.T) { for _, tc := range tt { t.Run(tc.Name, func(t *testing.T) { - result := tc.Share.IsParticipating(networkconfig.Mainnet, tc.Epoch) + result := tc.Share.IsParticipating(networkconfig.TestNetwork, tc.Epoch) require.Equal(t, tc.Expected, result) }) } diff --git a/ssvsigner/ekm/remote_key_manager_test.go b/ssvsigner/ekm/remote_key_manager_test.go index 5028712e6c..1b09bc4a36 100644 --- a/ssvsigner/ekm/remote_key_manager_test.go +++ b/ssvsigner/ekm/remote_key_manager_test.go @@ -29,7 +29,7 @@ import ( "github.com/ssvlabs/ssv/ssvsigner" ) -var testNetCfg = networkconfig.HoodiStage.BeaconConfig // using a real network config because https://github.com/ssvlabs/eth2-key-manager doesn't support min genesis time for networkconfig.TestNetwork +var testNetCfg = networkconfig.TestRealNetwork.BeaconConfig // using a real network config because https://github.com/ssvlabs/eth2-key-manager doesn't support min genesis time for networkconfig.TestNetwork type RemoteKeyManagerTestSuite struct { suite.Suite From 00af14dbca85e5bec08728c9c52c087828bf27c0 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 27 May 2025 13:05:14 -0300 Subject: [PATCH 30/34] rename BeaconName to NetworkName --- beacon/goclient/spec.go | 2 +- networkconfig/beacon.go | 12 ++++++------ networkconfig/beacon_mock.go | 28 ++++++++++++++-------------- networkconfig/network_mock.go | 28 ++++++++++++++-------------- networkconfig/test-network.go | 2 +- ssvsigner/ekm/local_key_manager.go | 2 +- ssvsigner/ekm/remote_key_manager.go | 4 ++-- ssvsigner/ekm/signer_storage.go | 4 ++-- utils/testutils.go | 2 +- 9 files changed, 42 insertions(+), 42 deletions(-) diff --git a/beacon/goclient/spec.go b/beacon/goclient/spec.go index 5637bab084..2de7b4464d 100644 --- a/beacon/goclient/spec.go +++ b/beacon/goclient/spec.go @@ -175,7 +175,7 @@ func (gc *GoClient) fetchBeaconConfig(ctx context.Context, client *eth2clienthtt } beaconConfig := networkconfig.BeaconConfig{ - BeaconName: networkName, + NetworkName: networkName, SlotDuration: slotDuration, SlotsPerEpoch: slotsPerEpoch, EpochsPerSyncCommitteePeriod: epochsPerSyncCommitteePeriod, diff --git a/networkconfig/beacon.go b/networkconfig/beacon.go index e902a41b1f..67eed08955 100644 --- a/networkconfig/beacon.go +++ b/networkconfig/beacon.go @@ -36,12 +36,12 @@ type Beacon interface { GetGenesisTime() time.Time GetSyncCommitteeSize() uint64 GetGenesisValidatorsRoot() phase0.Root - GetBeaconName() string + GetNetworkName() string ForkAtEpoch(epoch phase0.Epoch) (spec.DataVersion, *phase0.Fork) } type BeaconConfig struct { - BeaconName string + NetworkName string SlotDuration time.Duration SlotsPerEpoch uint64 EpochsPerSyncCommitteePeriod uint64 @@ -190,8 +190,8 @@ func (b BeaconConfig) GetGenesisValidatorsRoot() phase0.Root { return b.GenesisValidatorsRoot } -func (b BeaconConfig) GetBeaconName() string { - return b.BeaconName +func (b BeaconConfig) GetNetworkName() string { + return b.NetworkName } func (b BeaconConfig) ForkAtEpoch(epoch phase0.Epoch) (spec.DataVersion, *phase0.Fork) { @@ -222,8 +222,8 @@ func (b BeaconConfig) ForkAtEpoch(epoch phase0.Epoch) (spec.DataVersion, *phase0 } func (b BeaconConfig) AssertSame(other BeaconConfig) error { - if b.BeaconName != other.BeaconName { - return fmt.Errorf("different BeaconName") + if b.NetworkName != other.NetworkName { + return fmt.Errorf("different NetworkName") } if b.SlotDuration != other.SlotDuration { return fmt.Errorf("different SlotDuration") diff --git a/networkconfig/beacon_mock.go b/networkconfig/beacon_mock.go index 89f809c62b..8b829ba136 100644 --- a/networkconfig/beacon_mock.go +++ b/networkconfig/beacon_mock.go @@ -197,20 +197,6 @@ func (mr *MockBeaconMockRecorder) ForkAtEpoch(epoch any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForkAtEpoch", reflect.TypeOf((*MockBeacon)(nil).ForkAtEpoch), epoch) } -// GetBeaconName mocks base method. -func (m *MockBeacon) GetBeaconName() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBeaconName") - ret0, _ := ret[0].(string) - return ret0 -} - -// GetBeaconName indicates an expected call of GetBeaconName. -func (mr *MockBeaconMockRecorder) GetBeaconName() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBeaconName", reflect.TypeOf((*MockBeacon)(nil).GetBeaconName)) -} - // GetEpochFirstSlot mocks base method. func (m *MockBeacon) GetEpochFirstSlot(epoch phase0.Epoch) phase0.Slot { m.ctrl.T.Helper() @@ -267,6 +253,20 @@ func (mr *MockBeaconMockRecorder) GetGenesisValidatorsRoot() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGenesisValidatorsRoot", reflect.TypeOf((*MockBeacon)(nil).GetGenesisValidatorsRoot)) } +// GetNetworkName mocks base method. +func (m *MockBeacon) GetNetworkName() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetNetworkName") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetNetworkName indicates an expected call of GetNetworkName. +func (mr *MockBeaconMockRecorder) GetNetworkName() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNetworkName", reflect.TypeOf((*MockBeacon)(nil).GetNetworkName)) +} + // GetSlotDuration mocks base method. func (m *MockBeacon) GetSlotDuration() time.Duration { m.ctrl.T.Helper() diff --git a/networkconfig/network_mock.go b/networkconfig/network_mock.go index f6448d21e5..b311116b57 100644 --- a/networkconfig/network_mock.go +++ b/networkconfig/network_mock.go @@ -198,20 +198,6 @@ func (mr *MockNetworkMockRecorder) ForkAtEpoch(epoch any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForkAtEpoch", reflect.TypeOf((*MockNetwork)(nil).ForkAtEpoch), epoch) } -// GetBeaconName mocks base method. -func (m *MockNetwork) GetBeaconName() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetBeaconName") - ret0, _ := ret[0].(string) - return ret0 -} - -// GetBeaconName indicates an expected call of GetBeaconName. -func (mr *MockNetworkMockRecorder) GetBeaconName() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBeaconName", reflect.TypeOf((*MockNetwork)(nil).GetBeaconName)) -} - // GetDomainType mocks base method. func (m *MockNetwork) GetDomainType() types.DomainType { m.ctrl.T.Helper() @@ -282,6 +268,20 @@ func (mr *MockNetworkMockRecorder) GetGenesisValidatorsRoot() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGenesisValidatorsRoot", reflect.TypeOf((*MockNetwork)(nil).GetGenesisValidatorsRoot)) } +// GetNetworkName mocks base method. +func (m *MockNetwork) GetNetworkName() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetNetworkName") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetNetworkName indicates an expected call of GetNetworkName. +func (mr *MockNetworkMockRecorder) GetNetworkName() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNetworkName", reflect.TypeOf((*MockNetwork)(nil).GetNetworkName)) +} + // GetSlotDuration mocks base method. func (m *MockNetwork) GetSlotDuration() time.Duration { m.ctrl.T.Helper() diff --git a/networkconfig/test-network.go b/networkconfig/test-network.go index d4f9efe391..4cd6fc6e04 100644 --- a/networkconfig/test-network.go +++ b/networkconfig/test-network.go @@ -16,7 +16,7 @@ import ( var TestNetwork = NetworkConfig{ Name: "testnet", BeaconConfig: BeaconConfig{ - BeaconName: string(spectypes.BeaconTestNetwork), + NetworkName: string(spectypes.BeaconTestNetwork), SlotDuration: spectypes.BeaconTestNetwork.SlotDurationSec(), SlotsPerEpoch: spectypes.BeaconTestNetwork.SlotsPerEpoch(), EpochsPerSyncCommitteePeriod: 256, diff --git a/ssvsigner/ekm/local_key_manager.go b/ssvsigner/ekm/local_key_manager.go index f055cc3ca8..a87a5985a1 100644 --- a/ssvsigner/ekm/local_key_manager.go +++ b/ssvsigner/ekm/local_key_manager.go @@ -90,7 +90,7 @@ func NewLocalKeyManager( } } - beaconSigner := signer.NewSimpleSigner(wallet, protection, core.Network(beaconConfig.GetBeaconName())) + beaconSigner := signer.NewSimpleSigner(wallet, protection, core.Network(beaconConfig.GetNetworkName())) return &LocalKeyManager{ wallet: wallet, diff --git a/ssvsigner/ekm/remote_key_manager.go b/ssvsigner/ekm/remote_key_manager.go index cc2df5112e..f7f7c9d681 100644 --- a/ssvsigner/ekm/remote_key_manager.go +++ b/ssvsigner/ekm/remote_key_manager.go @@ -303,7 +303,7 @@ func (km *RemoteKeyManager) handleDomainAttester( return nil, errors.New("could not cast obj to AttestationData") } - network := core.Network(km.beaconConfig.GetBeaconName()) + network := core.Network(km.beaconConfig.GetNetworkName()) if !signer.IsValidFarFutureEpoch(network, data.Target.Epoch) { return nil, fmt.Errorf("target epoch too far into the future") } @@ -436,7 +436,7 @@ func (km *RemoteKeyManager) handleDomainProposer( blockSlot := ret.BlockHeader.Slot - network := core.Network(km.beaconConfig.GetBeaconName()) + network := core.Network(km.beaconConfig.GetNetworkName()) if !signer.IsValidFarFutureSlot(network, blockSlot) { return nil, fmt.Errorf("proposed block slot too far into the future") } diff --git a/ssvsigner/ekm/signer_storage.go b/ssvsigner/ekm/signer_storage.go index bbcb0e39c5..164be8736b 100644 --- a/ssvsigner/ekm/signer_storage.go +++ b/ssvsigner/ekm/signer_storage.go @@ -101,7 +101,7 @@ func (s *storage) DropRegistryData() error { } func (s *storage) objPrefix(obj string) []byte { - return []byte(s.beaconConfig.GetBeaconName() + obj) + return []byte(s.beaconConfig.GetNetworkName() + obj) } // Name returns storage name. @@ -111,7 +111,7 @@ func (s *storage) Name() string { // Network returns the network storage is related to. func (s *storage) Network() core.Network { - return core.Network(s.beaconConfig.GetBeaconName()) + return core.Network(s.beaconConfig.GetNetworkName()) } // SaveWallet stores the given wallet. diff --git a/utils/testutils.go b/utils/testutils.go index e5c5f79b00..6a0a065c9f 100644 --- a/utils/testutils.go +++ b/utils/testutils.go @@ -100,7 +100,7 @@ func SetupMockNetworkConfig(t *testing.T, domainType spectypes.DomainType, curre mockNetwork.EXPECT().GetDomainType().Return(domainType).AnyTimes() - mockNetwork.EXPECT().GetBeaconName().Return(string(beaconNetwork)).AnyTimes() + mockNetwork.EXPECT().GetNetworkName().Return(string(beaconNetwork)).AnyTimes() return mockNetwork } From 8fc6fde919080ce29f5009edca20284644338b44 Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 27 May 2025 13:30:31 -0300 Subject: [PATCH 31/34] refactor getting spec parameters --- beacon/goclient/spec.go | 152 +++++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 71 deletions(-) diff --git a/beacon/goclient/spec.go b/beacon/goclient/spec.go index 2de7b4464d..650cdb274c 100644 --- a/beacon/goclient/spec.go +++ b/beacon/goclient/spec.go @@ -72,94 +72,89 @@ func (gc *GoClient) fetchBeaconConfig(ctx context.Context, client *eth2clienthtt // types of most values are already cast: https://github.com/attestantio/go-eth2-client/blob/v0.21.7/http/spec.go#L78 - networkNameRaw, ok := specResponse["CONFIG_NAME"] - if !ok { - return networkconfig.BeaconConfig{}, fmt.Errorf("config name wasn't found in beacon node response") + networkName, err := get[string](specResponse, "CONFIG_NAME") + if err != nil { + return networkconfig.BeaconConfig{}, fmt.Errorf("get CONFIG_NAME: %w", err) } - networkName, ok := networkNameRaw.(string) - if !ok { - return networkconfig.BeaconConfig{}, fmt.Errorf("failed to decode config name") - } + slotDuration, err := get[time.Duration](specResponse, "SECONDS_PER_SLOT") + if err != nil { + gc.log.Warn("could not get extract parameter from beacon node response, using default value", + zap.Error(err), + zap.String("parameter", "SECONDS_PER_SLOT"), + zap.Any("default_value", DefaultSlotDuration)) - slotDuration := DefaultSlotDuration - if slotDurationRaw, ok := specResponse["SECONDS_PER_SLOT"]; ok { - if slotDurationDecoded, ok := slotDurationRaw.(time.Duration); ok { - slotDuration = slotDurationDecoded - } else { - gc.log.Warn("seconds per slot wasn't found in beacon node response, using default value", - zap.Any("value", slotDuration)) - } + slotDuration = DefaultSlotDuration } - slotsPerEpoch := DefaultSlotsPerEpoch - if slotsPerEpochRaw, ok := specResponse["SLOTS_PER_EPOCH"]; ok { - if slotsPerEpochDecoded, ok := slotsPerEpochRaw.(uint64); ok { - slotsPerEpoch = slotsPerEpochDecoded - } else { - gc.log.Warn("slots per epoch wasn't found in beacon node response, using default value", - zap.Uint64("value", slotsPerEpoch)) - } + slotsPerEpoch, err := get[uint64](specResponse, "SLOTS_PER_EPOCH") + if err != nil { + gc.log.Warn("could not get extract parameter from beacon node response, using default value", + zap.Error(err), + zap.String("parameter", "SLOTS_PER_EPOCH"), + zap.Any("default_value", DefaultSlotsPerEpoch)) + + slotsPerEpoch = DefaultSlotsPerEpoch } - epochsPerSyncCommitteePeriod := DefaultEpochsPerSyncCommitteePeriod - if epochsPerSyncCommitteePeriodRaw, ok := specResponse["EPOCHS_PER_SYNC_COMMITTEE_PERIOD"]; ok { - if epochsPerSyncCommitteePeriodDecoded, ok := epochsPerSyncCommitteePeriodRaw.(uint64); ok { - epochsPerSyncCommitteePeriod = epochsPerSyncCommitteePeriodDecoded - } else { - gc.log.Warn("epochs per sync committee wasn't found in beacon node response, using default value", - zap.Any("value", epochsPerSyncCommitteePeriod)) - } + epochsPerSyncCommitteePeriod, err := get[uint64](specResponse, "EPOCHS_PER_SYNC_COMMITTEE_PERIOD") + if err != nil { + gc.log.Warn("could not get extract parameter from beacon node response, using default value", + zap.Error(err), + zap.String("parameter", "EPOCHS_PER_SYNC_COMMITTEE_PERIOD"), + zap.Any("default_value", DefaultEpochsPerSyncCommitteePeriod)) + + epochsPerSyncCommitteePeriod = DefaultEpochsPerSyncCommitteePeriod } - syncCommitteeSize := DefaultSyncCommitteeSize - if syncCommitteeSizeRaw, ok := specResponse["SYNC_COMMITTEE_SIZE"]; ok { - if syncCommitteeSizeDecoded, ok := syncCommitteeSizeRaw.(uint64); ok { - syncCommitteeSize = syncCommitteeSizeDecoded - } else { - gc.log.Warn("sync committee size wasn't found in beacon node response, using default value", - zap.Any("value", syncCommitteeSize)) - } + syncCommitteeSize, err := get[uint64](specResponse, "SYNC_COMMITTEE_SIZE") + if err != nil { + gc.log.Warn("could not get extract parameter from beacon node response, using default value", + zap.Error(err), + zap.String("parameter", "SYNC_COMMITTEE_SIZE"), + zap.Any("default_value", DefaultSyncCommitteeSize)) + + syncCommitteeSize = DefaultSyncCommitteeSize } - targetAggregatorsPerCommittee := DefaultTargetAggregatorsPerCommittee - if targetAggregatorsPerCommitteeRaw, ok := specResponse["TARGET_AGGREGATORS_PER_COMMITTEE"]; ok { - if targetAggregatorsPerCommitteeDecoded, ok := targetAggregatorsPerCommitteeRaw.(uint64); ok { - targetAggregatorsPerCommittee = targetAggregatorsPerCommitteeDecoded - } else { - gc.log.Warn("target aggregators per committee wasn't found in beacon node response, using default value", - zap.Any("value", targetAggregatorsPerCommittee)) - } + targetAggregatorsPerCommittee, err := get[uint64](specResponse, "TARGET_AGGREGATORS_PER_COMMITTEE") + if err != nil { + gc.log.Warn("could not get extract parameter from beacon node response, using default value", + zap.Error(err), + zap.String("parameter", "TARGET_AGGREGATORS_PER_COMMITTEE"), + zap.Any("default_value", DefaultTargetAggregatorsPerCommittee)) + + targetAggregatorsPerCommittee = DefaultTargetAggregatorsPerCommittee } - targetAggregatorsPerSyncSubcommittee := DefaultTargetAggregatorsPerSyncSubcommittee - if targetAggregatorsPerSyncSubcommitteeRaw, ok := specResponse["TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE"]; ok { - if targetAggregatorsPerSyncSubcommitteeDecoded, ok := targetAggregatorsPerSyncSubcommitteeRaw.(uint64); ok { - targetAggregatorsPerSyncSubcommittee = targetAggregatorsPerSyncSubcommitteeDecoded - } else { - gc.log.Warn("target aggregators per sync subcommittee wasn't found in beacon node response, using default value", - zap.Any("value", targetAggregatorsPerSyncSubcommittee)) - } + targetAggregatorsPerSyncSubcommittee, err := get[uint64](specResponse, "TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE") + if err != nil { + gc.log.Warn("could not get extract parameter from beacon node response, using default value", + zap.Error(err), + zap.String("parameter", "TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE"), + zap.Any("default_value", DefaultTargetAggregatorsPerSyncSubcommittee)) + + targetAggregatorsPerSyncSubcommittee = DefaultTargetAggregatorsPerSyncSubcommittee } - intervalsPerSlot := DefaultIntervalsPerSlot - if intervalsPerSlotRaw, ok := specResponse["INTERVALS_PER_SLOT"]; ok { - if intervalsPerSlotDecoded, ok := intervalsPerSlotRaw.(uint64); ok { - intervalsPerSlot = intervalsPerSlotDecoded - } else { - gc.log.Warn("intervals per slot wasn't found in beacon node response, using default value", - zap.Any("value", intervalsPerSlot)) - } + intervalsPerSlot, err := get[uint64](specResponse, "INTERVALS_PER_SLOT") + if err != nil { + gc.log.Warn("could not get extract parameter from beacon node response, using default value", + zap.Error(err), + zap.String("parameter", "INTERVALS_PER_SLOT"), + zap.Any("default_value", DefaultIntervalsPerSlot)) + + intervalsPerSlot = DefaultIntervalsPerSlot } - syncCommitteeSubnetCount := DefaultSyncCommitteeSubnetCount - if syncCommitteeSubnetCountRaw, ok := specResponse["SYNC_COMMITTEE_SUBNET_COUNT"]; ok { - if syncCommitteeSubnetCountDecoded, ok := syncCommitteeSubnetCountRaw.(uint64); ok { - syncCommitteeSubnetCount = syncCommitteeSubnetCountDecoded - } else { - gc.log.Warn("sync committee subnet count wasn't found in beacon node response, using default value", - zap.Any("value", syncCommitteeSubnetCount)) - } + syncCommitteeSubnetCount, err := get[uint64](specResponse, "SYNC_COMMITTEE_SUBNET_COUNT") + if err != nil { + gc.log.Warn("could not get extract parameter from beacon node response, using default value", + zap.Error(err), + zap.String("parameter", "SYNC_COMMITTEE_SUBNET_COUNT"), + zap.Any("default_value", DefaultSyncCommitteeSubnetCount)) + + syncCommitteeSubnetCount = DefaultSyncCommitteeSubnetCount } forkData, err := gc.getForkData(specResponse) @@ -308,3 +303,18 @@ func (gc *GoClient) getForkData(specResponse map[string]any) (map[spec.DataVersi return forkEpochs, nil } + +func get[T any](response map[string]any, key string) (T, error) { + val, ok := response[key] + if !ok { + return val.(T), fmt.Errorf("missing key '%s' in response", key) + } + + var zero T + switch t := val.(type) { + case T: + return t, nil + default: + return zero, fmt.Errorf("key %s of type '%T' cannot be converted to '%T'", key, val, zero) + } +} From 4810da8ee78b5edbc992342d47153f188fb6296d Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 27 May 2025 13:31:39 -0300 Subject: [PATCH 32/34] update go.mod --- go.mod | 2 +- go.sum | 4 ++-- ssvsigner/go.mod | 2 +- ssvsigner/go.sum | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 4c8d66a908..6f33aebd1d 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/spf13/cobra v1.8.1 github.com/ssvlabs/eth2-key-manager v1.5.5 github.com/ssvlabs/ssv-spec v1.1.3 - github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527135742-46517c804400 + github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527163031-8fc6fde91908 github.com/status-im/keycard-go v0.2.0 github.com/stretchr/testify v1.9.0 github.com/wealdtech/go-eth2-types/v2 v2.8.1 diff --git a/go.sum b/go.sum index 7c4c41339a..67c629f4fc 100644 --- a/go.sum +++ b/go.sum @@ -756,8 +756,8 @@ github.com/ssvlabs/go-eth2-client v0.6.31-0.20250417062221-9cd9b891d4d6 h1:26sqP github.com/ssvlabs/go-eth2-client v0.6.31-0.20250417062221-9cd9b891d4d6/go.mod h1:fvULSL9WtNskkOB4i+Yyr6BKpNHXvmpGZj9969fCrfY= github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo8= github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527135742-46517c804400 h1:s0obHG5dvNM3HsXwbbHaj0j0e8mIMWMSPATpxCPey7k= -github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527135742-46517c804400/go.mod h1:SoeLhAtnyvAvhiHg0gQctkruAXAOPRh2sZzN4h8Jdic= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527163031-8fc6fde91908 h1:kL742CdbS76LbVCNuzOl+/nT8i8ow4yqfn0rDiw7V4c= +github.com/ssvlabs/ssv/ssvsigner v0.0.0-20250527163031-8fc6fde91908/go.mod h1:pGWwC0CvKjs7WEGLj83HAmdULrAp32B7QmL1Js+gMUY= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/ssvsigner/go.mod b/ssvsigner/go.mod index 04977e6ccd..62d57e2930 100644 --- a/ssvsigner/go.mod +++ b/ssvsigner/go.mod @@ -26,7 +26,7 @@ require ( github.com/microsoft/go-crypto-openssl v0.2.9 github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 github.com/ssvlabs/eth2-key-manager v1.5.5 - github.com/ssvlabs/ssv v1.2.1-0.20250527135742-46517c804400 + github.com/ssvlabs/ssv v1.2.1-0.20250527163031-8fc6fde91908 github.com/ssvlabs/ssv-spec v1.1.3 github.com/stretchr/testify v1.9.0 github.com/valyala/fasthttp v1.58.0 diff --git a/ssvsigner/go.sum b/ssvsigner/go.sum index 9a51a1f182..df0965e587 100644 --- a/ssvsigner/go.sum +++ b/ssvsigner/go.sum @@ -322,8 +322,8 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/ssvlabs/eth2-key-manager v1.5.5 h1:AzwNowGvcmVpRCVHq10FVnpkVIUpoDo5YbJWNMnYA8Q= github.com/ssvlabs/eth2-key-manager v1.5.5/go.mod h1:yeUzAP+SBJXgeXPiGBrLeLuHIQCpeJZV7Jz3Fwzm/zk= -github.com/ssvlabs/ssv v1.2.1-0.20250527135742-46517c804400 h1:ozh2bK3MVRSrK5N4nS5zd1LfCdGSdN9eLECtrH6UzR8= -github.com/ssvlabs/ssv v1.2.1-0.20250527135742-46517c804400/go.mod h1:wRnyLfbDrPEJeyZiGzgobXP5IqcFG6SPyrA7jOrpJ9Y= +github.com/ssvlabs/ssv v1.2.1-0.20250527163031-8fc6fde91908 h1:VJZGVaaxf73qbD2LacQK8AtDLzkh/ACgQjK0y9lKVEQ= +github.com/ssvlabs/ssv v1.2.1-0.20250527163031-8fc6fde91908/go.mod h1:DT9oD3vPPTRXNgSlpJZRkPw5Oq7JVO9P5m8IzbiBsGQ= github.com/ssvlabs/ssv-spec v1.1.3 h1:46K31kI4/vA7Vp3DaOuN7t2IABAmzeiMniCqYfzzpo8= github.com/ssvlabs/ssv-spec v1.1.3/go.mod h1:pto7dDv99uVfCZidiLrrKgFR6VYy6WY3PGI1TiGCsIU= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= From 2d09e23bdaed938ce58996d065c18a95e099487e Mon Sep 17 00:00:00 2001 From: Nikita Kryuchkov Date: Tue, 27 May 2025 16:56:48 -0300 Subject: [PATCH 33/34] fix type assertion --- beacon/goclient/spec.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/beacon/goclient/spec.go b/beacon/goclient/spec.go index 650cdb274c..5a5e09e0e6 100644 --- a/beacon/goclient/spec.go +++ b/beacon/goclient/spec.go @@ -305,12 +305,13 @@ func (gc *GoClient) getForkData(specResponse map[string]any) (map[spec.DataVersi } func get[T any](response map[string]any, key string) (T, error) { + var zero T + val, ok := response[key] if !ok { - return val.(T), fmt.Errorf("missing key '%s' in response", key) + return zero, fmt.Errorf("missing key '%s' in response", key) } - var zero T switch t := val.(type) { case T: return t, nil From 4d0175a8ed4c840e6f25b730ab8d859ca57eeff1 Mon Sep 17 00:00:00 2001 From: Matus Kysel Date: Wed, 28 May 2025 10:38:45 +0200 Subject: [PATCH 34/34] fix spec align --- scripts/spec-alignment/differ.config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/spec-alignment/differ.config.yaml b/scripts/spec-alignment/differ.config.yaml index 4ce7015ad9..d66e6a0faf 100644 --- a/scripts/spec-alignment/differ.config.yaml +++ b/scripts/spec-alignment/differ.config.yaml @@ -1,4 +1,4 @@ -ApprovedChanges: ["115ccce93a478b9a", "c8f122c9fb83793e", "220aede0f8fa5a4a", "fb9cab4ffb28869a", "3ca2431a8d79bc3a", "ca49cf46baf0a367", "50e5bb7eda99594e", "870a3a66aeccd737","4e22a08543b079b","56ceb03cd44ff702","188adfe8914e04c1","2438f9c5b82b69a3","1a716ee3bdb3170","90b166f78390af18","68219b82a1d9d829","c4c4caa5d0938b85","dfe99ce1d27b6cb1","35f5dab1f128d193","9a3973b64d7e8932","f33f07301a770d03","3e9e0dddfad3b302","d4fef6512374c1f5","b49f54cb45787e4b","59b2375130aef5df","f094cd0460432170","8e51881e527dd603","a7d6d58d9fa06379","1d124224ca4d0fe3","39ea06bfd1477d2d","7e2550bab51f22b2","87ebd29bd49fc52f","ef39dd5223e0d080","fe14e7f0503ea188","6146023d4d5708a2","aebb8e4348b6d667","973a2e6704dbf3","fb4cac598a68c592","257c7eb81d6eb245","2a8e94fe037e13fd","5e7eb878de54eec6","960a9c64cd4ec93c","57dfd255520bd849","ec333ff8a708db69","1cc1ff39ad91ee69","5714652b88e2d44f","7a53b3b037c56325","8c02ef1964464c30","19a268910a20da3d","af6e01ed565029f3","318b5169ac4dabb6","372c6b332e8ba699","c0d8a364c0db855a","4287381be4fb1841","b1614afc1da7794f","c214975412f3fd7","8bbf7eba3fa0cf7e","8e4ec8debe331b36","7a671d8fcefc3793","e2b0e9c6454c1c08","6707ecfefa5fec21","d5a7389d730464f1","8dfae3b3223d2de0","a81c092c985de728","968df5082c727ed6","9e53c73ee60b1cc2","9d265e99dd31d4f5","a34619e078d2e42f","17e8cec4f0625d53","e913f373aa88f333","cfc1e05c372d88dc","e5de6901d78b8833","57c1885b43dd8d19","e8a49856a5edd893","22ea21d10a2f861c","954e4fce01631c4e","108b9575f7c1d4bc","1f8d076449068f64","5a7ad98296703f6","159536003eeddac8","8ca8f82e67ddd3dd","16ebe47404323cc1","48bfe5cf1e578b47","dd83182b693a7216","308d21d9830f7047","6dde03147e012b1a","730c3e5e59393b7d","5b44a4b425ecc397","df5debc50ec8babc","92a41554b2910bb8","c36c680554dde59f","447feaa5cdc1a010","fda90c61f44cb149","cdbb4930eced584c","274336ec1127e6c0","2a496f5b3ad542d2","6b395912dde33b0e","cac56ec14994216b","8850900b5d9bcc65","15e7706486c6359e","cc22f28953b787ea","3bad6ae11596a574","8f84422a240d889c","5b265432dfbbaac7","43794bf5953db193","7975821460ebe1e7","173c505e12aabb8f","47ee0d148148a56f","8cc38593ebe049b6","bda3aec7157b095a","248712911696a851","f4d9c910f1dbaef7","1a2146fcad37acb8","b0b146f9bdab64b6","edfd442b4d725fbb","122f053573538a32","d720d714a20833e1", "f9c984e71b685f9b","8c6b4fee5a4c13ce","c0a8d2019a2c30d5", "717bef26105c733f","2f70630c27062353","2f70337ba7566a69","dd607a44e1341e6b","5210501625ac3de5","f786bf475b5085aa","18a66ed6e613d9c1","e8943e7741f6843d","276a489bd5a00032","ba3bba59f10bf6b","3c50ce0c8089d871","89ee72f6c610ab84","c92b95a85da2cb11","927ea6aed3f98f20","9338904026a0ce37","9683cfa19dc544a3","4d3fa2b8dfcb5f5b", "f19e9a2b295bcfb3", "b10199b2de6f03b8", "1afc17e358f9ca79","4b58762c0b433442","d293ec1bc61bb707","3e88c3b49d093605","4890ff80c88cc41d","5227ff3a225dd20d","81a60407a3a0ba80","db2ad807eb66254a","d308bd7c553ccdcf","bdaf172971637cbe","6ade9202843071fe","2fe8e14083997744","19c9a5362d1e1d3a","5956f803d239f178","92c55a4548a8b760","9a95524213bccfff","2f51a7338b86c229","e96966a281d74505","3ee479b9cbbc3a1d","82b392ba39c6c594","b9d2404e5c570019","24f528d85fb021f2","fe9609a785305d81","b0934079dcd986cc","a9c520a19b26049","d19a9403fd732d94","74a928f5dcb2fdd9","cbbfdb5e68cdac80","10e39d2ceda91f34","f99a004cf6697875","8fa5e8ebf7d223ec","6c80c145ba705243","fbabbc90d0b4178a","ab0c7f24e551ca6","af38a11cb8682c75","b110cba51df9f8d2","c4ff2ed3d20dc419","9295a5bb10efcec7","ab56ea44a75f898a","ff51ef26ab53ba58","df3771e2589008f9","106e5689655bcfc6","f90e0fb6883bff93","667656095cec39ee","9a5597af260c748a","9168b9cfb0cb98c8","875393173d59b0f2","a347ee50e92f7334","91073f39440ab37f","1bbcbe4e8194370d","2169fe3af9e88ab9","a85dccf18844fc79","2bf91d3c3920c5c8","f4ce01b385c68a2","4366899a2cb05197","6f0aecc3342b13c0","874b67f800dd74d6","587785bbbcdc2016","d7397265deb360a6","d9fabd130a8ecdfb","707b55fec1513c90","e51b0346b0d4b612","417e005d18c1f7d4","306964e5ede31618","8c7ca4bb2b8abe1e","b878d79c5774d12d","15599c2b2bd60293","a7891090c37daba1","4192f3dd9bdddea8","ba5b31e5a1adb8e2","dadf83703db9234","3fd72034ab5b908","e939b25394581c4","67d24278154582d6","bc6a77eea2a1ba4b","41fa2c6b8e3aed38","1b6e3c30093fcd6e","98377d7e6f0eea0a","267886c6b07733d7","280250b5f6148515","1b79a8c6288d49d8","47c23de3a5c71c7e","de0f0cd6b40ee150","e91f5b3d583f23af","2036a5ff6aed3717","5ed363e465b9c98b","3ed6b5d40fb4a3b0","e7219eac943d306f","186382b7e69faced","943be3ce709a99d3","3a8800d72c312f75","b9bf74de5674c15d","cb9ad84a103b6499","acdcac18a6e34419", "ee323f91ee6f543c","be9935e5c2bedaef","60ac8eb415e6c748","119e95426dc4affb","e918003e25abf4cd","44c0efaa4b189434","de6ef5f1aa07b38d","b71a695e14c7e892","c9b7984a5d2604b5","72e9cd10959558de","82f692ac2f5817f3","3e0d3d7ade790448","52595c2a99ba6031","ea6ad19cdc29b230","695cba9190654139","4418aa6010632480","e27b9c1ea1c64357","fe62097e8814c106","1cfd3a3660a62879","ddf404c2905d3b26","8ac6baea1b755066","2bc023c7e062f24b","8c43f241aeac6d75","832fc9a9a2b71d00","34e8b7999dfb14b5","ccc48c575f7ab4eb","9de0e5d104caf802","e46f98bfca35d4a0","db882c2be6efd7d4","6577bf381d78bae2","f66dbe09241b5a4","48884cab13bd3903","fd6796ea6d131c3","dfde38eed6f3305d","9b895440c1743c4e","783942f921da9985","e0c97cefd6558c77","75c75fa4503282","680487ae23f269a1","9b70726386e38170","ef7b63d9848dc185","3fe59bc388b9ef3","dd93140e21e6f919","143c7821cd65bcac","70d29c9e7a4ef797","b26376133e68b3db","31a354962a9bcfa0","50e62cbde34516ee","9273478f6feccd62","eddf20a67e3fddef","5a44c960cc4178dd","5499865be87b7e00","446545b04b35fba","8887c18020ddb307","3adda38e5fadcfb","9f105a95e82012a4","50cea598241b0bc9","6396e2866ef1b30","1c0da45940bfa76f","22b9026cb0221ce0","2011029b33aad319", "60f1d510640499ac","396137c9cb425893","7fd407d5e8c91bd4","a037c260bd97c7d2","d50f3cbac505793d","b841fc54d2df22d9","389037ae98d33f26", "f265acf7423fa9b1", "e710070bfb15d3ab","262a19d18869cedd","881fc8fbb6a4edb1","31bc6100f3d4db08","c7ce0261a1b6014f","1bd46741a98043b0","14dd874e7df81b37","3ddc92a39c324d69","f99137aa4377841c","5be5c4ce7d3212da","f2972b2906912d3a","c411b0f9f069c032","96631f77414215f5","3426003abbd5ebf0","e1d82f0619360a5","e07da5b414afe6a6","859884a25fccea80","8651bdc20c1946f3","6ccbcb02e457e66","98c46ae55d1d4e39","f9480b2e48319466","b3e7d9382b320d70","a20ea51df8b7d65b","9133b167cc5a601d","a748ad5c74850749","7f816e2f33da3186","1067c9a5622c3508","2314d7fa0b387cff","634abeefa604ee2","38faed802f80914b","bcb381e843ace421","5797f56a84b7ebef","b523eed171e5b6bf","601862214795ec47","11587bf00d05a4e2","78bcb24d3483e47a"] +ApprovedChanges: ["34e8b7999dfb14b5","56ceb03cd44ff702","ccc48c575f7ab4eb","262a19d18869cedd","e710070bfb15d3ab","1c0da45940bfa76f","881fc8fbb6a4edb1","31bc6100f3d4db08","c7ce0261a1b6014f","c4c4caa5d0938b85","60f1d510640499ac","91073f39440ab37f","d308bd7c553ccdcf","bdaf172971637cbe","396137c9cb425893","d4fef6512374c1f5","1bbcbe4e8194370d","59b2375130aef5df","1bd46741a98043b0","417e005d18c1f7d4","14dd874e7df81b37","50cea598241b0bc9","3ddc92a39c324d69","b0934079dcd986cc","e27b9c1ea1c64357","fe62097e8814c106","74a928f5dcb2fdd9","cbbfdb5e68cdac80","6577bf381d78bae2","39ea06bfd1477d2d","7e2550bab51f22b2","87ebd29bd49fc52f","ef39dd5223e0d080","aebb8e4348b6d667","6146023d4d5708a2","fe14e7f0503ea188","fb4cac598a68c592","257c7eb81d6eb245","62547d1b32ce44e3","5be5c4ce7d3212da","960a9c64cd4ec93c","df3771e2589008f9","c8f122c9fb83793e","2c6054db7088bcef","5714652b88e2d44f","7a53b3b037c56325","11587bf00d05a4e2","601862214795ec47","b523eed171e5b6bf","5797f56a84b7ebef","81a60407a3a0ba80","38faed802f80914b","bcb381e843ace421","1067c9a5622c3508","4b58762c0b433442","d293ec1bc61bb707","3e88c3b49d093605","4890ff80c88cc41d","9b70726386e38170","8bbf7eba3fa0cf7e","8cc38593ebe049b6","ef7b63d9848dc185","7f816e2f33da3186","2314d7fa0b387cff","267886c6b07733d7","f9480b2e48319466","98c46ae55d1d4e39","edfd442b4d725fbb","122f053573538a32","d720d714a20833e1","a81c092c985de728","143c7821cd65bcac","9e53c73ee60b1cc2","9d265e99dd31d4f5","70d29c9e7a4ef797","f2972b2906912d3a","c411b0f9f069c032","a037c260bd97c7d2","96631f77414215f5","389037ae98d33f26","b3e7d9382b320d70","3426003abbd5ebf0","22b9026cb0221ce0","e07da5b414afe6a6","50e62cbde34516ee","57c1885b43dd8d19","e8a49856a5edd893","9273478f6feccd62","1cfd3a3660a62879","859884a25fccea80","8651bdc20c1946f3","5a44c960cc4178dd","108b9575f7c1d4bc","5499865be87b7e00","159536003eeddac8","a20ea51df8b7d65b","9133b167cc5a601d","a748ad5c74850749","16ebe47404323cc1","48bfe5cf1e578b47","4366899a2cb05197","730c3e5e59393b7d","5b44a4b425ecc397","df5debc50ec8babc","92a41554b2910bb8","c36c680554dde59f","f265acf7423fa9b1","447feaa5cdc1a010","8ac6baea1b755066","2bc023c7e062f24b","274336ec1127e6c0","ddf404c2905d3b26","8c43f241aeac6d75","832fc9a9a2b71d00","8850900b5d9bcc65","cc22f28953b787ea","3bad6ae11596a574","8f84422a240d889c","82b392ba39c6c594","7975821460ebe1e7","173c505e12aabb8f","47ee0d148148a56f","6707ecfefa5fec21","d5a7389d730464f1","8e4ec8debe331b36","875393173d59b0f2","943be3ce709a99d3", "4e22a08543b079b", "f66dbe09241b5a4", "fd6796ea6d131c3", "634abeefa604ee2", "e939b25394581c4", "6ccbcb02e457e66", "e1d82f0619360a5", "5a7ad98296703f6", "f4ce01b385c68a2"] IgnoredIdentifiers: - logger