diff --git a/code/xcvm/cosmwasm/contracts/interpreter/src/contract.rs b/code/xcvm/cosmwasm/contracts/interpreter/src/contract.rs index 3b0cd2e1b44..7dcb55ddc6a 100644 --- a/code/xcvm/cosmwasm/contracts/interpreter/src/contract.rs +++ b/code/xcvm/cosmwasm/contracts/interpreter/src/contract.rs @@ -147,10 +147,10 @@ pub fn handle_execute_step( interpret_transfer(&mut deps, &env, &tip, to, assets), Instruction::Call { bindings, encoded } => interpret_call(deps.as_ref(), &env, bindings, encoded, instruction_pointer, &tip), - Instruction::Spawn { network, salt, assets, program } => - interpret_spawn(&mut deps, &env, network, salt, assets, program), - Instruction::Exchange { give, id, want } => - interpret_exchange(&mut deps, give, want, id, env.contract.address.clone()), + Instruction::Spawn { network_id, salt, assets, program } => + interpret_spawn(&mut deps, &env, network_id, salt, assets, program), + Instruction::Exchange { exchange_id, give, want } => + interpret_exchange(&mut deps, give, want, exchange_id, env.contract.address.clone()), }?; // Save the intermediate IP so that if the execution fails, we can recover at which // instruction it happened. diff --git a/code/xcvm/lib/core/protos/xcvm.proto b/code/xcvm/lib/core/protos/xcvm.proto index dbfdaf1f5bf..e6e9a9a8ccd 100644 --- a/code/xcvm/lib/core/protos/xcvm.proto +++ b/code/xcvm/lib/core/protos/xcvm.proto @@ -5,16 +5,16 @@ import "common.proto"; package cvm.xcvm; message PacketAsset { - AssetId assetId = 1; + cvm.common.Uint128 asset_id = 1; cvm.common.Uint128 amount = 2; // next tag: 3 } message Packet { - Account interpreter = 1; + bytes interpreter = 1; UserOrigin user_origin = 2; - Salt salt = 3; + bytes salt = 3; Program program = 4; repeated PacketAsset assets = 5; @@ -22,25 +22,19 @@ message Packet { } message UserOrigin { - Network network = 1; - Account account = 2; + uint32 network_id = 1; + bytes account = 2; // next tag: 3 } message Program { bytes tag = 1; - Instructions instructions = 2; + repeated Instruction instructions = 2; // next tag: 3 } -message Instructions { - repeated Instruction instructions = 1; - - // next tag: 2 -} - message Instruction { oneof instruction { Transfer transfer = 1; @@ -83,91 +77,49 @@ message Balance { // next tag: 4 } -message Account { - bytes account = 1; - - // next tag: 2 -} - -message AssetId { - cvm.common.Uint128 id = 1; - - // next tag: 2 -} - -message ExchangeId { - cvm.common.Uint128 id = 1; - - // next tag: 2 -} - message Asset { - AssetId assetId = 1; + cvm.common.Uint128 asset_id = 1; Balance balance = 2; // next tag: 3 } -message Self { - uint32 self = 1; - - // next tag: 2 -} - -message Tip { - uint32 id = 1; - - // next tag: 2 -} - -message Result { - uint32 result = 1; - - // next tag: 2 -} - message AssetAmount { - AssetId assetId = 1; + cvm.common.Uint128 asset_id = 1; Balance balance = 2; // next tag: 3 } -message IpRegister { - uint64 ip = 1; - - // next tag: 2 -} - message BindingValue { oneof type { - Self self = 1; - Tip tip = 2; - Result result = 3; - AssetAmount assetAmount = 4; - AssetId assetId = 5; - IpRegister ipRegister = 6; + Register register = 1; + cvm.common.Uint128 asset_id = 2; + AssetAmount asset_amount = 3; } - // next tag: 7 + // next tag: 4 } -message Binding { - uint32 position = 1; - BindingValue bindingValue = 2; +enum Register { + IP = 0; + TIP = 1; + THIS = 2; + RESULT = 3; - // next tag: 3 + // next tag: 4 } -message Bindings { - repeated Binding bindings = 1; +message Binding { + uint32 position = 1; + BindingValue binding_value = 2; - // next tag: 2 + // next tag: 3 } message Transfer { oneof account_type{ - Account account = 1; + bytes account = 1; Tip tip = 2; } repeated Asset assets = 3; @@ -175,29 +127,21 @@ message Transfer { // next tag: 4 } +message Tip { + // next tag: 1 +} + message Exchange { - ExchangeId id = 1; + cvm.common.Uint128 exchange_id = 1; repeated Asset give = 5; repeated Asset want = 6; // next tag: 7 } -message Salt { - bytes salt = 1; - - // next tag: 2 -} - -message Network { - uint32 networkId = 1; - - // next tag: 2 -} - message Spawn { - Network network = 1; - Salt salt = 3; + uint32 network_id = 1; + bytes salt = 3; Program program = 4; repeated Asset assets = 5; @@ -206,7 +150,7 @@ message Spawn { message Call { bytes payload = 1; - Bindings bindings = 2; + repeated Binding bindings = 2; // next tag: 3 } diff --git a/code/xcvm/lib/core/src/gateway/mod.rs b/code/xcvm/lib/core/src/gateway/mod.rs index 98fa6882ad4..7ec3a3e300a 100644 --- a/code/xcvm/lib/core/src/gateway/mod.rs +++ b/code/xcvm/lib/core/src/gateway/mod.rs @@ -299,7 +299,7 @@ mod tests { program: XcProgram { tag: b"spawn_with_asset".to_vec(), instructions: [Instruction::Spawn { - network: 3.into(), + network_id: 3.into(), salt: b"spawn_with_asset".to_vec(), assets: vec![(pica_on_osmosis, 1_000_000_000u128)].into(), program: XcProgram { @@ -378,7 +378,7 @@ mod tests { program: XcProgram { tag: b"spawn_with_asset".to_vec(), instructions: [Instruction::Spawn { - network: 3.into(), + network_id: 3.into(), salt: b"spawn_with_asset".to_vec(), assets: vec![(pica_on_osmosis, 1_000_000_000u128)].into(), program: XcProgram { @@ -488,19 +488,19 @@ mod tests { program: XcProgram { tag: b"spawn_with_asset".to_vec(), instructions: [Instruction::Spawn { - network: 3.into(), + network_id: 3.into(), salt: b"spawn_with_asset".to_vec(), assets: vec![(pica_on_osmosis, 1_000_000_000u128)].into(), program: XcProgram { tag: b"spawn_with_asset".to_vec(), instructions: [ XcInstruction::Exchange { - id: pica_osmo_on_osmosis.into(), + exchange_id: pica_osmo_on_osmosis.into(), give: XcFundsFilter::one(pica_on_osmosis, 1_000_000_000u128), want: XcFundsFilter::one(osmo_on_osmosis, 1_000u128), }, XcInstruction::Spawn { - network: 2.into(), + network_id: 2.into(), salt: b"spawn_with_asset".to_vec(), assets: XcFundsFilter::one(osmo_on_centauri, (100, 100)), program: XcProgram { @@ -564,7 +564,7 @@ mod tests { "instructions": [ { "exchange": { - "id": "237684489387467420151587012609", + "exchange_id": "237684489387467420151587012609", "give": [ [ "237684487542793012780631851009", @@ -667,7 +667,7 @@ mod tests { program: XcProgram { tag: b"spawn_with_asset".to_vec(), instructions: [Instruction::Spawn { - network: 2.into(), + network_id: 2.into(), salt: b"spawn_with_asset".to_vec(), assets: vec![(osmo_on_centauri, 1_000_000_000u128)].into(), program: XcProgram { diff --git a/code/xcvm/lib/core/src/instruction.rs b/code/xcvm/lib/core/src/instruction.rs index e95f3a2e23c..c8c90439672 100644 --- a/code/xcvm/lib/core/src/instruction.rs +++ b/code/xcvm/lib/core/src/instruction.rs @@ -76,7 +76,7 @@ pub enum Instruction { /// The program will be spawned with the desired [`Assets`]. /// The salt is used to track the program when events are dispatched in the network. Spawn { - network: crate::network::NetworkId, + network_id: crate::network::NetworkId, /// If JSON, than hex encoded non prefixed lower case string. #[serde(serialize_with = "hex::serialize", deserialize_with = "hex::deserialize")] #[cfg_attr(feature = "std", schemars(schema_with = "String::json_schema"))] @@ -85,7 +85,7 @@ pub enum Instruction { program: Program>, }, Exchange { - id: ExchangeId, + exchange_id: ExchangeId, give: Assets, want: Assets, }, diff --git a/code/xcvm/lib/core/src/lib.rs b/code/xcvm/lib/core/src/lib.rs index f19fa0f76ce..043bd1a5f59 100644 --- a/code/xcvm/lib/core/src/lib.rs +++ b/code/xcvm/lib/core/src/lib.rs @@ -83,7 +83,7 @@ where builder.instructions.push_back(Instruction::Spawn { salt: salt.into(), assets: assets.into(), - network: SpawningNetwork::ID, + network_id: SpawningNetwork::ID, program: f(ProgramBuilder::::new(tag.into()))? .build(), }); @@ -190,7 +190,7 @@ mod tests { Instruction::Call { bindings: vec![], encoded: vec![202, 254, 190, 239] }, // Move to ethereum Instruction::Spawn { - network: Ethereum::ID, + network_id: Ethereum::ID, salt: Vec::new(), assets: Funds::default(), program: Program { diff --git a/code/xcvm/lib/core/src/proto.rs b/code/xcvm/lib/core/src/proto.rs index ea65967fc9e..899665d8238 100644 --- a/code/xcvm/lib/core/src/proto.rs +++ b/code/xcvm/lib/core/src/proto.rs @@ -57,3 +57,61 @@ impl core::fmt::Display for DecodeError { } } } + +/// Maps elements of one sequence and produces the other. +/// +/// This is a convenience function for `Vec → Vec` operation (though it +/// works for any containers) where infallible `T → U` conversion exists. +fn from_sequence, T, U: From>( + sequence: impl core::iter::IntoIterator, +) -> R { + sequence.into_iter().map(U::from).collect() +} + +/// Tries to map elements of one sequence and produces the other. +/// +/// This is a convenience function for `Vec → Vec` operation (though it +/// works for any containers) where fallible `T → U` conversion exists. Returns +/// error on the first conversion that fails. +fn try_from_sequence, T, U: TryFrom>( + sequence: impl core::iter::IntoIterator, +) -> Result { + sequence.into_iter().map(U::try_from).collect::>().map_err(|_| ()) +} + +/// Trait providing method which converts ‘empty’ values to ‘Err(())’. +/// +/// Useful for checking whether fields in protocol buffer messages are set. +trait NonEmptyExt: Sized { + type Output: Sized; + fn non_empty(self) -> Result; +} + +impl NonEmptyExt for alloc::string::String { + type Output = Self; + fn non_empty(self) -> Result { + if self.is_empty() { + Err(()) + } else { + Ok(self) + } + } +} + +impl NonEmptyExt for alloc::vec::Vec { + type Output = Self; + fn non_empty(self) -> Result { + if self.is_empty() { + Err(()) + } else { + Ok(self) + } + } +} + +impl NonEmptyExt for Option { + type Output = T; + fn non_empty(self) -> Result { + self.ok_or(()) + } +} diff --git a/code/xcvm/lib/core/src/proto/common.rs b/code/xcvm/lib/core/src/proto/common.rs index fbc809f5bd1..4454f3649da 100644 --- a/code/xcvm/lib/core/src/proto/common.rs +++ b/code/xcvm/lib/core/src/proto/common.rs @@ -12,6 +12,26 @@ impl From for pb::common::Uint128 { } } +macro_rules! define_u128_wrapper { + ($($ty:ty),*) => { + $( + impl From for $ty { + fn from(value: pb::common::Uint128) -> Self { + u128::from(value).into() + } + } + + impl From<$ty> for pb::common::Uint128 { + fn from(value: $ty) -> Self { + u128::from(value).into() + } + } + )* + } +} + +define_u128_wrapper!(crate::AssetId); + #[test] fn test_u128_uint128_conversion() { let value = 0xDEAD_0000_0000_0000_BEEF_0000_0000_0000_u128; diff --git a/code/xcvm/lib/core/src/proto/xcvm.rs b/code/xcvm/lib/core/src/proto/xcvm.rs index a3521ddd16a..322e5bc0f89 100644 --- a/code/xcvm/lib/core/src/proto/xcvm.rs +++ b/code/xcvm/lib/core/src/proto/xcvm.rs @@ -11,14 +11,8 @@ pub use serde::{Deserialize, Serialize}; pub use parity_scale_codec::{Decode, Encode}; -#[cfg(feature = "std")] -pub use cosmwasm_schema::{cw_serde, QueryResponses}; - -#[cfg(feature = "std")] -pub use schemars::JsonSchema; - -use super::pb; -use crate::{shared::Displayed, Amount, Destination, Funds, NetworkId}; +use super::{pb, NonEmptyExt}; +use crate::{shared::Displayed, Amount, Destination, Funds}; pub type XCVMPacket = crate::Packet>; @@ -36,48 +30,6 @@ where type Message = pb::xcvm::Packet; } -impl From> for pb::xcvm::Salt { - fn from(value: Vec) -> Self { - Self { salt: value } - } -} - -impl From for pb::xcvm::Account { - fn from(crate::UserId(account): crate::UserId) -> Self { - Self { account } - } -} - -impl From for pb::xcvm::UserOrigin { - fn from(value: crate::UserOrigin) -> Self { - Self { network: Some(value.network_id.into()), account: Some(value.user_id.into()) } - } -} - -impl From<(crate::AssetId, Displayed)> for pb::xcvm::PacketAsset { - fn from((asset, amount): (crate::AssetId, Displayed)) -> Self { - Self { asset_id: Some(asset.into()), amount: Some(amount.into()) } - } -} - -impl From> - for pb::xcvm::Packet -where - TAbiEncoded: Into>, - TAccount: Into>, - TAssets: Into>, -{ - fn from(value: XCVMPacket) -> Self { - Self { - interpreter: Some(pb::xcvm::Account { account: value.interpreter }), - user_origin: Some(value.user_origin.into()), - salt: Some(value.salt.into()), - program: Some(value.program.into()), - assets: value.assets.0.into_iter().map(pb::xcvm::PacketAsset::from).collect(), - } - } -} - impl super::Isomorphism for XCVMProgram where @@ -92,19 +44,28 @@ impl TryFrom for crate::UserOrigin { type Error = (); fn try_from(value: pb::xcvm::UserOrigin) -> Result { Ok(crate::UserOrigin { - network_id: value.network.ok_or(())?.network_id.into(), - user_id: value.account.ok_or(())?.account.into(), + network_id: value.network_id.into(), + user_id: value.account.non_empty()?.into(), }) } } +impl From for pb::xcvm::UserOrigin { + fn from(value: crate::UserOrigin) -> Self { + Self { network_id: value.network_id.into(), account: value.user_id.into() } + } +} + impl TryFrom for (crate::AssetId, Displayed) { type Error = (); fn try_from(value: pb::xcvm::PacketAsset) -> Result { - Ok(( - crate::AssetId::from(u128::from(value.asset_id.ok_or(())?.id.ok_or(())?)), - value.amount.ok_or(())?.into(), - )) + Ok((value.asset_id.non_empty()?.into(), value.amount.non_empty()?.into())) + } +} + +impl From<(crate::AssetId, Displayed)> for pb::xcvm::PacketAsset { + fn from((asset, amount): (crate::AssetId, Displayed)) -> Self { + Self { asset_id: Some(asset.into()), amount: Some(amount.into()) } } } @@ -112,17 +73,17 @@ impl TryFrom for XCVMPacket where TAbiEncoded: TryFrom>, - TAccount: for<'a> TryFrom<&'a [u8]>, + TAccount: TryFrom>, TAssets: From>, { type Error = (); fn try_from(packet: pb::xcvm::Packet) -> Result { Ok(XCVMPacket { - interpreter: packet.interpreter.ok_or(())?.account, - user_origin: packet.user_origin.ok_or(())?.try_into()?, - salt: packet.salt.map(|s| s.salt).ok_or(())?, - program: packet.program.ok_or(())?.try_into()?, + interpreter: packet.interpreter.non_empty()?, + user_origin: packet.user_origin.non_empty()?.try_into()?, + salt: packet.salt, + program: packet.program.non_empty()?.try_into()?, assets: Funds( packet .assets @@ -134,11 +95,29 @@ where } } +impl From> + for pb::xcvm::Packet +where + TAbiEncoded: Into>, + TAccount: Into>, + TAssets: Into>, +{ + fn from(value: XCVMPacket) -> Self { + Self { + interpreter: value.interpreter, + user_origin: Some(value.user_origin.into()), + salt: value.salt, + program: Some(value.program.into()), + assets: value.assets.0.into_iter().map(pb::xcvm::PacketAsset::from).collect(), + } + } +} + impl TryFrom for XCVMProgram where TAbiEncoded: TryFrom>, - TAccount: for<'a> TryFrom<&'a [u8]>, + TAccount: TryFrom>, TAssets: From>, { type Error = (); @@ -146,26 +125,21 @@ where fn try_from(program: pb::xcvm::Program) -> Result { Ok(XCVMProgram { tag: program.tag, - instructions: program.instructions.ok_or(())?.try_into()?, + instructions: super::try_from_sequence(program.instructions)?, }) } } -impl TryFrom - for VecDeque> +impl From> + for pb::xcvm::Program where - TAbiEncoded: TryFrom>, - TAccount: for<'a> TryFrom<&'a [u8]>, - TAssets: From>, + TAbiEncoded: Into>, + TAccount: Into>, + TAssets: Into>, { - type Error = (); - - fn try_from(instructions: pb::xcvm::Instructions) -> Result { - let mut instrs = VecDeque::new(); - for inst in instructions.instructions { - instrs.push_back(inst.try_into()?); - } - Ok(instrs) + fn from(program: XCVMProgram) -> Self { + let instructions = super::from_sequence(program.instructions); + Self { tag: program.tag, instructions } } } @@ -173,26 +147,13 @@ impl TryFrom for crate::Instruction where TAbiEncoded: TryFrom>, - TAccount: for<'a> TryFrom<&'a [u8]>, + TAccount: TryFrom>, TAssets: From>, { type Error = (); fn try_from(instruction: pb::xcvm::Instruction) -> Result { - instruction.instruction.ok_or(())?.try_into() - } -} - -impl TryFrom - for crate::Instruction -where - TAbiEncoded: TryFrom>, - TAccount: for<'a> TryFrom<&'a [u8]>, - TAssets: From>, -{ - type Error = (); - - fn try_from(instruction: pb::xcvm::instruction::Instruction) -> Result { + let instruction = instruction.instruction.non_empty()?; match instruction { pb::xcvm::instruction::Instruction::Transfer(t) => t.try_into(), pb::xcvm::instruction::Instruction::Spawn(s) => s.try_into(), @@ -202,60 +163,25 @@ where } } -impl TryFrom +impl TryFrom for crate::Instruction where TAbiEncoded: TryFrom>, - TAccount: for<'a> TryFrom<&'a [u8]>, + TAccount: TryFrom>, TAssets: From>, { type Error = (); - fn try_from(call: pb::xcvm::Call) -> Result { - let bindings = call.bindings.ok_or(())?.try_into()?; - Ok(crate::Instruction::Call { bindings, encoded: call.payload.try_into().map_err(|_| ())? }) - } -} - -impl TryFrom for crate::Bindings { - type Error = (); - - fn try_from(bindings: pb::xcvm::Bindings) -> Result { - bindings - .bindings - .into_iter() - .map(|binding| { - let binding_value = binding.binding_value.ok_or(())?.try_into()?; - Ok((binding.position, binding_value)) - }) - .collect() - } -} - -impl TryFrom for crate::BindingValue { - type Error = (); - - fn try_from(binding_value: pb::xcvm::BindingValue) -> Result { - binding_value.r#type.ok_or(())?.try_into() - } -} - -impl TryFrom for crate::BindingValue { - type Error = (); - - fn try_from(binding_val: pb::xcvm::binding_value::Type) -> Result { - use pb::xcvm::binding_value::Type; - Ok(match binding_val { - Type::Self_(_) => crate::BindingValue::Register(crate::Register::This), - Type::Tip(_) => crate::BindingValue::Register(crate::Register::Tip), - Type::Result(_) => crate::BindingValue::Register(crate::Register::Result), - Type::IpRegister(_) => crate::BindingValue::Register(crate::Register::Ip), - Type::AssetAmount(pb::xcvm::AssetAmount { asset_id, balance }) => - crate::BindingValue::AssetAmount( - asset_id.ok_or(())?.try_into()?, - balance.ok_or(())?.try_into()?, - ), - Type::AssetId(asset_id) => crate::BindingValue::Asset(asset_id.try_into()?), + fn try_from(transfer: pb::xcvm::Transfer) -> Result { + let account_type = transfer.account_type.non_empty()?; + Ok(crate::Instruction::Transfer { + to: account_type.try_into()?, + assets: transfer + .assets + .into_iter() + .map(|asset| asset.try_into()) + .collect::, _>>()? + .into(), }) } } @@ -264,119 +190,205 @@ impl TryFrom for crate::Instruction where TAbiEncoded: TryFrom>, - TAccount: for<'a> TryFrom<&'a [u8]>, + TAccount: TryFrom>, TAssets: From>, { type Error = (); fn try_from(spawn: pb::xcvm::Spawn) -> Result { - let network = spawn.network.ok_or(())?.network_id.into(); - let salt = spawn.salt.ok_or(())?.salt; + let assets: Vec<(crate::AssetId, crate::Balance)> = super::try_from_sequence(spawn.assets)?; Ok(crate::Instruction::Spawn { - network, - salt, - assets: spawn - .assets - .into_iter() - .map(|asset| asset.try_into()) - .collect::, _>>()? - .into(), - program: XCVMProgram { - tag: Vec::new(), - instructions: spawn.program.ok_or(())?.instructions.ok_or(())?.try_into()?, - }, + network_id: spawn.network_id.into(), + salt: spawn.salt, + assets: assets.into(), + program: spawn.program.non_empty()?.try_into()?, }) } } -impl From for NetworkId { - fn from(network: pb::xcvm::Network) -> Self { - Self(network.network_id) - } -} - -impl TryFrom +impl TryFrom for crate::Instruction where TAbiEncoded: TryFrom>, - TAccount: for<'a> TryFrom<&'a [u8]>, + TAccount: TryFrom>, TAssets: From>, { type Error = (); - fn try_from(transfer: pb::xcvm::Transfer) -> Result { - let account_type = transfer.account_type.ok_or(())?; - Ok(crate::Instruction::Transfer { - to: account_type.try_into()?, - assets: transfer - .assets - .into_iter() - .map(|asset| asset.try_into()) - .collect::, _>>()? - .into(), + fn try_from(value: pb::xcvm::Exchange) -> Result { + Ok(crate::Instruction::Exchange { + exchange_id: value.exchange_id.non_empty()?.into(), + give: super::try_from_sequence::, _, _>(value.give)?.into(), + want: super::try_from_sequence::, _, _>(value.want)?.into(), }) } } -impl TryFrom +impl TryFrom for crate::Instruction where TAbiEncoded: TryFrom>, - TAccount: for<'a> TryFrom<&'a [u8]>, + TAccount: TryFrom>, TAssets: From>, { type Error = (); - fn try_from(value: pb::xcvm::Exchange) -> Result { - Ok(crate::Instruction::Exchange { - id: value.id.and_then(|x| x.id).map(TryInto::try_into).ok_or(())?.map_err(|_| ())?, - give: value - .give - .into_iter() - .map(|asset| asset.try_into()) - .collect::, _>>()? - .into(), - want: value - .want - .into_iter() - .map(|asset| asset.try_into()) - .collect::, _>>()? - .into(), + fn try_from(call: pb::xcvm::Call) -> Result { + let bindings = super::try_from_sequence(call.bindings)?; + let encoded = call.payload.try_into().map_err(|_| ())?; + Ok(crate::Instruction::Call { bindings, encoded }) + } +} + +impl From> + for pb::xcvm::Instruction +where + TAbiEncoded: Into>, + TAccount: Into>, + TAssets: Into>, +{ + fn from(instruction: crate::Instruction) -> Self { + use crate::Instruction; + use pb::xcvm::instruction::Instruction as Msg; + let instruction = match instruction { + Instruction::Transfer { to, assets } => Msg::Transfer(pb::xcvm::Transfer { + assets: assets.into().into_iter().map(|asset| asset.into()).collect(), + account_type: Some(to.into()), + }), + Instruction::Call { bindings, encoded } => Msg::Call(pb::xcvm::Call { + payload: encoded.into(), + bindings: super::from_sequence(bindings), + }), + Instruction::Spawn { network_id, salt, assets, program } => + Msg::Spawn(pb::xcvm::Spawn { + network_id: network_id.into(), + salt, + program: Some(program.into()), + assets: assets.into().into_iter().map(|asset| asset.into()).collect(), + }), + Instruction::Exchange { exchange_id, give, want } => + Msg::Exchange(pb::xcvm::Exchange { + exchange_id: Some(exchange_id.into()), + give: give.into().into_iter().map(|asset| asset.into()).collect(), + want: want.into().into_iter().map(|asset| asset.into()).collect(), + }), + }; + Self { instruction: Some(instruction) } + } +} + +impl TryFrom for crate::BindingValue { + type Error = (); + + fn try_from(binding_value: pb::xcvm::BindingValue) -> Result { + use pb::xcvm::binding_value::Type; + Ok(match binding_value.r#type.non_empty()? { + Type::Register(reg) => { + let reg = pb::xcvm::Register::from_i32(reg).ok_or(())?; + Self::Register(reg.into()) + }, + Type::AssetId(asset_id) => Self::Asset(asset_id.into()), + Type::AssetAmount(asset_amount) => Self::AssetAmount( + asset_amount.asset_id.non_empty()?.into(), + asset_amount.balance.non_empty()?.try_into()?, + ), }) } } +impl From for pb::xcvm::BindingValue { + fn from(binding_value: crate::BindingValue) -> Self { + use pb::xcvm::binding_value::Type; + let typ = match binding_value { + crate::BindingValue::Register(reg) => + Type::Register(pb::xcvm::Register::from(reg) as i32), + crate::BindingValue::Asset(asset_id) => Type::AssetId(asset_id.into()), + crate::BindingValue::AssetAmount(asset_id, balance) => + Type::AssetAmount(pb::xcvm::AssetAmount { + asset_id: Some(asset_id.into()), + balance: Some(balance.into()), + }), + }; + Self { r#type: Some(typ) } + } +} + +impl TryFrom for (u32, crate::BindingValue) { + type Error = (); + fn try_from(binding: pb::xcvm::Binding) -> Result { + Ok((binding.position, binding.binding_value.non_empty()?.try_into()?)) + } +} + +impl From<(u32, crate::BindingValue)> for pb::xcvm::Binding { + fn from((position, binding_value): (u32, crate::BindingValue)) -> Self { + Self { position, binding_value: Some(binding_value.into()) } + } +} + +impl From for crate::Register { + fn from(reg: pb::xcvm::Register) -> Self { + match reg { + pb::xcvm::Register::Ip => Self::Ip, + pb::xcvm::Register::Tip => Self::Tip, + pb::xcvm::Register::This => Self::This, + pb::xcvm::Register::Result => Self::Result, + } + } +} + +impl From for pb::xcvm::Register { + fn from(reg: crate::Register) -> Self { + match reg { + crate::Register::Ip => Self::Ip, + crate::Register::Tip => Self::Tip, + crate::Register::This => Self::This, + crate::Register::Result => Self::Result, + } + } +} + impl TryFrom for Destination where - TAccount: for<'a> TryFrom<&'a [u8]>, + TAccount: TryFrom>, { type Error = (); fn try_from(account_type: pb::xcvm::transfer::AccountType) -> Result { Ok(match account_type { - pb::xcvm::transfer::AccountType::Account(acc) => - Destination::Account(acc.account.as_slice().try_into().map_err(|_| ())?), + pb::xcvm::transfer::AccountType::Account(account) => + Destination::Account(account.try_into().map_err(|_| ())?), pb::xcvm::transfer::AccountType::Tip(_) => Destination::Tip, }) } } +impl From> for pb::xcvm::transfer::AccountType +where + TAccount: Into>, +{ + fn from(destination: crate::Destination) -> Self { + match destination { + Destination::Account(account) => Self::Account(account.into()), + Destination::Tip => Self::Tip(pb::xcvm::Tip {}), + } + } +} + impl TryFrom for (crate::AssetId, crate::Balance) { type Error = (); fn try_from(asset: pb::xcvm::Asset) -> Result { - let asset_id = asset.asset_id.ok_or(())?.try_into()?; - let amount = asset.balance.ok_or(())?.try_into()?; + let asset_id = asset.asset_id.non_empty()?.into(); + let amount = asset.balance.non_empty()?.try_into()?; Ok((asset_id, amount)) } } -impl TryFrom for crate::AssetId { - type Error = (); - - fn try_from(asset_id: pb::xcvm::AssetId) -> Result { - Ok(crate::AssetId(asset_id.id.ok_or(())?.into())) +impl From<(crate::AssetId, crate::Balance)> for pb::xcvm::Asset { + fn from((asset_id, amount): (crate::AssetId, crate::Balance)) -> Self { + Self { asset_id: Some(asset_id.into()), balance: Some(amount.into()) } } } @@ -386,12 +398,12 @@ impl TryFrom for crate::Balance { fn try_from(balance: pb::xcvm::Balance) -> Result { use pb::xcvm::balance::BalanceType; - let balance_type = balance.balance_type.ok_or(())?; + let balance_type = balance.balance_type.non_empty()?; match balance_type { BalanceType::Ratio(ratio) => Ok(crate::Balance::new(ratio.try_into()?, false)), BalanceType::Absolute(pb::xcvm::Absolute { value }) => { - let value = value.ok_or(())?; + let value = value.non_empty()?; Ok(crate::Balance::new(Amount::absolute(value.into()), false)) }, BalanceType::Unit(unit) => unit.try_into(), @@ -413,8 +425,8 @@ impl TryFrom for crate::Balance { type Error = (); fn try_from(unit: pb::xcvm::Unit) -> Result { - let integer = unit.integer.ok_or(())?; - let ratio = unit.ratio.ok_or(())?; + let integer = unit.integer.non_empty()?; + let ratio = unit.ratio.non_empty()?; Ok(crate::Balance::new( Amount::new( integer.into(), @@ -455,134 +467,6 @@ impl From for pb::xcvm::Balance { } } -impl From for pb::xcvm::AssetId { - fn from(asset_id: crate::AssetId) -> Self { - Self { id: Some(asset_id.0 .0.into()) } - } -} - -impl From<(crate::AssetId, crate::Balance)> for pb::xcvm::Asset { - fn from((asset_id, amount): (crate::AssetId, crate::Balance)) -> Self { - Self { asset_id: Some(asset_id.into()), balance: Some(amount.into()) } - } -} - -impl From for pb::xcvm::binding_value::Type { - fn from(binding_value: crate::BindingValue) -> Self { - match binding_value { - crate::BindingValue::Register(crate::Register::Ip) => - Self::IpRegister(pb::xcvm::IpRegister { ip: 0 }), - crate::BindingValue::Register(crate::Register::Tip) => - Self::Tip(pb::xcvm::Tip { id: 0 }), - crate::BindingValue::Register(crate::Register::Result) => - Self::Result(pb::xcvm::Result { result: 0 }), - crate::BindingValue::Register(crate::Register::This) => - Self::Self_(pb::xcvm::Self_ { self_: 0 }), - crate::BindingValue::Asset(asset_id) => Self::AssetId(asset_id.into()), - crate::BindingValue::AssetAmount(asset_id, balance) => - Self::AssetAmount(pb::xcvm::AssetAmount { - asset_id: Some(asset_id.into()), - balance: Some(balance.into()), - }), - } - } -} - -impl From for pb::xcvm::BindingValue { - fn from(binding_value: crate::BindingValue) -> Self { - Self { r#type: Some(binding_value.into()) } - } -} - -impl From for pb::xcvm::Network { - fn from(network_id: crate::NetworkId) -> Self { - Self { network_id: network_id.0 } - } -} - -impl From> for pb::xcvm::transfer::AccountType -where - TAccount: Into>, -{ - fn from(destination: crate::Destination) -> Self { - match destination { - Destination::Account(account) => - Self::Account(pb::xcvm::Account { account: account.into() }), - Destination::Tip => Self::Tip(pb::xcvm::Tip { id: 0 }), - } - } -} - -impl From<(u32, crate::BindingValue)> for pb::xcvm::Binding { - fn from((position, binding_value): (u32, crate::BindingValue)) -> Self { - Self { position, binding_value: Some(binding_value.into()) } - } -} - -impl From> - for pb::xcvm::instruction::Instruction -where - TAbiEncoded: Into>, - TAccount: Into>, - TAssets: Into>, -{ - fn from(instruction: crate::Instruction) -> Self { - match instruction { - crate::Instruction::Transfer { to, assets } => Self::Transfer(pb::xcvm::Transfer { - assets: assets.into().into_iter().map(|asset| asset.into()).collect(), - account_type: Some(to.into()), - }), - crate::Instruction::Call { bindings, encoded } => Self::Call(pb::xcvm::Call { - payload: encoded.into(), - bindings: Some(pb::xcvm::Bindings { - bindings: bindings.into_iter().map(|binding| binding.into()).collect(), - }), - }), - crate::Instruction::Spawn { network, salt, assets, program } => - Self::Spawn(pb::xcvm::Spawn { - network: Some(pb::xcvm::Network { network_id: network.into() }), - salt: Some(pb::xcvm::Salt { salt }), - program: Some(program.into()), - assets: assets.into().into_iter().map(|asset| asset.into()).collect(), - }), - crate::Instruction::Exchange { id, give, want } => Self::Exchange(pb::xcvm::Exchange { - id: Some(pb::xcvm::ExchangeId { id: Some(id.into()) }), - give: give.into().into_iter().map(|asset| asset.into()).collect(), - want: want.into().into_iter().map(|asset| asset.into()).collect(), - }), - } - } -} - -impl From> - for pb::xcvm::Instruction -where - TAbiEncoded: Into>, - TAccount: Into>, - TAssets: Into>, -{ - fn from(instruction: crate::Instruction) -> Self { - Self { instruction: Some(instruction.into()) } - } -} - -impl From> - for pb::xcvm::Program -where - TAbiEncoded: Into>, - TAccount: Into>, - TAssets: Into>, -{ - fn from(program: XCVMProgram) -> Self { - Self { - tag: program.tag, - instructions: Some(pb::xcvm::Instructions { - instructions: program.instructions.into_iter().map(|instr| instr.into()).collect(), - }), - } - } -} - #[test] fn test_balance_to_amount_works() { let ratio = pb::xcvm::Ratio { nominator: 3u64.into(), denominator: 5u64.into() };