diff --git a/contracts/sui/mock_dapp/tests/mock_dapp_tests.move b/contracts/sui/mock_dapp/tests/mock_dapp_tests.move index a22e1653..7d68740b 100644 --- a/contracts/sui/mock_dapp/tests/mock_dapp_tests.move +++ b/contracts/sui/mock_dapp/tests/mock_dapp_tests.move @@ -44,7 +44,8 @@ module mock_dapp::mock_dapp_tests { fun setup_connection(admin:address,mut scenario:Scenario):Scenario { let mut xcall_state= scenario.take_shared(); let adminCap=scenario.take_from_sender(); - xcall::register_connection(&mut xcall_state,&adminCap,string::utf8(b"netid"),string::utf8(b"centralized-1"),admin,scenario.ctx()); + xcall::register_connection_admin(&mut xcall_state,&adminCap,string::utf8(b"centralized-1"),admin,scenario.ctx()); + xcall::set_default_connection(&mut xcall_state,&adminCap,string::utf8(b"netid"),string::utf8(b"centralized-1"),scenario.ctx()); test_scenario::return_shared(xcall_state); scenario.return_to_sender(adminCap); scenario.next_tx(admin); diff --git a/contracts/sui/xcall/sources/centralized_connection/centralized_state.move b/contracts/sui/xcall/sources/centralized_connection/centralized_state.move index 60dafaf4..d195b7dc 100644 --- a/contracts/sui/xcall/sources/centralized_connection/centralized_state.move +++ b/contracts/sui/xcall/sources/centralized_connection/centralized_state.move @@ -50,8 +50,8 @@ module xcall::centralized_state { sn } - public fun get_fee(self: &State, netId: &String, response: bool): u64 { - let fee: u64 = if (response == true) { + public fun get_fee(self: &State, netId: &String, need_response: bool): u64 { + let fee: u64 = if (need_response == true) { utils::get_or_default(&self.message_fee, netId, 0) + utils::get_or_default(&self.response_fee, netId, 0) } else { diff --git a/contracts/sui/xcall/sources/connections.move b/contracts/sui/xcall/sources/connections.move index 32683470..41fb773e 100644 --- a/contracts/sui/xcall/sources/connections.move +++ b/contracts/sui/xcall/sources/connections.move @@ -1,58 +1,53 @@ #[allow(unused_field,unused_use,unused_const,unused_mut_parameter,unused_variable,unused_assignment)] module xcall::connections{ -use std::string::{Self, String}; -use sui::bag::{Bag, Self}; -use xcall::centralized_connection::{Self}; -use xcall::centralized_state::{Self,State}; -use xcall::xcall_state::{ConnCap}; - - use sui::coin::{Self,Coin}; + use std::string::{Self, String}; + use sui::bag::{Bag, Self}; + use xcall::centralized_connection::{Self}; + use xcall::centralized_state::{Self,State}; + use xcall::xcall_state::{ConnCap}; + use sui::coin::{Self,Coin}; use sui::balance::{Self, Balance}; use sui::sui::SUI; -const EConnectionNotFound:u64=0; - -const ConnCentralized:vector =b"centralized"; - - + const EConnectionNotFound:u64=0; + const ConnCentralized:vector =b"centralized"; public(package) fun register(states:&mut Bag,connection_id:String,ctx:&mut TxContext){ - + if (get_connection_type(&connection_id).bytes()==ConnCentralized){ - let state= centralized_connection::connect(); - bag::add(states, connection_id, state); + let state= centralized_connection::connect(); + bag::add(states, connection_id, state); }else{ - abort EConnectionNotFound + abort EConnectionNotFound } - } - public(package) fun get_fee(states:&Bag,connection_id:String,netId:String,response:bool):u64{ + public(package) fun get_fee(states:&Bag,connection_id:String,netId:String,response:bool):u64{ if (get_connection_type(&connection_id).bytes()==ConnCentralized){ let fee= centralized_connection::get_fee(states,connection_id,netId,response); fee }else{ - abort EConnectionNotFound + abort EConnectionNotFound } } - public(package) fun send_message(states:&mut Bag, - connection_id:String, - coin:Coin, - netId:String, - sn:u128, - msg:vector, - is_response:bool, - ctx:&mut TxContext){ - - if (get_connection_type(&connection_id).bytes()==ConnCentralized){ + public(package) fun send_message(states:&mut Bag, + connection_id:String, + coin:Coin, + netId:String, + sn:u128, + msg:vector, + is_response:bool, + ctx:&mut TxContext){ + + if (get_connection_type(&connection_id).bytes()==ConnCentralized){ centralized_connection::send_message(states,connection_id,coin,netId,sn,msg,is_response,ctx); }else{ - abort EConnectionNotFound + abort EConnectionNotFound } } diff --git a/contracts/sui/xcall/sources/main.move b/contracts/sui/xcall/sources/main.move index 686a8787..e7ff08e0 100644 --- a/contracts/sui/xcall/sources/main.move +++ b/contracts/sui/xcall/sources/main.move @@ -10,7 +10,7 @@ module xcall::main { use sui::balance::{Self, Balance}; use sui::sui::SUI; use xcall::xcall_utils as utils; - + use xcall::network_address::{Self,NetworkAddress}; use xcall::envelope::{Self,XCallEnvelope}; use xcall::connections::{Self,register}; @@ -28,12 +28,12 @@ module xcall::main { use sui::bag::{Bag, Self}; use sui::table::{Table,Self}; use sui::package::{Self,Publisher}; - + use sui::vec_map::{Self, VecMap}; use sui::versioned::{Self, Versioned}; - - use sui::address::{Self}; - use sui::package::UpgradeCap; + + use sui::address::{Self}; + use sui::package::UpgradeCap; const ENotOneTimeWitness: u64 = 0; @@ -50,7 +50,8 @@ module xcall::main { const EInfallible:u64 = 11; const EInvalidAccess:u64 =12; const EInvalidMsgCode:u64 =13; - const EDataTooBig:u64=14; + const EDataTooBig:u64 =14; + const EInvalidConnectionId:u64 =15; const MAX_DATA_SIZE: u64 = 2048; const CURRENT_VERSION: u64 = 1; @@ -97,17 +98,17 @@ module xcall::main { fun init(ctx: &mut TxContext) { let admin = xcall_state::create_admin_cap(ctx); let storage = xcall_state::create_storage( - CURRENT_VERSION, - &admin, - ctx + CURRENT_VERSION, + &admin, + ctx ); - xcall_state::share(storage); - xcall_state::transfer_admin_cap(admin,ctx); + xcall_state::share(storage); + xcall_state::transfer_admin_cap(admin,ctx); } public fun register_dapp(self:&Storage, - witness: T, - ctx: &mut TxContext + witness: T, + ctx: &mut TxContext ):IDCap { self.create_id_cap(ctx) } @@ -123,14 +124,22 @@ module xcall::main { } - entry public fun register_connection(self:&mut Storage,admin:&AdminCap,net_id:String,connection_id:String,relayer:address,ctx: &mut TxContext){ + entry public fun register_connection_admin(self:&mut Storage,admin:&AdminCap,connection_id:String,relayer:address,ctx: &mut TxContext){ self.enforce_version(CURRENT_VERSION); - self.set_connection(net_id,connection_id); let cap= xcall_state::new_conn_cap(self.get_id(),connection_id,ctx); xcall_state::transfer_conn_cap(cap,relayer,ctx); register(self.get_connection_states_mut(),connection_id,ctx); } + entry public fun set_default_connection(self:&mut Storage,admin:&AdminCap,net_id:String,connection_id:String,ctx: &mut TxContext){ + self.enforce_version(CURRENT_VERSION); + let connection_exists=bag::contains(self.get_connection_states(),connection_id); + if(!connection_exists){ + abort EInvalidConnectionId + }; + self.set_connection(net_id,connection_id); + } + public fun admin(self:&mut Storage):ID{ xcall_state::get_admin(self) } @@ -139,21 +148,22 @@ module xcall::main { xcall_state::get_protocol_fee_handler(self) } - fun get_connection_fee(self:&Storage,connection_id:String,net_id:String, need_response:bool ):u64{ + fun get_connection_fee(self:&Storage,connection_id:String,net_id:String, needs_response:bool):u64{ connections::get_fee( xcall_state::get_connection_states(self), connection_id, net_id, - need_response + needs_response ) } entry public fun get_fee(self:&Storage, net_id:String, rollback:bool, sources:Option>):u64{ let mut fee = xcall_state::get_protocol_fee(self); let mut sources= sources.get_with_default(vector::empty()); + if (sources.is_empty()){ - let connection = xcall_state::get_connection(self,net_id); - sources.push_back(connection); + let connection = xcall_state::get_connection(self,net_id); + sources.push_back(connection); }; if(isReply(self,net_id,sources) && !rollback){ @@ -174,7 +184,6 @@ module xcall::main { fun send_call_inner(self:&mut Storage,fee:Coin,from:NetworkAddress,to:NetworkAddress,envelope:XCallEnvelope,ctx: &mut TxContext):Coin{ self.enforce_version(CURRENT_VERSION); let sequence_no=get_next_sequence(self); - let rollback=envelope::rollback(&envelope); let msg_type=envelope::msg_type(&envelope); let mut need_response = false; @@ -185,19 +194,16 @@ module xcall::main { } else if(msg_type == call_message_rollback::msg_type()){ let msg = call_message_rollback::decode(&envelope::message(&envelope)); - //std::debug::print(&network_address::addr(&from)); let from_id = utils::id_from_hex_string(&network_address::addr(&from)); - let rollback = rollback_data::create( - from_id, - to.net_id(), - envelope.sources(), - msg.rollback(), - false + from_id, + to.net_id(), + envelope.sources(), + msg.rollback(), + false ); xcall_state::add_rollback(self,sequence_no,rollback); - need_response = true; data = call_message_rollback::data(&msg); } @@ -206,17 +212,17 @@ module xcall::main { }; let cs_request= message_request::create( - from, - to.addr(), - sequence_no, - envelope.msg_type(), - data, - envelope.destinations()); + from, + to.addr(), + sequence_no, + envelope.msg_type(), + data, + envelope.destinations()); let msg = message_request::encode(&cs_request); assert!(vector::length(&msg) <= MAX_DATA_SIZE, EDataTooBig); - + let fee = if(isReply(self,to.net_id(),envelope::sources(&envelope))){ xcall_state::remove_reply_state(self); xcall_state::set_call_reply(self,msg); @@ -224,8 +230,8 @@ module xcall::main { } else{ let sendSn = if (need_response) {sequence_no} else {0}; let cs_message=cs_message::from_message_request(cs_request); - - + + connection_send_message(self, fee, envelope::sources(&envelope), @@ -245,31 +251,35 @@ module xcall::main { if(vector::is_empty(&sources)){ let connection= xcall_state::get_connection(self,net_to); vector::push_back(&mut protocols,connection); - + }; - - let cs_message_bytes=cs_message::encode(&cs_message); - let mut i=0; - while(i < vector::length(&protocols)){ - let protocol=*vector::borrow(&protocols,i); - - let required_fee = get_connection_fee(self, protocol, net_to, is_response); - - let paid= fee.split(required_fee,ctx); - connections::send_message( - xcall_state::get_connection_states_mut(self), - protocol, - paid, - net_to, - sn, - cs_message_bytes, - is_response, - ctx); - - i=i+1; + + let cs_message_bytes=cs_message::encode(&cs_message); + let mut i=0; + while(i < vector::length(&protocols)){ + let protocol=*vector::borrow(&protocols,i); + + let required_fee = if (is_response){ + 0 + } else { + get_connection_fee(self, protocol, net_to, sn > 0) }; - fee + let paid= fee.split(required_fee,ctx); + connections::send_message( + xcall_state::get_connection_states_mut(self), + protocol, + paid, + net_to, + sn, + cs_message_bytes, + is_response, + ctx); + + i=i+1; + }; + + fee } fun get_next_sequence(self:&mut Storage):u128 { @@ -338,7 +348,6 @@ module xcall::main { if (msg_type == cs_message::request_code()) { handle_request(self,cap,from, payload, ctx); } else if (msg_type == cs_message::result_code()) { - handle_result(self, cap, payload, ctx); } else { abort EInvalidMsgCode @@ -366,9 +375,7 @@ module xcall::main { if(vector::length(&protocols) > 1){ let key = hash::keccak256(&payload); xcall_state::save_pending_requests(self, key, source); - if(!xcall_state::check_pending_requests(self, key, protocols)) return; - xcall_state::remove_pending_requests(self, key, protocols); }; let data_hash = hash::keccak256(&data); @@ -396,7 +403,7 @@ module xcall::main { assert!(source_valid, EInvalidSource); if(vector::length(&sources) > 1){ - let key = hash::keccak256(&payload); + let key = hash::keccak256(&payload); xcall_state::save_pending_responses(self, key, source); if(!xcall_state::check_pending_responses(self, key, sources)) return; @@ -405,20 +412,20 @@ module xcall::main { }; event::emit(ResponseMessage { sn: sequence_no, response_code: code }); - if (code == message_result::success()) { - xcall_state::remove_rollback(self, sequence_no); + if (code == message_result::success()) { + xcall_state::remove_rollback(self, sequence_no); - if (vector::length(&message) > 0) { - let msg = message_request::decode(&message); - handle_reply(self,&rollback, &msg, ctx); - }; + if (vector::length(&message) > 0) { + let msg = message_request::decode(&message); + handle_reply(self,&rollback, &msg, ctx); + }; - xcall_state::set_successful_responses(self, sequence_no); - } else { - let mut_rollback = xcall_state::get_mut_rollback(self, sequence_no); - rollback_data::enable_rollback(mut_rollback); - event::emit(RollbackMessage{sn:sequence_no, dapp: utils::id_to_hex_string(&rollback_data::from(&rollback)), data: rollback.rollback() }); - }; + xcall_state::set_successful_responses(self, sequence_no); + } else { + let mut_rollback = xcall_state::get_mut_rollback(self, sequence_no); + rollback_data::enable_rollback(mut_rollback); + event::emit(RollbackMessage{sn:sequence_no, dapp: utils::id_to_hex_string(&rollback_data::from(&rollback)), data: rollback.rollback() }); + }; } fun handle_reply(self:&mut Storage, rollback:&RollbackData, reply: &CSMessageRequest, ctx: &mut TxContext){ @@ -428,7 +435,7 @@ module xcall::main { let from = reply.from(); let to = reply.to(); let data = reply.data(); - let protocols = reply.protocols(); + let protocols = rollback.sources(); let sn = reply.sn(); let msg_type = reply.msg_type(); @@ -467,8 +474,13 @@ module xcall::main { ); ticket } - - + /** + - `self`: A mutable reference to the `Storage` object. + - `ticket`: An `ExecuteTicket` object containing details of the executed call. + - `success`: A boolean indicating whether the call was successful. + - `fee`: A mutable `Coin` object representing the fee which can be zero since reply is already paid on source . + - `ctx`: A reference to the transaction context (`TxContext`). + **/ public fun execute_call_result(self:&mut Storage,ticket:ExecuteTicket,success:bool,mut fee:Coin,ctx:&mut TxContext){ self.enforce_version(CURRENT_VERSION); let request_id=ticket.request_id(); @@ -502,13 +514,13 @@ module xcall::main { }; execute_ticket::consume(ticket); if(msg_type==call_message_rollback::msg_type()){ - let cs_message=cs_message::from_message_result(cs_message_result); - fee = connection_send_message(self,fee,protocols,net_to,cs_message,sn,true,ctx); + let cs_message=cs_message::from_message_result(cs_message_result); + fee = connection_send_message(self,fee,protocols,net_to,cs_message,sn,true,ctx); }; transfer::public_transfer(fee, ctx.sender()); event::emit(CallExecuted{req_id:request_id, code: code, err_msg: err_msg}); - + } public fun execute_rollback(self:&mut Storage,cap:&IDCap, sn:u128,ctx: &mut TxContext):RollbackTicket{ @@ -565,6 +577,7 @@ module xcall::main { scenario.next_tx(admin); scenario } + #[test_only] public fun configure_nid_test(self:&mut Storage,owner:&AdminCap, net_id:String,ctx: &mut TxContext){ if(!(net_id == b"".to_string())){ diff --git a/contracts/sui/xcall/tests/xcall_test.move b/contracts/sui/xcall/tests/xcall_test.move index b1f43466..12e41884 100644 --- a/contracts/sui/xcall/tests/xcall_test.move +++ b/contracts/sui/xcall/tests/xcall_test.move @@ -29,8 +29,9 @@ module xcall::xcall_tests { { let mut storage = test_scenario::take_shared(scenario); let adminCap = scenario.take_from_sender(); - main::register_connection(&mut storage, &adminCap,from_nid, string::utf8(b"centralized-1"),admin, scenario.ctx()); - main::register_connection(&mut storage, &adminCap,from_nid, string::utf8(b"centralized-2"),admin, scenario.ctx()); + main::register_connection_admin(&mut storage, &adminCap, string::utf8(b"centralized-1"),admin, scenario.ctx()); + main::register_connection_admin(&mut storage, &adminCap, string::utf8(b"centralized-2"),admin, scenario.ctx()); + main::set_default_connection(&mut storage, &adminCap,from_nid, string::utf8(b"centralized-2"), scenario.ctx()); test_scenario::return_shared(storage); scenario.return_to_sender(adminCap);