From e76f07b60a739b8d1e19d052865acc86f38601c2 Mon Sep 17 00:00:00 2001 From: AntonAndell Date: Sun, 13 Oct 2024 10:02:30 +0200 Subject: [PATCH 1/6] fix: Add auth on handle_error --- contracts/soroban/contracts/xcall/src/handle_message.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/soroban/contracts/xcall/src/handle_message.rs b/contracts/soroban/contracts/xcall/src/handle_message.rs index 3506b45e..56831a99 100644 --- a/contracts/soroban/contracts/xcall/src/handle_message.rs +++ b/contracts/soroban/contracts/xcall/src/handle_message.rs @@ -160,6 +160,7 @@ pub fn handle_reply( } pub fn handle_error(env: &Env, sender: Address, sequence_no: u128) -> Result<(), ContractError> { + sender.require_auth(); let cs_message_result = CSMessageResult::new( sequence_no, CSResponseType::CSResponseFailure, From 178531769d2fd7f45192dc284d2c847816768fa9 Mon Sep 17 00:00:00 2001 From: bishalbikram Date: Fri, 18 Oct 2024 12:28:11 +0545 Subject: [PATCH 2/6] fix: change proxy request account seeds derivation parameters --- .../solana/libs/xcall-lib/src/xcall_type.rs | 6 +++ .../centralized-connection/src/helper.rs | 2 + .../src/instructions/query_accounts.rs | 20 +++++--- .../centralized-connection/src/lib.rs | 2 +- .../instructions/execute_forced_rollback.rs | 5 +- .../programs/mock-dapp-multi/src/lib.rs | 5 +- .../programs/mock-dapp-multi/src/xcall.rs | 14 +++++- contracts/solana/programs/xcall/src/event.rs | 2 + .../xcall/src/instructions/execute_call.rs | 4 +- .../instructions/handle_forced_rollback.rs | 4 +- .../xcall/src/instructions/handle_message.rs | 48 ++++++++++++++----- .../xcall/src/instructions/query_accounts.rs | 24 ++++++++-- contracts/solana/programs/xcall/src/lib.rs | 44 +++++++++++++++-- .../centralized-connection.ts | 40 ++++++++++++++-- .../tests/centralized-connection/setup.ts | 3 +- contracts/solana/tests/xcall/setup.ts | 42 +++++++++++++--- 16 files changed, 215 insertions(+), 50 deletions(-) diff --git a/contracts/solana/libs/xcall-lib/src/xcall_type.rs b/contracts/solana/libs/xcall-lib/src/xcall_type.rs index 3ec5cf07..aaececfa 100644 --- a/contracts/solana/libs/xcall-lib/src/xcall_type.rs +++ b/contracts/solana/libs/xcall-lib/src/xcall_type.rs @@ -25,12 +25,14 @@ pub struct HandleMessageArgs { pub from_nid: String, pub message: Vec, pub sequence_no: u128, + pub conn_sn: u128, } #[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize)] pub struct HandleRequestArgs { pub from_nid: String, pub msg_payload: Vec, + pub conn_sn: u128, } #[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize)] @@ -38,6 +40,7 @@ pub struct HandleResultArgs { pub from_nid: String, pub msg_payload: Vec, pub sequence_no: u128, + pub conn_sn: u128, } #[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize)] @@ -48,4 +51,7 @@ pub struct HandleErrorArgs { #[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize)] pub struct HandleForcedRollback { pub req_id: u128, + pub from_nid: String, + pub conn_sn: u128, + pub connection: Pubkey, } diff --git a/contracts/solana/programs/centralized-connection/src/helper.rs b/contracts/solana/programs/centralized-connection/src/helper.rs index 927c17a5..96ead7ab 100644 --- a/contracts/solana/programs/centralized-connection/src/helper.rs +++ b/contracts/solana/programs/centralized-connection/src/helper.rs @@ -46,12 +46,14 @@ pub fn call_xcall_handle_message<'info>( from_nid: String, message: Vec, sequence_no: u128, + conn_sn: u128, ) -> Result<()> { let mut data = vec![]; let args = xcall_type::HandleMessageArgs { from_nid, message, sequence_no, + conn_sn, }; args.serialize(&mut data)?; diff --git a/contracts/solana/programs/centralized-connection/src/instructions/query_accounts.rs b/contracts/solana/programs/centralized-connection/src/instructions/query_accounts.rs index 7f149623..9f21112f 100644 --- a/contracts/solana/programs/centralized-connection/src/instructions/query_accounts.rs +++ b/contracts/solana/programs/centralized-connection/src/instructions/query_accounts.rs @@ -2,7 +2,7 @@ use anchor_lang::{ prelude::*, solana_program::{ instruction::Instruction, - program::{get_return_data, invoke}, + program::{get_return_data, invoke, invoke_signed}, system_program, }, }; @@ -35,8 +35,8 @@ pub fn query_send_message_accounts<'info>( }) } -pub fn query_recv_message_accounts( - ctx: Context, +pub fn query_recv_message_accounts<'info>( + ctx: Context<'_, '_, '_, 'info, QueryAccountsCtx<'info>>, src_network: String, conn_sn: u128, msg: Vec, @@ -65,8 +65,8 @@ pub fn query_recv_message_accounts( AccountMetadata::new(authority, false), ]; - let mut xcall_account_metas = vec![]; - let mut xcall_account_infos = vec![]; + let mut xcall_account_metas = vec![AccountMeta::new_readonly(config.key(), true)]; + let mut xcall_account_infos = vec![config.to_account_info()]; for (_, account) in ctx.remaining_accounts.iter().enumerate() { if account.is_writable { @@ -78,7 +78,7 @@ pub fn query_recv_message_accounts( xcall_account_infos.push(account.to_account_info()) } - let ix_data = get_handle_message_ix_data(src_network, msg, sequence_no)?; + let ix_data = get_handle_message_ix_data(src_network, msg, sequence_no, conn_sn)?; let ix = Instruction { program_id: config.xcall, @@ -86,7 +86,11 @@ pub fn query_recv_message_accounts( data: ix_data, }; - invoke(&ix, &xcall_account_infos)?; + invoke_signed( + &ix, + &xcall_account_infos, + &[&[Config::SEED_PREFIX.as_bytes(), &[config.bump]]], + )?; let (_, data) = get_return_data().unwrap(); let mut data_slice: &[u8] = &data; @@ -171,12 +175,14 @@ pub fn get_handle_message_ix_data( from_nid: String, message: Vec, sequence_no: u128, + conn_sn: u128, ) -> Result> { let mut ix_args_data = vec![]; let ix_args = xcall_type::HandleMessageArgs { from_nid, message, sequence_no, + conn_sn, }; ix_args.serialize(&mut ix_args_data)?; diff --git a/contracts/solana/programs/centralized-connection/src/lib.rs b/contracts/solana/programs/centralized-connection/src/lib.rs index 7bb0ac67..a7755eef 100644 --- a/contracts/solana/programs/centralized-connection/src/lib.rs +++ b/contracts/solana/programs/centralized-connection/src/lib.rs @@ -72,7 +72,7 @@ pub mod centralized_connection { msg: Vec, sequence_no: u128, ) -> Result<()> { - helper::call_xcall_handle_message(ctx, src_network, msg, sequence_no) + helper::call_xcall_handle_message(ctx, src_network, msg, sequence_no, conn_sn) } pub fn revert_message<'info>( diff --git a/contracts/solana/programs/mock-dapp-multi/src/instructions/execute_forced_rollback.rs b/contracts/solana/programs/mock-dapp-multi/src/instructions/execute_forced_rollback.rs index 3fe45ae7..7bd63c64 100644 --- a/contracts/solana/programs/mock-dapp-multi/src/instructions/execute_forced_rollback.rs +++ b/contracts/solana/programs/mock-dapp-multi/src/instructions/execute_forced_rollback.rs @@ -6,8 +6,11 @@ use crate::{state::*, xcall}; pub fn execute_forced_rollback<'info>( ctx: Context<'_, '_, '_, 'info, ExecuteForcedRollbackCtx<'info>>, req_id: u128, + from_nid: String, + conn_sn: u128, + connection: Pubkey, ) -> Result<()> { - let ix_data = xcall::get_handle_forced_rollback_ix_data(req_id)?; + let ix_data = xcall::get_handle_forced_rollback_ix_data(req_id, from_nid, conn_sn, connection)?; xcall::call_xcall_handle_forced_rollback( &ix_data, diff --git a/contracts/solana/programs/mock-dapp-multi/src/lib.rs b/contracts/solana/programs/mock-dapp-multi/src/lib.rs index c56b9bb8..2b0f3a86 100644 --- a/contracts/solana/programs/mock-dapp-multi/src/lib.rs +++ b/contracts/solana/programs/mock-dapp-multi/src/lib.rs @@ -64,8 +64,11 @@ pub mod mock_dapp_multi { pub fn execute_forced_rollback<'info>( ctx: Context<'_, '_, '_, 'info, ExecuteForcedRollbackCtx<'info>>, req_id: u128, + from_nid: String, + conn_sn: u128, + connection: Pubkey, ) -> Result<()> { - instructions::execute_forced_rollback(ctx, req_id) + instructions::execute_forced_rollback(ctx, req_id, from_nid, conn_sn, connection) } #[allow(unused_variables)] diff --git a/contracts/solana/programs/mock-dapp-multi/src/xcall.rs b/contracts/solana/programs/mock-dapp-multi/src/xcall.rs index d4cc32f7..7fd367fd 100644 --- a/contracts/solana/programs/mock-dapp-multi/src/xcall.rs +++ b/contracts/solana/programs/mock-dapp-multi/src/xcall.rs @@ -100,9 +100,19 @@ pub fn get_send_call_ix_data(msg: Vec, to: NetworkAddress) -> Result Ok(ix_data) } -pub fn get_handle_forced_rollback_ix_data(req_id: u128) -> Result> { +pub fn get_handle_forced_rollback_ix_data( + req_id: u128, + from_nid: String, + conn_sn: u128, + connection: Pubkey, +) -> Result> { let mut ix_args_data = vec![]; - let ix_args = xcall_type::HandleForcedRollback { req_id }; + let ix_args = xcall_type::HandleForcedRollback { + req_id, + from_nid, + conn_sn, + connection, + }; ix_args.serialize(&mut ix_args_data)?; let ix_data = helpers::get_instruction_data(HANDLE_FORCED_ROLLBACK_IX, ix_args_data); diff --git a/contracts/solana/programs/xcall/src/event.rs b/contracts/solana/programs/xcall/src/event.rs index c2190054..3d4bf653 100644 --- a/contracts/solana/programs/xcall/src/event.rs +++ b/contracts/solana/programs/xcall/src/event.rs @@ -16,6 +16,8 @@ pub struct CallMessage { pub sn: u128, pub reqId: u128, pub data: Vec, + pub connection: Pubkey, + pub connSn: u128, } #[event] diff --git a/contracts/solana/programs/xcall/src/instructions/execute_call.rs b/contracts/solana/programs/xcall/src/instructions/execute_call.rs index 1ea976b7..32935034 100644 --- a/contracts/solana/programs/xcall/src/instructions/execute_call.rs +++ b/contracts/solana/programs/xcall/src/instructions/execute_call.rs @@ -96,7 +96,7 @@ pub fn execute_call<'info>( } #[derive(Accounts)] -#[instruction(req_id : u128)] +#[instruction(req_id : u128, from_nid: String, conn_sn: u128, connection: Pubkey)] pub struct ExecuteCallCtx<'info> { /// The account that signs and pays for the transaction. This account is mutable /// because it will be debited for any fees or rent required during the transaction. @@ -125,7 +125,7 @@ pub struct ExecuteCallCtx<'info> { /// calls. The account is closed after use, with any remaining funds sent to the `admin`. #[account( mut, - seeds = [ProxyRequest::SEED_PREFIX.as_bytes(), &req_id.to_be_bytes()], + seeds = [ProxyRequest::SEED_PREFIX.as_bytes(), from_nid.as_bytes(), &conn_sn.to_be_bytes(), &connection.to_bytes()], bump = proxy_request.bump, close = admin )] diff --git a/contracts/solana/programs/xcall/src/instructions/handle_forced_rollback.rs b/contracts/solana/programs/xcall/src/instructions/handle_forced_rollback.rs index 19b02b37..424ec86d 100644 --- a/contracts/solana/programs/xcall/src/instructions/handle_forced_rollback.rs +++ b/contracts/solana/programs/xcall/src/instructions/handle_forced_rollback.rs @@ -77,7 +77,7 @@ pub fn handle_forced_rollback<'info>( } #[derive(Accounts)] -#[instruction(req_id: u128)] +#[instruction(req_id: u128, from_nid: String, conn_sn: u128, connection: Pubkey)] pub struct HandleForcedRollbackCtx<'info> { /// The account that signs and pays for the transaction. This account is mutable because /// it will be debited for any fees or rent required during the transaction. @@ -111,7 +111,7 @@ pub struct HandleForcedRollbackCtx<'info> { /// calls and is closed after use, with any remaining funds sent to the `admin`. #[account( mut, - seeds = [ProxyRequest::SEED_PREFIX.as_bytes(), &req_id.to_be_bytes()], + seeds = [ProxyRequest::SEED_PREFIX.as_bytes(), from_nid.as_bytes(), &conn_sn.to_be_bytes(), &connection.to_bytes()], bump = proxy_request.bump, close = admin )] diff --git a/contracts/solana/programs/xcall/src/instructions/handle_message.rs b/contracts/solana/programs/xcall/src/instructions/handle_message.rs index 562ea80e..7450194b 100644 --- a/contracts/solana/programs/xcall/src/instructions/handle_message.rs +++ b/contracts/solana/programs/xcall/src/instructions/handle_message.rs @@ -26,6 +26,8 @@ use crate::{ /// - `message`: The encoded message payload received from the chain. /// - `sequence_no`: The sequence number associated with the message, used to track message /// ordering and responses. +/// - `conn_sn`: The sequence number of connection associated with the message, used to derive +/// unique proxy request account with the combination of other parameters /// /// # Returns /// - `Result<()>`: Returns `Ok(())` if successful, or an appropriate error if any validation or @@ -35,6 +37,7 @@ pub fn handle_message<'info>( from_nid: String, message: Vec, sequence_no: u128, + conn_sn: u128, ) -> Result<()> { let config = &ctx.accounts.config; if config.network_id == from_nid.to_string() { @@ -48,7 +51,7 @@ pub fn handle_message<'info>( return Err(XcallError::PendingResponseAccountMustNotBeSpecified.into()); } - invoke_handle_request(ctx, from_nid, cs_message.payload)? + invoke_handle_request(ctx, from_nid, cs_message.payload, conn_sn)? } CSMessageType::CSMessageResult => { let rollback_account = ctx @@ -67,7 +70,7 @@ pub fn handle_message<'info>( return Ok(()); } - invoke_handle_result(ctx, from_nid, cs_message.payload, sequence_no)?; + invoke_handle_result(ctx, from_nid, cs_message.payload, sequence_no, conn_sn)?; } } Ok(()) @@ -84,6 +87,8 @@ pub fn handle_message<'info>( /// - `ctx`: Context containing all relevant accounts and program-specific information. /// - `from_nid`: Network ID of the source chain that sent the request. /// - `payload`: Encoded payload of the request message. +/// - `conn_sn`: The sequence number of connection associated with the message, used to derive +/// unique proxy request account with the combination of other parameters /// /// # Returns /// - `Result<()>`: Returns `Ok(())` if the request is successfully processed, or an error if @@ -92,6 +97,7 @@ pub fn handle_request( ctx: Context, from_nid: String, payload: &[u8], + conn_sn: u128, ) -> Result<()> { let mut req: CSMessageRequest = payload.try_into()?; @@ -128,7 +134,9 @@ pub fn handle_request( to: req.to().clone(), sn: req.sequence_no(), reqId: req_id, - data: req.data() + data: req.data(), + connection: source.owner.to_owned(), + connSn: conn_sn }); let proxy_request = &mut ctx.accounts.proxy_request; @@ -151,11 +159,13 @@ pub fn handle_request( /// # Arguments /// - `ctx`: The context of accounts involved in the operation. /// - `payload`: The raw result data from the cross-chain operation, which is decoded and processed. +/// - `conn_sn`: The sequence number of connection associated with the message, used to derive +/// unique proxy request account with the combination of other parameters /// /// # Returns /// - `Result<()>`: Returns `Ok(())` if the operation completes successfully, or an error if something /// goes wrong. -pub fn handle_result(ctx: Context, payload: &[u8]) -> Result<()> { +pub fn handle_result(ctx: Context, payload: &[u8], conn_sn: u128) -> Result<()> { let result: CSMessageResult = payload.try_into()?; let proxy_request = &ctx.accounts.proxy_request; let rollback_account = &mut ctx.accounts.rollback_account; @@ -180,7 +190,7 @@ pub fn handle_result(ctx: Context, payload: &[u8]) -> Result<() success_res.success = true; if let Some(message) = &mut result.message() { - handle_reply(ctx, message)?; + handle_reply(ctx, message, conn_sn)?; } else { if proxy_request.is_some() { return Err(XcallError::ProxyRequestAccountMustNotBeSpecified.into()); @@ -250,11 +260,17 @@ pub fn handle_error(ctx: Context, sequence_no: u128) -> Result<( /// # Arguments /// * `ctx` - The context containing relevant accounts for handling the reply. /// * `reply` - The mutable reference to the incoming reply message to be processed. +/// * `conn_sn`: The sequence number of connection associated with the message, used to derive +/// unique proxy request account with the combination of other parameters /// /// # Returns /// - `Result<()>`: Returns `Ok(())` if the operation completes successfully, or an error if something /// goes wrong. -pub fn handle_reply(ctx: Context, reply: &mut CSMessageRequest) -> Result<()> { +pub fn handle_reply( + ctx: Context, + reply: &mut CSMessageRequest, + conn_sn: u128, +) -> Result<()> { let rollback = &ctx.accounts.rollback_account.rollback; if rollback.to().nid() != reply.from().nid() { return Err(XcallError::InvalidReplyReceived.into()); @@ -267,7 +283,9 @@ pub fn handle_reply(ctx: Context, reply: &mut CSMessageRequest) to: reply.to().clone(), sn: reply.sequence_no(), reqId: req_id, - data: reply.data() + data: reply.data(), + connection: ctx.accounts.connection.owner.to_owned(), + connSn: conn_sn }); let proxy_request = ctx @@ -295,6 +313,8 @@ pub fn handle_reply(ctx: Context, reply: &mut CSMessageRequest) /// - `ctx`: The context containing the accounts and program-specific info needed for the instruction. /// - `from_nid`: The network ID of the chain that sent the request. /// - `msg_payload`: The payload of the request message received from the source chain. +/// - `conn_sn`: The sequence number of connection associated with the message, used to derive +/// unique proxy request account with the combination of other parameters /// /// # Returns /// - `Result<()>`: Indicates whether the invocation was successful or encountered an error. @@ -302,11 +322,13 @@ pub fn invoke_handle_request<'info>( ctx: Context<'_, '_, '_, 'info, HandleMessageCtx<'info>>, from_nid: String, msg_payload: Vec, + conn_sn: u128, ) -> Result<()> { let mut data = vec![]; let args = xcall_lib::xcall_type::HandleRequestArgs { from_nid, msg_payload, + conn_sn, }; args.serialize(&mut data)?; let ix_data = helper::get_instruction_data(xcall_lib::xcall_type::HANDLE_REQUEST_IX, data); @@ -362,6 +384,8 @@ pub fn invoke_handle_request<'info>( /// - `from_nid`: The network ID of the chain that sent the response. /// - `msg_payload`: The payload of the message received from the destination chain. /// - `sequence_no`: The sequence number associated with the original request message. +/// - `conn_sn`: The sequence number of connection associated with the message, used to derive +/// unique proxy request account with the combination of other parameters /// /// # Returns /// - `Result<()>`: Indicates whether the invocation was successful or encountered an error. @@ -370,12 +394,14 @@ pub fn invoke_handle_result<'info>( from_nid: String, msg_payload: Vec, sequence_no: u128, + conn_sn: u128, ) -> Result<()> { let mut data = vec![]; let args = xcall_lib::xcall_type::HandleResultArgs { from_nid, msg_payload, sequence_no, + conn_sn, }; args.serialize(&mut data)?; let ix_data = helper::get_instruction_data(xcall_lib::xcall_type::HANDLE_RESULT_IX, data); @@ -547,7 +573,7 @@ pub struct HandleMessageCtx<'info> { } #[derive(Accounts)] -#[instruction(from_nid: String, msg_payload: Vec)] +#[instruction(from_nid: String, msg_payload: Vec, conn_sn: u128)] pub struct HandleRequestCtx<'info> { /// The account that signs and pays for the transaction. This account is mutable /// because it will be debited for any fees or rent required during the transaction. @@ -590,7 +616,7 @@ pub struct HandleRequestCtx<'info> { init_if_needed, payer = signer, space = ProxyRequest::SIZE, - seeds = [ProxyRequest::SEED_PREFIX.as_bytes(), &(config.last_req_id + 1).to_be_bytes()], + seeds = [ProxyRequest::SEED_PREFIX.as_bytes(), from_nid.as_bytes(), &conn_sn.to_be_bytes(), &connection.owner.to_bytes()], bump )] pub proxy_request: Account<'info, ProxyRequest>, @@ -609,7 +635,7 @@ pub struct HandleRequestCtx<'info> { } #[derive(Accounts)] -#[instruction(from_nid: String, msg_payload: Vec, sequence_no: u128)] +#[instruction(from_nid: String, msg_payload: Vec, sequence_no: u128, conn_sn: u128)] pub struct HandleResultCtx<'info> { /// The account that signs and pays for the transaction. This account is mutable /// because it will be debited for any fees or rent required during the transaction. @@ -664,7 +690,7 @@ pub struct HandleResultCtx<'info> { init_if_needed, payer = signer, space = ProxyRequest::SIZE, - seeds = [ProxyRequest::SEED_PREFIX.as_bytes(), &(config.last_req_id + 1).to_be_bytes()], + seeds = [ProxyRequest::SEED_PREFIX.as_bytes(), from_nid.as_bytes(), &conn_sn.to_be_bytes(), &connection.owner.to_bytes()], bump )] pub proxy_request: Option>, diff --git a/contracts/solana/programs/xcall/src/instructions/query_accounts.rs b/contracts/solana/programs/xcall/src/instructions/query_accounts.rs index 23038e50..296e6483 100644 --- a/contracts/solana/programs/xcall/src/instructions/query_accounts.rs +++ b/contracts/solana/programs/xcall/src/instructions/query_accounts.rs @@ -28,15 +28,20 @@ use crate::{ pub fn query_handle_message_accounts( ctx: Context, + from_nid: String, msg: Vec, + conn_sn: u128, ) -> Result { + let connection = &ctx.accounts.connection; let config = &ctx.accounts.config; let admin = config.admin; let (proxy_request, _) = Pubkey::find_program_address( &[ ProxyRequest::SEED_PREFIX.as_bytes(), - &(config.last_req_id + 1).to_be_bytes(), + from_nid.as_bytes(), + &conn_sn.to_be_bytes(), + &connection.owner.to_bytes(), ], &id(), ); @@ -149,7 +154,9 @@ pub fn query_handle_message_accounts( pub fn query_execute_call_accounts( ctx: Context, - req_id: u128, + from_nid: String, + conn_sn: u128, + connection: Pubkey, data: Vec, page: u8, limit: u8, @@ -158,7 +165,12 @@ pub fn query_execute_call_accounts( let req = &ctx.accounts.proxy_request.req; let (proxy_request, _) = Pubkey::find_program_address( - &[ProxyRequest::SEED_PREFIX.as_bytes(), &req_id.to_be_bytes()], + &[ + ProxyRequest::SEED_PREFIX.as_bytes(), + from_nid.as_bytes(), + &conn_sn.to_be_bytes(), + &connection.to_bytes(), + ], &id(), ); @@ -342,7 +354,7 @@ pub fn query_connection_send_message_accoounts<'info>( } #[derive(Accounts)] -#[instruction(req_id: u128, data: Vec)] +#[instruction(req_id: u128, from_nid: String, conn_sn: u128, connection: Pubkey, data: Vec)] pub struct QueryExecuteCallAccountsCtx<'info> { #[account( seeds = [Config::SEED_PREFIX.as_bytes()], @@ -351,7 +363,7 @@ pub struct QueryExecuteCallAccountsCtx<'info> { pub config: Account<'info, Config>, #[account( - seeds = [ProxyRequest::SEED_PREFIX.as_bytes(), &req_id.to_be_bytes()], + seeds = [ProxyRequest::SEED_PREFIX.as_bytes(), from_nid.as_bytes(), &conn_sn.to_be_bytes(), &connection.to_bytes()], bump = proxy_request.bump )] pub proxy_request: Account<'info, ProxyRequest>, @@ -360,6 +372,8 @@ pub struct QueryExecuteCallAccountsCtx<'info> { #[derive(Accounts)] #[instruction(from_nid: String, msg: Vec, sequence_no: u128)] pub struct QueryHandleMessageAccountsCtx<'info> { + pub connection: Signer<'info>, + #[account( seeds = [Config::SEED_PREFIX.as_bytes()], bump = config.bump, diff --git a/contracts/solana/programs/xcall/src/lib.rs b/contracts/solana/programs/xcall/src/lib.rs index 4506dc4e..c4179343 100644 --- a/contracts/solana/programs/xcall/src/lib.rs +++ b/contracts/solana/programs/xcall/src/lib.rs @@ -137,6 +137,8 @@ pub mod xcall { /// - `msg`: The encoded message payload received from the chain. /// - `sequence_no`: The sequence number associated with the message, used to track message /// ordering and responses. + /// - `conn_sn`: The sequence number of connection associated with the message, used to derive + /// unique proxy request account with the combination of other parameters /// /// # Returns /// - `Result<()>`: Returns `Ok(())` if the message is successfully handled, or an error if any @@ -146,8 +148,9 @@ pub mod xcall { from_nid: String, msg: Vec, sequence_no: u128, + conn_sn: u128, ) -> Result<()> { - instructions::handle_message(ctx, from_nid, msg, sequence_no) + instructions::handle_message(ctx, from_nid, msg, sequence_no, conn_sn) } /// Instruction: Handle Request @@ -162,16 +165,20 @@ pub mod xcall { /// - `ctx`: Context containing all relevant accounts and program-specific information. /// - `from_nid`: Network ID of the chain that sent the request. /// - `msg_payload`: Encoded payload of the request message. + /// - `conn_sn`: The sequence number of connection associated with the message, used to derive + /// unique proxy request account with the combination of other parameters /// /// # Returns /// - `Result<()>`: Returns `Ok(())` if the request is processed successfully, or an error if /// validation or processing fails. + #[allow(unused_variables)] pub fn handle_request<'info>( ctx: Context<'_, '_, '_, 'info, HandleRequestCtx<'info>>, from_nid: String, msg_payload: Vec, + conn_sn: u128, ) -> Result<()> { - instructions::handle_request(ctx, from_nid, &msg_payload) + instructions::handle_request(ctx, from_nid, &msg_payload, conn_sn) } /// Instruction: Handle Result @@ -187,6 +194,8 @@ pub mod xcall { /// - `from_nid`: Network ID of the chain that sent the result. /// - `msg_payload`: Encoded payload of the result message. /// - `sequence_no`: Unique sequence number of the result message. + /// - `conn_sn`: The sequence number of connection associated with the message, used to derive + /// unique proxy request account with the combination of other parameters /// /// # Returns /// - `Result<()>`: Returns `Ok(())` if the result is processed successfully, or an error if @@ -197,8 +206,9 @@ pub mod xcall { from_nid: String, msg_payload: Vec, sequence_no: u128, + conn_sn: u128, ) -> Result<()> { - instructions::handle_result(ctx, &msg_payload) + instructions::handle_result(ctx, &msg_payload, conn_sn) } /// Instruction: Handle Error @@ -357,13 +367,22 @@ pub mod xcall { /// # Parameters /// - `ctx`: The context of the solana program instruction /// - `req_id`: The unique identifier for the request being processed. + /// - `from_nid`: Network ID of the chain that sent the request. + /// - `conn_sn`: The sequence number of connection associated with the message, used to derive + /// unique proxy request account with the combination of other parameters + /// - `connection`: The connection key used to derive proxy request account with the combination + /// of other parameters /// - `data`: The data associated with the call request, which will be verified and processed. /// /// # Returns /// - `Result<()>`: Returns `Ok(())` if the call was executed successfully, or an error if it failed. + #[allow(unused_variables)] pub fn execute_call<'info>( ctx: Context<'_, '_, '_, 'info, ExecuteCallCtx<'info>>, req_id: u128, + from_nid: String, + conn_sn: u128, + connection: Pubkey, data: Vec, ) -> Result<()> { instructions::execute_call(ctx, req_id, data) @@ -402,6 +421,11 @@ pub mod xcall { /// # Arguments /// * `ctx` - Context containing the accounts required for processing the forced rollback. /// * `req_id` - The unique request ID associated with the message being rolled back. + /// - `from_nid`: Network ID of the chain that sent the request. + /// - `conn_sn`: The sequence number of connection associated with the message, used to derive + /// unique proxy request account with the combination of other parameters + /// - `connection`: The connection key used to derive proxy request account with the combination + /// of other parameters /// /// # Returns /// * `Result<()>` - Returns `Ok(())` on successful execution, or an error if the rollback process @@ -410,18 +434,27 @@ pub mod xcall { pub fn handle_forced_rollback<'info>( ctx: Context<'_, '_, '_, 'info, HandleForcedRollbackCtx<'info>>, req_id: u128, + from_nid: String, + conn_sn: u128, + connection: Pubkey, ) -> Result<()> { instructions::handle_forced_rollback(ctx) } + #[allow(unused_variables)] pub fn query_execute_call_accounts<'info>( ctx: Context<'_, '_, '_, 'info, QueryExecuteCallAccountsCtx<'info>>, req_id: u128, + from_nid: String, + conn_sn: u128, + connection: Pubkey, data: Vec, page: u8, limit: u8, ) -> Result { - instructions::query_execute_call_accounts(ctx, req_id, data, page, limit) + instructions::query_execute_call_accounts( + ctx, from_nid, conn_sn, connection, data, page, limit, + ) } #[allow(unused_variables)] @@ -440,8 +473,9 @@ pub mod xcall { from_nid: String, msg: Vec, sequence_no: u128, + conn_sn: u128, ) -> Result { - instructions::query_handle_message_accounts(ctx, msg) + instructions::query_handle_message_accounts(ctx, from_nid, msg, conn_sn) } pub fn query_handle_error_accounts( diff --git a/contracts/solana/tests/centralized-connection/centralized-connection.ts b/contracts/solana/tests/centralized-connection/centralized-connection.ts index 7d3d51f2..8b873a64 100644 --- a/contracts/solana/tests/centralized-connection/centralized-connection.ts +++ b/contracts/solana/tests/centralized-connection/centralized-connection.ts @@ -182,6 +182,7 @@ describe("CentralizedConnection", () => { ).encode(); let recvMessageAccounts = await ctx.getRecvMessageAccounts( + fromNetwork, connSn, nextSequenceNo, cs_message, @@ -212,7 +213,11 @@ describe("CentralizedConnection", () => { expect(await ctx.getReceipt(fromNetwork, nextSequenceNo)).to.be.empty; // expect proxy request in xcall PDA's account - let proxyRequest = await xcallCtx.getProxyRequest(nextReqId); + let proxyRequest = await xcallCtx.getProxyRequest( + fromNetwork, + connSn, + connectionProgram.programId + ); expect(proxyRequest.req.protocols).to.includes( connectionProgram.programId.toString() ); @@ -229,17 +234,30 @@ describe("CentralizedConnection", () => { // call xcall execute_call let executeCallAccounts = await xcallCtx.getExecuteCallAccounts( nextReqId, + fromNetwork, + connSn, + connectionProgram.programId, data ); await xcallProgram.methods - .executeCall(new anchor.BN(nextReqId), Buffer.from(data)) + .executeCall( + new anchor.BN(nextReqId), + fromNetwork, + new anchor.BN(connSn), + connectionProgram.programId, + Buffer.from(data) + ) .accounts({ signer: ctx.admin.publicKey, systemProgram: SYSTEM_PROGRAM_ID, config: XcallPDA.config().pda, admin: xcallConfig.admin, - proxyRequest: XcallPDA.proxyRequest(nextReqId).pda, + proxyRequest: XcallPDA.proxyRequest( + fromNetwork, + connSn, + connectionProgram.programId + ).pda, }) .remainingAccounts([...executeCallAccounts.slice(4)]) .signers([ctx.admin]) @@ -348,6 +366,7 @@ describe("CentralizedConnection", () => { ).encode(); let recvMessageAccounts = await ctx.getRecvMessageAccounts( + ctx.dstNetworkId, connSn, nextSequenceNo, csMessage, @@ -467,6 +486,7 @@ describe("CentralizedConnection", () => { ).encode(); let recvMessageAccounts = await ctx.getRecvMessageAccounts( + ctx.dstNetworkId, connSn, nextSequenceNo, csMessage, @@ -664,6 +684,7 @@ describe("CentralizedConnection", () => { ).encode(); let recvMessageAccounts = await ctx.getRecvMessageAccounts( + fromNetwork, connSn, nextSequenceNo, cs_message, @@ -691,7 +712,12 @@ describe("CentralizedConnection", () => { await sleep(2); let executeForcedRollbackIx = await mockDappProgram.methods - .executeForcedRollback(new anchor.BN(nextReqId)) + .executeForcedRollback( + new anchor.BN(nextReqId), + fromNetwork, + new anchor.BN(connSn), + connectionProgram.programId + ) .accountsStrict({ config: DappPDA.config().pda, systemProgram: SYSTEM_PROGRAM_ID, @@ -710,7 +736,11 @@ describe("CentralizedConnection", () => { isWritable: true, }, { - pubkey: XcallPDA.proxyRequest(nextReqId).pda, + pubkey: XcallPDA.proxyRequest( + fromNetwork, + connSn, + connectionProgram.programId + ).pda, isSigner: false, isWritable: true, }, diff --git a/contracts/solana/tests/centralized-connection/setup.ts b/contracts/solana/tests/centralized-connection/setup.ts index de6eacb2..02e7dee6 100644 --- a/contracts/solana/tests/centralized-connection/setup.ts +++ b/contracts/solana/tests/centralized-connection/setup.ts @@ -77,6 +77,7 @@ export class TestContext { } async getRecvMessageAccounts( + fromNetwork: string, connSn: number, sequenceNo: number, csMessage: Uint8Array, @@ -106,7 +107,7 @@ export class TestContext { let res = await connectionProgram.methods .queryRecvMessageAccounts( - this.dstNetworkId, + fromNetwork, new anchor.BN(connSn), Buffer.from(csMessage), new anchor.BN(sequenceNo), diff --git a/contracts/solana/tests/xcall/setup.ts b/contracts/solana/tests/xcall/setup.ts index 7cf19fee..f826cd43 100644 --- a/contracts/solana/tests/xcall/setup.ts +++ b/contracts/solana/tests/xcall/setup.ts @@ -82,12 +82,27 @@ export class TestContext { await sleep(2); } - async getExecuteCallAccounts(reqId: number, data: Uint8Array) { + async getExecuteCallAccounts( + reqId: number, + fromNetwork: string, + connSn: number, + connection: PublicKey, + data: Uint8Array + ) { const res = await xcallProgram.methods - .queryExecuteCallAccounts(new anchor.BN(reqId), Buffer.from(data), 1, 30) + .queryExecuteCallAccounts( + new anchor.BN(reqId), + fromNetwork, + new anchor.BN(connSn), + connection, + Buffer.from(data), + 1, + 30 + ) .accountsStrict({ config: XcallPDA.config().pda, - proxyRequest: XcallPDA.proxyRequest(reqId).pda, + proxyRequest: XcallPDA.proxyRequest(fromNetwork, connSn, connection) + .pda, }) .remainingAccounts([ { @@ -145,9 +160,13 @@ export class TestContext { return await xcallProgram.account.config.fetch(pda); } - async getProxyRequest(requestId: number) { + async getProxyRequest( + fromNetwork: string, + connSn: number, + connection: PublicKey + ) { return await xcallProgram.account.proxyRequest.fetch( - XcallPDA.proxyRequest(requestId).pda, + XcallPDA.proxyRequest(fromNetwork, connSn, connection).pda, "confirmed" ); } @@ -192,9 +211,18 @@ export class XcallPDA { return { bump, pda }; } - static proxyRequest(requestId: number) { + static proxyRequest( + fromNetwork: string, + connSn: number, + connection: PublicKey + ) { const [pda, bump] = PublicKey.findProgramAddressSync( - [Buffer.from("proxy"), uint128ToArray(requestId)], + [ + Buffer.from("proxy"), + Buffer.from(fromNetwork), + uint128ToArray(connSn), + connection.toBuffer(), + ], xcallProgram.programId ); From 7cc4e80bd6f2c196841a324d01e5fb5284e24e6d Mon Sep 17 00:00:00 2001 From: bishalbikram Date: Fri, 18 Oct 2024 15:18:13 +0545 Subject: [PATCH 3/6] fix: close redundant proxy request account --- .../solana/programs/xcall/src/instructions/handle_message.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contracts/solana/programs/xcall/src/instructions/handle_message.rs b/contracts/solana/programs/xcall/src/instructions/handle_message.rs index 7450194b..ef3e6617 100644 --- a/contracts/solana/programs/xcall/src/instructions/handle_message.rs +++ b/contracts/solana/programs/xcall/src/instructions/handle_message.rs @@ -122,6 +122,11 @@ pub fn handle_request( pending_request.sources.push(source.owner.to_owned()) } if pending_request.sources.len() != req.protocols().len() { + // close the proxy request as it's no longer needed + ctx.accounts + .proxy_request + .close(ctx.accounts.signer.to_account_info())?; + return Ok(()); } pending_request.close(ctx.accounts.admin.clone())?; From 84aa843d0ca05c50ec35295235eedef27361b99f Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Wed, 23 Oct 2024 12:31:32 +0545 Subject: [PATCH 4/6] fix: make changes for eth abi --- .../sui/libs/sui_rlp/sources/decoder.move | 6 ++ .../sui/libs/sui_rlp/sources/encoder.move | 37 ++++++------ contracts/sui/libs/sui_rlp/sources/utils.move | 58 +++++++++++-------- 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/contracts/sui/libs/sui_rlp/sources/decoder.move b/contracts/sui/libs/sui_rlp/sources/decoder.move index 3fa18a96..7e794f6b 100644 --- a/contracts/sui/libs/sui_rlp/sources/decoder.move +++ b/contracts/sui/libs/sui_rlp/sources/decoder.move @@ -151,5 +151,11 @@ module sui_rlp::decoder { bcs::peel_address(&mut bcs) } + public fun decode_bool(vec:&vector):bool{ + let val= *vector::borrow(vec,0); + val==1 + + } + } \ No newline at end of file diff --git a/contracts/sui/libs/sui_rlp/sources/encoder.move b/contracts/sui/libs/sui_rlp/sources/encoder.move index 88c43c3d..4ea80dbe 100644 --- a/contracts/sui/libs/sui_rlp/sources/encoder.move +++ b/contracts/sui/libs/sui_rlp/sources/encoder.move @@ -48,25 +48,19 @@ module sui_rlp::encoder { let total_length = result.length(); let len=vector::length(&result); - if( total_length<= 55){ - encoded_list=encode_length(len,0xc0); - vector::append(&mut encoded_list,result); + if( total_length<= 55){ + encoded_list=encode_length(len,0xc0); + vector::append(&mut encoded_list,result); - } else { - let length_bytes = utils::to_bytes_u64(len); - let prefix = (0xf7 + vector::length(&length_bytes)) as u8; - //std::debug::print(&b"PREFIX".to_string()); - //std::debug::print(&prefix); - vector::push_back(&mut encoded_list, prefix); - //std::debug::print(&encoded_list); - vector::append(&mut encoded_list, length_bytes); - //std::debug::print(&encoded_list); + } else { + let length_bytes = utils::to_bytes_u64(len); + let prefix = (0xf7 + vector::length(&length_bytes)) as u8; + vector::push_back(&mut encoded_list, prefix); + vector::append(&mut encoded_list, length_bytes); + vector::append(&mut encoded_list, result); - vector::append(&mut encoded_list, result); - //std::debug::print(&encoded_list); - - } + } }else{ vector::push_back(&mut encoded_list,0xc0); @@ -132,8 +126,11 @@ module sui_rlp::encoder { let vec= bcs::to_bytes(addr); encode(&vec) } -} - - - + public fun encode_bool(val:bool):vector{ + if(val==true){ + return vector[1] + }; + vector[0] + } +} \ No newline at end of file diff --git a/contracts/sui/libs/sui_rlp/sources/utils.move b/contracts/sui/libs/sui_rlp/sources/utils.move index f73f0472..d222da66 100644 --- a/contracts/sui/libs/sui_rlp/sources/utils.move +++ b/contracts/sui/libs/sui_rlp/sources/utils.move @@ -1,6 +1,7 @@ module sui_rlp::utils { use std::vector::{Self}; use std::string::{Self,String}; + use std::bcs; public fun to_bytes_u32(number: u32): vector { let mut bytes: vector = vector::empty(); let mut i:u8=0; @@ -33,20 +34,6 @@ module sui_rlp::utils { result } - public fun to_bytes_u64(number: u64): vector { - let mut bytes: vector = vector::empty(); - let mut i:u8=0; - while(i < 8){ - let val =( (number>>(i * 8) & 0xFF) as u8) ; - vector::push_back(&mut bytes,val); - i=i+1; - }; - bytes.reverse(); - let mut prefix = vector[0]; - prefix.append(truncate_zeros(&bytes)); - prefix - } - fun truncate_zeros(bytes: &vector): vector { let mut i = 0; let mut started = false; @@ -85,21 +72,42 @@ module sui_rlp::utils { result } - - - // Convert u128 to bytes - public fun to_bytes_u128(number: u128): vector { - let mut bytes: vector = vector::empty(); - let mut i:u8=0; + public fun to_bytes_u128(number:u128):vector{ + let mut right:u128= 128; + let mut i=1; while(i < 16){ - let val = ((number>>(i * 8) & 0xFF) as u8) ; - vector::push_back(&mut bytes,val); + right=right << 8; + i=i+1; + + }; + let mut bytes=bcs::to_bytes(&number); + bytes.reverse(); + if (number < right){ + truncate_zeros(&bytes) + }else { + let mut prefix = vector[0]; + prefix.append(truncate_zeros(&bytes)); + prefix + } + } + + public fun to_bytes_u64(number:u64):vector{ + let mut right:u64= 128; + let mut i=1; + while(i < 8){ + right=right << 8; i=i+1; + }; + let mut bytes=bcs::to_bytes(&number); bytes.reverse(); - let mut prefix = vector[0]; - prefix.append(truncate_zeros(&bytes)); - prefix + if (number < right){ + truncate_zeros(&bytes) + }else { + let mut prefix = vector[0]; + prefix.append(truncate_zeros(&bytes)); + prefix + } } // Convert bytes to u128 From 359651896b805d82ecdaa8ad9e0852a459c747fb Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Wed, 23 Oct 2024 12:53:18 +0545 Subject: [PATCH 5/6] fix: fix tests --- contracts/sui/xcall/sources/types/message_result.move | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/sui/xcall/sources/types/message_result.move b/contracts/sui/xcall/sources/types/message_result.move index 0f53df48..9130009c 100644 --- a/contracts/sui/xcall/sources/types/message_result.move +++ b/contracts/sui/xcall/sources/types/message_result.move @@ -87,7 +87,7 @@ module xcall::message_result_tests { let msg= message_result::create(1,message_result::success(),vector::empty()); let encoded= message_result::encode(&msg); std::debug::print(&encoded); - assert!(encoded==x"c58200010180",0x01); + assert!(encoded==x"c3010180",0x01); let decoded=message_result::decode(&encoded); assert!(decoded==msg,0x01); @@ -99,7 +99,7 @@ module xcall::message_result_tests { let msg= message_result::create(2,message_result::failure(),vector::empty()); let encoded= message_result::encode(&msg); std::debug::print(&encoded); - assert!(encoded==x"c58200020080",0x01); + assert!(encoded==x"c3020080",0x01); let decoded=message_result::decode(&encoded); assert!(decoded==msg,0x01); From dfeb7cc2155d235f4fc801445f8790e4998f80b7 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Thu, 24 Oct 2024 21:10:34 +0545 Subject: [PATCH 6/6] fix: sui eth-rlp fixes --- .../sui/libs/sui_rlp/sources/decoder.move | 1 - .../sui/libs/sui_rlp/sources/encoder.move | 30 ++- contracts/sui/libs/sui_rlp/sources/utils.move | 193 +++++++----------- .../sui/libs/sui_rlp/tests/rlp_tests.move | 74 +++++++ 4 files changed, 159 insertions(+), 139 deletions(-) diff --git a/contracts/sui/libs/sui_rlp/sources/decoder.move b/contracts/sui/libs/sui_rlp/sources/decoder.move index 7e794f6b..acd27d51 100644 --- a/contracts/sui/libs/sui_rlp/sources/decoder.move +++ b/contracts/sui/libs/sui_rlp/sources/decoder.move @@ -20,7 +20,6 @@ module sui_rlp::decoder { } else { let length_len = byte - 0xb7; let length_bytes = utils::slice_vector(encoded, 1, length_len as u64); - //debug::print(&length_bytes); let length = utils::from_bytes_u64(&length_bytes); let data_start = (length_len + 1) as u64; utils::slice_vector(encoded, data_start, length) diff --git a/contracts/sui/libs/sui_rlp/sources/encoder.move b/contracts/sui/libs/sui_rlp/sources/encoder.move index 4ea80dbe..ea0dadff 100644 --- a/contracts/sui/libs/sui_rlp/sources/encoder.move +++ b/contracts/sui/libs/sui_rlp/sources/encoder.move @@ -21,14 +21,11 @@ module sui_rlp::encoder { vector::append(&mut result,*bytes); result }; - //std::debug::print(&encoded); encoded } public fun encode_list(list:&vector>,raw:bool):vector{ - //std::debug::print(&b"ENCODELIST".to_string()); - //std::debug::print(list); let mut result=vector::empty(); let mut encoded_list = vector::empty(); let mut list=*list; @@ -40,7 +37,6 @@ module sui_rlp::encoder { vector::append(&mut result,encode(&vector::pop_back(&mut list))); }else{ vector::append(&mut result,vector::pop_back(&mut list)); - //std::debug::print(&result); }; }; @@ -53,21 +49,17 @@ module sui_rlp::encoder { vector::append(&mut encoded_list,result); } else { - let length_bytes = utils::to_bytes_u64(len); - let prefix = (0xf7 + vector::length(&length_bytes)) as u8; - vector::push_back(&mut encoded_list, prefix); - vector::append(&mut encoded_list, length_bytes); - vector::append(&mut encoded_list, result); - - + let length_bytes = utils::to_bytes_u64(len); + let prefix = (0xf7 + vector::length(&length_bytes)) as u8; + vector::push_back(&mut encoded_list, prefix); + vector::append(&mut encoded_list, length_bytes); + vector::append(&mut encoded_list, result); } }else{ vector::push_back(&mut encoded_list,0xc0); }; - //std::debug::print(&b"FINAL_ENCODED_LIST".to_string()); - //std::debug::print(&encoded_list); encoded_list } @@ -77,11 +69,11 @@ module sui_rlp::encoder { let len_u8=(len as u8); vector::push_back(&mut length_info,(offset+len_u8)); }else { - let length_bytes=utils::to_bytes_u64(len); - let length_byte_len=vector::length(&length_bytes); - let length_byte_len=offset+(length_byte_len as u8); - vector::push_back(&mut length_info,length_byte_len); - vector::append(&mut length_info,length_bytes); + let length_bytes=utils::to_bytes_u64(len); + let length_byte_len=vector::length(&length_bytes); + let length_byte_len=offset+(length_byte_len as u8); + vector::push_back(&mut length_info,length_byte_len); + vector::append(&mut length_info,length_bytes); }; length_info } @@ -133,4 +125,6 @@ module sui_rlp::encoder { }; vector[0] } + + } \ No newline at end of file diff --git a/contracts/sui/libs/sui_rlp/sources/utils.move b/contracts/sui/libs/sui_rlp/sources/utils.move index d222da66..e09d9d88 100644 --- a/contracts/sui/libs/sui_rlp/sources/utils.move +++ b/contracts/sui/libs/sui_rlp/sources/utils.move @@ -1,139 +1,99 @@ module sui_rlp::utils { - use std::vector::{Self}; - use std::string::{Self,String}; - use std::bcs; - public fun to_bytes_u32(number: u32): vector { - let mut bytes: vector = vector::empty(); - let mut i:u8=0; - while(i < 4){ - let val =( (number>>(i * 8) & 0xFF) as u8) ; - vector::push_back(&mut bytes,val); - i=i+1; - }; - bytes.reverse(); - bytes - } + use std::bcs; + // Convert bytes to u32 - public fun from_bytes_u32(bytes: &vector): u32 {let mut result = 0; - let mut multiplier = 1; - let length = vector::length(bytes); - - let mut i = length; - while (i > 0) { - i = i - 1; - //std::debug::print(vector::borrow(bytes, i)); - result = result + ((*vector::borrow(bytes, i) as u32) * multiplier); - //std::debug::print(&result); - - if (i > 0) { - multiplier = multiplier * 256 - }; - + public fun from_bytes_u32(bytes: &vector): u32 { + let mut bytes= truncate_zeros(bytes); + bytes.reverse(); + let mut diff= 4-bytes.length(); + while (diff > 0) { + bytes.push_back(0_u8); + diff=diff-1; }; - result + sui::bcs::peel_u32(&mut sui::bcs::new(bytes)) } - fun truncate_zeros(bytes: &vector): vector { - let mut i = 0; - let mut started = false; - let mut result: vector = vector::empty(); - while (i < vector::length(bytes)) { - let val = *vector::borrow(bytes, i) as u8; - if (val > 0 || started) { - started = true; - vector::push_back(&mut result, val); - }; - i = i + 1; + // Convert bytes to u64 + public fun from_bytes_u64(bytes: &vector): u64 { + let mut bytes= truncate_zeros(bytes); + bytes.reverse(); + let mut diff= 8-bytes.length(); + while (diff > 0) { + bytes.push_back(0_u8); + diff=diff-1; }; + sui::bcs::peel_u64(&mut sui::bcs::new(bytes)) - result } - // Convert bytes to u64 - public fun from_bytes_u64(bytes: &vector): u64 { - let bytes = truncate_zeros(bytes); - let mut result = 0; - let mut multiplier = 1; - let length = vector::length(&bytes); - - let mut i = length; - while (i > 0) { - i = i - 1; - //std::debug::print(vector::borrow(bytes, i)); - result = result + ((*vector::borrow(&bytes, i) as u64) * (multiplier)); - //std::debug::print(&result); - if (i > 0) { - multiplier = multiplier * 256 - }; - + // Convert bytes to u128 + public fun from_bytes_u128(bytes: &vector): u128 { + let mut bytes= truncate_zeros(bytes); + bytes.reverse(); + let mut diff= 16-bytes.length(); + while (diff > 0) { + bytes.push_back(0_u8); + diff=diff-1; }; - result + sui::bcs::peel_u128(&mut sui::bcs::new(bytes)) + } public fun to_bytes_u128(number:u128):vector{ - let mut right:u128= 128; - let mut i=1; - while(i < 16){ - right=right << 8; - i=i+1; - - }; - let mut bytes=bcs::to_bytes(&number); - bytes.reverse(); - if (number < right){ - truncate_zeros(&bytes) - }else { - let mut prefix = vector[0]; - prefix.append(truncate_zeros(&bytes)); - prefix - } + let bytes=bcs::to_bytes(&number); + to_signed_bytes(bytes) } + public fun to_bytes_u64(number:u64):vector{ - let mut right:u64= 128; - let mut i=1; - while(i < 8){ - right=right << 8; - i=i+1; + let bytes=bcs::to_bytes(&number); + to_signed_bytes(bytes) + } - }; - let mut bytes=bcs::to_bytes(&number); + public fun to_bytes_u32(number: u32): vector { + let bytes=bcs::to_bytes(&number); + to_signed_bytes(bytes) + } + + fun to_signed_bytes(mut bytes:vector):vector{ bytes.reverse(); - if (number < right){ - truncate_zeros(&bytes) + let truncated=truncate_zeros(&bytes); + let first_byte=*truncated.borrow(0); + + if (first_byte >= 128) { + let mut prefix = vector[0]; + prefix.append(truncated); + prefix + }else { - let mut prefix = vector[0]; - prefix.append(truncate_zeros(&bytes)); - prefix + truncated } + } - // Convert bytes to u128 - public fun from_bytes_u128(bytes: &vector): u128 { - let bytes = truncate_zeros(bytes); - let mut result = 0; - let mut multiplier = 1; - let length = vector::length(&bytes); - - let mut i = length; - while (i > 0) { - i = i - 1; - //std::debug::print(vector::borrow(bytes, i)); - result = result + ((*vector::borrow(&bytes, i) as u128) * multiplier); - //std::debug::print(&result); - - if (i > 0) { - multiplier = multiplier * 256 + fun truncate_zeros(bytes: &vector): vector { + let mut i = 0; + let mut started = false; + let mut result: vector = vector::empty(); + while (i < vector::length(bytes)) { + let val = *vector::borrow(bytes, i) as u8; + if (val > 0 || started) { + started = true; + vector::push_back(&mut result, val); }; - + + i = i + 1; }; + result } + + /* end is exclusive in slice*/ - public fun slice_vector(vec: &vector, start: u64, length: u64): vector { + public fun slice_vector(vec: &vector, start: u64, length: u64): vector { let mut result = vector::empty(); let mut i = 0; while (i < length) { @@ -141,27 +101,23 @@ module sui_rlp::utils { vector::push_back(&mut result, value); i = i + 1; }; - //std::debug::print(&result); result } - + } module sui_rlp::utils_test { use sui_rlp::utils::{Self}; - use std::vector::{Self}; - use std::debug; - use sui::bcs::{Self}; - #[test] + #[test] fun test_u32_conversion() { let num= (122 as u32); let bytes= utils::to_bytes_u32(num); let converted=utils::from_bytes_u32(&bytes); assert!(num==converted,0x01); - + } #[test] @@ -172,7 +128,7 @@ module sui_rlp::utils_test { std::debug::print(&bytes); std::debug::print(&converted); assert!(num==converted,0x01); - + } #[test] @@ -183,7 +139,7 @@ module sui_rlp::utils_test { let converted=utils::from_bytes_u128(&bytes); std::debug::print(&converted); assert!(num==converted,0x01); - + } #[test] @@ -191,16 +147,13 @@ module sui_rlp::utils_test { let data=create_vector(10); let slice= utils::slice_vector(&data,0,3); let expected= create_vector(3); - //debug::print(&expected); - //debug::print(&slice); - //debug::print(&data); assert!(slice==expected,0x01); - + } fun create_vector(n:u8):vector{ - let mut data=vector::empty(); + let mut data=vector::empty(); let mut i=0; while(i < n){ vector::push_back(&mut data,i); diff --git a/contracts/sui/libs/sui_rlp/tests/rlp_tests.move b/contracts/sui/libs/sui_rlp/tests/rlp_tests.move index 2632c074..11ded18d 100644 --- a/contracts/sui/libs/sui_rlp/tests/rlp_tests.move +++ b/contracts/sui/libs/sui_rlp/tests/rlp_tests.move @@ -80,6 +80,80 @@ module sui_rlp::rlp_tests { list } + + #[test] + fun test_encoding_u128(){ + let num:u128=100; + let bytes=x"64"; + let encoded= encoder::encode_u128(num); + assert!(encoded==bytes); + let decoded=decoder::decode_u128(&decoder::decode(&encoded)); + assert!(decoded==num); + + //// + /// + let num:u128=200; + let bytes=x"8200c8"; + let encoded= encoder::encode_u128(num); + assert!(encoded==bytes); + let decoded=decoder::decode_u128(&decoder::decode(&encoded)); + assert!(decoded==num); + /// + /// + let num:u128=3000000; + let bytes=x"832dc6c0"; + let encoded= encoder::encode_u128(num); + std::debug::print(&encoded); + assert!(encoded==bytes); + let decoded=decoder::decode_u128(&decoder::decode(&encoded)); + assert!(decoded==num); + + let num:u128=273468273; + let bytes=x"84104ccb71"; + let encoded= encoder::encode_u128(num); + assert!(encoded==bytes); + let decoded=decoder::decode_u128(&decoder::decode(&encoded)); + assert!(decoded==num); + + let num:u128=2342312; + let bytes=x"8323bda8"; + let encoded= encoder::encode_u128(num); + assert!(encoded==bytes); + let decoded=decoder::decode_u128(&decoder::decode(&encoded)); + assert!(decoded==num); + + let num:u128=1233; + let bytes=x"8204d1"; + let encoded= encoder::encode_u128(num); + assert!(encoded==bytes); + let decoded=decoder::decode_u128(&decoder::decode(&encoded)); + assert!(decoded==num); + + let num:u128=412926; + let bytes=x"83064cfe"; + let encoded= encoder::encode_u128(num); + assert!(encoded==bytes); + let decoded=decoder::decode_u128(&decoder::decode(&encoded)); + assert!(decoded==num); + + let num:u128=9434628989898; + let bytes=x"860894abb5a3ca"; + let encoded= encoder::encode_u128(num); + assert!(encoded==bytes); + let decoded=decoder::decode_u128(&decoder::decode(&encoded)); + assert!(decoded==num); + + let num:u128=92625222222121112; + let bytes=x"88014912261bca8898"; + let encoded= encoder::encode_u128(num); + assert!(encoded==bytes); + let decoded=decoder::decode_u128(&decoder::decode(&encoded)); + assert!(decoded==num); + + + + } +