Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Host impl #2

Merged
merged 12 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
302 changes: 138 additions & 164 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
resolver = "2"

members = [
"ibc",
"ibc/meta"
"host",
"host/meta"
]
14 changes: 14 additions & 0 deletions common/common-modules/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "common-modules"
version = "0.0.0"
authors = ["Dorin Iancu <dorin.iancu@multiversx.com>"]
edition = "2021"

[lib]
path = "src/lib.rs"

[dependencies.multiversx-sc]
version = "=0.53.0"

[dependencies.common-types]
path = "../common-types"
48 changes: 48 additions & 0 deletions common/common-modules/src/client_lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use common_types::ClientId;

multiversx_sc::imports!();

// TODO: Change this if needed
const MAX_CLIENT_ID_LEN: usize = 128;

#[multiversx_sc::module]
pub trait ClientLibModule {
/// client_id must be non-empty and max length of MAX_CLIENT_ID_LEN
///
/// client_id must be in the form of `^[a-z][a-z0-9-]*[a-z0-9]$`
///
/// i.e. Must start with a-z
///
/// contains any of a-z, 0-9 or -
///
/// ends with a-z or 0-9
fn is_valid_client_id(&self, client_id: &ClientId<Self::Api>) -> bool {
let len = client_id.len();
if len == 0 || len > MAX_CLIENT_ID_LEN {
return false;
}

let mut as_array = [0u8; MAX_CLIENT_ID_LEN];
let slice = client_id.load_to_byte_array(&mut as_array);
let first_char = slice[0];
if !first_char.is_ascii_lowercase() {
return false;
}

let last_char = slice[len - 1];
if !last_char.is_ascii_lowercase() && !last_char.is_ascii_digit() {
return false;
}

// clippy suggestion is dumb
#[allow(clippy::needless_range_loop)]
for i in 1..len - 1 {
let character = slice[i];
if !character.is_ascii_lowercase() && !character.is_ascii_digit() && character != b'-' {
return false;
}
}

true
}
}
37 changes: 37 additions & 0 deletions common/common-modules/src/host_lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use common_types::PortId;

multiversx_sc::imports!();

const MIN_PORT_LEN: usize = 2;
const MAX_PORT_LEN: usize = 128;
const SPECIAL_CHARS: &[u8] = b"._+-#[]<>";

#[multiversx_sc::module]
pub trait HostLibModule {
/// check if the string consist of characters in one of the following categories only:
///
/// - Alphanumeric
///
/// - `.`, `_`, `+`, `-`, `#`
///
/// - `[`, `]`, `<`, `>`
fn is_valid_port_id(&self, port_id: &PortId<Self::Api>) -> bool {
let port_len = port_id.len();

// Clippy suggestion makes code unreadable
#[allow(clippy::manual_range_contains)]
if port_len < MIN_PORT_LEN || port_len > MAX_PORT_LEN {
return false;
}

let mut as_array = [0; MAX_PORT_LEN];
let slice = port_id.load_to_byte_array(&mut as_array);
for character in slice {
if !character.is_ascii_alphanumeric() && !SPECIAL_CHARS.contains(character) {
return false;
}
}

true
}
}
5 changes: 5 additions & 0 deletions common/common-modules/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#![no_std]

pub mod client_lib;
pub mod host_lib;
pub mod utils;
12 changes: 12 additions & 0 deletions common/common-modules/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
multiversx_sc::imports!();

#[multiversx_sc::module]
pub trait UtilsModule {
fn require_valid_address(&self, address: &ManagedAddress) {
let own_sc_address = self.blockchain().get_sc_address();
require!(
address != &own_sc_address && !address.is_zero(),
"Invalid address"
);
}
}
11 changes: 11 additions & 0 deletions common/common-types/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "common-types"
version = "0.0.0"
authors = ["Dorin Iancu <dorin.iancu@multiversx.com>"]
edition = "2021"

[lib]
path = "src/lib.rs"

[dependencies.multiversx-sc]
version = "=0.53.0"
229 changes: 229 additions & 0 deletions common/common-types/src/channel_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
pub mod channel {
use crate::{channel_types::channel_counterparty, Sequence};

multiversx_sc::imports!();
multiversx_sc::derive_imports!();

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Default)]
pub enum State {
#[default]
StateUninitializedUnspecified,
StateInit,
StateTryOpen,
StateOpen,
StateClosed,
StateFlushing,
StateFlushComplete,
}

impl State {
pub fn is_uninitialized(&self) -> bool {
matches!(self, State::StateUninitializedUnspecified)
}
}

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Default)]
pub enum Order {
#[default]
OrderNoneUnspecified,
OrderUnordered,
OrderOrdered,
}

impl Order {
pub fn is_unspecified(&self) -> bool {
matches!(self, Order::OrderNoneUnspecified)
}
}

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Default)]
pub struct Data<M: ManagedTypeApi> {
pub state: State,
pub ordering: Order,
pub counterparty: channel_counterparty::Data<M>,
pub connection_hops: ManagedVec<M, ManagedBuffer<M>>, // TODO: Maybe custom type
pub version: ManagedBuffer<M>,
pub upgrade_sequence: Sequence,
}

impl<M: ManagedTypeApi> Data<M> {
pub fn is_empty(&self) -> bool {
if !self.state.is_uninitialized() {
return false;
}

if !self.ordering.is_unspecified() {
return false;
}

if !self.connection_hops.is_empty() {
return false;
}

if !self.version.is_empty() {
return false;
}

if self.upgrade_sequence != 0 {
return false;
}

true
}
}
}

pub mod channel_counterparty {
multiversx_sc::imports!();
multiversx_sc::derive_imports!();

use crate::{ChannelId, PortId};

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Default)]
pub struct Data<M: ManagedTypeApi> {
pub port_id: PortId<M>,
pub channel_id: ChannelId<M>,
}

impl<M: ManagedTypeApi> Data<M> {
pub fn is_empty(&self) -> bool {
if !self.port_id.is_empty() {
return false;
}

if !self.channel_id.is_empty() {
return false;
}

true
}
}
}

pub mod height {
multiversx_sc::imports!();
multiversx_sc::derive_imports!();

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Default)]
pub struct Data {
pub revision_number: u64,
pub revision_height: u64,
}

impl Data {
pub fn is_empty(&self) -> bool {
if self.revision_number != 0 {
return false;
}

if self.revision_height != 0 {
return false;
}

true
}
}
}

pub mod timeout {
use crate::channel_types::height;
use crate::Timestamp;

multiversx_sc::imports!();
multiversx_sc::derive_imports!();

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Default)]
pub struct Data {
pub height: height::Data,
pub timestamp: Timestamp,
}

impl Data {
#[inline]
pub fn is_empty(&self) -> bool {
self.timestamp == 0
}
}
}

pub mod upgrade {
use crate::Sequence;

use super::{timeout, upgrade_fields};

multiversx_sc::imports!();
multiversx_sc::derive_imports!();

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Default)]
pub struct Data<M: ManagedTypeApi> {
pub fields: upgrade_fields::Data<M>,
pub timeout: timeout::Data,
pub next_sequence_send: Sequence,
}

impl<M: ManagedTypeApi> Data<M> {
#[inline]
pub fn is_empty(&self) -> bool {
self.next_sequence_send == 0
}
}
}

pub mod upgrade_fields {
use super::channel;

multiversx_sc::imports!();
multiversx_sc::derive_imports!();

#[derive(TypeAbi, TopEncode, TopDecode, NestedEncode, NestedDecode, Default)]
pub struct Data<M: ManagedTypeApi> {
pub ordering: channel::Order,
pub connection_hops: ManagedVec<M, ManagedBuffer<M>>, // TODO: Maybe custom type
pub version: ManagedBuffer<M>,
}

impl<M: ManagedTypeApi> Data<M> {
pub fn is_empty(&self) -> bool {
if !self.ordering.is_unspecified() {
return false;
}

if !self.connection_hops.is_empty() {
return false;
}

if !self.version.is_empty() {
return false;
}

true
}
}
}

pub mod error_receipt {
use crate::Sequence;

multiversx_sc::imports!();
multiversx_sc::derive_imports!();

#[derive(TypeAbi, TopEncode, TopDecode, Default)]
pub struct Data<M: ManagedTypeApi> {
pub sequence: Sequence,
pub message: ManagedBuffer<M>,
}

impl<M: ManagedTypeApi> Data<M> {
pub fn is_empty(&self) -> bool {
if self.sequence != 0 {
return false;
}

if !self.message.is_empty() {
return false;
}

true
}
}
}
Loading
Loading