#[cfg(not(feature = "std"))]
extern crate alloc;
use crate::endpoint::{
CollectedFee, Endpoint, EndpointRequest, EndpointRequestWithCollectedFee, EndpointResponse,
};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use parity_scale_codec::{Decode, Encode};
use scale_info::TypeInfo;
pub use sp_domains::{ChainId, ChannelId};
use sp_runtime::app_crypto::sp_core::U256;
use sp_runtime::DispatchError;
use sp_subspace_mmr::ConsensusChainMmrLeafProof;
use sp_trie::StorageProof;
pub type Nonce = U256;
pub type MessageId = (ChannelId, Nonce);
pub type MessageKey = (ChainId, ChannelId, Nonce);
#[derive(Default, Debug, Encode, Decode, Clone, Copy, Eq, PartialEq, TypeInfo)]
pub struct FeeModel<Balance> {
pub relay_fee: Balance,
}
#[derive(Default, Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub enum ChannelState {
#[default]
Initiated,
Open,
Closed,
}
#[derive(Default, Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub struct Channel<Balance, AccountId> {
pub channel_id: ChannelId,
pub state: ChannelState,
pub next_inbox_nonce: Nonce,
pub next_outbox_nonce: Nonce,
pub latest_response_received_message_nonce: Option<Nonce>,
pub max_outgoing_messages: u32,
pub fee: FeeModel<Balance>,
pub maybe_owner: Option<AccountId>,
pub channel_reserve_fee: Balance,
}
#[derive(Default, Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo, Copy)]
pub struct ChannelOpenParams<Balance> {
pub max_outgoing_messages: u32,
pub fee_model: FeeModel<Balance>,
}
#[derive(Debug, Encode, Decode, Eq, PartialEq, TypeInfo, Copy, Clone)]
pub struct ChannelOpenParamsV1 {
pub max_outgoing_messages: u32,
}
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub enum ProtocolMessageRequest<ChannelOpenParams> {
ChannelOpen(ChannelOpenParams),
ChannelClose,
}
impl<Balance: Default> From<ProtocolMessageRequest<ChannelOpenParamsV1>>
for ProtocolMessageRequest<ChannelOpenParams<Balance>>
{
fn from(value: ProtocolMessageRequest<ChannelOpenParamsV1>) -> Self {
match value {
ProtocolMessageRequest::ChannelOpen(params) => {
ProtocolMessageRequest::ChannelOpen(ChannelOpenParams {
max_outgoing_messages: params.max_outgoing_messages,
fee_model: FeeModel::default(),
})
}
ProtocolMessageRequest::ChannelClose => ProtocolMessageRequest::ChannelClose,
}
}
}
impl<Balance: Default> From<ProtocolMessageRequest<ChannelOpenParams<Balance>>>
for ProtocolMessageRequest<ChannelOpenParamsV1>
{
fn from(value: ProtocolMessageRequest<ChannelOpenParams<Balance>>) -> Self {
match value {
ProtocolMessageRequest::ChannelOpen(params) => {
ProtocolMessageRequest::ChannelOpen(ChannelOpenParamsV1 {
max_outgoing_messages: params.max_outgoing_messages,
})
}
ProtocolMessageRequest::ChannelClose => ProtocolMessageRequest::ChannelClose,
}
}
}
pub type ProtocolMessageResponse = Result<(), DispatchError>;
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub enum RequestResponse<Request, Response> {
Request(Request),
Response(Response),
}
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub enum Payload<Balance> {
Protocol(
RequestResponse<
ProtocolMessageRequest<ChannelOpenParams<Balance>>,
ProtocolMessageResponse,
>,
),
Endpoint(RequestResponse<EndpointRequest, EndpointResponse>),
}
impl<Balance: Default> From<PayloadV1<Balance>> for Payload<Balance> {
fn from(value: PayloadV1<Balance>) -> Self {
match value {
PayloadV1::Protocol(RequestResponse::Request(req)) => {
Payload::Protocol(RequestResponse::Request(req.into()))
}
PayloadV1::Protocol(RequestResponse::Response(resp)) => {
Payload::Protocol(RequestResponse::Response(resp))
}
PayloadV1::Endpoint(RequestResponse::Request(req)) => {
Payload::Endpoint(RequestResponse::Request(req.into()))
}
PayloadV1::Endpoint(RequestResponse::Response(resp)) => {
Payload::Endpoint(RequestResponse::Response(resp))
}
}
}
}
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub enum PayloadV1<Balance> {
Protocol(RequestResponse<ProtocolMessageRequest<ChannelOpenParamsV1>, ProtocolMessageResponse>),
Endpoint(RequestResponse<EndpointRequestWithCollectedFee<Balance>, EndpointResponse>),
}
impl<Balance: Default> From<Payload<Balance>> for PayloadV1<Balance> {
fn from(value: Payload<Balance>) -> Self {
match value {
Payload::Protocol(RequestResponse::Request(req)) => {
PayloadV1::Protocol(RequestResponse::Request(req.into()))
}
Payload::Protocol(RequestResponse::Response(resp)) => {
PayloadV1::Protocol(RequestResponse::Response(resp))
}
Payload::Endpoint(RequestResponse::Request(req)) => {
PayloadV1::Endpoint(RequestResponse::Request(req.into()))
}
Payload::Endpoint(RequestResponse::Response(resp)) => {
PayloadV1::Endpoint(RequestResponse::Response(resp))
}
}
}
}
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub enum VersionedPayload<Balance> {
#[codec(index = 0)]
V0(Payload<Balance>),
#[codec(index = 1)]
V1(PayloadV1<Balance>),
}
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub struct ConvertedPayload<Balance> {
pub payload: Payload<Balance>,
pub is_v1: bool,
}
impl<Balance> From<Payload<Balance>> for ConvertedPayload<Balance> {
fn from(value: Payload<Balance>) -> Self {
ConvertedPayload {
payload: value,
is_v1: false,
}
}
}
impl<Balance: Default> From<PayloadV1<Balance>> for ConvertedPayload<Balance> {
fn from(value: PayloadV1<Balance>) -> Self {
ConvertedPayload {
payload: value.into(),
is_v1: true,
}
}
}
impl<Balance: Default + Clone> VersionedPayload<Balance> {
pub fn into_payload_v0(self) -> ConvertedPayload<Balance> {
match self {
VersionedPayload::V0(payload) => payload.into(),
VersionedPayload::V1(payload) => payload.into(),
}
}
pub fn maybe_collected_fee(&self) -> Option<CollectedFee<Balance>> {
match self {
VersionedPayload::V1(PayloadV1::Endpoint(RequestResponse::Request(req))) => {
Some(req.collected_fee.clone())
}
_ => None,
}
}
}
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo, Default)]
pub enum MessageWeightTag {
ProtocolChannelOpen,
ProtocolChannelClose,
EndpointRequest(Endpoint),
EndpointResponse(Endpoint),
#[default]
None,
}
impl MessageWeightTag {
pub fn outbox<Balance>(outbox_payload: &VersionedPayload<Balance>) -> Self {
match outbox_payload {
VersionedPayload::V0(Payload::Protocol(RequestResponse::Request(
ProtocolMessageRequest::ChannelOpen(_),
)))
| VersionedPayload::V1(PayloadV1::Protocol(RequestResponse::Request(
ProtocolMessageRequest::ChannelOpen(_),
))) => MessageWeightTag::ProtocolChannelOpen,
VersionedPayload::V0(Payload::Protocol(RequestResponse::Request(
ProtocolMessageRequest::ChannelClose,
)))
| VersionedPayload::V1(PayloadV1::Protocol(RequestResponse::Request(
ProtocolMessageRequest::ChannelClose,
))) => MessageWeightTag::ProtocolChannelClose,
VersionedPayload::V0(Payload::Endpoint(RequestResponse::Request(req)))
| VersionedPayload::V1(PayloadV1::Endpoint(RequestResponse::Request(
EndpointRequestWithCollectedFee { req, .. },
))) => MessageWeightTag::EndpointRequest(req.dst_endpoint.clone()),
_ => MessageWeightTag::None,
}
}
pub fn inbox_response<Balance>(
req_type: MessageWeightTag,
resp_payload: &VersionedPayload<Balance>,
) -> Self {
match (req_type, resp_payload) {
(
MessageWeightTag::ProtocolChannelOpen,
VersionedPayload::V0(Payload::Protocol(RequestResponse::Response(Ok(_)))),
) => MessageWeightTag::ProtocolChannelOpen,
(
MessageWeightTag::EndpointRequest(endpoint),
VersionedPayload::V0(Payload::Endpoint(RequestResponse::Response(_))),
) => MessageWeightTag::EndpointResponse(endpoint),
(
MessageWeightTag::ProtocolChannelOpen,
VersionedPayload::V1(PayloadV1::Protocol(RequestResponse::Response(Ok(_)))),
) => MessageWeightTag::ProtocolChannelOpen,
(
MessageWeightTag::EndpointRequest(endpoint),
VersionedPayload::V1(PayloadV1::Endpoint(RequestResponse::Response(_))),
) => MessageWeightTag::EndpointResponse(endpoint),
_ => MessageWeightTag::None,
}
}
}
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub struct Message<Balance> {
pub src_chain_id: ChainId,
pub dst_chain_id: ChainId,
pub channel_id: ChannelId,
pub nonce: Nonce,
pub payload: VersionedPayload<Balance>,
pub last_delivered_message_response_nonce: Option<Nonce>,
}
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub enum Proof<CBlockNumber, CBlockHash, MmrHash> {
Consensus {
consensus_chain_mmr_proof: ConsensusChainMmrLeafProof<CBlockNumber, CBlockHash, MmrHash>,
message_proof: StorageProof,
},
Domain {
consensus_chain_mmr_proof: ConsensusChainMmrLeafProof<CBlockNumber, CBlockHash, MmrHash>,
domain_proof: StorageProof,
message_proof: StorageProof,
},
}
impl<CBlockNumber, CBlockHash, MmrHash> Proof<CBlockNumber, CBlockHash, MmrHash> {
pub fn message_proof(&self) -> StorageProof {
match self {
Proof::Consensus { message_proof, .. } => message_proof.clone(),
Proof::Domain { message_proof, .. } => message_proof.clone(),
}
}
pub fn consensus_mmr_proof(
&self,
) -> ConsensusChainMmrLeafProof<CBlockNumber, CBlockHash, MmrHash>
where
CBlockNumber: Clone,
CBlockHash: Clone,
MmrHash: Clone,
{
match self {
Proof::Consensus {
consensus_chain_mmr_proof,
..
} => consensus_chain_mmr_proof.clone(),
Proof::Domain {
consensus_chain_mmr_proof,
..
} => consensus_chain_mmr_proof.clone(),
}
}
pub fn domain_proof(&self) -> Option<StorageProof> {
match self {
Proof::Consensus { .. } => None,
Proof::Domain { domain_proof, .. } => Some(domain_proof.clone()),
}
}
}
#[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)]
pub struct CrossDomainMessage<CBlockNumber, CBlockHash, MmrHash> {
pub src_chain_id: ChainId,
pub dst_chain_id: ChainId,
pub channel_id: ChannelId,
pub nonce: Nonce,
pub proof: Proof<CBlockNumber, CBlockHash, MmrHash>,
pub weight_tag: MessageWeightTag,
}
#[derive(Debug, Encode, Decode, TypeInfo, Clone, Eq, PartialEq)]
pub struct BlockMessageWithStorageKey {
pub src_chain_id: ChainId,
pub dst_chain_id: ChainId,
pub channel_id: ChannelId,
pub nonce: Nonce,
pub storage_key: Vec<u8>,
pub weight_tag: MessageWeightTag,
}
impl BlockMessageWithStorageKey {
pub fn id(&self) -> (ChannelId, Nonce) {
(self.channel_id, self.nonce)
}
}
#[derive(Default, Debug, Encode, Decode, TypeInfo, Clone, Eq, PartialEq)]
pub struct BlockMessagesWithStorageKey {
pub outbox: Vec<BlockMessageWithStorageKey>,
pub inbox_responses: Vec<BlockMessageWithStorageKey>,
}
impl BlockMessagesWithStorageKey {
pub fn is_empty(&self) -> bool {
self.outbox.is_empty() && self.inbox_responses.is_empty()
}
}
impl<BlockNumber, BlockHash, MmrHash> CrossDomainMessage<BlockNumber, BlockHash, MmrHash> {
pub fn from_relayer_msg_with_proof(
r_msg: BlockMessageWithStorageKey,
proof: Proof<BlockNumber, BlockHash, MmrHash>,
) -> Self {
CrossDomainMessage {
src_chain_id: r_msg.src_chain_id,
dst_chain_id: r_msg.dst_chain_id,
channel_id: r_msg.channel_id,
nonce: r_msg.nonce,
proof,
weight_tag: r_msg.weight_tag,
}
}
}