Skip to content
This repository was archived by the owner on Aug 9, 2024. It is now read-only.

Commit

Permalink
feat(operator): simplify logic (#173)
Browse files Browse the repository at this point in the history
* clean

* fix
  • Loading branch information
ratankaliani authored May 3, 2024
1 parent d653cd5 commit 4ffe174
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 51 deletions.
127 changes: 82 additions & 45 deletions bin/vectorx.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::cmp::min;
use std::env;

use alloy_primitives::{Address, Bytes, FixedBytes, B256};
Expand All @@ -9,6 +8,7 @@ use ethers::contract::abigen;
use ethers::providers::{Http, Provider};
use log::{error, info};
use succinct_client::request::SuccinctClient;
use vectorx::consts::MAX_AUTHORITY_SET_SIZE;
use vectorx::input::RpcDataFetcher;

// Note: Update ABI when updating contract.
Expand All @@ -33,7 +33,9 @@ struct VectorXOperator {

#[derive(Debug)]
struct HeaderRangeContractData {
current_block: u32,
vectorx_latest_block: u32,
avail_current_block: u32,
header_range_commitment_tree_size: u32,
next_authority_set_hash_exists: bool,
header_range_function_id: B256,
}
Expand Down Expand Up @@ -198,13 +200,14 @@ impl VectorXOperator {
}
}

async fn find_and_request_header_range(&mut self, max_block_to_step_to: u32) {
// Ideally, post a header range update every ideal_block_interval blocks.
async fn find_and_request_header_range(&mut self, ideal_block_interval: u32) {
let header_range_contract_data = self.get_contract_data_for_header_range().await;

// The current authority set id is the authority set id of the block before the current block.
let current_authority_set_id = self
.data_fetcher
.get_authority_set_id(header_range_contract_data.current_block - 1)
.get_authority_set_id(header_range_contract_data.vectorx_latest_block - 1)
.await;

// Get the last justified block by the current authority set id.
Expand All @@ -215,7 +218,7 @@ impl VectorXOperator {

// If this is the last justified block, check for header range with next authority set.
let mut request_authority_set_id = current_authority_set_id;
if header_range_contract_data.current_block == last_justified_block {
if header_range_contract_data.vectorx_latest_block == last_justified_block {
let next_authority_set_id = current_authority_set_id + 1;

// Check if the next authority set id exists in the contract. If not, a rotate is needed.
Expand All @@ -225,9 +228,16 @@ impl VectorXOperator {
request_authority_set_id = next_authority_set_id;
}

// Step as far as possible within blocks attested by the requested authority set.
// Find the block to step to. If no block is returned, either 1) there is no block satisfying
// the conditions that is available to step to or 2) something has gone wrong with the indexer.
let block_to_step_to = self
.find_block_to_step_to(max_block_to_step_to, request_authority_set_id)
.find_block_to_step_to(
ideal_block_interval,
header_range_contract_data.header_range_commitment_tree_size,
header_range_contract_data.vectorx_latest_block,
header_range_contract_data.avail_current_block,
request_authority_set_id,
)
.await;
if block_to_step_to.is_none() {
return;
Expand All @@ -241,7 +251,7 @@ impl VectorXOperator {
// Request the header range proof to block_to_step_to.
match self
.request_header_range(
header_range_contract_data.current_block,
header_range_contract_data.vectorx_latest_block,
request_authority_set_id,
block_to_step_to.unwrap(),
header_range_contract_data.header_range_function_id,
Expand All @@ -251,7 +261,7 @@ impl VectorXOperator {
Ok(request_id) => {
info!(
"Header range request submitted from block {} to block {} with request ID: {}",
header_range_contract_data.current_block,
header_range_contract_data.vectorx_latest_block,
block_to_step_to.unwrap(),
request_id
)
Expand Down Expand Up @@ -298,13 +308,20 @@ impl VectorXOperator {
async fn get_contract_data_for_header_range(&mut self) -> HeaderRangeContractData {
let header_range_function_id: B256 =
FixedBytes(self.contract.header_range_function_id().await.unwrap());
let current_block = self.contract.latest_block().await.unwrap();
let vectorx_latest_block = self.contract.latest_block().await.unwrap();
let header_range_commitment_tree_size = self
.contract
.header_range_commitment_tree_size()
.await
.unwrap();

let current_authority_set_id = self
let avail_current_block = self.data_fetcher.get_head().await.number;

let vectorx_current_authority_set_id = self
.data_fetcher
.get_authority_set_id(current_block - 1)
.get_authority_set_id(vectorx_latest_block - 1)
.await;
let next_authority_set_id = current_authority_set_id + 1;
let next_authority_set_id = vectorx_current_authority_set_id + 1;

let next_authority_set_hash = self
.contract
Expand All @@ -313,7 +330,9 @@ impl VectorXOperator {
.unwrap();

HeaderRangeContractData {
current_block,
vectorx_latest_block,
avail_current_block,
header_range_commitment_tree_size,
next_authority_set_hash_exists: B256::from_slice(&next_authority_set_hash)
!= B256::ZERO,
header_range_function_id,
Expand Down Expand Up @@ -354,24 +373,64 @@ impl VectorXOperator {
self.config.clone()
}

// If the authority_set_id is the current authority set, return the max_block_to_request. Else,
// return the minimum of max_block_to_request and last_justified_block.
// The logic for finding the block to step to is as follows:
// 1. If the current epoch in the contract is not the latest epoch, step to the last justified block
// of the epoch.
// 2. If the block has a valid justification, return the block number.
// 3. If the block has no valid justification, return None.
async fn find_block_to_step_to(
&mut self,
max_block_to_request: u32,
ideal_block_interval: u32,
header_range_commitment_tree_size: u32,
vectorx_current_block: u32,
avail_current_block: u32,
authority_set_id: u64,
) -> Option<u32> {
let last_justified_block = self
.data_fetcher
.last_justified_block(authority_set_id)
.await;

// Last justified block will be 0 in this is the current authority set.
if last_justified_block == 0 {
return Some(max_block_to_request);
// Step to the last justified block of the current epoch if it is in range. When the last
// justified block is 0, the VectorX contract's latest epoch is the current epoch on the
// Avail chain.
if last_justified_block != 0
&& last_justified_block <= vectorx_current_block + header_range_commitment_tree_size
{
return Some(last_justified_block);
}

let mut block_to_step_to = vectorx_current_block + ideal_block_interval;
// If the block to step to is greater than the current head of Avail, return None.
if block_to_step_to > avail_current_block {
return None;
}

Some(min(max_block_to_request, last_justified_block))
// Check that block_to_step_to has a valid justification. If not, iterate up until the maximum_vectorx_target_block
// to find a valid justification. If we're unable to find a justification, something has gone
// deeply wrong with the jusitification indexer.
loop {
if block_to_step_to > vectorx_current_block + header_range_commitment_tree_size {
info!(
"Unable to find any valid justifications after searching from block {} to block {}. This is likely caused by an issue with the justification indexer.",
vectorx_current_block + ideal_block_interval,
vectorx_current_block + header_range_commitment_tree_size
);
return None;
}

if self
.data_fetcher
.get_justification_from_block::<MAX_AUTHORITY_SET_SIZE>(block_to_step_to)
.await
.is_ok()
{
break;
}
block_to_step_to += 1;
}

Some(block_to_step_to)
}

async fn run(&mut self) {
Expand All @@ -382,30 +441,8 @@ impl VectorXOperator {
// Check if there is a rotate available for the next authority set.
self.find_and_request_rotate().await;

// Get latest block of the Avail chain.
let avail_chain_latest_block_nb = self.data_fetcher.get_head().await.number;

// Get latest block of contract.
let contract_latest_block_nb = self.contract.latest_block().await.unwrap();

// Get the header range commitment tree size.
let header_range_commitment_tree_size: u32 = self
.contract
.header_range_commitment_tree_size()
.await
.unwrap();

// block_to_request is the closest interval of block_interval less than min(avail_chain_latest_block_nb, header_range_commitment_tree_size + current_block)
let max_block = std::cmp::min(
avail_chain_latest_block_nb,
header_range_commitment_tree_size + contract_latest_block_nb,
);
let block_to_request = max_block - (max_block % block_interval);

if block_to_request > contract_latest_block_nb {
info!("Attempting to step to block: {}", block_to_request);
self.find_and_request_header_range(block_to_request).await;
}
// Check if there is a header range request available.
self.find_and_request_header_range(block_interval).await;

// Sleep for N minutes.
info!("Sleeping for {} minutes.", loop_delay_mins);
Expand Down
2 changes: 1 addition & 1 deletion contracts/lib/succinctx
Submodule succinctx updated 252 files
6 changes: 2 additions & 4 deletions contracts/script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {ERC1967Proxy} from "@openzeppelin/proxy/ERC1967/ERC1967Proxy.sol";
contract DeployScript is Script {
function setUp() public {}

function run() public {
function run() public returns (address, address) {
vm.startBroadcast();

bytes32 create2Salt = bytes32(vm.envBytes("CREATE2_SALT"));
Expand All @@ -18,8 +18,6 @@ contract DeployScript is Script {
// Deploy contract
VectorX lightClientImpl = new VectorX{salt: bytes32(create2Salt)}();

console.logAddress(address(lightClientImpl));

VectorX lightClient;
if (!upgrade) {
lightClient = VectorX(
Expand Down Expand Up @@ -78,6 +76,6 @@ contract DeployScript is Script {
);
}

console.logAddress(address(lightClient));
return (address(lightClientImpl), address(lightClient));
}
}
39 changes: 39 additions & 0 deletions contracts/script/DeployCustomProver.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.16;

import "forge-std/Script.sol";
import {VectorX} from "../src/VectorX.sol";
import {SuccinctGateway} from "@succinctx/SuccinctGateway.sol";
import {ISuccinctGateway, WhitelistStatus} from "@succinctx/interfaces/ISuccinctGateway.sol";
import {ERC1967Proxy} from "@openzeppelin/proxy/ERC1967/ERC1967Proxy.sol";

contract DeployScript is Script {
function setUp() public {}

function run() public {
vm.startBroadcast();

SuccinctGateway succinctGateway = SuccinctGateway(
vm.envAddress("GATEWAY_ADDRESS")
);

bytes32 headerRangeFunctionId = vm.envBytes32(
"HEADER_RANGE_FUNCTION_ID"
);
bytes32 rotateFunctionId = vm.envBytes32("ROTATE_FUNCTION_ID");

address customProver = vm.envAddress("CUSTOM_PROVER");

succinctGateway.setWhitelistStatus(
headerRangeFunctionId,
WhitelistStatus.Custom
);
succinctGateway.addCustomProver(headerRangeFunctionId, customProver);

succinctGateway.setWhitelistStatus(
rotateFunctionId,
WhitelistStatus.Custom
);
succinctGateway.addCustomProver(rotateFunctionId, customProver);
}
}

0 comments on commit 4ffe174

Please sign in to comment.