Skip to content

Commit

Permalink
feat: add sudt into test case
Browse files Browse the repository at this point in the history
  • Loading branch information
liyukun committed Sep 6, 2023
1 parent ed4cd0a commit 3eee8cf
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 19 deletions.
2 changes: 1 addition & 1 deletion crates/relayer/src/chain/ckb4ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1169,7 +1169,7 @@ impl ChainEndpoint for Ckb4IbcChain {
} else {
// no matter the `data` is empty or not, we recognize the acknowledge is committed
// if the `WriteAck` cell exists
let ack_commitment = keccak256(&ibc_packet.packet.data).to_vec();
let ack_commitment = keccak256(&ibc_packet.packet.rlp_bytes()).to_vec();
Ok((ack_commitment, None))
}
} else {
Expand Down
29 changes: 21 additions & 8 deletions tools/ibc-test/src/tests/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,19 @@ impl BinaryChannelTest for CKB4IbcPacketTest {

// 2. trigger SendPacket event on ChainA
info!("send send_packet transaction to chain_a");
let message = b"ping".to_vec();
let relayer_on_a = chain_a_config.user_lock_script().calc_script_hash();
let message = ICS20Transfer {
denom: "AT".to_owned(),
amount: 1000,
sender: relayer_on_a.raw_data().to_vec(),
receiver: relayer_on_a.raw_data().to_vec(),
};
let send_packet_tx = generate_send_packet_transaction(
&rt,
&chain_a_config,
&chain_a_url,
&chain_a_signer,
message,
&message,
)?;
let hash = send_transaction(&chain_a_url, send_packet_tx)?;
info!(
Expand All @@ -104,18 +110,20 @@ impl BinaryChannelTest for CKB4IbcPacketTest {
listen_and_wait_packet_cell(&rt, &chain_b_url, &chain_b_config, |packet| {
packet.is_recv_packet()
})?;
info!("🍻 successfully find recv_packet cell on chain_b");
let payload: ICS20Transfer =
serde_json::from_slice(&recv_packet.packet.packet.data).expect("ics20 message");
let relayer_on_b = chain_b_config.user_lock_script().calc_script_hash();
assert!(payload == message && payload.receiver == relayer_on_b.raw_data().to_vec());
info!("🍻 successfully find recv_packet cell on chain_b: {payload}");

// 4. trigger WriteAck event on ChainB
info!("send write_ack transaction to chain_b");
let acknowledgemnt = b"pong".to_vec();
let write_ack_tx = generate_write_ack_transaction(
&rt,
&chain_b_config,
&chain_b_url,
&chain_b_signer,
recv_packet,
acknowledgemnt,
)?;
let hash = send_transaction(&chain_b_url, write_ack_tx)?;
info!(
Expand Down Expand Up @@ -163,14 +171,19 @@ fn trigger_send_packet() {

let (chain_a_config, chain_a_url, chain_a_signer) =
prepare_artificials(&config, &chain_id_a, &channel_id_a).unwrap();

let message = b"ping".to_vec();
let relayer_on_a = chain_a_config.user_lock_script().calc_script_hash();
let message = ICS20Transfer {
denom: "AT".to_owned(),
amount: 1000,
sender: relayer_on_a.raw_data().to_vec(),
receiver: relayer_on_a.raw_data().to_vec(),
};
let send_packet_tx = generate_send_packet_transaction(
&rt,
&chain_a_config,
&chain_a_url,
&chain_a_signer,
message,
&message,
)
.unwrap();

Expand Down
143 changes: 133 additions & 10 deletions tools/ibc-test/src/tests/packet/utils.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use ckb_jsonrpc_types::{OutputsValidator, TransactionView as JsonTxView};
use ckb_sdk::constants::TYPE_ID_CODE_HASH;
use ckb_sdk::rpc::ckb_indexer::ScriptSearchMode;
use ckb_sdk::rpc::ckb_light_client::{Order, ScriptType, SearchKey};
use ckb_sdk::traits::SecpCkbRawKeySigner;
use ckb_sdk::traits::{CellQueryOptions, SecpCkbRawKeySigner, ValueRangeOption};
use ckb_sdk::unlock::{ScriptSigner, SecpSighashScriptSigner};
use ckb_sdk::{AddressPayload, CkbRpcClient, HumanCapacity};
use ckb_sdk::{ScriptGroup, ScriptGroupType};
use ckb_types::core::{Capacity, ScriptHashType, TransactionBuilder, TransactionView};
use ckb_types::packed::{CellDep, CellOutput, Script};
use ckb_types::packed::{CellDep, CellInput, CellOutput, Script};
use ckb_types::prelude::{Builder, Entity, Pack, Unpack};
use ckb_types::H256;
use eyre::{eyre, Result as EyreResult};
Expand All @@ -27,14 +28,37 @@ use relayer::chain::ckb::prelude::{CkbReader, TxCompleter};
use relayer::chain::ckb::rpc_client::RpcClient;
use relayer::chain::ChainType;
use relayer::config::ChainConfig;
use rlp::Encodable;
use secp256k1::{Secp256k1, SecretKey};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::str::FromStr;
use tiny_keccak::Hasher;
use tokio::runtime::Runtime;

use crate::consts::CLIENT_TYPE_ARGS;
use crate::consts::{CLIENT_TYPE_ARGS, SUDT_CODE_HASH, SUDT_TYPE_ARGS};
use crate::generator::{get_lock_script, PRIVKEY};

#[derive(Serialize, Deserialize, PartialEq)]
pub struct ICS20Transfer {
pub denom: String,
pub amount: u64,
pub sender: Vec<u8>,
pub receiver: Vec<u8>,
}

impl std::fmt::Display for ICS20Transfer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&format!(
"Ics20_transfer {{ denom: {}, amount: {}, sender: {}, receiver: {} }}",
self.denom,
self.amount,
hex::encode(&self.sender),
hex::encode(&self.receiver)
))
}
}

fn error_cast<T: ToString>(error: T) -> eyre::Error {
eyre!("{}", error.to_string())
}
Expand Down Expand Up @@ -109,9 +133,10 @@ fn complete_partial_transaction(
sdk_config: &SdkConfig,
envelope: Option<Envelope>,
signer: &SecpSighashScriptSigner,
signature_start: Option<usize>,
) -> EyreResult<TransactionView> {
let partial_tx = partial_tx.build();
let signature_start = partial_tx.inputs().len();
let signature_start = signature_start.unwrap_or(partial_tx.inputs().len());
let unsigned_tx_without_envelope =
fill_transaction_with_secp256k1_change(rt, ckb_url, partial_tx)?;
let unsigned_tx = envelope.map_or(unsigned_tx_without_envelope.clone(), |value| {
Expand All @@ -132,6 +157,77 @@ fn complete_partial_transaction(
Ok(signed_tx)
}

fn search_sudt_cells(
rt: &Runtime,
ckb_url: &str,
) -> EyreResult<(CellDep, CellInput, CellOutput, u128)> {
let sdk_rpc = SdkRpcClient::new(ckb_url.to_owned());

// search sUDT contract
let sudt_contract_type_script = Script::new_builder()
.code_hash(TYPE_ID_CODE_HASH.pack())
.hash_type(ScriptHashType::Type.into())
.args(SUDT_TYPE_ARGS.as_bytes().pack())
.build();
let mut query = CellQueryOptions::new_type(sudt_contract_type_script);
query.script_search_mode = Some(ScriptSearchMode::Exact);
let sudt_contract_cell = rt
.block_on(sdk_rpc.get_cells(query.into(), Order::Asc, 1.into(), None))
.map_err(error_cast)?
.objects
.first()
.cloned()
.ok_or(eyre!("sudt contract not deployed"))?;
let sudt_celldep = CellDep::new_builder()
.out_point(sudt_contract_cell.out_point.into())
.build();

// search sUDT cell
let (lock_script, _, address) = get_lock_script(PRIVKEY);
let sudt_type_script = Script::new_builder()
.code_hash(SUDT_CODE_HASH.pack())
.hash_type(ScriptHashType::Type.into())
.args(lock_script.calc_script_hash().as_slice().pack())
.build();
let mut query = CellQueryOptions::new_type(sudt_type_script);
query.with_data = Some(true);
query.data_len_range = Some(ValueRangeOption::new_exact(16));
query.script_search_mode = Some(ScriptSearchMode::Exact);
let sudt_cell = rt
.block_on(sdk_rpc.get_cells(query.into(), Order::Asc, 1.into(), None))
.map_err(error_cast)?
.objects
.first()
.cloned()
.ok_or(eyre!("sudt cell not found on {address}"))?;

let sudt_input = CellInput::new_builder()
.previous_output(sudt_cell.out_point.into())
.build();
let sudt_amount = u128::from_le_bytes(
sudt_cell
.output_data
.unwrap()
.as_bytes()
.try_into()
.unwrap(),
);
Ok((
sudt_celldep,
sudt_input,
sudt_cell.output.into(),
sudt_amount,
))
}

pub fn keccak256(slice: &[u8]) -> [u8; 32] {
let mut hasher = tiny_keccak::Keccak::v256();
hasher.update(slice);
let mut output = [0u8; 32];
hasher.finalize(&mut output);
output
}

pub fn tx_error_cast<T: ToString>(error: T, tx: TransactionView) -> eyre::Error {
eyre!(
"{}\n\ntransaction info: {}\n",
Expand Down Expand Up @@ -252,30 +348,46 @@ pub fn generate_send_packet_transaction(
sdk_config: &SdkConfig,
ckb_url: &str,
signer: &SecpSighashScriptSigner,
payload: Vec<u8>,
message: &ICS20Transfer,
) -> EyreResult<TransactionView> {
// prepare ingredients
let (sudt_celldep, sudt_input, sudt_output, total_amount) = search_sudt_cells(rt, ckb_url)?;
let (metadata_celldep, channel_contract_celldep, _, ibc_channel) =
prepare_celldeps_and_channel(rt, ckb_url, sdk_config)?;

// assemble partial transaction
let (send_packet_tx, envelope) = assemble_send_packet_partial_transaction(
metadata_celldep,
channel_contract_celldep,
sdk_config,
ibc_channel,
payload,
serde_json::to_vec(message).unwrap(),
0,
0,
)
.map_err(error_cast)?;
if message.amount as u128 > total_amount {
return Err(eyre!(
"sufficient token: {} > {total_amount}",
message.amount
));
}
let sudt_amount = total_amount - message.amount as u128;
let partial_tx = send_packet_tx
.cell_dep(sudt_celldep)
.input(sudt_input)
.output(sudt_output)
.output_data(sudt_amount.to_le_bytes().to_vec().pack());

// complete partial transaction
let signed_tx = complete_partial_transaction(
rt,
send_packet_tx,
partial_tx,
ckb_url,
sdk_config,
Some(envelope),
signer,
Some(1),
)?;
Ok(signed_tx)
}
Expand Down Expand Up @@ -303,30 +415,40 @@ pub fn generate_write_ack_transaction(
ckb_url: &str,
signer: &SecpSighashScriptSigner,
recv_packet: PacketCell,
acknowledgement: Vec<u8>,
) -> EyreResult<TransactionView> {
// prepare ingredients
let (sudt_celldep, _, sudt_output, total_amount) = search_sudt_cells(rt, ckb_url)?;
let (metadata_celldep, channel_contract_celldep, packet_contract_celldep, ibc_channel) =
prepare_celldeps_and_channel(rt, ckb_url, sdk_config)?;

// assemble partial transaction
let acknowledgement = keccak256(&recv_packet.packet.packet.rlp_bytes());
let payload: ICS20Transfer = serde_json::from_slice(&recv_packet.packet.packet.data).unwrap();
let (write_ack_tx, envelope) = assemble_write_ack_partial_transaction(
metadata_celldep,
channel_contract_celldep,
packet_contract_celldep,
sdk_config,
ibc_channel,
recv_packet,
acknowledgement,
acknowledgement.to_vec(),
)
.map_err(error_cast)?;
let sudt_amount = total_amount + payload.amount as u128;
let partial_tx = write_ack_tx
.cell_dep(sudt_celldep)
.output(sudt_output)
.output_data(sudt_amount.to_le_bytes().to_vec().pack());

// complete partial transaction
let signed_tx = complete_partial_transaction(
rt,
write_ack_tx,
partial_tx,
ckb_url,
sdk_config,
Some(envelope),
signer,
None,
)?;
Ok(signed_tx)
}
Expand Down Expand Up @@ -363,6 +485,7 @@ pub fn generate_consume_ack_packet_transaction(
sdk_config,
Some(envelope),
signer,
None,
)?;
Ok(signed_tx)
}

0 comments on commit 3eee8cf

Please sign in to comment.