diff --git a/src/ic_message/ic_message.did b/src/ic_message/ic_message.did index 5d0f82a..5a998ca 100644 --- a/src/ic_message/ic_message.did +++ b/src/ic_message/ic_message.did @@ -23,6 +23,7 @@ type ChannelECDHInput = record { type ChannelInfo = record { id : nat32; dek : blob; + gas : nat64; updated_at : nat64; members : vec principal; managers : vec principal; diff --git a/src/ic_message_channel/ic_message_channel.did b/src/ic_message_channel/ic_message_channel.did index 2940539..23fa5d5 100644 --- a/src/ic_message_channel/ic_message_channel.did +++ b/src/ic_message_channel/ic_message_channel.did @@ -23,6 +23,7 @@ type CanisterStatusType = variant { stopped; stopping; running }; type ChainArgs = variant { Upgrade : UpgradeArgs; Init : InitArgs }; type ChannelBasicInfo = record { id : nat32; + gas : nat64; updated_at : nat64; name : text; paid : nat64; @@ -38,6 +39,7 @@ type ChannelECDHInput = record { type ChannelInfo = record { id : nat32; dek : blob; + gas : nat64; updated_at : nat64; members : vec principal; managers : vec principal; @@ -108,8 +110,10 @@ type Result_8 = variant { Ok : vec Message; Err : text }; type Result_9 = variant { Ok : vec record { nat32; nat32 }; Err : text }; type StateInfo = record { channel_id : nat32; + incoming_gas : nat; managers : vec principal; name : text; + burned_gas : nat; channels_total : nat64; messages_total : nat64; }; diff --git a/src/ic_message_channel/src/api_query.rs b/src/ic_message_channel/src/api_query.rs index 728c74c..991ea40 100644 --- a/src/ic_message_channel/src/api_query.rs +++ b/src/ic_message_channel/src/api_query.rs @@ -12,6 +12,8 @@ fn get_state() -> Result { name: s.name.clone(), managers: s.managers.clone(), channel_id: s.channel_id, + incoming_gas: s.incoming_gas, + burned_gas: s.burned_gas, channels_total: store::channel::channels_total(), messages_total: store::channel::messages_total(), })) diff --git a/src/ic_message_channel/src/store.rs b/src/ic_message_channel/src/store.rs index 8d3d158..756a65a 100644 --- a/src/ic_message_channel/src/store.rs +++ b/src/ic_message_channel/src/store.rs @@ -16,6 +16,9 @@ use std::{ use crate::types; +const MESSAGE_PER_USER_GAS: u64 = 10000; +const MESSAGE_PER_BYTE_GAS: u64 = 1000; + type Memory = VirtualMemory; #[derive(Clone, Default, Deserialize, Serialize)] @@ -24,6 +27,10 @@ pub struct State { pub managers: BTreeSet, pub channel_id: u32, pub user_channels: HashMap>, + #[serde(default)] + pub incoming_gas: u128, + #[serde(default)] + pub burned_gas: u128, } impl Storable for State { @@ -68,6 +75,8 @@ pub struct Channel { pub latest_message_by: Principal, #[serde(rename = "pa")] pub paid: u64, + #[serde(rename = "g")] + pub gas: u64, } impl Channel { @@ -102,6 +111,7 @@ impl Channel { latest_message_by: self.latest_message_by, updated_at: self.updated_at, paid: self.paid, + gas: self.gas, my_setting, } } @@ -349,18 +359,16 @@ pub mod channel { if mid.1 == u32::MAX { ic_cdk::trap("message id overflow"); } + let message = Message { + kind: 1, + reply_to: 0, + created_at: now_ms, + created_by: caller, + payload: to_cbor_bytes(&message).into(), + }; MESSAGE_STORE.with(|r| { - r.borrow_mut().insert( - mid, - Message { - kind: 1, - reply_to: 0, - created_at: now_ms, - created_by: caller, - payload: to_cbor_bytes(&message).into(), - }, - ); + r.borrow_mut().insert(mid, message); }); } @@ -370,6 +378,7 @@ pub mod channel { now_ms: u64, ) -> Result { let id = state::with_mut(|s| { + s.incoming_gas = s.incoming_gas.saturating_add(input.paid as u128); s.channel_id = s.channel_id.saturating_add(1); s.channel_id }); @@ -408,6 +417,7 @@ pub mod channel { latest_message_at: 1, latest_message_by: caller, paid: input.paid, + gas: input.paid, updated_at: now_ms, }; @@ -541,10 +551,17 @@ pub mod channel { if v.latest_message_at == u32::MAX { Err("message id overflow".to_string())?; } - + let gas = MESSAGE_PER_USER_GAS * (v.managers.len() + v.members.len()) as u64 + + MESSAGE_PER_BYTE_GAS * msg.payload.len() as u64; + if v.gas < gas { + Err("not enough gas".to_string())?; + } + v.gas = v.gas.saturating_sub(gas); v.latest_message_by = msg.created_by; let mid = v.latest_message_at; state::with_mut(|s| { + s.burned_gas = s.burned_gas.saturating_add(gas as u128); + for (p, c) in v.managers.iter_mut() { if p != &msg.created_by { c.unread += 1; @@ -612,6 +629,7 @@ pub mod channel { latest_message_at: v.latest_message_at, latest_message_by: v.latest_message_by, paid: v.paid, + gas: v.gas, my_setting: my_setting.to_owned().into(), }); } diff --git a/src/ic_message_channel/src/types.rs b/src/ic_message_channel/src/types.rs index d53c64f..5d7498f 100644 --- a/src/ic_message_channel/src/types.rs +++ b/src/ic_message_channel/src/types.rs @@ -11,4 +11,6 @@ pub struct StateInfo { pub channel_id: u32, pub channels_total: u64, pub messages_total: u64, + pub incoming_gas: u128, + pub burned_gas: u128, } diff --git a/src/ic_message_types/src/channel.rs b/src/ic_message_types/src/channel.rs index 3c4740d..ff1c44d 100644 --- a/src/ic_message_types/src/channel.rs +++ b/src/ic_message_types/src/channel.rs @@ -29,6 +29,7 @@ pub struct ChannelInfo { pub created_by: Principal, pub updated_at: u64, pub paid: u64, + pub gas: u64, pub message_start: u32, pub latest_message_at: u32, pub latest_message_by: Principal, @@ -44,6 +45,7 @@ pub struct ChannelBasicInfo { pub latest_message_at: u32, pub latest_message_by: Principal, pub paid: u64, + pub gas: u64, pub my_setting: ChannelSetting, }