diff --git a/crates/dtp-core/src/network/localhost_internal.rs b/crates/dtp-core/src/network/localhost_internal.rs index 8c435b5..9d9971c 100644 --- a/crates/dtp-core/src/network/localhost_internal.rs +++ b/crates/dtp-core/src/network/localhost_internal.rs @@ -5,6 +5,7 @@ use super::host_internal::*; //use std::str::FromStr; use sui_keys::keystore::AccountKeystore; //use sui_sdk::json::SuiJsonValue; +use sui_adapter::execution_mode; use sui_sdk::types::base_types::{ObjectID, SuiAddress}; use sui_sdk::types::messages::Transaction; use sui_types::intent::Intent; @@ -56,7 +57,7 @@ pub(crate) async fn create_localhost_on_network( let create_host_call = sui_client .transaction_builder() - .move_call( + .move_call::( rpc.client_address, txn.package_id, "host", diff --git a/crates/dtp-core/src/types/mod.rs b/crates/dtp-core/src/types/mod.rs index 478e419..7acd717 100644 --- a/crates/dtp-core/src/types/mod.rs +++ b/crates/dtp-core/src/types/mod.rs @@ -1,11 +1,15 @@ // Flatten many sub modules/files under the same dtp_core::types module. // // Allows to do: -// use dtp_core::types::{DTPError, SomethingElseInFuture} +// use dtp_core::types::{DTPError, PingStats} // // Instead of verbose: // use dtp_core::types::error::DTPError; -// use dtp_core::somethingelseinfuture::SomethingElseInFuture; +// use dtp_core::types::stats::PingStats; +// ... + pub use self::error::*; +pub use self::stats::*; pub mod error; +pub mod stats; diff --git a/crates/dtp-sdk/src/lib.rs b/crates/dtp-sdk/src/lib.rs index 16e39de..220f61b 100644 --- a/crates/dtp-sdk/src/lib.rs +++ b/crates/dtp-sdk/src/lib.rs @@ -26,7 +26,10 @@ // TODO Define the error. use anyhow::bail; -use dtp_core::network::{HostInternal, LocalhostInternal, NetworkManager}; +use dtp_core::{ + network::{HostInternal, LocalhostInternal, NetworkManager}, + types::PingStats, +}; use sui_sdk::types::base_types::{ObjectID, SuiAddress}; use tokio::time::Duration; @@ -175,7 +178,7 @@ impl DTP { &self, _localhost: &Localhost, _target_host: &Host, - ) -> Result<(), anyhow::Error> { + ) -> Result { // Verify parameters are children of this NetworkManager. // // Particularly useful for the Localhost for an early detection @@ -192,7 +195,13 @@ impl DTP { self.netmgr.ping(localhost, target_host) */ - Ok(()) + // TODO WIP Obviously... + let stats = PingStats { + ping_count_attempted: 1, + ..Default::default() + }; + + Ok(stats) } // Initialize Firewall Service diff --git a/crates/dtp-sdk/tests/api_tests.rs b/crates/dtp-sdk/tests/api_tests.rs index 07954f0..697b3e1 100644 --- a/crates/dtp-sdk/tests/api_tests.rs +++ b/crates/dtp-sdk/tests/api_tests.rs @@ -1,14 +1,27 @@ -use dtp_sdk::DTP; +use dtp_sdk::{Host, Localhost, DTP}; //use sui_sdk::types::base_types::{ObjectID, SuiAddress}; -//use anyhow::anyhow; +use anyhow::Result; use dtp_test_helper::{Sender, SuiNetworkForTest}; use serial_test::serial; mod common; -#[tokio::test] -#[serial] -async fn localhost_instantiation_localnet() -> Result<(), anyhow::Error> { +struct TwoHostsSetup { + #[allow(dead_code)] + pub network: SuiNetworkForTest, + #[allow(dead_code)] + pub dtp: DTP, + #[allow(dead_code)] + pub dtp_peer: DTP, + #[allow(dead_code)] + pub localhost: Localhost, + #[allow(dead_code)] + pub host: Host, +} + +// This is a series of objects that are assumed to be always present +// for a single bi-directional connection. +async fn create_two_hosts_setup() -> Result { let network: SuiNetworkForTest = common::setup_localnet()?; let owner = network.get_sender_address(Sender::Test).clone(); @@ -16,7 +29,7 @@ async fn localhost_instantiation_localnet() -> Result<(), anyhow::Error> { dtp.add_rpc("http://0.0.0.0:9000", None, None).await?; dtp.set_package_id(network.dtp_package_id); // This won't be needed for mainnet. - // Check if localhost already exists, if yes, will skip first instantion test. + // Create and test a localhost. let mut result = dtp.get_localhost().await.ok(); if result.is_none() { @@ -48,5 +61,50 @@ async fn localhost_instantiation_localnet() -> Result<(), anyhow::Error> { assert_eq!(*localhost_id, api_dtp_localhost_id); assert_eq!(api_localhost_id, localhost_id); + // Create the second host. + let second_owner = network.get_sender_address(Sender::PeerServer).clone(); + let mut dtp2: DTP = DTP::new(second_owner, None).await?; + dtp2.add_rpc("http://0.0.0.0:9000", None, None).await?; + dtp2.set_package_id(network.dtp_package_id); // This won't be needed for mainnet. + + let mut result2 = dtp2.get_localhost().await.ok(); + + if result2.is_none() { + // Check the API is consistent. + assert_eq!(*dtp2.localhost_id(), None); + + let new_localhost2 = dtp2 + .create_localhost_on_network() + .await + .map_err(|e| e.context("Is the sui localnet process running on your machine?"))?; + result2 = Some(new_localhost2); + } + // Ownership from the creation that was just done. + let localhost2 = result2.expect("Creation of second Localhost failed"); + let host2_id = localhost2.id(); + + // Now test doing a get_Host of these host ids using both clients. + let host = dtp.get_host(*host2_id).await?; + + Ok(TwoHostsSetup { + network, + dtp, + dtp_peer: dtp2, + localhost, + host, + }) +} + +#[tokio::test] +#[serial] +async fn integration_localnet() -> Result<(), anyhow::Error> { + #[allow(dead_code)] + let two_hosts = create_two_hosts_setup().await?; + #[allow(dead_code)] + let _ping_result = two_hosts + .dtp + .ping(&two_hosts.localhost, &two_hosts.host) + .await?; + Ok(()) } diff --git a/crates/dtp-test-helper/src/lib.rs b/crates/dtp-test-helper/src/lib.rs index 332beda..598ba3e 100644 --- a/crates/dtp-test-helper/src/lib.rs +++ b/crates/dtp-test-helper/src/lib.rs @@ -125,9 +125,7 @@ impl SuiNetworkForTest { // Note: Object not existing not considered an error. // Verification using self-contain code (its own SuiClient and all). - let sui = SuiClient::new("http://0.0.0.0:9000", None, None) - .await - .map_err(|e| e.context("Is localnet sui process running?"))?; + let sui = SuiClient::new("http://0.0.0.0:9000", None, None).await?; // TODO: Check the different error code to differentiate inexistence from call failure. This is very incomplete. let result = sui.read_api().get_parsed_object(object_id).await; diff --git a/move/sources/pipe.move b/move/sources/pipe.move index 8925baf..d851061 100644 --- a/move/sources/pipe.move +++ b/move/sources/pipe.move @@ -7,7 +7,7 @@ module dtp::pipe { use std::vector::{Self}; use sui::object::{Self, UID, ID, uid_to_address, id_from_address}; - use sui::tx_context::{Self, TxContext}; + use sui::tx_context::{TxContext}; use sui::transfer; #[test_only] @@ -25,7 +25,7 @@ module dtp::pipe { send_call_completed: u64, } - public(friend) fun create_internal( ctx: &mut TxContext ): ID { + public(friend) fun create_internal( ctx: &mut TxContext, recipient: address ): ID { let pipe = Pipe { id: object::new(ctx), byte_payload_sent: 0, @@ -33,7 +33,7 @@ module dtp::pipe { send_call_completed: 0 }; let id_copy = id_from_address(uid_to_address(&pipe.id)); - transfer::transfer(pipe, tx_context::sender(ctx)); + transfer::transfer(pipe, recipient ); id_copy } diff --git a/move/sources/transport_control.move b/move/sources/transport_control.move index daac5dd..7f2500e 100644 --- a/move/sources/transport_control.move +++ b/move/sources/transport_control.move @@ -42,7 +42,7 @@ module dtp::transport_control { // // Shared object with public entry functions allowed only // for the client and server of the related connection. - struct TransportControl has key, store { + struct TransportControl has key { id: UID, client_host: Option, // Not set on broadcast. @@ -146,13 +146,13 @@ module dtp::transport_control { self.client_authority } - // The TransportController is the shared object for the + // The TransportControl is the shared object for the // connection between two hosts. // // It is created by the client and provides also unique capabilities // to the server. // - // There are two ways of creating a TransportController: + // There are two ways of creating a TransportControl: // // best_effort: // Created without checking for approval with the server Host @@ -187,12 +187,12 @@ module dtp::transport_control { return_port: Option, ctx: &mut TxContext ) { - // Create the client tx pipe and the TransportController itself. + // Create the tx pipes and the TransportControl itself. // // A "Connection Request" event is emited. The server may choose to // accept the connection, ignore the request or pro-actively // refuse the request (which is relatively nice since it save the - // client some storage fee by allowing to delete the TransportController). + // client some storage fee by allowing to delete the object created). // let tc = dtp::transport_control::new( client_host, server_host, @@ -200,15 +200,16 @@ module dtp::transport_control { option::none(), option::none(), protocol, port, return_port, ctx ); - // Weak reference between Pipe and TC using ID (for recovery scenario). - tc.client_tx_pipe = option::some(dtp::pipe::create_internal(ctx)); + let sender = tx_context::sender(ctx); + // Weak references between Pipes and TC using ID (for recovery scenario). + tc.client_tx_pipe = option::some(dtp::pipe::create_internal(ctx, sender)); + tc.server_tx_pipe = option::some(dtp::pipe::create_internal(ctx, server_admin)); // Emit the "Connection Request" Move event. + // The server will see the sender object therefore will know the TC and plenty of info! event::emit(BEConReq { sender: tx_context::sender(ctx), // Allows to filter out early spammers. - // tc_id: new::ID(tc.UID), The server will see the sender object therefor will know the TC! } ); - transfer::share_object(tc); } @@ -242,7 +243,7 @@ module dtp::transport_control { // // Note: All epoch timeout may differ depending of the connection SLA. // - // TODO + // TODO State machine is for storage+fund management (to be done eventually) } @@ -279,8 +280,8 @@ module dtp::test_transport_control { { let ctx = test_scenario::ctx(scenario); - fake_client_pipe_id = pipe::create_internal(ctx); - fake_server_pipe_id = pipe::create_internal(ctx); + fake_client_pipe_id = pipe::create_internal(ctx, fake_client_address); + fake_server_pipe_id = pipe::create_internal(ctx, fake_client_address); let fake_client_host = host::new(ctx); let fake_client_host_id = object::id(&fake_client_host);