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

feat: constructed persistent account keys from instruction #191

Merged
merged 2 commits into from
Jan 15, 2025
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
1 change: 1 addition & 0 deletions omni-relayer/clippy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
too-many-lines-threshold = 200
18 changes: 9 additions & 9 deletions omni-relayer/example-mainnet-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,20 @@ expected_finalization_time = 1066
rpc_http_url = "https://api.mainnet-beta.solana.com"
rpc_ws_url = "wss://api.mainnet-beta.solana.com"
# Program ID on Solana is an account ID whitch the bridge contract (basically bridge_token_factory_address on Solana)
program_id = ""
program_id = "dahPEoZGXfyV58JqqH85okdHmpN8U2q8owgPUXSCPxe"
# This is the wormhole contract ID on Solana (can be found here https://wormhole.com/docs/build/reference/contract-addresses/#__tabbed_1_2)
wormhole_id = ""
wormhole_id = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth"
# There's a list of account keys and they are store in a strict order. We need indexes to get the right key
init_transfer_sender_index = 0
init_transfer_token_index = 6
init_transfer_emitter_index = 15
init_transfer_sol_sender_index = 0
init_transfer_sol_emitter_index = 11
init_transfer_sender_index = 5
init_transfer_token_index = 1
init_transfer_emitter_index = 6
init_transfer_sol_sender_index = 1
init_transfer_sol_emitter_index = 3
# Discriminators are used to identify the type of the event (can be found during the building process of solana's contract)
init_transfer_discriminator = [174, 50, 134, 99, 122, 243, 243, 224]
init_transfer_sol_discriminator = [124, 167, 164, 191, 81, 140, 108, 30]
finalize_transfer_emitter_index = 9
finalize_transfer_sol_emitter_index = 8
finalize_transfer_emitter_index = 6
finalize_transfer_sol_emitter_index = 5
finalize_transfer_discriminator = [124, 126, 103, 188, 144, 65, 135, 51]
finalize_transfer_sol_discriminator = [104, 27, 121, 69, 3, 70, 217, 66]

Expand Down
14 changes: 7 additions & 7 deletions omni-relayer/example-testnet-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,16 @@ program_id = "Gy1XPwYZURfBzHiGAxnw3SYC33SfqsEpGSS5zeBge28p"
# This is the wormhole contract ID on Solana (can be found here https://wormhole.com/docs/build/reference/contract-addresses/#__tabbed_1_2)
wormhole_id = "3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5"
# There's a list of account keys and they are store in a strict order. We need indexes to get the right key
init_transfer_sender_index = 0
init_transfer_token_index = 6
init_transfer_emitter_index = 15
init_transfer_sol_sender_index = 0
init_transfer_sol_emitter_index = 11
init_transfer_sender_index = 5
init_transfer_token_index = 1
init_transfer_emitter_index = 6
init_transfer_sol_sender_index = 1
init_transfer_sol_emitter_index = 3
# Discriminators are used to identify the type of the event (can be found during the building process of solana's contract)
init_transfer_discriminator = [174, 50, 134, 99, 122, 243, 243, 224]
init_transfer_sol_discriminator = [124, 167, 164, 191, 81, 140, 108, 30]
finalize_transfer_emitter_index = 9
finalize_transfer_sol_emitter_index = 8
finalize_transfer_emitter_index = 6
finalize_transfer_sol_emitter_index = 5
finalize_transfer_discriminator = [124, 126, 103, 188, 144, 65, 135, 51]
finalize_transfer_sol_discriminator = [104, 27, 121, 69, 3, 70, 217, 66]

Expand Down
15 changes: 8 additions & 7 deletions omni-relayer/src/startup/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,19 @@ pub async fn start_indexer(
arb.expected_finalization_time,
)
}
_ => anyhow::bail!("Unsupported chain kind: {:?}", chain_kind),
_ => anyhow::bail!("Unsupported chain kind: {chain_kind:?}"),
};

let http_provider = ProviderBuilder::new().on_http(rpc_http_url.parse().context(format!(
"Failed to parse {:?} rpc provider as url",
chain_kind
"Failed to parse {chain_kind:?} rpc provider as url",
))?);

let ws_provider = ProviderBuilder::new()
.on_ws(WsConnect::new(rpc_ws_url))
.await
.context(format!("Failed to initialize {:?} WS provider", chain_kind))?;
.context(format!("Failed to initialize {chain_kind:?} WS provider"))?;

let last_processed_block_key = utils::redis::get_last_processed_key(chain_kind).await;
let last_processed_block_key = utils::redis::get_last_processed_key(chain_kind);
let latest_block = http_provider.get_block_number().await?;
let from_block = match start_block {
Some(block) => block,
Expand All @@ -100,7 +99,9 @@ pub async fn start_indexer(
.to_vec(),
);

for current_block in (from_block..latest_block).step_by(block_processing_batch_size as usize) {
for current_block in
(from_block..latest_block).step_by(usize::try_from(block_processing_batch_size)?)
{
let logs = http_provider
.get_logs(
&filter
Expand Down Expand Up @@ -201,7 +202,7 @@ async fn process_log(

utils::redis::update_last_processed(
redis_connection,
&utils::redis::get_last_processed_key(chain_kind).await,
&utils::redis::get_last_processed_key(chain_kind),
block_number,
)
.await;
Expand Down
5 changes: 1 addition & 4 deletions omni-relayer/src/startup/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,7 @@ fn build_evm_bridge_client(
.private_key(Some(crate::config::get_private_key(chain_kind)))
.bridge_token_factory_address(Some(evm.bridge_token_factory_address.to_string()))
.build()
.context(format!(
"Failed to build EvmBridgeClient ({:?})",
chain_kind
))
.context(format!("Failed to build EvmBridgeClient ({chain_kind:?})"))
})
.transpose()
}
Expand Down
10 changes: 6 additions & 4 deletions omni-relayer/src/startup/near.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,13 @@ async fn create_lake_config(
Some(block) => block,
None => utils::redis::get_last_processed::<&str, u64>(
redis_connection,
&utils::redis::get_last_processed_key(ChainKind::Near).await,
&utils::redis::get_last_processed_key(ChainKind::Near),
)
.await
.map(|block_height| block_height + 1)
.unwrap_or(utils::near::get_final_block(jsonrpc_client).await?),
.map_or(
utils::near::get_final_block(jsonrpc_client).await?,
|block_height| block_height + 1,
),
};

info!("NEAR Lake will start from block: {}", start_block_height);
Expand Down Expand Up @@ -127,7 +129,7 @@ pub async fn start_indexer(

utils::redis::update_last_processed(
&mut redis_connection,
&utils::redis::get_last_processed_key(ChainKind::Near).await,
&utils::redis::get_last_processed_key(ChainKind::Near),
streamer_message.block.header.height,
)
.await;
Expand Down
47 changes: 22 additions & 25 deletions omni-relayer/src/startup/solana.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,31 +86,28 @@ async fn process_recent_signatures(
program_id: &Pubkey,
start_signature: Option<String>,
) -> Result<()> {
let from_signature = match start_signature {
Some(signature) => {
utils::redis::add_event(
redis_connection,
utils::redis::SOLANA_EVENTS,
signature.clone(),
// TODO: It's better to come up with a solution that wouldn't require storing `Null` value
serde_json::Value::Null,
)
.await;

Signature::from_str(&signature)?
}
None => {
let Some(signature) = utils::redis::get_last_processed::<&str, String>(
redis_connection,
&utils::redis::get_last_processed_key(ChainKind::Sol).await,
)
.await
.and_then(|s| Signature::from_str(&s).ok()) else {
return Ok(());
};

signature
}
let from_signature = if let Some(signature) = start_signature {
utils::redis::add_event(
redis_connection,
utils::redis::SOLANA_EVENTS,
signature.clone(),
// TODO: It's better to come up with a solution that wouldn't require storing `Null` value
serde_json::Value::Null,
)
.await;

Signature::from_str(&signature)?
} else {
let Some(signature) = utils::redis::get_last_processed::<&str, String>(
redis_connection,
&utils::redis::get_last_processed_key(ChainKind::Sol),
)
.await
.and_then(|s| Signature::from_str(&s).ok()) else {
return Ok(());
};

signature
};

let signatures: Vec<RpcConfirmedTransactionStatusWithSignature> = http_client
Expand Down
7 changes: 2 additions & 5 deletions omni-relayer/src/utils/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,10 @@ pub async fn construct_prover_args(
borsh::to_vec(&evm_proof_args).ok()
}

pub async fn string_to_evm_omniaddress(
chain_kind: ChainKind,
address: String,
) -> Result<OmniAddress> {
pub fn string_to_evm_omniaddress(chain_kind: ChainKind, address: &str) -> Result<OmniAddress> {
OmniAddress::new_from_evm_address(
chain_kind,
H160::from_str(&address)
H160::from_str(address)
.map_err(|err| anyhow::anyhow!("Failed to parse as H160 address: {:?}", err))?,
)
.map_err(|err| anyhow::anyhow!("Failed to parse as EvmOmniAddress address: {:?}", err))
Expand Down
4 changes: 2 additions & 2 deletions omni-relayer/src/utils/redis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ pub const SLEEP_TIME_AFTER_EVENTS_PROCESS_SECS: u64 = 10;
const QUERY_RETRY_ATTEMPTS: u64 = 10;
const QUERY_RETRY_SLEEP_SECS: u64 = 1;

pub async fn get_last_processed_key(chain_kind: ChainKind) -> String {
pub fn get_last_processed_key(chain_kind: ChainKind) -> String {
match chain_kind {
ChainKind::Sol => "SOLANA_LAST_PROCESSED_SIGNATURE".to_string(),
_ => format!("{:?}_LAST_PROCESSED_BLOCK", chain_kind),
_ => format!("{chain_kind:?}_LAST_PROCESSED_BLOCK"),
}
}

Expand Down
38 changes: 29 additions & 9 deletions omni-relayer/src/utils/solana.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,19 @@ pub async fn process_message(
signature: Signature,
) {
for instruction in message.instructions.clone() {
let account_keys = instruction
.accounts
.into_iter()
.map(|i| message.account_keys.get(usize::from(i)).cloned())
.collect::<Vec<_>>();

if let Err(err) = decode_instruction(
redis_connection,
solana,
signature,
transaction,
&instruction.data,
&message.account_keys,
account_keys,
)
.await
{
Expand All @@ -48,7 +54,7 @@ async fn decode_instruction(
signature: Signature,
transaction: &EncodedTransactionWithStatusMeta,
data: &str,
account_keys: &[String],
account_keys: Vec<Option<String>>,
) -> Result<()> {
let decoded_data = bs58::decode(data).into_vec()?;

Expand Down Expand Up @@ -78,21 +84,31 @@ async fn decode_instruction(
let (sender, token, emitter) = if discriminator == &solana.init_transfer_discriminator {
let sender = account_keys
.get(solana.init_transfer_sender_index)
.context("Missing sender account key")?;
.context("Missing sender account key")?
.as_ref()
.context("Sender account key is None")?;
let token = account_keys
.get(solana.init_transfer_token_index)
.context("Missing token account key")?;
.context("Missing token account key")?
.as_ref()
.context("Sender account key is None")?;
let emitter = account_keys
.get(solana.init_transfer_emitter_index)
.context("Missing emitter account key")?;
.context("Missing emitter account key")?
.as_ref()
.context("Emitter key is None")?;
(sender, token, emitter)
} else {
let sender = account_keys
.get(solana.init_transfer_sol_sender_index)
.context("Missing SOL sender account key")?;
.context("Missing SOL sender account key")?
.as_ref()
.context("SOL sender account key is None")?;
let emitter = account_keys
.get(solana.init_transfer_sol_emitter_index)
.context("Missing SOL emitter account key")?;
.context("Missing SOL emitter account key")?
.as_ref()
.context("Sol emitter key is None")?;
(sender, &Pubkey::default().to_string(), emitter)
};

Expand All @@ -104,7 +120,7 @@ async fn decode_instruction(
let Some(sequence) = log
.split_ascii_whitespace()
.last()
.map(|sequence| sequence.to_string())
.map(std::string::ToString::to_string)
else {
warn!("Failed to parse sequence number from log: {:?}", log);
continue;
Expand Down Expand Up @@ -150,10 +166,14 @@ async fn decode_instruction(
account_keys
.get(solana.finalize_transfer_emitter_index)
.context("Missing emitter account key")?
.as_ref()
.context("Emitter account key is None")?
} else {
account_keys
.get(solana.finalize_transfer_sol_emitter_index)
.context("Missing SOL emitter account key")?
.as_ref()
.context("SOL emitter account key is None")?
};

if let Some(OptionSerializer::Some(logs)) =
Expand All @@ -164,7 +184,7 @@ async fn decode_instruction(
let Some(sequence) = log
.split_ascii_whitespace()
.last()
.map(|sequence| sequence.to_string())
.map(std::string::ToString::to_string)
else {
warn!("Failed to parse sequence number from log: {:?}", log);
continue;
Expand Down
37 changes: 7 additions & 30 deletions omni-relayer/src/utils/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,28 @@ async fn get_token_id(
let omni_token_address = match chain_kind {
ChainKind::Near => {
let token = AccountId::from_str(token_address).map_err(|_| {
format!(
"Failed to parse token address as AccountId: {:?}",
token_address
)
format!("Failed to parse token address as AccountId: {token_address:?}",)
})?;
Ok(OmniAddress::Near(token))
}
ChainKind::Eth | ChainKind::Base | ChainKind::Arb => {
utils::evm::string_to_evm_omniaddress(chain_kind, token_address.to_string())
.await
utils::evm::string_to_evm_omniaddress(chain_kind, token_address)
.map_err(|err| err.to_string())
}
ChainKind::Sol => {
let token = Pubkey::from_str(token_address).map_err(|_| {
format!(
"Failed to parse token address as Pubkey: {:?}",
token_address
)
format!("Failed to parse token address as Pubkey: {token_address:?}",)
})?;
OmniAddress::new_from_slice(ChainKind::Sol, &token.to_bytes())
}
}
.map_err(|_| {
format!(
"Failed to convert token address to OmniAddress: {:?}",
token_address
)
})?;
.map_err(|_| format!("Failed to convert token address to OmniAddress: {token_address:?}",))?;

let token_id = connector
.near_get_token_id(omni_token_address.clone())
.await
.map_err(|_| {
format!(
"Failed to get token id by omni token address: {:?}",
omni_token_address
)
format!("Failed to get token id by omni token address: {omni_token_address:?}",)
})?;

Ok(token_id)
Expand All @@ -69,10 +54,7 @@ async fn add_storage_deposit_action(
.near_get_required_storage_deposit(token_id.clone(), account_id.clone())
.await
.map_err(|_| {
format!(
"Failed to get required storage deposit for account: {:?}",
account_id
)
format!("Failed to get required storage deposit for account: {account_id:?}",)
})? {
amount if amount > 0 => Some(amount),
_ => None,
Expand Down Expand Up @@ -124,12 +106,7 @@ pub async fn get_storage_deposit_actions(
let token_id = connector
.near_get_native_token_id(chain_kind)
.await
.map_err(|_| {
format!(
"Failed to get native token id by chain kind: {:?}",
chain_kind
)
})?;
.map_err(|_| format!("Failed to get native token id by chain kind: {chain_kind:?}",))?;

let relayer = connector
.near_bridge_client()
Expand Down
Loading
Loading