-
Notifications
You must be signed in to change notification settings - Fork 0
/
manager.go
155 lines (135 loc) · 5.21 KB
/
manager.go
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package state
import (
"context"
"fmt"
"math/big"
"time"
"github.com/Seb369888/poolsea-go/rocketpool"
"github.com/Seb369888/smartnode/shared/services/beacon"
"github.com/Seb369888/smartnode/shared/services/config"
cfgtypes "github.com/Seb369888/smartnode/shared/types/config"
"github.com/Seb369888/smartnode/shared/utils/log"
"github.com/ethereum/go-ethereum/common"
)
type NetworkStateManager struct {
cfg *config.RocketPoolConfig
rp *rocketpool.RocketPool
ec rocketpool.ExecutionClient
bc beacon.Client
log *log.ColorLogger
Config *config.RocketPoolConfig
Network cfgtypes.Network
ChainID uint
BeaconConfig beacon.Eth2Config
}
// Create a new manager for the network state
func NewNetworkStateManager(rp *rocketpool.RocketPool, cfg *config.RocketPoolConfig, ec rocketpool.ExecutionClient, bc beacon.Client, log *log.ColorLogger) (*NetworkStateManager, error) {
// Create the manager
m := &NetworkStateManager{
cfg: cfg,
rp: rp,
ec: ec,
bc: bc,
log: log,
Config: cfg,
Network: cfg.Smartnode.Network.Value.(cfgtypes.Network),
ChainID: cfg.Smartnode.GetChainID(),
}
// Get the Beacon config info
var err error
m.BeaconConfig, err = m.bc.GetEth2Config()
if err != nil {
return nil, err
}
return m, nil
}
// Get the state of the network using the latest Execution layer block
func (m *NetworkStateManager) GetHeadState() (*NetworkState, error) {
targetSlot, err := m.GetHeadSlot()
if err != nil {
return nil, fmt.Errorf("error getting latest Beacon slot: %w", err)
}
return m.getState(targetSlot)
}
// Get the state of the network for a single node using the latest Execution layer block, along with the total effective RPL stake for the network
func (m *NetworkStateManager) GetHeadStateForNode(nodeAddress common.Address, calculateTotalEffectiveStake bool) (*NetworkState, *big.Int, error) {
targetSlot, err := m.GetHeadSlot()
if err != nil {
return nil, nil, fmt.Errorf("error getting latest Beacon slot: %w", err)
}
return m.getStateForNode(nodeAddress, targetSlot, calculateTotalEffectiveStake)
}
// Get the state of the network at the provided Beacon slot
func (m *NetworkStateManager) GetStateForSlot(slotNumber uint64) (*NetworkState, error) {
return m.getState(slotNumber)
}
// Gets the latest valid block
func (m *NetworkStateManager) GetLatestBeaconBlock() (beacon.BeaconBlock, error) {
targetSlot, err := m.GetHeadSlot()
if err != nil {
return beacon.BeaconBlock{}, fmt.Errorf("error getting head slot: %w", err)
}
return m.getLatestProposedBeaconBlock(targetSlot)
}
// Gets the latest valid finalized block
func (m *NetworkStateManager) GetLatestFinalizedBeaconBlock() (beacon.BeaconBlock, error) {
head, err := m.bc.GetBeaconHead()
if err != nil {
return beacon.BeaconBlock{}, fmt.Errorf("error getting Beacon chain head: %w", err)
}
targetSlot := head.FinalizedEpoch*m.BeaconConfig.SlotsPerEpoch + (m.BeaconConfig.SlotsPerEpoch - 1)
return m.getLatestProposedBeaconBlock(targetSlot)
}
// Gets the Beacon slot for the latest execution layer block
func (m *NetworkStateManager) GetHeadSlot() (uint64, error) {
// Get the latest EL block
latestBlockHeader, err := m.ec.HeaderByNumber(context.Background(), nil)
if err != nil {
return 0, fmt.Errorf("error getting latest EL block: %w", err)
}
// Get the corresponding Beacon slot based on the timestamp
latestBlockTime := time.Unix(int64(latestBlockHeader.Time), 0)
genesisTime := time.Unix(int64(m.BeaconConfig.GenesisTime), 0)
secondsSinceGenesis := uint64(latestBlockTime.Sub(genesisTime).Seconds())
targetSlot := secondsSinceGenesis / m.BeaconConfig.SecondsPerSlot
return targetSlot, nil
}
// Gets the target Beacon block, or if it was missing, the first one under it that wasn't missing
func (m *NetworkStateManager) getLatestProposedBeaconBlock(targetSlot uint64) (beacon.BeaconBlock, error) {
for {
// Try to get the current block
block, exists, err := m.bc.GetBeaconBlock(fmt.Sprint(targetSlot))
if err != nil {
return beacon.BeaconBlock{}, fmt.Errorf("error getting Beacon block %d: %w", targetSlot, err)
}
// If the block was missing, try the previous one
if !exists {
m.logLine("Slot %d was missing, trying the previous one...", targetSlot)
targetSlot--
} else {
return block, nil
}
}
}
// Get the state of the network at the provided Beacon slot
func (m *NetworkStateManager) getState(slotNumber uint64) (*NetworkState, error) {
state, err := CreateNetworkState(m.cfg, m.rp, m.ec, m.bc, m.log, slotNumber, m.BeaconConfig)
if err != nil {
return nil, err
}
return state, nil
}
// Get the state of the network for a specific node only at the provided Beacon slot
func (m *NetworkStateManager) getStateForNode(nodeAddress common.Address, slotNumber uint64, calculateTotalEffectiveStake bool) (*NetworkState, *big.Int, error) {
state, totalEffectiveStake, err := CreateNetworkStateForNode(m.cfg, m.rp, m.ec, m.bc, m.log, slotNumber, m.BeaconConfig, nodeAddress, calculateTotalEffectiveStake)
if err != nil {
return nil, nil, err
}
return state, totalEffectiveStake, nil
}
// Logs a line if the logger is specified
func (m *NetworkStateManager) logLine(format string, v ...interface{}) {
if m.log != nil {
m.log.Printlnf(format, v)
}
}