From ac77c0f02a97424475c676528b98b720626d492f Mon Sep 17 00:00:00 2001 From: mario4tier Date: Sun, 18 Feb 2024 22:59:25 -0500 Subject: [PATCH] Add errors.move, start coding Host and Transport Control --- move/sources/consts.move | 6 +- move/sources/errors.move | 33 ++++++ move/sources/host.move | 37 +++--- move/sources/service_type.move | 103 +++++++++++------ move/sources/transport_control.move | 172 ++++++++++++++-------------- 5 files changed, 219 insertions(+), 132 deletions(-) create mode 100644 move/sources/errors.move diff --git a/move/sources/consts.move b/move/sources/consts.move index 70f7b7a..73fbf6c 100644 --- a/move/sources/consts.move +++ b/move/sources/consts.move @@ -11,12 +11,12 @@ module dtp::consts { // // If you need more connections, consider creating additional hosts. const C_MAX_CONNECTION_PER_SERVICE: u16 = 4096; - public(friend) fun MAX_CONNECTION_PER_SERVICE() : u16 { C_MAX_CONNECTION_PER_SERVICE } + public fun MAX_CONNECTION_PER_SERVICE() : u16 { C_MAX_CONNECTION_PER_SERVICE } const C_MAX_SERVICE_PER_HOST: u8 = 16; - public(friend) fun MAX_SERVICE_PER_HOST() : u8 { C_MAX_SERVICE_PER_HOST } + public fun MAX_SERVICE_PER_HOST() : u8 { C_MAX_SERVICE_PER_HOST } - public(friend) fun MAX_CONNECTION_PER_HOST() : u32 { + public fun MAX_CONNECTION_PER_HOST() : u32 { (C_MAX_CONNECTION_PER_SERVICE as u32) * (C_MAX_SERVICE_PER_HOST as u32) } } \ No newline at end of file diff --git a/move/sources/errors.move b/move/sources/errors.move new file mode 100644 index 0000000..bc86fbe --- /dev/null +++ b/move/sources/errors.move @@ -0,0 +1,33 @@ +module dtp::errors { + // === Imports === + + // === Friends === + + // === Errors === + + // === Constants === + // TODO Could error code be 32 bits? + // TODO Refactor once public consts are supported. + // TODO Consider public(package) once available. + public fun EOnePipeRequired() : u64 { 1 } + public fun EHostAddressMismatch1() : u64 { 2 } + public fun EHostAddressMismatch2() : u64 { 3 } + public fun EPipeInstanceSame() : u64 { 4 } + public fun EServiceIdxOutOfRange() : u64 { 5 } + + // === Structs === + + // === Public-Mutative Functions === + + // === Public-View Functions === + + // === Admin Functions === + + // === Public-Friend Functions === + + // === Private Functions === + + // === Test Functions === + + +} \ No newline at end of file diff --git a/move/sources/host.move b/move/sources/host.move index d85bb10..86f9334 100644 --- a/move/sources/host.move +++ b/move/sources/host.move @@ -21,6 +21,8 @@ module dtp::host { service_type::{ServiceType}, stats::{ConnectionAcceptedStats, ConnectionRejectedStats, ConnectionClosedStats}, basic_types::{WeakID}, + consts::{Self}, + errors::{Self}, }; #[test_only] @@ -40,7 +42,7 @@ module dtp::host { } public struct Service has store { - srvc_type: ServiceType, + service_idx: u8, // Each connection requested increments one member of either con_accepted or con_rejected. con_accepted: ConnectionAcceptedStats, @@ -70,7 +72,7 @@ module dtp::host { // // The protocol will progressively close LRU connections until eventual // respect the new limit. - max_con: u16, + max_con: u32, } @@ -79,24 +81,29 @@ module dtp::host { flgs: u8, // DTP version+esc flags always after UID. + // Creation timestamp (UTC) + // TODO - // Settings that may change from time to time. - // + // Last SLA Update timestamp (UTC) + // TODO - // Aggregated connections statistic (updated periodically). + // Last Server Heartbeat timestamp (UTC) // TODO - // ************************************************************* - // Information that do not change for the lifetime of the Node. - // ************************************************************* + // Last Config Update timestamp (UTC) - For debugging purpose. + // TODO - // Creation time info + // Last Protocol Sync timestamp (UTC) - For debugging purpose. // TODO - // Service Level Agreements + // Settings controlled by AdminCap. + config: HostConfig, + + // Aggregated connections statistic (updated periodically). // TODO - // Future proofing. + // Service Level Agreements + // TODO } // Constructors @@ -105,12 +112,14 @@ module dtp::host { public(friend) fun new(ctx: &mut TxContext) : Host { Host { id: object::new(ctx), - flgs: 0 + flgs: 0, + config: HostConfig { + max_con: consts::MAX_CONNECTION_PER_HOST(), + }, } } - public entry fun create( ctx: &mut TxContext ) { transfer::share_object(new(ctx)); } - + public entry fun create( ctx: &mut TxContext ) { transfer::share_object(new(ctx)); } } #[test_only] diff --git a/move/sources/service_type.move b/move/sources/service_type.move index 79acc88..14e4133 100644 --- a/move/sources/service_type.move +++ b/move/sources/service_type.move @@ -8,63 +8,102 @@ module dtp::service_type { // // Intended to mimic https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers // + // Keep in mind that DTP provide "layer 7" services, so it will not + // match exactly IANA RFC numbers.abort + // + // As an example, DTP can add gRPC specific functionality, while in the IP + // world it is served by HTTPS. + // // Example: // :443 --> HTTPS server // :22 --> SSH + port: u32, - // The end-user and DTP API uses the protocol port. + // The end-users and DTP API uses the protocol_port. // - // The DTP SDKs convert the port to idx when interacting - // with the Move modules. + // The DTP SDKs convert the port to ServiceTypeIdx when + // interacting with the Move modules. // // This is to optimize fast service object access using a vector. // - // [1..254] (0 and 255 reserved) + // [0..SERVICE_TYPE.length - 1] + // where SERVICE_TYPE.length <= 256 + // 0 means invalid + // 255 is for future use. idx: u8, } - // TODO Searcheable list of supported type. - // Think hard before adding a new type... these are forever. + // Add new Service only at the end of the list. + + // Invalid Service Type + const C_SERVICE_TYPE_INVALID_IDX: u8 = 0; + const C_SERVICE_TYPE_INVALID_NAME: vector = b"Invalid"; + const C_SERVICE_TYPE_INVALID_PORT: u32 = 0; // UDP Tunelling. - const SERVICE_TYPE_UDP_IDX: u8 = 1; - const SERVICE_TYPE_UDP_NAME: vector = b"UDP"; - const SERVICE_TYPE_UDP_PORT: u32 = 1; + const C_SERVICE_TYPE_UDP_IDX: u8 = 1; + const C_SERVICE_TYPE_UDP_NAME: vector = b"UDP"; + const C_SERVICE_TYPE_UDP_PORT: u32 = 1; // Remote Procedure Call (RPC) - const SERVICE_TYPE_JSON_RPC_2_0_IDX: u8 = 2; - const SERVICE_TYPE_JSON_RPC_2_0_NAME: vector = b"JSON-RPC 2.0"; - const SERVICE_TYPE_JSON_RPC_2_0_PORT: u32 = 2; + const C_SERVICE_TYPE_JSON_RPC_2_0_IDX: u8 = 2; + const C_SERVICE_TYPE_JSON_RPC_2_0_NAME: vector = b"JSON-RPC 2.0"; + const C_SERVICE_TYPE_JSON_RPC_2_0_PORT: u32 = 2; // GraphQL Service - const SERVICE_TYPE_GRAPHQL_IDX: u8 = 3; - const SERVICE_TYPE_GRAPHQL_NAME: vector = b"GRAPHQL"; - const SERVICE_TYPE_GRAPHQL_PORT: u32 = 3; + const C_SERVICE_TYPE_GRAPHQL_IDX: u8 = 3; + const C_SERVICE_TYPE_GRAPHQL_NAME: vector = b"GRAPHQL"; + const C_SERVICE_TYPE_GRAPHQL_PORT: u32 = 3; // HTTP (optionally encrypted) - const SERVICE_TYPE_HTTP_IDX: u8 = 4; - const SERVICE_TYPE_HTTP_NAME: vector = b"HTTP"; - const SERVICE_TYPE_HTTP_PORT: u32 = 80; + const C_SERVICE_TYPE_HTTP_IDX: u8 = 4; + const C_SERVICE_TYPE_HTTP_NAME: vector = b"HTTP"; + const C_SERVICE_TYPE_HTTP_PORT: u32 = 80; // HTTPS (always encrypted) - const SERVICE_TYPE_HTTPS_IDX: u8 = 5; - const SERVICE_TYPE_HTTPS_NAME: vector = b"HTTPS"; - const SERVICE_TYPE_HTTPS_PORT: u32 = 443; + const C_SERVICE_TYPE_HTTPS_IDX: u8 = 5; + const C_SERVICE_TYPE_HTTPS_NAME: vector = b"HTTPS"; + const C_SERVICE_TYPE_HTTPS_PORT: u32 = 443; - // Secure Shell Protocol - const SERVICE_TYPE_SSH_IDX: u16 = 6; - const SERVICE_TYPE_SSH_NAME: vector = b"SSH"; - const SERVICE_TYPE_SSH_PORT: u32 = 22; + // Ping (ICMP Echo Request/Reply) + const C_SERVICE_TYPE_ECHO_IDX: u8 = 7; + const C_SERVICE_TYPE_ECHO_NAME: vector = b"ECHO"; + const C_SERVICE_TYPE_ECHO_PORT: u32 = 7; + + // gRPC + const C_SERVICE_TYPE_GRPC_IDX: u8 = 8; + const C_SERVICE_TYPE_GRPC_NAME: vector = b"GRPC"; + const C_SERVICE_TYPE_GRPC_PORT: u32 = 8; - // Ping - const SERVICE_TYPE_ECHO_IDX: u16 = 7; - const SERVICE_TYPE_ECHO_NAME: vector = b"ECHO"; - const SERVICE_TYPE_ECHO_PORT: u32 = 7; + // Discard Protocol + // + // Connection used to send any data. No guarantees of being process + // by the receiver. Data retention time is minimized (drop on network + // as soon as possible). Sender pays all costs. + // + // Intended for testing/benchmarking of sender. + const C_SERVICE_TYPE_DISCARD_IDX: u8 = 9; + const C_SERVICE_TYPE_DISCARD_NAME: vector = b"DISCARD"; + const C_SERVICE_TYPE_DISCARD_PORT: u32 = 9; + + // [10..20] Available // File Transfer - const SERVICE_TYPE_FTP_IDX: u16 = 8; - const SERVICE_TYPE_FTP_NAME: vector = b"FTP"; - const SERVICE_TYPE_FTP_PORT: u32 = 21; + const C_SERVICE_TYPE_FTP_IDX: u8 = 21; + const C_SERVICE_TYPE_FTP_NAME: vector = b"FTP"; + const C_SERVICE_TYPE_FTP_PORT: u32 = 21; + + // Secure Shell Protocol + const C_SERVICE_TYPE_SSH_IDX: u8 = 22; + const C_SERVICE_TYPE_SSH_NAME: vector = b"SSH"; + const C_SERVICE_TYPE_SSH_PORT: u32 = 22; + + // !!! Update SERVICE_TYPE_MAX_IDX when appending new service types. !!! + const C_SERVICE_TYPE_MAX_IDX: u8 = C_SERVICE_TYPE_SSH_IDX; + + public fun SERVICE_TYPE_MAX_IDX() : u8 { + C_SERVICE_TYPE_MAX_IDX + } } \ No newline at end of file diff --git a/move/sources/transport_control.move b/move/sources/transport_control.move index 819b6e8..f1b0089 100644 --- a/move/sources/transport_control.move +++ b/move/sources/transport_control.move @@ -2,10 +2,6 @@ module dtp::transport_control { - public struct BEConReq has copy, drop { - sender: address, // Sender Requesting a Connection - } - // Code order guideline? (WIP - still learning): // use (std, sui, other, dtp) // { friend } @@ -25,31 +21,52 @@ module dtp::transport_control { // Other private Less Accessible // ================ Tests ===================== // Unit Tests - use std::option::{Self, Option}; - use sui::object::{Self, ID, UID}; - use sui::tx_context::{Self,TxContext}; - use sui::event; - use sui::transfer; + use std:: { + option::{Self, Option}, + }; + + use sui:: { + object::{Self, ID, UID}, + tx_context::{Self,TxContext}, + event, + transfer + }; + + use dtp:: { + service_type::{Self}, + errors::{Self}, + }; #[test_only] friend dtp::test_transport_control; + public struct BEConReq has copy, drop { + sender: address, // Sender Requesting a Connection + } + // Control Plane of a connection. // - // Shared object with public entry functions allowed only - // for the client and server of the related connection. + // Shared object + // + // Authorized Callers: + // - Connection Initiator (Client) + // - Host owner (Server) + // public struct TransportControl has key, store { id: UID, flags: u8, // DTP version+esc flags always after UID. + + service_idx: u8, // UDP, Ping, HTTPS etc... - client_host: Option, // Not set on broadcast. + // Hosts involved in the connection. + client_host: ID, server_host: ID, - - // Do not change for the lifetime of this object. - client_adm: Option
, // Not set on broadcast. - server_adm: address, + + // Authorization verified by sender ID address. + client_addr: address, + server_addr: address, // Connection Type. // @@ -59,65 +76,61 @@ module dtp::transport_control { // // Intended for slow discovery. // - // It is expected that related DTP endpoints - // will cache these IDs. - // - // TODO Just one pipe per direction for now (Multi-Channel later) + // It is expected that DTP off-chain will cache these IDs. + // + // Optional in case of uni-directiobal connection. client_tx_pipe: Option, - server_tx_pipe: Option, - - // {Protocol,Port} tupple aka the Service. - protocol: u16, - port: Option, - - // Intended for traffic returning to the client in a bi-directional connection. - return_port: Option, - - // Pipe Aggregated statistics (updated periodically) - // Useful as a "feedback/debug" for the peer. - // TODO + server_tx_pipe: Option, } // Constructors - fun init(_ctx: &mut TxContext) {} - public(friend) fun new( - client_host: Option, server_host: ID, - client_adm: Option
, server_adm: address, - client_tx_pipe: Option, server_tx_pipe: Option, - protocol: u16, port: Option, return_port: Option, + service_idx: u8, + client_host: ID, server_host: ID, + client_addr: address, server_addr: address, + client_tx_pipe: Option, server_tx_pipe: Option, ctx: &mut TxContext): TransportControl { + + // If address are same, then the host ID must be the same, else the host ID must be different. + if (client_addr == server_addr) { + assert!(client_host == server_host, errors::EHostAddressMismatch1()); + } else { + assert!(client_host != server_host, errors::EHostAddressMismatch2()); + }; + + // Verify that at least one pipe is provided._ + assert!(option::is_some(&client_tx_pipe) || option::is_some(&server_tx_pipe), errors::EOnePipeRequired()); + + // If two pipes are provided, they must be different. + if (option::is_some(&client_tx_pipe) && option::is_some(&server_tx_pipe)) { + let pipe1 = option::some(client_tx_pipe); + let pipe2 = option::some(server_tx_pipe); + assert!(pipe1 != pipe2, errors::EPipeInstanceSame()); + }; + + // Check service_idx is in-range. + assert!(service_idx < service_type::SERVICE_TYPE_MAX_IDX(), errors::EServiceIdxOutOfRange()); + TransportControl { id: object::new(ctx), flags: 0, + service_idx, client_host, server_host, - client_adm, server_adm, - client_tx_pipe, server_tx_pipe, - protocol, port, return_port + client_addr, server_addr, + client_tx_pipe, server_tx_pipe, } } public(friend) fun delete( self: TransportControl ) { let TransportControl { id, flags: _, - client_host, server_host: _, - client_adm, server_adm: _, - client_tx_pipe, server_tx_pipe, - protocol: _, port: _, return_port: _ + service_idx: _, + client_host: _, server_host: _, + client_addr: _, server_addr: _, + client_tx_pipe, server_tx_pipe, } = self; - if (option::is_some(&client_host)) { - option::destroy_some(client_host); - } else { - option::destroy_none(client_host); - }; - - if (option::is_some(&client_adm)) { - option::destroy_some(client_adm); - } else { - option::destroy_none(client_adm); - }; if (option::is_some(&client_tx_pipe)) { option::destroy_some(client_tx_pipe); @@ -135,12 +148,12 @@ module dtp::transport_control { } // Read accessors - public(friend) fun server_adm(self: &TransportControl): address { - self.server_adm + public(friend) fun server_addr(self: &TransportControl): address { + self.server_addr } - public(friend) fun client_adm(self: &TransportControl): Option
{ - self.client_adm + public(friend) fun client_addr(self: &TransportControl): address { + self.client_addr } // The TransportControl is the shared object for the @@ -172,17 +185,14 @@ module dtp::transport_control { // wasted gas attempting to connect. // // Pre-approved Service is a more controlled approach where the connection is - // very likely to work for the approved user. It is more appropriate in any - // circumstance where a service level agreement is expected (e.g. customer - // and business relationship). Firewall and controlled access is possible, - // the server ressources is reserved for their intended users. + // very likely to work for the approved user. It is more appropriate in + // circumstance where there is an off-chain business relationship. // - public entry fun create_best_effort( client_host: ID, + public entry fun create_best_effort( service_idx: u8, + client_host: ID, server_host: ID, - server_adm: address, - protocol: u16, - port: u16, - return_port: u16, + server_addr: address, + _return_port: u16, ctx: &mut TxContext ) { // Create the tx pipes and the TransportControl itself. @@ -194,17 +204,18 @@ module dtp::transport_control { // let sender = tx_context::sender(ctx); let mut tc = dtp::transport_control::new( - option::some(client_host), + service_idx, + client_host, server_host, - option::some(sender), - server_adm, - option::none(), + sender, + server_addr, + option::none(), // Pipe are not known yet. option::none(), - protocol, option::some(port), option::some(return_port), ctx ); + 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_adm)); + tc.server_tx_pipe = option::some(dtp::pipe::create_internal(ctx, server_addr)); // Emit the "Connection Request" Move event. // The server will see the sender object therefore will know the TC and plenty of info! @@ -267,13 +278,8 @@ module dtp::test_transport_control { let scenario_val = test_scenario::begin(creator); let scenario = &mut scenario_val; - /* TODO Figure out how to call init, or is it always called by default? - { - transport_control::init(ctx); - };*/ - - let fake_client_address = @0x2; - let fake_server_address = @0x3; + let fake_client_address = @0x20; + let fake_server_address = @0x30; let fake_client_pipe_id; let fake_server_pipe_id; @@ -301,7 +307,7 @@ module dtp::test_transport_control { ctx ); // Test accessors - assert!(transport_control::server_adm(&tc) == fake_server_address, 1); + assert!(transport_control::server_addr(&tc) == fake_server_address, 1); //debug::print(&tc);