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

Relayer: fix block submission #923

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions eth2near/contract_wrapper/src/dao_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ mod tests {
SIGNER_PRIVATE_KEY,
DAO_CONTRACT_ACCOUNT_ID,
None,
None,
);

let mut dao_contract = DAOContract::new(Box::new(near_contract_wrapper));
Expand Down
46 changes: 25 additions & 21 deletions eth2near/contract_wrapper/src/dao_eth_client_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,16 @@ impl EthClientContractTrait for DaoEthClientContract {
&mut self,
light_client_update: LightClientUpdate,
) -> Result<FinalExecutionOutcomeView, Box<dyn Error>> {
// Check for already submitted updates
let last_proposal_id = self.dao_contract.get_last_proposal_id()?;
if last_proposal_id > 0 {
let last_proposal_output = self.dao_contract.get_proposal(last_proposal_id - 1)?;
if last_proposal_output.proposal.status == dao_types::ProposalStatus::InProgress
&& last_proposal_output.proposal.proposer.to_string()
== self
.dao_contract
.contract_wrapper
.get_signer_account_id()
.to_string()
{
return Err(format!(
"A proposal {} has already been submitted by this relayer which is in progress",
last_proposal_id
)
.into());
}
}

// Submmit new proposal
let (proposal_id, execution_outcome) =
self.dao_contract.submit_light_client_update_proposal(
near_sdk::AccountId::from_str(&self.eth_client_contract.get_account_id())?,
light_client_update,
)?;

loop {
let max_num_of_iterations = 10;
let mut count = 0;
while count < max_num_of_iterations {
let proposal_status = self.dao_contract.get_proposal(proposal_id);
if let Ok(staus) = proposal_status {
if staus.proposal.status != dao_types::ProposalStatus::InProgress {
Expand All @@ -72,11 +54,32 @@ impl EthClientContractTrait for DaoEthClientContract {
}

thread::sleep(Duration::from_secs(10));
count += 1;
}

Ok(execution_outcome)
}

fn is_ready_to_submit_light_client_update(&self) -> Result<bool, Box<dyn Error>> {
// Check for already submitted updates
let last_proposal_id = self.dao_contract.get_last_proposal_id()?;
if last_proposal_id > 0 {
let last_proposal_output = self.dao_contract.get_proposal(last_proposal_id - 1)?;
if last_proposal_output.proposal.status == dao_types::ProposalStatus::InProgress
&& last_proposal_output.proposal.proposer.to_string()
== self
.dao_contract
.contract_wrapper
.get_signer_account_id()
.to_string()
{
return Ok(false);
}
}

return Ok(true);
}

fn get_finalized_beacon_block_hash(&self) -> Result<H256, Box<dyn Error>> {
self.eth_client_contract.get_finalized_beacon_block_hash()
}
Expand Down Expand Up @@ -166,6 +169,7 @@ mod tests {
&signer_private_key,
CONTRACT_ACCOUNT_ID,
None,
None,
));

let eth_client = eth_client_contract::EthClientContract::new(near_contract_wrapper);
Expand Down
4 changes: 4 additions & 0 deletions eth2near/contract_wrapper/src/eth_client_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ impl EthClientContractTrait for EthClientContract {
)
}

fn is_ready_to_submit_light_client_update(&self) -> Result<bool, Box<dyn Error>> {
Ok(true)
}

fn get_finalized_beacon_block_hash(&self) -> Result<H256, Box<dyn Error>> {
let result = self.contract_wrapper.call_view_function(
"finalized_beacon_block_root".to_string(),
Expand Down
3 changes: 3 additions & 0 deletions eth2near/contract_wrapper/src/eth_client_contract_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ pub trait EthClientContractTrait {
light_client_update: LightClientUpdate,
) -> Result<FinalExecutionOutcomeView, Box<dyn Error>>;

/// Check if the client is ready to accept new update
fn is_ready_to_submit_light_client_update(&self) -> Result<bool, Box<dyn Error>>;

/// Gets finalized beacon block hash from Ethereum Light Client on NEAR
fn get_finalized_beacon_block_hash(&self) -> Result<H256, Box<dyn Error>>;

Expand Down
4 changes: 4 additions & 0 deletions eth2near/contract_wrapper/src/file_eth_client_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ impl EthClientContractTrait for FileEthClientContract {
.send_light_client_update(light_client_update)
}

fn is_ready_to_submit_light_client_update(&self) -> Result<bool, Box<dyn Error>> {
Ok(true)
}

fn get_finalized_beacon_block_hash(&self) -> Result<H256, Box<dyn Error>> {
self.eth_client_contract.get_finalized_beacon_block_hash()
}
Expand Down
60 changes: 53 additions & 7 deletions eth2near/contract_wrapper/src/near_contract_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ use near_sdk::{Balance, Gas};
use serde_json::Value;
use std::error::Error;
use std::string::String;
use std::time;
use std::vec::Vec;
use tokio::runtime::Runtime;

pub const MAX_GAS: Gas = Gas(Gas::ONE_TERA.0 * 300);
pub const DEFAULT_WAIT_FINAL_OUTCOME_TIMEOUT_SEC: u64 = 500;

/// Implementation of interaction with a contract on NEAR.
pub struct NearContractWrapper {
Expand Down Expand Up @@ -42,12 +44,18 @@ impl NearContractWrapper {
signer_secret_key: &str,
contract_account_id: &str,
timeout: Option<std::time::Duration>,
api_key: Option<String>,
) -> NearContractWrapper {
let signer_account_id = account_id
.parse()
.expect("Error on parsing account id during creation near contract wrapper");
let client =
let mut client =
JsonRpcClient::with(utils::new_near_rpc_client(timeout)).connect(near_endpoint);

if let Some(api_key) = api_key {
client = client.header(near_jsonrpc_client::auth::ApiKey::new(api_key).unwrap());
}

let contract_account = contract_account_id
.parse()
.expect("Error on parsing contract account id during creation near contract wrapper");
Expand Down Expand Up @@ -80,6 +88,7 @@ impl NearContractWrapper {
path_to_signer_secret_key: &str,
contract_account_id: &str,
timeout: Option<std::time::Duration>,
api_key: Option<String>,
) -> NearContractWrapper {
let v: Value = serde_json::from_str(
&std::fs::read_to_string(path_to_signer_secret_key).expect("Unable to read file"),
Expand All @@ -96,6 +105,7 @@ impl NearContractWrapper {
&signer_secret_key,
contract_account_id,
timeout,
api_key,
)
}
}
Expand Down Expand Up @@ -185,15 +195,42 @@ impl ContractWrapper for NearContractWrapper {
actions,
};

let request = methods::broadcast_tx_commit::RpcBroadcastTxCommitRequest {
let request = methods::broadcast_tx_async::RpcBroadcastTxAsyncRequest {
signed_transaction: transaction.sign(&self.signer),
};

let request_result = rt.block_on(async_std::future::timeout(
std::time::Duration::from_secs(600),
self.client.call(&request),
))?;
Ok(request_result?)
let hash = rt.block_on(self.client.call(&request))?;
let sent_at = time::Instant::now();
let tx_info = methods::tx::TransactionInfo::TransactionId {
hash,
account_id: self.signer.account_id.clone(),
};

loop {
let response =
rt.block_on(self.client.call(methods::tx::RpcTransactionStatusRequest {
transaction_info: tx_info.clone(),
}));

let delta = (time::Instant::now() - sent_at).as_secs();
if delta > DEFAULT_WAIT_FINAL_OUTCOME_TIMEOUT_SEC {
Err(format!(
"Timeout on waiting for final transaction outcome {}",
hash.to_string()
))?;
}

match response {
Err(err) => match err.handler_error() {
Some(_err) => {
std::thread::sleep(time::Duration::from_secs(2));
continue;
}
_ => Err(format!("RpcTransactionError {}", err))?,
},
Ok(response) => return Ok(response),
}
}
}

fn call_change_method(
Expand All @@ -210,4 +247,13 @@ impl ContractWrapper for NearContractWrapper {
gas,
)
}

// fn wait_for_tx_final_outcome(
// hash: CryptoHash,
// account_id: AccountId,
// server_addr: url::Url,
// timeout_sec: u64,
// ) -> Result<FinalExecutionOutcomeView, CustomError> {

// }
}
6 changes: 5 additions & 1 deletion eth2near/contract_wrapper/src/near_rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ use std::error::Error;
pub struct NearRPCClient {
endpoint_url: String,
client: Client,
api_key: String,
}

impl NearRPCClient {
pub fn new(endpoint_url: &str) -> Self {
pub fn new(endpoint_url: &str, api_key: &Option<String>) -> Self {
Self {
endpoint_url: endpoint_url.to_string(),
client: reqwest::blocking::Client::new(),
api_key: api_key.clone().unwrap_or_default(),
}
}

Expand All @@ -30,6 +32,7 @@ impl NearRPCClient {
let res = self
.client
.post(&self.endpoint_url)
.header("x-api-key", self.api_key.clone())
.json(&json_value)
.send()?
.text()?;
Expand All @@ -50,6 +53,7 @@ impl NearRPCClient {
let res = self
.client
.post(&self.endpoint_url)
.header("x-api-key", self.api_key.clone())
.json(&json_value)
.send()?
.text()?;
Expand Down
8 changes: 7 additions & 1 deletion eth2near/eth2near-block-relay-rs/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ pub struct Config {
// endpoint for a full node on the NEAR chain
pub near_endpoint: String,

// api key for the NEAR endpoint
pub near_endpoint_api_key: Option<String>,

// Account id from which relay make requests
pub signer_account_id: String,

Expand Down Expand Up @@ -77,6 +80,9 @@ pub struct Config {
// Sleep time in seconds after blocks/light_client_update submission to client
pub sleep_time_after_submission_secs: u64,

// Sleep time in seconds waiting for in-progress proposal to be processed
pub sleep_time_on_in_progress_proposal_secs: u64,

/// Max number of stored blocks in the storage of the eth2 client contract.
/// Events that happen past this threshold cannot be verified by the client.
/// It is used on initialization of the Eth2 client.
Expand Down Expand Up @@ -119,7 +125,7 @@ impl Config {
}

fn check_account_id(&self) {
let near_rpc_client = NearRPCClient::new(&self.near_endpoint);
let near_rpc_client = NearRPCClient::new(&self.near_endpoint, &self.near_endpoint_api_key);

// check `signer_account_id`
let _signer_account_id: near_sdk::AccountId = self
Expand Down
Loading
Loading