Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Checkpoint calculations from deployed slot #195

Merged
merged 1 commit into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
log "github.com/sirupsen/logrus"
)

// How often onchain validators are reloaded: 600 slots is 2 hours
var UpdateValidatorsIntervalSlots = uint64(600)
// How often onchain validators are reloaded: 1200 slots is 4 hours
var UpdateValidatorsIntervalSlots = uint64(1200)

// logs file and path
const LogsName = "logs.txt"
Expand Down Expand Up @@ -283,9 +283,18 @@ func mainLoop(oracleInstance *oracle.Oracle, onchain *oracle.Onchain, cfg *oracl
oracleInstance.SetBeaconValidators(onchain.Validators())
}

// Every CheckPointSizeInSlots we commit the state given some conditions
if oracleInstance.State().LatestProcessedSlot%cfg.CheckPointSizeInSlots == 0 {
log.Info("Checkpoint reached, latest processed slot: ", oracleInstance.State().LatestProcessedSlot)
// Every CheckPointSizeInSlots we commit the state given some conditions, starting from
// when the contract was deployed.
isCheckpoint, err := oracleInstance.IsCheckpoint()
if err != nil {
log.Fatal("Could not check if we are at a checkpoint: ", err)
}
if isCheckpoint {
log.WithFields(log.Fields{
"LatestProcessedSlot": oracleInstance.State().LatestProcessedSlot,
"CheckPointSizeInSlots": cfg.CheckPointSizeInSlots,
"DeployedSlot": oracleInstance.State().DeployedSlot,
}).Info("Checkpoint reached")

// This wont work since we need an archival geth node to fetch balances at specific blocks that are not the last
// as it is it errors "missing trie node". Leaving here for reference
Expand Down Expand Up @@ -372,13 +381,20 @@ func mainLoop(oracleInstance *oracle.Oracle, onchain *oracle.Onchain, cfg *oracl
log.Fatal("Could not get onchain slot and root: ", err)
}

log.WithFields(log.Fields{
"OnchainRoot": onchainRoot,
"OnchainSlot": onchainSlot,
"OracleRoot": newState.MerkleRoot,
"OracleSlot": newState.Slot,
}).Info("Local vs onchain roots and slots")

// If the oracle has permission to update the contract root (!dryRun), we have enough data
// to construct a merkle tree.
if !cfg.DryRun && enoughData {
// If the new state is the one onchain + checkpoint size then its time to update the root
// Then we can update the new merkle root. onchainSlot == 0 is an special case when the
// contract was just initialized and there is no root yet.
if (newState.Slot == onchainSlot+cfg.CheckPointSizeInSlots) || onchainSlot == 0 {
if newState.Slot == onchainSlot+cfg.CheckPointSizeInSlots {
log.WithFields(log.Fields{
"Root": newState.MerkleRoot,
"Slot": newState.Slot,
Expand Down
24 changes: 24 additions & 0 deletions oracle/oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,30 @@ func (or *Oracle) State() *OracleState {
return or.state
}

// Returns wether a checkpoint has been reached or not. A checkpoint is reached
// when CheckPointSizeInSlots have passed from the last checkpoint
func (or *Oracle) IsCheckpoint() (bool, error) {
or.mutex.RLock()
defer or.mutex.RUnlock()
latestProcSlot := or.State().LatestProcessedSlot

if latestProcSlot == 0 {
return false, errors.New(
fmt.Sprintf("cannot determine if checkpoint has been reached, no slots have been processed yet. latest=%d",
latestProcSlot))
}

if or.cfg.DeployedSlot > latestProcSlot {
return false, errors.New(fmt.Sprintf("deployed slot can't be greater than latest slot. deployed=%d, latest=%d",
or.cfg.DeployedSlot, latestProcSlot))
}

if (latestProcSlot-or.cfg.DeployedSlot)%or.cfg.CheckPointSizeInSlots == 0 {
return true, nil
}
return false, nil
}

// Returns the state of the oracle, recalculating the hash of the state for
// verification purposes
func (or *Oracle) StateWithHash() (*OracleState, error) {
Expand Down
37 changes: 37 additions & 0 deletions oracle/oracle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2434,6 +2434,43 @@ func Test_getMerkleRootIfAny(t *testing.T) {
require.Equal(t, true, enough)
}

func Test_IsCheckpoint(t *testing.T) {
oracle := NewOracle(&Config{
DeployedSlot: 7750448,
CheckPointSizeInSlots: 28800,
})

// We are behind the checkpoint
oracle.state.LatestProcessedSlot = 7750448 + 100
isCheckpoint, err := oracle.IsCheckpoint()
require.NoError(t, err)
require.Equal(t, false, isCheckpoint)

// We are at the checkpoint
oracle.state.LatestProcessedSlot = 7750448 + 28800
isCheckpoint, err = oracle.IsCheckpoint()
require.NoError(t, err)
require.Equal(t, true, isCheckpoint)

// We are at the checkpoint way in the future
oracle.state.LatestProcessedSlot = 7750448 + 28800*10
isCheckpoint, err = oracle.IsCheckpoint()
require.NoError(t, err)
require.Equal(t, true, isCheckpoint)

// We are not at the checkpoint but way in the future
oracle.state.LatestProcessedSlot = 7750448 + 28800*10 + 7
isCheckpoint, err = oracle.IsCheckpoint()
require.NoError(t, err)
require.Equal(t, false, isCheckpoint)

// Errors if no last processed slot
oracle.state.LatestProcessedSlot = 0
isCheckpoint, err = oracle.IsCheckpoint()
require.Error(t, err)
require.Equal(t, false, isCheckpoint)
}

func Test_GetWithdrawalAndType(t *testing.T) {
// Test eth1 credentials
validator1 := &v1.Validator{
Expand Down
Loading