diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 04fe9a623..6adc5968a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - run: sudo apt install -y gcc-aarch64-linux-gnu libc6-dev-arm64-cross g++-aarch64-linux-gnu + - run: sudo apt update && sudo apt install -y gcc-aarch64-linux-gnu libc6-dev-arm64-cross g++-aarch64-linux-gnu - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: diff --git a/rocketpool/watchtower/submit-network-balances.go b/rocketpool/watchtower/submit-network-balances.go index 7814edc89..446d77a67 100644 --- a/rocketpool/watchtower/submit-network-balances.go +++ b/rocketpool/watchtower/submit-network-balances.go @@ -158,8 +158,16 @@ func (t *submitNetworkBalances) run(state *state.NetworkState) error { } targetBlockNumber := targetBlockHeader.Number.Uint64() - if targetBlockNumber > state.ElBlockNumber { - // No submission needed: target block in the future + if targetBlockNumber > state.ElBlockNumber || targetBlockNumber == lastSubmissionBlock { + if targetBlockNumber > state.ElBlockNumber { + // No submission needed: Target block in the future + t.log.Println("not enough time has passed for the next price/balances submission") + return nil + } + if targetBlockNumber == lastSubmissionBlock { + // No submission needed: Already submitted for this block + t.log.Println("balances have already been submitted for this block") + } return nil } diff --git a/rocketpool/watchtower/utils/utils.go b/rocketpool/watchtower/utils/utils.go index bf0da9e36..7c3b35009 100644 --- a/rocketpool/watchtower/utils/utils.go +++ b/rocketpool/watchtower/utils/utils.go @@ -49,34 +49,49 @@ func FindLastBlockWithExecutionPayload(bc beacon.Client, slotNumber uint64) (bea } func FindNextSubmissionTarget(rp *rocketpool.RocketPool, eth2Config beacon.Eth2Config, bc beacon.Client, ec rocketpool.ExecutionClient, lastSubmissionBlock uint64, referenceTimestamp int64, submissionIntervalInSeconds int64) (uint64, time.Time, *types.Header, error) { - // Get the time of the last submission - lastSubmissionBlockHeader, err := rp.Client.HeaderByNumber(context.Background(), big.NewInt(int64(lastSubmissionBlock))) - if err != nil { - return 0, time.Time{}, nil, fmt.Errorf("can't get the latest submission block header: %w", err) - } + lastSubmissionSlotTimestamp := referenceTimestamp - // Get the time of the latest block - latestEth1Block, err := rp.Client.HeaderByNumber(context.Background(), nil) - if err != nil { - return 0, time.Time{}, nil, fmt.Errorf("can't get the latest block time: %w", err) - } - latestBlockTimestamp := int64(latestEth1Block.Time) + genesisTime := time.Unix(int64(eth2Config.GenesisTime), 0) + + if lastSubmissionBlock > 0 { + lastSubmissionBlockHeader, err := rp.Client.HeaderByNumber(context.Background(), big.NewInt(int64(lastSubmissionBlock))) + if err != nil { + return 0, time.Time{}, nil, fmt.Errorf("can't get the latest submission block header: %w", err) + } + + lastSubmissionParent, _, err := bc.GetBeaconBlock(lastSubmissionBlockHeader.ParentBeaconRoot.Hex()) + if err != nil { + return 0, time.Time{}, nil, fmt.Errorf("can't get the parent block: %w", err) + } - if int64(lastSubmissionBlockHeader.Time)+submissionIntervalInSeconds > latestBlockTimestamp { - return 0, time.Time{}, nil, fmt.Errorf("not enough time has passed for the next price/balances submission") + lastSubmissionSlot := lastSubmissionParent.Slot + 1 + lastSubmissionSlotTimestamp = genesisTime.Add(time.Duration((lastSubmissionSlot)*eth2Config.SecondsPerSlot) * time.Second).Unix() } - // Calculate the next submission timestamp - submissionTimestamp, err := FindNextSubmissionTimestamp(latestBlockTimestamp, referenceTimestamp, submissionIntervalInSeconds) + beaconHead, err := bc.GetBeaconHead() if err != nil { return 0, time.Time{}, nil, err } + headEpoch := beaconHead.Epoch + + // Calculate the timestamp at the start of the head epoch + headEpochStartSlot := headEpoch * eth2Config.SlotsPerEpoch + headEpochTimestamp := genesisTime.Add(time.Duration(headEpochStartSlot*eth2Config.SecondsPerSlot) * time.Second) + + // Find the highest valid submissionTimestamp that is <= headTime + maxSubmissionTimestamp := int64(0) + n := int64(0) + for { + ts := lastSubmissionSlotTimestamp + n*submissionIntervalInSeconds + if ts > headEpochTimestamp.Unix() { + break + } + maxSubmissionTimestamp = ts + n++ + } - // Convert the submission timestamp to time.Time - nextSubmissionTime := time.Unix(submissionTimestamp, 0) - - // Get the Beacon block corresponding to this time - genesisTime := time.Unix(int64(eth2Config.GenesisTime), 0) + // Now, use this maxSubmissionTimestamp for slot calculations + nextSubmissionTime := time.Unix(maxSubmissionTimestamp, 0) timeSinceGenesis := nextSubmissionTime.Sub(genesisTime) slotNumber := uint64(timeSinceGenesis.Seconds()) / eth2Config.SecondsPerSlot @@ -94,11 +109,6 @@ func FindNextSubmissionTarget(rp *rocketpool.RocketPool, eth2Config beacon.Eth2C } requiredEpoch := slotNumber / eth2Config.SlotsPerEpoch - // Check if the required epoch is finalized yet - beaconHead, err := bc.GetBeaconHead() - if err != nil { - return 0, time.Time{}, nil, err - } finalizedEpoch := beaconHead.FinalizedEpoch if requiredEpoch > finalizedEpoch { return 0, time.Time{}, nil, fmt.Errorf("balances must be reported for EL block %d, waiting until Epoch %d is finalized (currently %d)", targetBlockNumber, requiredEpoch, finalizedEpoch) @@ -106,22 +116,3 @@ func FindNextSubmissionTarget(rp *rocketpool.RocketPool, eth2Config beacon.Eth2C return slotNumber, nextSubmissionTime, targetBlockHeader, nil } - -func FindNextSubmissionTimestamp(latestBlockTimestamp int64, referenceTimestamp int64, submissionIntervalInSeconds int64) (int64, error) { - if latestBlockTimestamp == 0 || referenceTimestamp == 0 || submissionIntervalInSeconds == 0 { - return 0, fmt.Errorf("FindNextSubmissionTimestamp can't use zero values") - } - - // Calculate the difference between latestBlockTime and the reference timestamp - timeDifference := latestBlockTimestamp - referenceTimestamp - if timeDifference < 0 { - return 0, fmt.Errorf("FindNextSubmissionTimestamp referenceTimestamp in the future") - } - - // Calculate the remainder to find out how far off from a multiple of the interval the current time is - remainder := timeDifference % submissionIntervalInSeconds - - // Subtract the remainder from current time to find the first multiple of the interval in the past - submissionTimeRef := latestBlockTimestamp - remainder - return submissionTimeRef, nil -}