Skip to content

Commit

Permalink
Merge pull request #708 from rocket-pool/v1-update-metrics-exporter
Browse files Browse the repository at this point in the history
V1 Update Metrics Exporter and deprecate SnapshotDelegation
  • Loading branch information
0xfornax authored Dec 1, 2024
2 parents 9f32066 + 86a553b commit baa42e3
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 727 deletions.
107 changes: 89 additions & 18 deletions rocketpool/node/collectors/snapshot-collector.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package collectors

import (
"context"
"fmt"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/prometheus/client_golang/prometheus"
"github.com/rocket-pool/rocketpool-go/network"
"github.com/rocket-pool/rocketpool-go/rocketpool"
"github.com/rocket-pool/rocketpool-go/utils/eth"
"github.com/rocket-pool/smartnode/rocketpool/api/pdao"
"github.com/rocket-pool/smartnode/shared/services"
"github.com/rocket-pool/smartnode/shared/services/config"
"github.com/rocket-pool/smartnode/shared/services/proposals"
"golang.org/x/sync/errgroup"
)

Expand All @@ -35,14 +40,23 @@ type SnapshotCollector struct {
// The current delegate voting power on Snapshot
delegateVotingPower *prometheus.Desc

// The Rocket Pool Contract manager
rp *rocketpool.RocketPool

// The Rocket Pool config
cfg *config.RocketPoolConfig

// The Rocket Pool Execution Client manager
ec *services.ExecutionClientManager

// The Rocket Pool Beacon Client manager
bc *services.BeaconClientManager

// the node wallet address
nodeAddress common.Address

// the delegate address
delegateAddress common.Address
// the signalling address
signallingAddress common.Address

// Store values from the latest API call
cachedNodeVotingPower float64
Expand All @@ -60,7 +74,7 @@ type SnapshotCollector struct {
}

// Create a new SnapshotCollector instance
func NewSnapshotCollector(rp *rocketpool.RocketPool, cfg *config.RocketPoolConfig, nodeAddress common.Address, delegateAddress common.Address) *SnapshotCollector {
func NewSnapshotCollector(rp *rocketpool.RocketPool, cfg *config.RocketPoolConfig, ec *services.ExecutionClientManager, bc *services.BeaconClientManager, nodeAddress common.Address, signallingAddress common.Address) *SnapshotCollector {
subsystem := "snapshot"
return &SnapshotCollector{
activeProposals: prometheus.NewDesc(prometheus.BuildFQName(namespace, subsystem, "proposals_active"),
Expand All @@ -87,10 +101,13 @@ func NewSnapshotCollector(rp *rocketpool.RocketPool, cfg *config.RocketPoolConfi
"The delegate current voting power on Snapshot",
nil, nil,
),
cfg: cfg,
nodeAddress: nodeAddress,
delegateAddress: delegateAddress,
logPrefix: "Snapshot Collector",
rp: rp,
cfg: cfg,
ec: ec,
bc: bc,
nodeAddress: nodeAddress,
signallingAddress: signallingAddress,
logPrefix: "Snapshot Collector",
}
}

Expand All @@ -109,6 +126,11 @@ func (collector *SnapshotCollector) Collect(channel chan<- prometheus.Metric) {

// Sync
var wg errgroup.Group
var err error
var propMgr *proposals.ProposalManager
var blockNumber uint64
var onchainVotingDelegate common.Address
var isVotingInitialized bool
activeProposals := float64(0)
closedProposals := float64(0)
votesActiveProposals := float64(0)
Expand All @@ -118,7 +140,7 @@ func (collector *SnapshotCollector) Collect(channel chan<- prometheus.Metric) {
// Get the number of votes on Snapshot proposals
wg.Go(func() error {
if time.Since(collector.lastApiCallTimestamp).Hours() >= hoursToWait {
votedProposals, err := pdao.GetSnapshotVotedProposals(collector.cfg.Smartnode.GetSnapshotApiDomain(), collector.cfg.Smartnode.GetSnapshotID(), collector.nodeAddress, collector.delegateAddress)
votedProposals, err := pdao.GetSnapshotVotedProposals(collector.cfg.Smartnode.GetSnapshotApiDomain(), collector.cfg.Smartnode.GetSnapshotID(), collector.nodeAddress, collector.signallingAddress)
if err != nil {
return fmt.Errorf("Error getting Snapshot voted proposals: %w", err)
}
Expand Down Expand Up @@ -164,38 +186,77 @@ func (collector *SnapshotCollector) Collect(channel chan<- prometheus.Metric) {
return nil
})

// Get the node's voting power
// Get latest block number
wg.Go(func() error {
if time.Since(collector.lastApiCallTimestamp).Hours() >= hoursToWait {

votingPowerResponse, err := pdao.GetSnapshotVotingPower(collector.cfg.Smartnode.GetSnapshotApiDomain(), collector.cfg.Smartnode.GetSnapshotID(), collector.nodeAddress)
blockNumber, err = collector.ec.BlockNumber(context.Background())
if err != nil {
return fmt.Errorf("Error getting Snapshot voted proposals for node address: %w", err)
return fmt.Errorf("Error getting block number: %w", err)
}
}
return nil

})

collector.cachedNodeVotingPower = votingPowerResponse.Data.Vp.Vp
// Get the propMgr
wg.Go(func() error {
if time.Since(collector.lastApiCallTimestamp).Hours() >= hoursToWait {
propMgr, err = proposals.NewProposalManager(nil, collector.cfg, collector.rp, collector.bc)
if err != nil {
return fmt.Errorf("Error getting the prop manager: %w", err)
}
}
return nil
})

// Get the delegate's voting power
// Get the node onchain voting delegate
wg.Go(func() error {
if time.Since(collector.lastApiCallTimestamp).Hours() >= hoursToWait {
votingPowerResponse, err := pdao.GetSnapshotVotingPower(collector.cfg.Smartnode.GetSnapshotApiDomain(), collector.cfg.Smartnode.GetSnapshotID(), collector.delegateAddress)
onchainVotingDelegate, err = network.GetCurrentVotingDelegate(collector.rp, collector.nodeAddress, nil)
if err != nil {
return fmt.Errorf("Error getting Snapshot voted proposals for delegate address: %w", err)
return fmt.Errorf("Error getting the on-chain voting delegate: %w", err)
}
}
return err
})

collector.cachedDelegateVotingPower = votingPowerResponse.Data.Vp.Vp
// Get Voting Initialized status
wg.Go(func() error {
if time.Since(collector.lastApiCallTimestamp).Hours() >= hoursToWait {
isVotingInitialized, err = network.GetVotingInitialized(collector.rp, collector.nodeAddress, nil)
if err != nil {
return fmt.Errorf("Error checking if voting is initialized: %w", err)
}
}
return nil
return err
})

// Wait for data
if err := wg.Wait(); err != nil {
collector.logError(err)
return
}

// Check if sufficient time has passed and voting is initialized
if time.Since(collector.lastApiCallTimestamp).Hours() >= hoursToWait && isVotingInitialized {
// Get voting power for the node
nodeVotingPower, err := getVotingPower(propMgr, uint32(blockNumber), collector.nodeAddress)
if err != nil {
collector.logError(fmt.Errorf("error getting node voting power: %w", err))
collector.cachedNodeVotingPower = 0
} else {
collector.cachedNodeVotingPower = nodeVotingPower
}
// Get voting power for the delegate
delegateVotingPower, err := getVotingPower(propMgr, uint32(blockNumber), onchainVotingDelegate)
if err != nil {
collector.logError(fmt.Errorf("error getting delegate voting power: %w", err))
collector.cachedDelegateVotingPower = 0
} else {
collector.cachedDelegateVotingPower = delegateVotingPower
}
}

if time.Since(collector.lastApiCallTimestamp).Hours() >= hoursToWait {
collector.lastApiCallTimestamp = time.Now()
}
Expand All @@ -218,3 +279,13 @@ func (collector *SnapshotCollector) Collect(channel chan<- prometheus.Metric) {
func (collector *SnapshotCollector) logError(err error) {
fmt.Printf("[%s] %s\n", collector.logPrefix, err.Error())
}

func getVotingPower(propMgr *proposals.ProposalManager, blockNumber uint32, address common.Address) (float64, error) {
// Get the total voting power
totalDelegatedVP, _, _, err := propMgr.GetArtifactsForVoting(blockNumber, address)
if err != nil {
return 0, fmt.Errorf("error getting voting power: %w", err)
}

return eth.WeiToEth(totalDelegatedVP), nil
}
16 changes: 10 additions & 6 deletions rocketpool/node/metrics-exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"os"
"strings"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/rocket-pool/smartnode/rocketpool/node/collectors"
Expand Down Expand Up @@ -37,7 +39,7 @@ func runMetricsServer(c *cli.Context, logger log.ColorLogger, stateLocker *colle
if err != nil {
return err
}
s, err := services.GetSnapshotDelegation(c)
reg, err := services.GetRocketSignerRegistry(c)
if err != nil {
return err
}
Expand Down Expand Up @@ -80,14 +82,16 @@ func runMetricsServer(c *cli.Context, logger log.ColorLogger, stateLocker *colle
registry.MustRegister(smoothingPoolCollector)

// Set up snapshot checking if enabled
votingId := cfg.Smartnode.GetVotingSnapshotID()
if s != nil {
votingDelegate, err := s.Delegation(nil, nodeAccount.Address, votingId)
if cfg.Smartnode.GetRocketSignerRegistryAddress() != "" {
signallingAddress, err := reg.NodeToSigner(&bind.CallOpts{}, nodeAccount.Address)
if err != nil {
return fmt.Errorf("Error getting node delegate: %w", err)
logger.Printlnf("Error getting the signalling address: %w", err)
// Set signallingAddress to blank address instead of erroring out of the task loop.
signallingAddress = common.Address{}
}
snapshotCollector := collectors.NewSnapshotCollector(rp, cfg, nodeAccount.Address, votingDelegate)
snapshotCollector := collectors.NewSnapshotCollector(rp, cfg, ec, bc, nodeAccount.Address, signallingAddress)
registry.MustRegister(snapshotCollector)

}

// Start the HTTP server
Expand Down
13 changes: 0 additions & 13 deletions shared/services/config/smartnode-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,6 @@ type SmartnodeConfig struct {
// The contract address of the RPL token
rplTokenAddress map[config.Network]string `yaml:"-"`

// The contract address for Snapshot delegation
snapshotDelegationAddress map[config.Network]string `yaml:"-"`

// The Snapshot API domain
snapshotApiDomain map[config.Network]string `yaml:"-"`

Expand Down Expand Up @@ -569,12 +566,6 @@ func NewSmartnodeConfig(cfg *RocketPoolConfig) *SmartnodeConfig {
config.Network_Holesky: "0x9294Fc6F03c64Cc217f5BE8697EA3Ed2De77e2F8",
},

snapshotDelegationAddress: map[config.Network]string{
config.Network_Mainnet: "0x469788fE6E9E9681C6ebF3bF78e7Fd26Fc015446",
config.Network_Devnet: "",
config.Network_Holesky: "",
},

snapshotApiDomain: map[config.Network]string{
config.Network_Mainnet: "hub.snapshot.org",
config.Network_Devnet: "",
Expand Down Expand Up @@ -802,10 +793,6 @@ func (cfg *SmartnodeConfig) GetRplTokenAddress() string {
return cfg.rplTokenAddress[cfg.Network.Value.(config.Network)]
}

func (cfg *SmartnodeConfig) GetSnapshotDelegationAddress() string {
return cfg.snapshotDelegationAddress[cfg.Network.Value.(config.Network)]
}

func (cfg *SmartnodeConfig) GetSmartnodeContainerTag() string {
return smartnodeTag
}
Expand Down
Loading

0 comments on commit baa42e3

Please sign in to comment.