Skip to content

Commit

Permalink
feat(voyager): dump failing messages when submitting a batch
Browse files Browse the repository at this point in the history
  • Loading branch information
benluelo committed Jul 16, 2024
1 parent 373bf30 commit 8693e7d
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 78 deletions.
2 changes: 1 addition & 1 deletion evm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ This links are working if you run a local devnet on a x86 machine only (Blocksco
- CometblsClient: [0xc4f27a952faba4174ce0ee6d9d0c6f4c41524d49](http://localhost/address/0xc4f27a952faba4174ce0ee6d9d0c6f4c41524d49)
- UCS01: [0xa9d03ba6e27b43c69a64c87f845485b73a8e5d46](http://localhost/address/0xa9d03ba6e27b43c69a64c87f845485b73a8e5d46)
- UCS02: [0x524d4d28fc90dc5a257162abe37081f52681c7d6](http://localhost/address/0x524d4d28fc90dc5a257162abe37081f52681c7d6)
- Multicall: [0x72459D25D5e30ec16b9Ac91cfB7e5a7969347E58](http://localhost/address/0x72459D25D5e30ec16b9Ac91cfB7e5a7969347E58?tab=contract)
- Multicall: [0x9fd9D9528c8373D990a1380B9414bDE179007A35](http://localhost/address/0x9fd9D9528c8373D990a1380B9414bDE179007A35?tab=contract)

## Testnet 8

Expand Down
147 changes: 81 additions & 66 deletions lib/chain-utils/src/cosmos_sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use tracing::{debug, error, info, warn};
use unionlabs::{
cosmos::{
auth::base_account::BaseAccount,
base::coin::Coin,
base::{abci::gas_info::GasInfo, coin::Coin},
crypto::{secp256k1, AnyPubKey},
tx::{
auth_info::AuthInfo, fee::Fee, mode_info::ModeInfo, sign_doc::SignDoc,
Expand Down Expand Up @@ -192,74 +192,12 @@ pub trait CosmosSdkChainExt: CosmosSdkChainRpcs {
messages: impl IntoIterator<Item = protos::google::protobuf::Any> + Clone,
memo: String,
) -> Result<(H256, u64), BroadcastTxCommitError> {
use protos::cosmos::tx;

let account = self.account_info(&signer.to_string()).await;

let mut client = tx::v1beta1::service_client::ServiceClient::connect(self.grpc_url())
let (tx_body, mut auth_info, simulation_gas_info) = self
.simulate_tx(signer, messages, memo)
.await
.unwrap();

let tx_body = TxBody {
messages: messages.clone().into_iter().collect(),
// TODO(benluelo): What do we want to use as our memo?
memo,
timeout_height: 0,
extension_options: vec![],
non_critical_extension_options: vec![],
};

let mut auth_info = AuthInfo {
signer_infos: [SignerInfo {
public_key: Some(AnyPubKey::Secp256k1(secp256k1::PubKey {
key: signer.public_key(),
})),
mode_info: ModeInfo::Single {
mode: SignMode::Direct,
},
sequence: account.sequence,
}]
.to_vec(),
fee: self.gas_config().mk_fee(self.gas_config().max_gas).clone(),
};

let simulation_signature = signer
.try_sign(
&SignDoc {
body_bytes: tx_body.clone().encode_as::<Proto>(),
auth_info_bytes: auth_info.clone().encode_as::<Proto>(),
chain_id: self.tm_chain_id().to_string(),
account_number: account.account_number,
}
.encode_as::<Proto>(),
)
.expect("signing failed")
.to_vec();

let simulation_gas_info = {
let result = client
.simulate(tx::v1beta1::SimulateRequest {
tx_bytes: Tx {
body: tx_body.clone(),
auth_info: auth_info.clone(),
signatures: [simulation_signature.clone()].to_vec(),
}
.encode_as::<Proto>(),
..Default::default()
})
.await;

match result {
Ok(ok) => ok
.into_inner()
.gas_info
.expect("gas info is present on successful simulation result"),
Err(err) => {
error!(error = %err.message(), "tx simulation failed");
return Err(BroadcastTxCommitError::SimulateTx(err.message().to_owned()));
}
}
};
.map_err(BroadcastTxCommitError::SimulateTx)?;

info!(
gas_used = %simulation_gas_info.gas_used,
Expand Down Expand Up @@ -397,6 +335,83 @@ pub trait CosmosSdkChainExt: CosmosSdkChainRpcs {
}
}

async fn simulate_tx(
&self,
signer: &CosmosSigner,
messages: impl IntoIterator<Item = protos::google::protobuf::Any> + Clone,
memo: String,
) -> Result<(TxBody, AuthInfo, GasInfo), String> {
use protos::cosmos::tx;

let account = self.account_info(&signer.to_string()).await;

let mut client = tx::v1beta1::service_client::ServiceClient::connect(self.grpc_url())
.await
.unwrap();

let tx_body = TxBody {
messages: messages.clone().into_iter().collect(),
memo,
timeout_height: 0,
extension_options: vec![],
non_critical_extension_options: vec![],
};

let auth_info = AuthInfo {
signer_infos: [SignerInfo {
public_key: Some(AnyPubKey::Secp256k1(secp256k1::PubKey {
key: signer.public_key(),
})),
mode_info: ModeInfo::Single {
mode: SignMode::Direct,
},
sequence: account.sequence,
}]
.to_vec(),
fee: self.gas_config().mk_fee(self.gas_config().max_gas).clone(),
};

let simulation_signature = signer
.try_sign(
&SignDoc {
body_bytes: tx_body.clone().encode_as::<Proto>(),
auth_info_bytes: auth_info.clone().encode_as::<Proto>(),
chain_id: self.tm_chain_id().to_string(),
account_number: account.account_number,
}
.encode_as::<Proto>(),
)
.expect("signing failed")
.to_vec();

let result = client
.simulate(tx::v1beta1::SimulateRequest {
tx_bytes: Tx {
body: tx_body.clone(),
auth_info: auth_info.clone(),
signatures: [simulation_signature.clone()].to_vec(),
}
.encode_as::<Proto>(),
..Default::default()
})
.await;

match result {
Ok(ok) => Ok((
tx_body,
auth_info,
ok.into_inner()
.gas_info
.expect("gas info is present on successful simulation result")
.into(),
)),
Err(err) => {
info!(error = %err.message(), "tx simulation failed");
Err(err.message().to_owned())
}
}
}

async fn account_info(&self, account: &str) -> BaseAccount {
debug!(%account, "fetching account");
let Any(account) =
Expand Down
60 changes: 50 additions & 10 deletions lib/relay-message/src/chain/cosmos_sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ use chain_utils::{
keyring::ChainKeyring,
};
use frame_support_procedural::{CloneNoBound, PartialEqNoBound};
use futures::{stream, FutureExt, StreamExt};
use queue_msg::{data, effect, fetch, noop, seq, wait, Op};
use tracing::{debug, info};
use tracing::{debug, error, info};
use unionlabs::{
encoding::{Decode, DecodeAs, DecodeErrorOf, Encode, Proto},
google::protobuf::any::{mk_any, IntoAny},
Expand Down Expand Up @@ -70,27 +71,66 @@ where
.with(|signer| {
let msg = msg.clone();

// TODO: Figure out a way to thread this value through
let memo = format!("Voyager {}", env!("CARGO_PKG_VERSION"));

async move {
let msgs = process_msgs(msg, signer, mk_create_client_states, mk_client_message);
let mut msgs =
process_msgs(msg, signer, mk_create_client_states, mk_client_message);

let simulation_results = stream::iter(msgs.clone().into_iter().enumerate())
.then(|(idx, msg)| {
let type_url = msg.type_url.clone();
hc.simulate_tx(signer, [msg], memo.clone())
.map(move |res| (idx, type_url, res))
})
.collect::<Vec<(usize, String, Result<_, _>)>>()
.await;

// iterate backwards such that when we remove items from msgs, we don't shift the relative indices
for (idx, type_url, simulation_result) in simulation_results.into_iter().rev() {
match simulation_result {
Ok((_, _, gas_info)) => {
debug!(
msg = %type_url,
%idx,
gas_wanted = %gas_info.gas_wanted,
gas_used = %gas_info.gas_used,
"individual message simulation successful"
)
}
Err(error) => {
error!(
%error,
msg = %type_url,
%idx,
"individual message simulation failed"
);

msgs.remove(idx);
}
}
}

if msgs.is_empty() {
info!(
"no messages remaining to submit after filtering out failed transactions"
);
return Ok(());
}

let batch_size = msgs.len();
let msg_names = msgs.iter().map(|x| x.type_url.clone()).collect::<Vec<_>>();

let (tx_hash, gas_used) = hc
.broadcast_tx_commit(
signer,
msgs,
// TODO: Figure out a way to thread this value through
format!("Voyager {}", env!("CARGO_PKG_VERSION")),
)
.await?;
let (tx_hash, gas_used) = hc.broadcast_tx_commit(signer, msgs, memo).await?;

info!(
%tx_hash,
%gas_used,
batch.size = %batch_size,
"submitted cosmos transaction"
);

for msg in msg_names {
info!(%tx_hash, %msg, "cosmos tx");
}
Expand Down
1 change: 1 addition & 0 deletions lib/unionlabs/src/cosmos/base.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod abci;
pub mod coin;
pub mod query;
1 change: 1 addition & 0 deletions lib/unionlabs/src/cosmos/base/abci.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod gas_info;
25 changes: 25 additions & 0 deletions lib/unionlabs/src/cosmos/base/abci/gas_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use macros::model;

#[model(proto(raw(protos::cosmos::base::abci::v1beta1::GasInfo), from, into))]
pub struct GasInfo {
pub gas_wanted: u64,
pub gas_used: u64,
}

impl From<protos::cosmos::base::abci::v1beta1::GasInfo> for GasInfo {
fn from(value: protos::cosmos::base::abci::v1beta1::GasInfo) -> Self {
Self {
gas_wanted: value.gas_wanted,
gas_used: value.gas_used,
}
}
}

impl From<GasInfo> for protos::cosmos::base::abci::v1beta1::GasInfo {
fn from(value: GasInfo) -> Self {
Self {
gas_wanted: value.gas_wanted,
gas_used: value.gas_used,
}
}
}
2 changes: 1 addition & 1 deletion voyager-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"preset_base": "minimal",
"ibc_commitment_slot": "0",
"ibc_handler_address": "0xed2af2ad7fe0d92011b26a2e5d1b4dc7d12a47c5",
"multicall_address": "0x72459D25D5e30ec16b9Ac91cfB7e5a7969347E58",
"multicall_address": "0x9fd9D9528c8373D990a1380B9414bDE179007A35",
"keyring": {
"name": "ethereum-devnet",
"keys": [
Expand Down

0 comments on commit 8693e7d

Please sign in to comment.