From 5b53033b84bbba1e7c2167da049523ff642f9fb7 Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 8 Jun 2023 10:47:20 +0100 Subject: [PATCH 01/11] migrated --- Cargo.lock | 58 +++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 11 +++++++++ flake.nix | 19 ++++++++++++++- vm-wasmi/Cargo.toml | 9 ++----- vm/Cargo.toml | 11 +++++---- 5 files changed, 93 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 608ded3..05055f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,6 +216,14 @@ dependencies = [ "syn", ] +[[package]] +name = "cosmwasm-derive" +version = "1.2.5" +source = "git+https://github.com/dzmitry-lahoda-forks/cosmwasm?rev=f483c3c4695fcb094539b5aead223d54cb0e23b2#f483c3c4695fcb094539b5aead223d54cb0e23b2" +dependencies = [ + "syn", +] + [[package]] name = "cosmwasm-orchestrate" version = "0.1.0" @@ -305,11 +313,29 @@ dependencies = [ "uint", ] +[[package]] +name = "cosmwasm-std" +version = "1.2.5" +source = "git+https://github.com/dzmitry-lahoda-forks/cosmwasm?rev=f483c3c4695fcb094539b5aead223d54cb0e23b2#f483c3c4695fcb094539b5aead223d54cb0e23b2" +dependencies = [ + "base64", + "cosmwasm-derive 1.2.5", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm 0.5.1", + "sha2 0.10.6", + "thiserror-core", + "uint", +] + [[package]] name = "cosmwasm-vm" version = "0.1.0" dependencies = [ - "cosmwasm-std 1.2.0", + "cosmwasm-std 1.2.5", "env_logger 0.9.3", "log", "num", @@ -320,7 +346,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm-wasmi" -version = "0.1.0" +version = "0.2.0" dependencies = [ "cosmwasm-crypto 1.1.5", "cosmwasm-std 1.2.0", @@ -1584,6 +1610,14 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-json-wasm" +version = "0.5.1" +source = "git+https://github.com/dzmitry-lahoda-forks/serde-json-wasm?rev=8a7e522c0e4de36a6dfb535766f26a9941017d81#8a7e522c0e4de36a6dfb535766f26a9941017d81" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" version = "1.0.152" @@ -1753,6 +1787,26 @@ dependencies = [ "thiserror-impl", ] +[[package]] +name = "thiserror-core" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" +dependencies = [ + "thiserror-core-impl", +] + +[[package]] +name = "thiserror-core-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thiserror-impl" version = "1.0.38" diff --git a/Cargo.toml b/Cargo.toml index 72c7200..1a36541 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,3 +2,14 @@ members = ["vm", "vm-wasmi", "orchestrate"] exclude = ["fixtures/recursion-test"] resolver = "2" + + +[workspace.dependencies] +cosmwasm-std = { git = "https://github.com/dzmitry-lahoda-forks/cosmwasm", rev = "f483c3c4695fcb094539b5aead223d54cb0e23b2", default-features = false, features = [ + "iterator", + "cosmwasm_1_2", +] } +serde = { version = "1", default-features = false, features = ["derive"] } +serde_json = { version = "1", default-features = false, features = ["alloc"] } +log = { version = "0.4", default-features = false } +num = { version = "0.4", default-features = false } \ No newline at end of file diff --git a/flake.nix b/flake.nix index 661ca66..54eead8 100644 --- a/flake.nix +++ b/flake.nix @@ -28,6 +28,23 @@ crane-nightly = crane-lib.overrideToolchain rust-nightly; + features = " --features iterator"; + package="cosmwasm-vm"; + check-no-std = pkgs.writeShellApplication rec { + name = "check-no-std"; + runtimeInputs = [ rust-nightly ]; + text = '' + cargo build --locked --no-default-features --target thumbv7em-none-eabi --package ${package} ${features} + ''; + }; + check-wasm-std = pkgs.writeShellApplication rec { + name = "check-wasm-std"; + runtimeInputs = [ rust-nightly ]; + text = '' + cargo build --target wasm32-unknown-unknown --locked ${features},std --package ${package} + ''; + }; + src = pkgs.lib.cleanSourceWith { filter = pkgs.lib.cleanSourceFilter; src = pkgs.lib.cleanSourceWith { @@ -61,7 +78,7 @@ }; devShell = pkgs.mkShell { buildInputs = [ rust-nightly ] - ++ (with pkgs; [ openssl openssl.dev pkgconfig taplo nixfmt bacon flamegraph cargo-flamegraph]); + ++ (with pkgs; [ openssl openssl.dev pkgconfig taplo nixfmt bacon flamegraph cargo-flamegraph check-no-std check-wasm-std]); }; }); } diff --git a/vm-wasmi/Cargo.toml b/vm-wasmi/Cargo.toml index 5af1beb..0f64d31 100644 --- a/vm-wasmi/Cargo.toml +++ b/vm-wasmi/Cargo.toml @@ -1,13 +1,8 @@ [package] name = "cosmwasm-vm-wasmi" -version = "0.1.0" +version = "0.2.0" edition = "2021" -authors = [ - "Hussein Ait Lahcen hussein.aitlahcen@gmail.com", - "Abdullah Eryuzlu abdullaheryuzlu@gmail.com", - "Composable Developers", -] -homepage = "https://composable.finance" + # [[bin]] # name = "research" diff --git a/vm/Cargo.toml b/vm/Cargo.toml index a60244a..6ed63b8 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -14,16 +14,17 @@ default = ["iterator", "stargate", "ibc3"] iterator = ["cosmwasm-std/iterator"] stargate = ["cosmwasm-std/stargate"] ibc3 = ["cosmwasm-std/ibc3"] +std = ["cosmwasm-std/std"] [dependencies] -cosmwasm-std = { git = "https://github.com/ComposableFi/cosmwasm", rev = "34af48221c90e6818fe341d6d5b15116dfeab671", default-features = false, features = [ +cosmwasm-std = { workspace = true, default-features = false, features = [ "iterator", "cosmwasm_1_2", ] } -log = { version = "0.4", default-features = false } -num = { version = "0.4", default-features = false } -serde = { version = "1", default-features = false, features = ["derive"] } -serde_json = { version = "1", default-features = false, features = ["alloc"] } +log = { workspace = true, default-features = false } +num = { workspace = true, default-features = false } +serde = { workspace = true, default-features = false, features = ["derive"] } +serde_json = { workspace = true, default-features = false, features = ["alloc"] } [dev-dependencies] From 55b6414d354353c2f14e258cd39eff01c0199a60 Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 8 Jun 2023 11:07:18 +0100 Subject: [PATCH 02/11] who cares --- Cargo.lock | 4 +- flake.nix | 25 +- vm-wasmi/Cargo.toml | 9 +- vm-wasmi/src/bin/research.rs | 2254 +++++++++++++++++----------------- vm/Cargo.toml | 8 +- vm/src/executor.rs | 26 +- vm/src/has.rs | 24 - vm/src/input.rs | 24 - vm/src/lib.rs | 32 +- vm/src/memory.rs | 24 - vm/src/system.rs | 26 +- vm/src/tagged.rs | 24 - vm/src/transaction.rs | 24 - 13 files changed, 1150 insertions(+), 1354 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05055f9..2097dca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -333,7 +333,7 @@ dependencies = [ [[package]] name = "cosmwasm-vm" -version = "0.1.0" +version = "0.2.0" dependencies = [ "cosmwasm-std 1.2.5", "env_logger 0.9.3", @@ -349,7 +349,7 @@ name = "cosmwasm-vm-wasmi" version = "0.2.0" dependencies = [ "cosmwasm-crypto 1.1.5", - "cosmwasm-std 1.2.0", + "cosmwasm-std 1.2.5", "cosmwasm-vm", "cw20-ics20", "either", diff --git a/flake.nix b/flake.nix index 54eead8..475d435 100644 --- a/flake.nix +++ b/flake.nix @@ -28,20 +28,18 @@ crane-nightly = crane-lib.overrideToolchain rust-nightly; - features = " --features iterator"; - package="cosmwasm-vm"; - check-no-std = pkgs.writeShellApplication rec { - name = "check-no-std"; + check-crate = pkgs.writeShellApplication rec { + name = "check-crate"; runtimeInputs = [ rust-nightly ]; text = '' - cargo build --locked --no-default-features --target thumbv7em-none-eabi --package ${package} ${features} - ''; - }; - check-wasm-std = pkgs.writeShellApplication rec { - name = "check-wasm-std"; - runtimeInputs = [ rust-nightly ]; - text = '' - cargo build --target wasm32-unknown-unknown --locked ${features},std --package ${package} + EXTRA_FEATURES="" + if [[ -n "''${2-}" ]]; then + EXTRA_FEATURES="--features $2" + fi + # shellcheck disable=SC2086 + cargo build --target wasm32-unknown-unknown --locked --all-features --package "$1" $EXTRA_FEATURES + # shellcheck disable=SC2086 + cargo build --locked --no-default-features --target thumbv7em-none-eabi --package "$1" $EXTRA_FEATURES ''; }; @@ -68,6 +66,7 @@ packages = rec { cosmwasm-vm = crane-nightly.buildPackage common-cached-args; default = cosmwasm-vm; + inherit check-crate; }; checks = { package = packages.default; @@ -78,7 +77,7 @@ }; devShell = pkgs.mkShell { buildInputs = [ rust-nightly ] - ++ (with pkgs; [ openssl openssl.dev pkgconfig taplo nixfmt bacon flamegraph cargo-flamegraph check-no-std check-wasm-std]); + ++ (with pkgs; [ openssl openssl.dev pkgconfig taplo nixfmt bacon flamegraph cargo-flamegraph check-crate]); }; }); } diff --git a/vm-wasmi/Cargo.toml b/vm-wasmi/Cargo.toml index 0f64d31..4248332 100644 --- a/vm-wasmi/Cargo.toml +++ b/vm-wasmi/Cargo.toml @@ -13,16 +13,17 @@ default = ["iterator", "stargate", "ibc3"] iterator = ["cosmwasm-vm/iterator"] stargate = ["cosmwasm-vm/stargate"] ibc3 = ["cosmwasm-vm/ibc3"] +std = ["cosmwasm-std/std"] [dependencies] -serde = { version = "1", default-features = false, features = ["derive"] } -serde_json = { version = "1", default-features = false, features = ["alloc"] } +serde = { workspaace = true, default-features = false, features = ["derive"] } +serde_json = { workspaace = true, default-features = false, features = ["alloc"] } either = { version = "1.8", default-features = false } -log = { version = "0.4", default-features = false } +log = { workspace = true, default-features = false } wasmi = { version = "0.26", default-features = false } wasmi-validation = { version = "0.5", default-features = false } wasm-instrument = { version = "0.2", default-features = false } -cosmwasm-std = { git = "https://github.com/ComposableFi/cosmwasm", rev = "34af48221c90e6818fe341d6d5b15116dfeab671", default-features = false, features = [ +cosmwasm-std = { workspace = true, default-features = false, features = [ "iterator", "cosmwasm_1_2" ] } diff --git a/vm-wasmi/src/bin/research.rs b/vm-wasmi/src/bin/research.rs index 0937238..3dba5b9 100644 --- a/vm-wasmi/src/bin/research.rs +++ b/vm-wasmi/src/bin/research.rs @@ -1,1130 +1,1130 @@ -#![feature(trait_alias)] -#![feature(assert_matches)] -#![allow(soft_unstable)] -#![feature(test)] - -extern crate alloc; - -extern crate std; - -use cosmwasm_vm::vm::VMBase; - -use alloc::{ - collections::BTreeMap, - format, - string::{String, ToString}, - vec, - vec::Vec, -}; -use core::{ - assert_matches::assert_matches, - fmt::{Debug, Display}, - num::NonZeroU32, - str::FromStr, -}; -#[cfg(feature = "stargate")] -use cosmwasm_std::IbcTimeout; -#[cfg(feature = "iterator")] -use cosmwasm_std::Order; -use cosmwasm_std::{ - Addr, Attribute, Binary, BlockInfo, CanonicalAddr, CodeInfoResponse, Coin, ContractInfo, - ContractInfoResponse, ContractResult, Empty, Env, Event, MessageInfo, Reply, SystemResult, - Timestamp, -}; -use cosmwasm_vm::{ - executor::{ - cosmwasm_call, CosmwasmExecutionResult, CosmwasmQueryResult, ExecuteCall, ExecuteResult, - ExecutorError, InstantiateCall, InstantiateResult, MigrateCall, QueryCall, QueryResult, - ReplyCall, - }, - has::Has, - memory::{MemoryReadError, MemoryWriteError}, - system::{ - cosmwasm_system_entrypoint, cosmwasm_system_entrypoint_hook, cosmwasm_system_run, - CosmwasmCodeId, CosmwasmContractMeta, SystemError, - }, - transaction::Transactional, - vm::{VmErrorOf, VmGas, VmGasCheckpoint}, -}; -use cosmwasm_vm_wasmi::{ - code_gen, new_wasmi_vm, OwnedWasmiVM, WasmiContext, WasmiInput, WasmiModule, WasmiOutput, - WasmiVMError, -}; -use tracing::instrument::WithSubscriber; -use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt; -use wasm_instrument::gas_metering::Rules; -use wasmi::core::HostError; - -const CANONICAL_LENGTH: usize = 54; -const SHUFFLES_ENCODE: usize = 18; -const SHUFFLES_DECODE: usize = 2; - -#[derive(PartialEq, Debug)] -enum SimpleVMError { - Interpreter, - VMError(WasmiVMError), - CodeNotFound(CosmwasmCodeId), - ContractNotFound(BankAccount), - InvalidAddress, - InvalidAccountFormat, - NoCustomQuery, - NoCustomMessage, - Unsupported, - OutOfGas, - #[cfg(feature = "iterator")] - IteratorDoesNotExist, - CannotDeserialize, - Crypto, -} - -impl HostError for SimpleVMError {} - -impl From for SimpleVMError { - fn from(_: wasmi::Error) -> Self { - Self::Interpreter - } -} -impl From for SimpleVMError { - fn from(e: WasmiVMError) -> Self { - SimpleVMError::VMError(e) - } -} -impl From for SimpleVMError { - fn from(e: SystemError) -> Self { - SimpleVMError::VMError(e.into()) - } -} -impl From for SimpleVMError { - fn from(e: ExecutorError) -> Self { - SimpleVMError::VMError(e.into()) - } -} -impl From for SimpleVMError { - fn from(e: MemoryReadError) -> Self { - SimpleVMError::VMError(e.into()) - } -} -impl From for SimpleVMError { - fn from(e: MemoryWriteError) -> Self { - SimpleVMError::VMError(e.into()) - } -} -impl Display for SimpleVMError { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "{self:?}") - } -} - -#[derive(Default, Clone, PartialEq, Eq, Debug)] -struct Gas { - checkpoints: Vec, -} - -impl Gas { - fn new(initial_value: u64) -> Self { - Gas { - checkpoints: vec![initial_value], - } - } - - fn current(&self) -> &u64 { - self.checkpoints.last().expect("impossible") - } - fn current_mut(&mut self) -> &mut u64 { - self.checkpoints.last_mut().expect("impossible") - } - fn push(&mut self, checkpoint: &VmGasCheckpoint) -> Result<(), SimpleVMError> { - match checkpoint { - VmGasCheckpoint::Unlimited => { - let parent = self.current_mut(); - let value = *parent; - *parent = 0; - self.checkpoints.push(value); - Ok(()) - } - VmGasCheckpoint::Limited(limit) if limit <= self.current() => { - *self.current_mut() -= limit; - self.checkpoints.push(*limit); - Ok(()) - } - VmGasCheckpoint::Limited(_) => Err(SimpleVMError::OutOfGas), - } - } - fn pop(&mut self) { - let child = self.checkpoints.pop().expect("impossible"); - let parent = self.current_mut(); - *parent += child; - } - fn charge(&mut self, value: u64) -> Result<(), SimpleVMError> { - let current = self.current_mut(); - if *current >= value { - *current -= value; - Ok(()) - } else { - Err(SimpleVMError::OutOfGas) - } - } -} - -#[cfg(feature = "iterator")] -#[derive(Default, Clone, Debug)] -struct Iter { - data: Vec<(Vec, Vec)>, - position: usize, -} - -#[derive(Default, Clone, Debug)] -struct SimpleWasmiVMStorage { - data: BTreeMap, Vec>, - #[cfg(feature = "iterator")] - iterators: BTreeMap, -} - -#[cfg(feature = "stargate")] -#[derive(Debug, Clone, PartialEq, Eq)] -struct SimpleIBCPacket { - channel_id: String, - data: Binary, - timeout: IbcTimeout, -} - -#[cfg(feature = "stargate")] -#[derive(Default, Clone, Debug, PartialEq, Eq)] -struct SimpleIBCState { - packets_sent: Vec, -} - -#[derive(Default, Clone)] -struct SimpleWasmiVMExtension { - #[cfg(feature = "stargate")] - ibc: BTreeMap, - storage: BTreeMap, - codes: BTreeMap>, - contracts: BTreeMap>, - next_account_id: BankAccount, - transaction_depth: u32, - gas: Gas, -} - -struct SimpleWasmiVM<'a> { - /// module which is in context of vm and executable now - executing_module: Option, - pub env: Env, - info: MessageInfo, - extension: &'a mut SimpleWasmiVMExtension, -} - -impl<'a> WasmiContext for SimpleWasmiVM<'a> { - fn executing_module(&self) -> Option { - self.executing_module.clone() - } - - fn set_wasmi_context(&mut self, instance: wasmi::Instance, memory: wasmi::Memory) { - self.executing_module = Some(WasmiModule { instance, memory }); - } -} - -impl<'a> SimpleWasmiVM<'a> { - pub fn load_subvm( - &mut self, - address: ::Address, - funds: Vec, - ) -> Result, VmErrorOf> { - log::debug!("Loading sub-vm, contract address: {:?}", address); - let code = (|| { - let CosmwasmContractMeta { code_id, .. } = self - .extension - .contracts - .get(&address) - .cloned() - .ok_or(SimpleVMError::ContractNotFound(address))?; - self.extension - .codes - .get(&code_id) - .ok_or(SimpleVMError::CodeNotFound(code_id)) - .cloned() - })()?; - let sub_vm = SimpleWasmiVM { - executing_module: None, - env: Env { - block: self.env.block.clone(), - transaction: self.env.transaction.clone(), - contract: ContractInfo { - address: address.into(), - }, - }, - info: MessageInfo { - sender: self.env.contract.address.clone(), - funds, - }, - extension: self.extension, - }; - let sub_vm = new_wasmi_vm::(&code, sub_vm)?; - Ok(sub_vm) - } -} - -#[derive(Debug, Clone)] -struct CanonicalAddress(pub CanonicalAddr); - -impl TryFrom> for CanonicalAddress { - type Error = SimpleVMError; - fn try_from(value: Vec) -> Result { - Ok(CanonicalAddress(CanonicalAddr(Binary::from(value)))) - } -} - -impl From for Vec { - fn from(addr: CanonicalAddress) -> Self { - addr.0.into() - } -} - -impl From for CanonicalAddr { - fn from(addr: CanonicalAddress) -> Self { - addr.0 - } -} - -impl<'a> VMBase for SimpleWasmiVM<'a> { - type Input<'x> = WasmiInput>; - type Output<'x> = WasmiOutput>; - type QueryCustom = Empty; - type MessageCustom = Empty; - type ContractMeta = CosmwasmContractMeta; - type Address = BankAccount; - type CanonicalAddress = CanonicalAddress; - type StorageKey = Vec; - type StorageValue = Vec; - type Error = SimpleVMError; - - fn running_contract_meta(&mut self) -> Result { - Ok(self - .extension - .contracts - .get( - &BankAccount::try_from(self.env.contract.address.clone()) - .expect("contract address is set by vm, this should never happen"), - ) - .cloned() - .expect("contract is inserted by vm, this should never happen")) - } - - fn set_contract_meta( - &mut self, - address: Self::Address, - contract_meta: Self::ContractMeta, - ) -> Result<(), Self::Error> { - let meta = self - .extension - .contracts - .get_mut(&address) - .ok_or(SimpleVMError::ContractNotFound(address))?; - - *meta = contract_meta; - - Ok(()) - } - - fn contract_meta(&mut self, address: Self::Address) -> Result { - self.extension - .contracts - .get_mut(&address) - .ok_or(SimpleVMError::ContractNotFound(address)) - .cloned() - } - - fn continue_query( - &mut self, - address: Self::Address, - message: &[u8], - ) -> Result { - let mut sub_vm = self.load_subvm(address, vec![])?; - cosmwasm_call::>(&mut sub_vm, message) - } - - fn continue_execute( - &mut self, - address: Self::Address, - funds: Vec, - message: &[u8], - event_handler: &mut dyn FnMut(Event), - ) -> Result, Self::Error> { - let mut sub_vm = self.load_subvm(address, funds)?; - cosmwasm_system_run::, _>( - &mut sub_vm, - message, - event_handler, - ) - } - - fn continue_instantiate( - &mut self, - contract_meta: Self::ContractMeta, - funds: Vec, - message: &[u8], - event_handler: &mut dyn FnMut(Event), - ) -> Result<(Self::Address, Option), Self::Error> { - let BankAccount(address) = self.extension.next_account_id; - self.extension.next_account_id = BankAccount(address + 1); - self.extension - .contracts - .insert(BankAccount(address), contract_meta); - - let mut sub_vm = self.load_subvm(BankAccount(address), funds)?; - cosmwasm_system_run::, _>( - &mut sub_vm, - message, - event_handler, - ) - .map(|data| (BankAccount(address), data)) - } - - fn continue_instantiate2( - &mut self, - contract_meta: Self::ContractMeta, - funds: Vec, - message: &[u8], - _salt: &[u8], - event_handler: &mut dyn FnMut(Event), - ) -> Result<(Self::Address, Option), Self::Error> { - let BankAccount(address) = self.extension.next_account_id; - self.extension.next_account_id = BankAccount(address + 1); - self.extension - .contracts - .insert(BankAccount(address), contract_meta); - - let mut sub_vm = self.load_subvm(BankAccount(address), funds)?; - cosmwasm_system_run::, _>( - &mut sub_vm, - message, - event_handler, - ) - .map(|data| (BankAccount(address), data)) - } - - fn continue_migrate( - &mut self, - address: Self::Address, - message: &[u8], - event_handler: &mut dyn FnMut(Event), - ) -> Result, Self::Error> { - let mut sub_vm = self.load_subvm(address, vec![])?; - cosmwasm_system_run::, _>( - &mut sub_vm, - message, - event_handler, - ) - } - - fn continue_reply( - &mut self, - message: Reply, - event_handler: &mut dyn FnMut(Event), - ) -> Result, Self::Error> { - let mut sub_vm = self.load_subvm( - self.env.contract.address.clone().into_string().try_into()?, - vec![], - )?; - - cosmwasm_system_run::, OwnedWasmiVM>( - &mut sub_vm, - &serde_json::to_vec(&message).map_err(|_| SimpleVMError::CannotDeserialize)?, - event_handler, - ) - } - - fn query_custom( - &mut self, - _: Self::QueryCustom, - ) -> Result, Self::Error> { - Err(SimpleVMError::NoCustomQuery) - } - - fn message_custom( - &mut self, - _: Self::MessageCustom, - _: &mut dyn FnMut(Event), - ) -> Result, Self::Error> { - Err(SimpleVMError::NoCustomMessage) - } - - fn query_raw( - &mut self, - address: Self::Address, - key: Self::StorageKey, - ) -> Result, Self::Error> { - Ok(self - .extension - .storage - .get(&address) - .unwrap_or(&SimpleWasmiVMStorage::default()) - .data - .get(&key) - .cloned()) - } - - fn transfer_from( - &mut self, - from: &Self::Address, - to: &Self::Address, - funds: &[Coin], - ) -> Result<(), Self::Error> { - log::debug!("Transfer from: {:?} -> {:?}\n{:?}", from, to, funds); - Ok(()) - } - - fn transfer(&mut self, to: &Self::Address, funds: &[Coin]) -> Result<(), Self::Error> { - log::debug!( - "Transfer: {:?} -> {:?}\n{:?}", - self.env.contract.address, - to, - funds - ); - Ok(()) - } - - fn burn(&mut self, funds: &[Coin]) -> Result<(), Self::Error> { - log::debug!("Burn: {:?}\n{:?}", self.env.contract.address, funds); - Ok(()) - } - - fn balance(&mut self, _: &Self::Address, _: String) -> Result { - log::debug!("Query balance."); - Err(SimpleVMError::Unsupported) - } - - fn supply(&mut self, _: String) -> Result { - log::debug!("Supply."); - Err(SimpleVMError::Unsupported) - } - - fn all_balance(&mut self, _: &Self::Address) -> Result, Self::Error> { - log::debug!("Query all balance."); - Ok(vec![]) - } - - fn query_contract_info( - &mut self, - _: Self::Address, - ) -> Result { - Err(SimpleVMError::Unsupported) - } - - fn query_code_info(&mut self, _: CosmwasmCodeId) -> Result { - Err(SimpleVMError::Unsupported) - } - - fn debug(&mut self, message: Vec) -> Result<(), Self::Error> { - log::info!("[contract-debug] {}", String::from_utf8_lossy(&message)); - Ok(()) - } - - #[cfg(feature = "iterator")] - #[tracing::instrument(skip(self, _order))] - fn db_scan( - &mut self, - _start: Option, - _end: Option, - _order: Order, - ) -> Result { - let contract_addr = self.env.contract.address.clone().try_into()?; - let mut empty = SimpleWasmiVMStorage::default(); - let storage = self - .extension - .storage - .get_mut(&contract_addr) - .unwrap_or(&mut empty); - - let data = storage.data.clone().into_iter().collect::>(); - // Exceeding u32 size is fatal - let last_id: u32 = storage - .iterators - .len() - .try_into() - .expect("Found more iterator IDs than supported"); - - let new_id = last_id + 1; - let iter = Iter { data, position: 0 }; - storage.iterators.insert(new_id, iter); - - Ok(new_id) - } - - #[cfg(feature = "iterator")] - #[tracing::instrument(skip(self))] - fn db_next( - &mut self, - iterator_id: u32, - ) -> Result<(Self::StorageKey, Self::StorageValue), Self::Error> { - let contract_addr = self.env.contract.address.clone().try_into()?; - let storage = self - .extension - .storage - .get_mut(&contract_addr) - .ok_or(SimpleVMError::IteratorDoesNotExist)?; - - let iterator = storage - .iterators - .get_mut(&iterator_id) - .ok_or(SimpleVMError::IteratorDoesNotExist)?; - - let position = iterator.position; - if iterator.data.len() > position { - iterator.position += 1; - Ok(iterator.data[position].clone()) - } else { - // Empty data works like `None` in rust iterators - Ok((Vec::default(), Vec::default())) - } - } - - fn secp256k1_verify( - &mut self, - message_hash: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - cosmwasm_crypto::secp256k1_verify(message_hash, signature, public_key) - .map_err(|_| SimpleVMError::Crypto) - } - - fn secp256k1_recover_pubkey( - &mut self, - message_hash: &[u8], - signature: &[u8], - recovery_param: u8, - ) -> Result, ()>, Self::Error> { - Ok( - cosmwasm_crypto::secp256k1_recover_pubkey(message_hash, signature, recovery_param) - .map_err(|_| ()), - ) - } - - fn ed25519_verify( - &mut self, - message: &[u8], - signature: &[u8], - public_key: &[u8], - ) -> Result { - cosmwasm_crypto::ed25519_verify(message, signature, public_key) - .map_err(|_| SimpleVMError::Crypto) - } - - fn ed25519_batch_verify( - &mut self, - messages: &[&[u8]], - signatures: &[&[u8]], - public_keys: &[&[u8]], - ) -> Result { - cosmwasm_crypto::ed25519_batch_verify(messages, signatures, public_keys) - .map_err(|_| SimpleVMError::Crypto) - } - - fn addr_validate(&mut self, input: &str) -> Result, Self::Error> { - let canonical = match self.addr_canonicalize(input)? { - Ok(canonical) => canonical, - Err(e) => return Ok(Err(e)), - }; - let normalized = match self.addr_humanize(&canonical)? { - Ok(canonical) => canonical, - Err(e) => return Ok(Err(e)), - }; - let account = BankAccount::try_from(input.to_string())?; - Ok(if account == normalized { - Ok(()) - } else { - Err(SimpleVMError::InvalidAddress) - }) - } - - fn addr_canonicalize( - &mut self, - input: &str, - ) -> Result, Self::Error> { - // mimicks formats like hex or bech32 where different casings are valid for one address - let normalized = input.to_lowercase(); - - // Dummy input validation. This is more sophisticated for formats like bech32, where format and checksum are validated. - if normalized.len() < 3 { - return Ok(Err(SimpleVMError::InvalidAddress)); - } - - if normalized.len() > CANONICAL_LENGTH { - return Ok(Err(SimpleVMError::InvalidAddress)); - } - - let mut out = Vec::from(normalized); - // pad to canonical length with NULL bytes - out.resize(CANONICAL_LENGTH, 0x00); - // content-dependent rotate followed by shuffle to destroy - let rotate_by = digit_sum(&out) % CANONICAL_LENGTH; - out.rotate_left(rotate_by); - for _ in 0..SHUFFLES_ENCODE { - out = riffle_shuffle(&out); - } - Ok(Ok(out.try_into()?)) - } - - fn addr_humanize( - &mut self, - addr: &Self::CanonicalAddress, - ) -> Result, Self::Error> { - if addr.0.len() != CANONICAL_LENGTH { - return Ok(Err(SimpleVMError::InvalidAddress)); - } - - let mut tmp: Vec = addr.clone().into(); - // Shuffle two more times which restored the original value (24 elements are back to original after 20 rounds) - for _ in 0..SHUFFLES_DECODE { - tmp = riffle_shuffle(&tmp); - } - // Rotate back - let rotate_by = digit_sum(&tmp) % CANONICAL_LENGTH; - tmp.rotate_right(rotate_by); - // Remove NULL bytes (i.e. the padding) - let trimmed = tmp.into_iter().filter(|&x| x != 0x00).collect(); - // decode UTF-8 bytes into string - let Ok(human) = String::from_utf8(trimmed) else { return Ok(Err(SimpleVMError::InvalidAddress)) }; - Ok( - BankAccount::try_from(Addr::unchecked(human)) - .map_err(|_| SimpleVMError::InvalidAddress), - ) - } - - #[tracing::instrument(skip(self))] - fn db_read( - &mut self, - key: Self::StorageKey, - ) -> Result, Self::Error> { - let contract_addr = self.env.contract.address.clone().try_into()?; - let empty = SimpleWasmiVMStorage::default(); - Ok(self - .extension - .storage - .get(&contract_addr) - .unwrap_or(&empty) - .data - .get(&key) - .cloned()) - } - - #[tracing::instrument(skip(self))] - fn db_write( - &mut self, - key: Self::StorageKey, - value: Self::StorageValue, - ) -> Result<(), Self::Error> { - let contract_addr = self.env.contract.address.clone().try_into()?; - self.extension - .storage - .entry(contract_addr) - .or_insert_with(SimpleWasmiVMStorage::default) - .data - .insert(key, value); - Ok(()) - } - - #[tracing::instrument(skip(self))] - fn db_remove(&mut self, key: Self::StorageKey) -> Result<(), Self::Error> { - let contract_addr = self.env.contract.address.clone().try_into()?; - self.extension - .storage - .get_mut(&contract_addr) - .map(|contract_storage| contract_storage.data.remove(&key)); - Ok(()) - } - - fn abort(&mut self, message: String) -> Result<(), Self::Error> { - log::debug!("Contract aborted: {}", message); - Err(SimpleVMError::from(WasmiVMError::from( - SystemError::ContractExecutionFailure(message), - ))) - } - - fn charge(&mut self, value: VmGas) -> Result<(), Self::Error> { - let gas_to_charge = match value { - VmGas::Instrumentation { metered } => u64::from(metered), - x => { - log::debug!("Charging gas: {:?}", x); - 1u64 - } - }; - self.extension.gas.charge(gas_to_charge)?; - Ok(()) - } - - fn gas_checkpoint_push(&mut self, checkpoint: VmGasCheckpoint) -> Result<(), Self::Error> { - log::debug!("> Gas before: {:?}", self.extension.gas); - self.extension.gas.push(&checkpoint)?; - log::debug!("> Gas after: {:?}", self.extension.gas); - Ok(()) - } - - fn gas_checkpoint_pop(&mut self) -> Result<(), Self::Error> { - log::debug!("> Gas before: {:?}", self.extension.gas); - self.extension.gas.pop(); - log::debug!("> Gas after: {:?}", self.extension.gas); - Ok(()) - } - - fn gas_ensure_available(&mut self) -> Result<(), Self::Error> { - let checkpoint = self - .extension - .gas - .checkpoints - .last() - .expect("invalis gas checkpoint state"); - if *checkpoint > 0 { - Ok(()) - } else { - Err(SimpleVMError::OutOfGas) - } - } - - #[cfg(feature = "stargate")] - fn ibc_transfer( - &mut self, - _channel_id: String, - _to_address: String, - _amount: Coin, - _timeout: IbcTimeout, - ) -> Result<(), Self::Error> { - todo!() - } - - #[cfg(feature = "stargate")] - fn ibc_send_packet( - &mut self, - channel_id: String, - data: Binary, - timeout: IbcTimeout, - ) -> Result<(), Self::Error> { - let contract_addr = self.env.contract.address.clone().try_into()?; - let entry = self.extension.ibc.entry(contract_addr).or_default(); - entry.packets_sent.push(SimpleIBCPacket { - channel_id, - data, - timeout, - }); - Ok(()) - } - - #[cfg(feature = "stargate")] - fn ibc_close_channel(&mut self, _channel_id: String) -> Result<(), Self::Error> { - todo!() - } -} - -#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -struct BankAccount(u128); - -impl TryFrom for BankAccount { - type Error = SimpleVMError; - fn try_from(value: Addr) -> Result { - value.to_string().try_into() - } -} - -impl TryFrom for BankAccount { - type Error = SimpleVMError; - fn try_from(value: String) -> Result { - Ok(BankAccount( - u128::from_str(&value).map_err(|_| SimpleVMError::InvalidAccountFormat)?, - )) - } -} - -impl From for Addr { - fn from(BankAccount(account): BankAccount) -> Self { - Addr::unchecked(format!("{account}")) - } -} - -impl<'a> Has for SimpleWasmiVM<'a> { - fn get(&self) -> Env { - self.env.clone() - } -} -impl<'a> Has for SimpleWasmiVM<'a> { - fn get(&self) -> MessageInfo { - self.info.clone() - } -} - -impl<'a> Transactional for SimpleWasmiVM<'a> { - type Error = SimpleVMError; - fn transaction_begin(&mut self) -> Result<(), Self::Error> { - self.extension.transaction_depth += 1; - log::debug!("> Transaction begin: {}", self.extension.transaction_depth); - Ok(()) - } - fn transaction_commit(&mut self) -> Result<(), Self::Error> { - self.extension.transaction_depth -= 1; - log::debug!("< Transaction end: {}", self.extension.transaction_depth); - Ok(()) - } - fn transaction_rollback(&mut self) -> Result<(), Self::Error> { - self.extension.transaction_depth -= 1; - log::debug!("< Transaction abort: {}", self.extension.transaction_depth); - Ok(()) - } -} - -struct ConstantCostRules; -impl Rules for ConstantCostRules { - fn instruction_cost( - &self, - _: &wasm_instrument::parity_wasm::elements::Instruction, - ) -> Option { - Some(42) - } - - fn memory_grow_cost(&self) -> wasm_instrument::gas_metering::MemoryGrowCost { - wasm_instrument::gas_metering::MemoryGrowCost::Linear( - NonZeroU32::new(1024).expect("impossible"), - ) - } -} - -fn instrument_contract(code: &[u8]) -> Vec { - let module = - wasm_instrument::parity_wasm::elements::Module::from_bytes(code).expect("impossible"); - let instrumented_module = - wasm_instrument::gas_metering::inject(module, &ConstantCostRules, "env") - .expect("impossible"); - instrumented_module.into_bytes().expect("impossible") -} - -pub fn initialize() { - use std::sync::Once; - static INIT: Once = Once::new(); - INIT.call_once(|| { - // setup this one to tune output - let mut builder = env_logger::builder(); - builder.format_timestamp_nanos(); - builder.try_init().unwrap(); - - let collector = tracing_subscriber::fmt() - .with_max_level(tracing::Level::TRACE) - .finish(); - let collector = tracing_subscriber::fmt::layer() - .with_level(true) - .with_line_number(true); - let tracer = opentelemetry::sdk::export::trace::stdout::new_pipeline().install_simple(); - let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); - let subscriber = tracing_subscriber::Registry::default() - .with(telemetry) - .with(collector); - tracing::subscriber::set_global_default(subscriber).unwrap(); - }); -} - -fn create_vm( - extension: &mut SimpleWasmiVMExtension, - env: Env, - info: MessageInfo, -) -> Result, SimpleVMError> { - initialize(); - let code = extension - .codes - .get( - &extension - .contracts - .get(&env.clone().contract.address.try_into().unwrap()) - .expect("contract should have been uploaded") - .code_id, - ) - .expect("contract should have been uploaded") - .clone(); - let vm = SimpleWasmiVM { - executing_module: None, - env, - info, - extension, - }; - let vm = new_wasmi_vm::(&code, vm)?; - Ok(vm) -} - -fn create_simple_vm( - sender: BankAccount, - contract: BankAccount, - funds: Vec, - extension: &mut SimpleWasmiVMExtension, -) -> Result, SimpleVMError> { - create_vm( - extension, - Env { - block: BlockInfo { - height: 0xDEAD_C0DE, - time: Timestamp::from_seconds(10000), - chain_id: "abstract-test".into(), - }, - transaction: None, - contract: ContractInfo { - address: contract.into(), - }, - }, - MessageInfo { - sender: sender.into(), - funds, - }, - ) -} +// #![feature(trait_alias)] +// #![feature(assert_matches)] +// #![allow(soft_unstable)] +// #![feature(test)] + +// extern crate alloc; + +// extern crate std; + +// use cosmwasm_vm::vm::VMBase; + +// use alloc::{ +// collections::BTreeMap, +// format, +// string::{String, ToString}, +// vec, +// vec::Vec, +// }; +// use core::{ +// assert_matches::assert_matches, +// fmt::{Debug, Display}, +// num::NonZeroU32, +// str::FromStr, +// }; +// #[cfg(feature = "stargate")] +// use cosmwasm_std::IbcTimeout; +// #[cfg(feature = "iterator")] +// use cosmwasm_std::Order; +// use cosmwasm_std::{ +// Addr, Attribute, Binary, BlockInfo, CanonicalAddr, CodeInfoResponse, Coin, ContractInfo, +// ContractInfoResponse, ContractResult, Empty, Env, Event, MessageInfo, Reply, SystemResult, +// Timestamp, +// }; +// use cosmwasm_vm::{ +// executor::{ +// cosmwasm_call, CosmwasmExecutionResult, CosmwasmQueryResult, ExecuteCall, ExecuteResult, +// ExecutorError, InstantiateCall, InstantiateResult, MigrateCall, QueryCall, QueryResult, +// ReplyCall, +// }, +// has::Has, +// memory::{MemoryReadError, MemoryWriteError}, +// system::{ +// cosmwasm_system_entrypoint, cosmwasm_system_entrypoint_hook, cosmwasm_system_run, +// CosmwasmCodeId, CosmwasmContractMeta, SystemError, +// }, +// transaction::Transactional, +// vm::{VmErrorOf, VmGas, VmGasCheckpoint}, +// }; +// use cosmwasm_vm_wasmi::{ +// code_gen, new_wasmi_vm, OwnedWasmiVM, WasmiContext, WasmiInput, WasmiModule, WasmiOutput, +// WasmiVMError, +// }; +// use tracing::instrument::WithSubscriber; +// use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt; +// use wasm_instrument::gas_metering::Rules; +// use wasmi::core::HostError; + +// const CANONICAL_LENGTH: usize = 54; +// const SHUFFLES_ENCODE: usize = 18; +// const SHUFFLES_DECODE: usize = 2; + +// #[derive(PartialEq, Debug)] +// enum SimpleVMError { +// Interpreter, +// VMError(WasmiVMError), +// CodeNotFound(CosmwasmCodeId), +// ContractNotFound(BankAccount), +// InvalidAddress, +// InvalidAccountFormat, +// NoCustomQuery, +// NoCustomMessage, +// Unsupported, +// OutOfGas, +// #[cfg(feature = "iterator")] +// IteratorDoesNotExist, +// CannotDeserialize, +// Crypto, +// } + +// impl HostError for SimpleVMError {} + +// impl From for SimpleVMError { +// fn from(_: wasmi::Error) -> Self { +// Self::Interpreter +// } +// } +// impl From for SimpleVMError { +// fn from(e: WasmiVMError) -> Self { +// SimpleVMError::VMError(e) +// } +// } +// impl From for SimpleVMError { +// fn from(e: SystemError) -> Self { +// SimpleVMError::VMError(e.into()) +// } +// } +// impl From for SimpleVMError { +// fn from(e: ExecutorError) -> Self { +// SimpleVMError::VMError(e.into()) +// } +// } +// impl From for SimpleVMError { +// fn from(e: MemoryReadError) -> Self { +// SimpleVMError::VMError(e.into()) +// } +// } +// impl From for SimpleVMError { +// fn from(e: MemoryWriteError) -> Self { +// SimpleVMError::VMError(e.into()) +// } +// } +// impl Display for SimpleVMError { +// fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { +// write!(f, "{self:?}") +// } +// } + +// #[derive(Default, Clone, PartialEq, Eq, Debug)] +// struct Gas { +// checkpoints: Vec, +// } + +// impl Gas { +// fn new(initial_value: u64) -> Self { +// Gas { +// checkpoints: vec![initial_value], +// } +// } + +// fn current(&self) -> &u64 { +// self.checkpoints.last().expect("impossible") +// } +// fn current_mut(&mut self) -> &mut u64 { +// self.checkpoints.last_mut().expect("impossible") +// } +// fn push(&mut self, checkpoint: &VmGasCheckpoint) -> Result<(), SimpleVMError> { +// match checkpoint { +// VmGasCheckpoint::Unlimited => { +// let parent = self.current_mut(); +// let value = *parent; +// *parent = 0; +// self.checkpoints.push(value); +// Ok(()) +// } +// VmGasCheckpoint::Limited(limit) if limit <= self.current() => { +// *self.current_mut() -= limit; +// self.checkpoints.push(*limit); +// Ok(()) +// } +// VmGasCheckpoint::Limited(_) => Err(SimpleVMError::OutOfGas), +// } +// } +// fn pop(&mut self) { +// let child = self.checkpoints.pop().expect("impossible"); +// let parent = self.current_mut(); +// *parent += child; +// } +// fn charge(&mut self, value: u64) -> Result<(), SimpleVMError> { +// let current = self.current_mut(); +// if *current >= value { +// *current -= value; +// Ok(()) +// } else { +// Err(SimpleVMError::OutOfGas) +// } +// } +// } + +// #[cfg(feature = "iterator")] +// #[derive(Default, Clone, Debug)] +// struct Iter { +// data: Vec<(Vec, Vec)>, +// position: usize, +// } + +// #[derive(Default, Clone, Debug)] +// struct SimpleWasmiVMStorage { +// data: BTreeMap, Vec>, +// #[cfg(feature = "iterator")] +// iterators: BTreeMap, +// } + +// #[cfg(feature = "stargate")] +// #[derive(Debug, Clone, PartialEq, Eq)] +// struct SimpleIBCPacket { +// channel_id: String, +// data: Binary, +// timeout: IbcTimeout, +// } + +// #[cfg(feature = "stargate")] +// #[derive(Default, Clone, Debug, PartialEq, Eq)] +// struct SimpleIBCState { +// packets_sent: Vec, +// } + +// #[derive(Default, Clone)] +// struct SimpleWasmiVMExtension { +// #[cfg(feature = "stargate")] +// ibc: BTreeMap, +// storage: BTreeMap, +// codes: BTreeMap>, +// contracts: BTreeMap>, +// next_account_id: BankAccount, +// transaction_depth: u32, +// gas: Gas, +// } + +// struct SimpleWasmiVM<'a> { +// /// module which is in context of vm and executable now +// executing_module: Option, +// pub env: Env, +// info: MessageInfo, +// extension: &'a mut SimpleWasmiVMExtension, +// } + +// impl<'a> WasmiContext for SimpleWasmiVM<'a> { +// fn executing_module(&self) -> Option { +// self.executing_module.clone() +// } + +// fn set_wasmi_context(&mut self, instance: wasmi::Instance, memory: wasmi::Memory) { +// self.executing_module = Some(WasmiModule { instance, memory }); +// } +// } + +// impl<'a> SimpleWasmiVM<'a> { +// pub fn load_subvm( +// &mut self, +// address: ::Address, +// funds: Vec, +// ) -> Result, VmErrorOf> { +// log::debug!("Loading sub-vm, contract address: {:?}", address); +// let code = (|| { +// let CosmwasmContractMeta { code_id, .. } = self +// .extension +// .contracts +// .get(&address) +// .cloned() +// .ok_or(SimpleVMError::ContractNotFound(address))?; +// self.extension +// .codes +// .get(&code_id) +// .ok_or(SimpleVMError::CodeNotFound(code_id)) +// .cloned() +// })()?; +// let sub_vm = SimpleWasmiVM { +// executing_module: None, +// env: Env { +// block: self.env.block.clone(), +// transaction: self.env.transaction.clone(), +// contract: ContractInfo { +// address: address.into(), +// }, +// }, +// info: MessageInfo { +// sender: self.env.contract.address.clone(), +// funds, +// }, +// extension: self.extension, +// }; +// let sub_vm = new_wasmi_vm::(&code, sub_vm)?; +// Ok(sub_vm) +// } +// } + +// #[derive(Debug, Clone)] +// struct CanonicalAddress(pub CanonicalAddr); + +// impl TryFrom> for CanonicalAddress { +// type Error = SimpleVMError; +// fn try_from(value: Vec) -> Result { +// Ok(CanonicalAddress(CanonicalAddr(Binary::from(value)))) +// } +// } + +// impl From for Vec { +// fn from(addr: CanonicalAddress) -> Self { +// addr.0.into() +// } +// } + +// impl From for CanonicalAddr { +// fn from(addr: CanonicalAddress) -> Self { +// addr.0 +// } +// } + +// impl<'a> VMBase for SimpleWasmiVM<'a> { +// type Input<'x> = WasmiInput>; +// type Output<'x> = WasmiOutput>; +// type QueryCustom = Empty; +// type MessageCustom = Empty; +// type ContractMeta = CosmwasmContractMeta; +// type Address = BankAccount; +// type CanonicalAddress = CanonicalAddress; +// type StorageKey = Vec; +// type StorageValue = Vec; +// type Error = SimpleVMError; + +// fn running_contract_meta(&mut self) -> Result { +// Ok(self +// .extension +// .contracts +// .get( +// &BankAccount::try_from(self.env.contract.address.clone()) +// .expect("contract address is set by vm, this should never happen"), +// ) +// .cloned() +// .expect("contract is inserted by vm, this should never happen")) +// } + +// fn set_contract_meta( +// &mut self, +// address: Self::Address, +// contract_meta: Self::ContractMeta, +// ) -> Result<(), Self::Error> { +// let meta = self +// .extension +// .contracts +// .get_mut(&address) +// .ok_or(SimpleVMError::ContractNotFound(address))?; + +// *meta = contract_meta; + +// Ok(()) +// } + +// fn contract_meta(&mut self, address: Self::Address) -> Result { +// self.extension +// .contracts +// .get_mut(&address) +// .ok_or(SimpleVMError::ContractNotFound(address)) +// .cloned() +// } + +// fn continue_query( +// &mut self, +// address: Self::Address, +// message: &[u8], +// ) -> Result { +// let mut sub_vm = self.load_subvm(address, vec![])?; +// cosmwasm_call::>(&mut sub_vm, message) +// } + +// fn continue_execute( +// &mut self, +// address: Self::Address, +// funds: Vec, +// message: &[u8], +// event_handler: &mut dyn FnMut(Event), +// ) -> Result, Self::Error> { +// let mut sub_vm = self.load_subvm(address, funds)?; +// cosmwasm_system_run::, _>( +// &mut sub_vm, +// message, +// event_handler, +// ) +// } + +// fn continue_instantiate( +// &mut self, +// contract_meta: Self::ContractMeta, +// funds: Vec, +// message: &[u8], +// event_handler: &mut dyn FnMut(Event), +// ) -> Result<(Self::Address, Option), Self::Error> { +// let BankAccount(address) = self.extension.next_account_id; +// self.extension.next_account_id = BankAccount(address + 1); +// self.extension +// .contracts +// .insert(BankAccount(address), contract_meta); + +// let mut sub_vm = self.load_subvm(BankAccount(address), funds)?; +// cosmwasm_system_run::, _>( +// &mut sub_vm, +// message, +// event_handler, +// ) +// .map(|data| (BankAccount(address), data)) +// } + +// fn continue_instantiate2( +// &mut self, +// contract_meta: Self::ContractMeta, +// funds: Vec, +// message: &[u8], +// _salt: &[u8], +// event_handler: &mut dyn FnMut(Event), +// ) -> Result<(Self::Address, Option), Self::Error> { +// let BankAccount(address) = self.extension.next_account_id; +// self.extension.next_account_id = BankAccount(address + 1); +// self.extension +// .contracts +// .insert(BankAccount(address), contract_meta); + +// let mut sub_vm = self.load_subvm(BankAccount(address), funds)?; +// cosmwasm_system_run::, _>( +// &mut sub_vm, +// message, +// event_handler, +// ) +// .map(|data| (BankAccount(address), data)) +// } + +// fn continue_migrate( +// &mut self, +// address: Self::Address, +// message: &[u8], +// event_handler: &mut dyn FnMut(Event), +// ) -> Result, Self::Error> { +// let mut sub_vm = self.load_subvm(address, vec![])?; +// cosmwasm_system_run::, _>( +// &mut sub_vm, +// message, +// event_handler, +// ) +// } + +// fn continue_reply( +// &mut self, +// message: Reply, +// event_handler: &mut dyn FnMut(Event), +// ) -> Result, Self::Error> { +// let mut sub_vm = self.load_subvm( +// self.env.contract.address.clone().into_string().try_into()?, +// vec![], +// )?; + +// cosmwasm_system_run::, OwnedWasmiVM>( +// &mut sub_vm, +// &serde_json::to_vec(&message).map_err(|_| SimpleVMError::CannotDeserialize)?, +// event_handler, +// ) +// } + +// fn query_custom( +// &mut self, +// _: Self::QueryCustom, +// ) -> Result, Self::Error> { +// Err(SimpleVMError::NoCustomQuery) +// } + +// fn message_custom( +// &mut self, +// _: Self::MessageCustom, +// _: &mut dyn FnMut(Event), +// ) -> Result, Self::Error> { +// Err(SimpleVMError::NoCustomMessage) +// } + +// fn query_raw( +// &mut self, +// address: Self::Address, +// key: Self::StorageKey, +// ) -> Result, Self::Error> { +// Ok(self +// .extension +// .storage +// .get(&address) +// .unwrap_or(&SimpleWasmiVMStorage::default()) +// .data +// .get(&key) +// .cloned()) +// } + +// fn transfer_from( +// &mut self, +// from: &Self::Address, +// to: &Self::Address, +// funds: &[Coin], +// ) -> Result<(), Self::Error> { +// log::debug!("Transfer from: {:?} -> {:?}\n{:?}", from, to, funds); +// Ok(()) +// } + +// fn transfer(&mut self, to: &Self::Address, funds: &[Coin]) -> Result<(), Self::Error> { +// log::debug!( +// "Transfer: {:?} -> {:?}\n{:?}", +// self.env.contract.address, +// to, +// funds +// ); +// Ok(()) +// } + +// fn burn(&mut self, funds: &[Coin]) -> Result<(), Self::Error> { +// log::debug!("Burn: {:?}\n{:?}", self.env.contract.address, funds); +// Ok(()) +// } + +// fn balance(&mut self, _: &Self::Address, _: String) -> Result { +// log::debug!("Query balance."); +// Err(SimpleVMError::Unsupported) +// } + +// fn supply(&mut self, _: String) -> Result { +// log::debug!("Supply."); +// Err(SimpleVMError::Unsupported) +// } + +// fn all_balance(&mut self, _: &Self::Address) -> Result, Self::Error> { +// log::debug!("Query all balance."); +// Ok(vec![]) +// } + +// fn query_contract_info( +// &mut self, +// _: Self::Address, +// ) -> Result { +// Err(SimpleVMError::Unsupported) +// } + +// fn query_code_info(&mut self, _: CosmwasmCodeId) -> Result { +// Err(SimpleVMError::Unsupported) +// } + +// fn debug(&mut self, message: Vec) -> Result<(), Self::Error> { +// log::info!("[contract-debug] {}", String::from_utf8_lossy(&message)); +// Ok(()) +// } + +// #[cfg(feature = "iterator")] +// #[tracing::instrument(skip(self, _order))] +// fn db_scan( +// &mut self, +// _start: Option, +// _end: Option, +// _order: Order, +// ) -> Result { +// let contract_addr = self.env.contract.address.clone().try_into()?; +// let mut empty = SimpleWasmiVMStorage::default(); +// let storage = self +// .extension +// .storage +// .get_mut(&contract_addr) +// .unwrap_or(&mut empty); + +// let data = storage.data.clone().into_iter().collect::>(); +// // Exceeding u32 size is fatal +// let last_id: u32 = storage +// .iterators +// .len() +// .try_into() +// .expect("Found more iterator IDs than supported"); + +// let new_id = last_id + 1; +// let iter = Iter { data, position: 0 }; +// storage.iterators.insert(new_id, iter); + +// Ok(new_id) +// } + +// #[cfg(feature = "iterator")] +// #[tracing::instrument(skip(self))] +// fn db_next( +// &mut self, +// iterator_id: u32, +// ) -> Result<(Self::StorageKey, Self::StorageValue), Self::Error> { +// let contract_addr = self.env.contract.address.clone().try_into()?; +// let storage = self +// .extension +// .storage +// .get_mut(&contract_addr) +// .ok_or(SimpleVMError::IteratorDoesNotExist)?; + +// let iterator = storage +// .iterators +// .get_mut(&iterator_id) +// .ok_or(SimpleVMError::IteratorDoesNotExist)?; + +// let position = iterator.position; +// if iterator.data.len() > position { +// iterator.position += 1; +// Ok(iterator.data[position].clone()) +// } else { +// // Empty data works like `None` in rust iterators +// Ok((Vec::default(), Vec::default())) +// } +// } + +// fn secp256k1_verify( +// &mut self, +// message_hash: &[u8], +// signature: &[u8], +// public_key: &[u8], +// ) -> Result { +// cosmwasm_crypto::secp256k1_verify(message_hash, signature, public_key) +// .map_err(|_| SimpleVMError::Crypto) +// } + +// fn secp256k1_recover_pubkey( +// &mut self, +// message_hash: &[u8], +// signature: &[u8], +// recovery_param: u8, +// ) -> Result, ()>, Self::Error> { +// Ok( +// cosmwasm_crypto::secp256k1_recover_pubkey(message_hash, signature, recovery_param) +// .map_err(|_| ()), +// ) +// } + +// fn ed25519_verify( +// &mut self, +// message: &[u8], +// signature: &[u8], +// public_key: &[u8], +// ) -> Result { +// cosmwasm_crypto::ed25519_verify(message, signature, public_key) +// .map_err(|_| SimpleVMError::Crypto) +// } + +// fn ed25519_batch_verify( +// &mut self, +// messages: &[&[u8]], +// signatures: &[&[u8]], +// public_keys: &[&[u8]], +// ) -> Result { +// cosmwasm_crypto::ed25519_batch_verify(messages, signatures, public_keys) +// .map_err(|_| SimpleVMError::Crypto) +// } + +// fn addr_validate(&mut self, input: &str) -> Result, Self::Error> { +// let canonical = match self.addr_canonicalize(input)? { +// Ok(canonical) => canonical, +// Err(e) => return Ok(Err(e)), +// }; +// let normalized = match self.addr_humanize(&canonical)? { +// Ok(canonical) => canonical, +// Err(e) => return Ok(Err(e)), +// }; +// let account = BankAccount::try_from(input.to_string())?; +// Ok(if account == normalized { +// Ok(()) +// } else { +// Err(SimpleVMError::InvalidAddress) +// }) +// } + +// fn addr_canonicalize( +// &mut self, +// input: &str, +// ) -> Result, Self::Error> { +// // mimicks formats like hex or bech32 where different casings are valid for one address +// let normalized = input.to_lowercase(); + +// // Dummy input validation. This is more sophisticated for formats like bech32, where format and checksum are validated. +// if normalized.len() < 3 { +// return Ok(Err(SimpleVMError::InvalidAddress)); +// } + +// if normalized.len() > CANONICAL_LENGTH { +// return Ok(Err(SimpleVMError::InvalidAddress)); +// } + +// let mut out = Vec::from(normalized); +// // pad to canonical length with NULL bytes +// out.resize(CANONICAL_LENGTH, 0x00); +// // content-dependent rotate followed by shuffle to destroy +// let rotate_by = digit_sum(&out) % CANONICAL_LENGTH; +// out.rotate_left(rotate_by); +// for _ in 0..SHUFFLES_ENCODE { +// out = riffle_shuffle(&out); +// } +// Ok(Ok(out.try_into()?)) +// } + +// fn addr_humanize( +// &mut self, +// addr: &Self::CanonicalAddress, +// ) -> Result, Self::Error> { +// if addr.0.len() != CANONICAL_LENGTH { +// return Ok(Err(SimpleVMError::InvalidAddress)); +// } + +// let mut tmp: Vec = addr.clone().into(); +// // Shuffle two more times which restored the original value (24 elements are back to original after 20 rounds) +// for _ in 0..SHUFFLES_DECODE { +// tmp = riffle_shuffle(&tmp); +// } +// // Rotate back +// let rotate_by = digit_sum(&tmp) % CANONICAL_LENGTH; +// tmp.rotate_right(rotate_by); +// // Remove NULL bytes (i.e. the padding) +// let trimmed = tmp.into_iter().filter(|&x| x != 0x00).collect(); +// // decode UTF-8 bytes into string +// let Ok(human) = String::from_utf8(trimmed) else { return Ok(Err(SimpleVMError::InvalidAddress)) }; +// Ok( +// BankAccount::try_from(Addr::unchecked(human)) +// .map_err(|_| SimpleVMError::InvalidAddress), +// ) +// } + +// #[tracing::instrument(skip(self))] +// fn db_read( +// &mut self, +// key: Self::StorageKey, +// ) -> Result, Self::Error> { +// let contract_addr = self.env.contract.address.clone().try_into()?; +// let empty = SimpleWasmiVMStorage::default(); +// Ok(self +// .extension +// .storage +// .get(&contract_addr) +// .unwrap_or(&empty) +// .data +// .get(&key) +// .cloned()) +// } + +// #[tracing::instrument(skip(self))] +// fn db_write( +// &mut self, +// key: Self::StorageKey, +// value: Self::StorageValue, +// ) -> Result<(), Self::Error> { +// let contract_addr = self.env.contract.address.clone().try_into()?; +// self.extension +// .storage +// .entry(contract_addr) +// .or_insert_with(SimpleWasmiVMStorage::default) +// .data +// .insert(key, value); +// Ok(()) +// } + +// #[tracing::instrument(skip(self))] +// fn db_remove(&mut self, key: Self::StorageKey) -> Result<(), Self::Error> { +// let contract_addr = self.env.contract.address.clone().try_into()?; +// self.extension +// .storage +// .get_mut(&contract_addr) +// .map(|contract_storage| contract_storage.data.remove(&key)); +// Ok(()) +// } + +// fn abort(&mut self, message: String) -> Result<(), Self::Error> { +// log::debug!("Contract aborted: {}", message); +// Err(SimpleVMError::from(WasmiVMError::from( +// SystemError::ContractExecutionFailure(message), +// ))) +// } + +// fn charge(&mut self, value: VmGas) -> Result<(), Self::Error> { +// let gas_to_charge = match value { +// VmGas::Instrumentation { metered } => u64::from(metered), +// x => { +// log::debug!("Charging gas: {:?}", x); +// 1u64 +// } +// }; +// self.extension.gas.charge(gas_to_charge)?; +// Ok(()) +// } + +// fn gas_checkpoint_push(&mut self, checkpoint: VmGasCheckpoint) -> Result<(), Self::Error> { +// log::debug!("> Gas before: {:?}", self.extension.gas); +// self.extension.gas.push(&checkpoint)?; +// log::debug!("> Gas after: {:?}", self.extension.gas); +// Ok(()) +// } + +// fn gas_checkpoint_pop(&mut self) -> Result<(), Self::Error> { +// log::debug!("> Gas before: {:?}", self.extension.gas); +// self.extension.gas.pop(); +// log::debug!("> Gas after: {:?}", self.extension.gas); +// Ok(()) +// } + +// fn gas_ensure_available(&mut self) -> Result<(), Self::Error> { +// let checkpoint = self +// .extension +// .gas +// .checkpoints +// .last() +// .expect("invalis gas checkpoint state"); +// if *checkpoint > 0 { +// Ok(()) +// } else { +// Err(SimpleVMError::OutOfGas) +// } +// } + +// #[cfg(feature = "stargate")] +// fn ibc_transfer( +// &mut self, +// _channel_id: String, +// _to_address: String, +// _amount: Coin, +// _timeout: IbcTimeout, +// ) -> Result<(), Self::Error> { +// todo!() +// } + +// #[cfg(feature = "stargate")] +// fn ibc_send_packet( +// &mut self, +// channel_id: String, +// data: Binary, +// timeout: IbcTimeout, +// ) -> Result<(), Self::Error> { +// let contract_addr = self.env.contract.address.clone().try_into()?; +// let entry = self.extension.ibc.entry(contract_addr).or_default(); +// entry.packets_sent.push(SimpleIBCPacket { +// channel_id, +// data, +// timeout, +// }); +// Ok(()) +// } + +// #[cfg(feature = "stargate")] +// fn ibc_close_channel(&mut self, _channel_id: String) -> Result<(), Self::Error> { +// todo!() +// } +// } + +// #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +// struct BankAccount(u128); + +// impl TryFrom for BankAccount { +// type Error = SimpleVMError; +// fn try_from(value: Addr) -> Result { +// value.to_string().try_into() +// } +// } + +// impl TryFrom for BankAccount { +// type Error = SimpleVMError; +// fn try_from(value: String) -> Result { +// Ok(BankAccount( +// u128::from_str(&value).map_err(|_| SimpleVMError::InvalidAccountFormat)?, +// )) +// } +// } + +// impl From for Addr { +// fn from(BankAccount(account): BankAccount) -> Self { +// Addr::unchecked(format!("{account}")) +// } +// } + +// impl<'a> Has for SimpleWasmiVM<'a> { +// fn get(&self) -> Env { +// self.env.clone() +// } +// } +// impl<'a> Has for SimpleWasmiVM<'a> { +// fn get(&self) -> MessageInfo { +// self.info.clone() +// } +// } + +// impl<'a> Transactional for SimpleWasmiVM<'a> { +// type Error = SimpleVMError; +// fn transaction_begin(&mut self) -> Result<(), Self::Error> { +// self.extension.transaction_depth += 1; +// log::debug!("> Transaction begin: {}", self.extension.transaction_depth); +// Ok(()) +// } +// fn transaction_commit(&mut self) -> Result<(), Self::Error> { +// self.extension.transaction_depth -= 1; +// log::debug!("< Transaction end: {}", self.extension.transaction_depth); +// Ok(()) +// } +// fn transaction_rollback(&mut self) -> Result<(), Self::Error> { +// self.extension.transaction_depth -= 1; +// log::debug!("< Transaction abort: {}", self.extension.transaction_depth); +// Ok(()) +// } +// } + +// struct ConstantCostRules; +// impl Rules for ConstantCostRules { +// fn instruction_cost( +// &self, +// _: &wasm_instrument::parity_wasm::elements::Instruction, +// ) -> Option { +// Some(42) +// } + +// fn memory_grow_cost(&self) -> wasm_instrument::gas_metering::MemoryGrowCost { +// wasm_instrument::gas_metering::MemoryGrowCost::Linear( +// NonZeroU32::new(1024).expect("impossible"), +// ) +// } +// } + +// fn instrument_contract(code: &[u8]) -> Vec { +// let module = +// wasm_instrument::parity_wasm::elements::Module::from_bytes(code).expect("impossible"); +// let instrumented_module = +// wasm_instrument::gas_metering::inject(module, &ConstantCostRules, "env") +// .expect("impossible"); +// instrumented_module.into_bytes().expect("impossible") +// } + +// pub fn initialize() { +// use std::sync::Once; +// static INIT: Once = Once::new(); +// INIT.call_once(|| { +// // setup this one to tune output +// let mut builder = env_logger::builder(); +// builder.format_timestamp_nanos(); +// builder.try_init().unwrap(); + +// let collector = tracing_subscriber::fmt() +// .with_max_level(tracing::Level::TRACE) +// .finish(); +// let collector = tracing_subscriber::fmt::layer() +// .with_level(true) +// .with_line_number(true); +// let tracer = opentelemetry::sdk::export::trace::stdout::new_pipeline().install_simple(); +// let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); +// let subscriber = tracing_subscriber::Registry::default() +// .with(telemetry) +// .with(collector); +// tracing::subscriber::set_global_default(subscriber).unwrap(); +// }); +// } + +// fn create_vm( +// extension: &mut SimpleWasmiVMExtension, +// env: Env, +// info: MessageInfo, +// ) -> Result, SimpleVMError> { +// initialize(); +// let code = extension +// .codes +// .get( +// &extension +// .contracts +// .get(&env.clone().contract.address.try_into().unwrap()) +// .expect("contract should have been uploaded") +// .code_id, +// ) +// .expect("contract should have been uploaded") +// .clone(); +// let vm = SimpleWasmiVM { +// executing_module: None, +// env, +// info, +// extension, +// }; +// let vm = new_wasmi_vm::(&code, vm)?; +// Ok(vm) +// } + +// fn create_simple_vm( +// sender: BankAccount, +// contract: BankAccount, +// funds: Vec, +// extension: &mut SimpleWasmiVMExtension, +// ) -> Result, SimpleVMError> { +// create_vm( +// extension, +// Env { +// block: BlockInfo { +// height: 0xDEAD_C0DE, +// time: Timestamp::from_seconds(10000), +// chain_id: "abstract-test".into(), +// }, +// transaction: None, +// contract: ContractInfo { +// address: contract.into(), +// }, +// }, +// MessageInfo { +// sender: sender.into(), +// funds, +// }, +// ) +// } fn main() { - let iter = 100; - let cw20_base_code = instrument_contract(include_bytes!("../../../fixtures/cw20_base.wasm")); - let hackatom_code = instrument_contract(include_bytes!("../../../fixtures/hackatom.wasm")); - let reflect_code = instrument_contract(include_bytes!("../../../fixtures/reflect.wasm")); - - let sender = BankAccount(100); - let cw20_address = BankAccount(10_000); - let hackatom_address = BankAccount(10_002); - let reflect_address = BankAccount(10_003); - let funds = vec![]; - let mut extension = SimpleWasmiVMExtension { - storage: BTreeMap::default(), - codes: BTreeMap::from([ - (0x1337, cw20_base_code), - (0x1338, hackatom_code), - (0x1339, reflect_code), - ]), - contracts: BTreeMap::from([ - ( - cw20_address, - CosmwasmContractMeta { - code_id: 0x1337, - admin: None, - label: String::new(), - }, - ), - ( - hackatom_address, - CosmwasmContractMeta { - code_id: 0x1338, - admin: None, - label: String::new(), - }, - ), - ( - reflect_address, - CosmwasmContractMeta { - code_id: 0x1339, - admin: None, - label: String::new(), - }, - ), - ]), - next_account_id: BankAccount(10_004), - transaction_depth: 0, - gas: Gas::new(u64::MAX), - ..Default::default() - }; - - { - { - let mut vm = - create_simple_vm(sender, cw20_address, funds.clone(), &mut extension).unwrap(); - - assert_matches!( - cosmwasm_call::, OwnedWasmiVM>( - &mut vm, - r#"{ - "name": "Picasso", - "symbol": "PICA", - "decimals": 12, - "initial_balances": [], - "mint": null, - "marketing": null - }"# - .as_bytes(), - ) - .unwrap(), - InstantiateResult(CosmwasmExecutionResult::Ok(_)) - ); - - for _ in 0..iter { - cosmwasm_call::>( - &mut vm, - r#"{ "token_info": {} }"#.as_bytes(), - ) - .unwrap(); - } - } - { - let mut vm = - create_simple_vm(sender, reflect_address, funds.clone(), &mut extension).unwrap(); - let _ = cosmwasm_system_entrypoint::>( - &mut vm, - r#"{}"#.as_bytes(), - ) - .unwrap(); - - for _ in 0..iter { - let (_, events) = - cosmwasm_system_entrypoint::>( - &mut vm, - r#"{ - "reflect_sub_msg": { - "msgs": [{ - "id": 10, - "msg": { - "wasm": { - "execute": { - "contract_addr": "10001", - "msg": "eyAicmVsZWFzZSI6IHt9IH0=", - "funds": [] - } - } - }, - "gas_limit": null, - "reply_on": "always" - }] - } - }"# - .as_bytes(), - ) - .unwrap(); - } - } - - { - let mut vm = - create_simple_vm(sender, hackatom_address, funds.clone(), &mut extension).unwrap(); - - let (_, events) = cosmwasm_system_entrypoint::( - &mut vm, - r#"{"verifier": "10000", "beneficiary": "10000"}"#.as_bytes(), - ) - .unwrap(); - for _ in 0..iter { - cosmwasm_call::>( - &mut vm, - r#"{ "recurse": { "depth": 10, "work": 10 }}"#.as_bytes(), - ) - .unwrap(); - } - } - } -} - -pub fn digit_sum(input: &[u8]) -> usize { - input.iter().map(|v| *v as usize).sum() -} - -pub fn riffle_shuffle(input: &[T]) -> Vec { - assert!( - input.len() % 2 == 0, - "Method only defined for even number of elements" - ); - let mid = input.len() / 2; - let (left, right) = input.split_at(mid); - let mut out = Vec::::with_capacity(input.len()); - for i in 0..mid { - out.push(right[i].clone()); - out.push(left[i].clone()); - } - out +// let iter = 100; +// let cw20_base_code = instrument_contract(include_bytes!("../../../fixtures/cw20_base.wasm")); +// let hackatom_code = instrument_contract(include_bytes!("../../../fixtures/hackatom.wasm")); +// let reflect_code = instrument_contract(include_bytes!("../../../fixtures/reflect.wasm")); + +// let sender = BankAccount(100); +// let cw20_address = BankAccount(10_000); +// let hackatom_address = BankAccount(10_002); +// let reflect_address = BankAccount(10_003); +// let funds = vec![]; +// let mut extension = SimpleWasmiVMExtension { +// storage: BTreeMap::default(), +// codes: BTreeMap::from([ +// (0x1337, cw20_base_code), +// (0x1338, hackatom_code), +// (0x1339, reflect_code), +// ]), +// contracts: BTreeMap::from([ +// ( +// cw20_address, +// CosmwasmContractMeta { +// code_id: 0x1337, +// admin: None, +// label: String::new(), +// }, +// ), +// ( +// hackatom_address, +// CosmwasmContractMeta { +// code_id: 0x1338, +// admin: None, +// label: String::new(), +// }, +// ), +// ( +// reflect_address, +// CosmwasmContractMeta { +// code_id: 0x1339, +// admin: None, +// label: String::new(), +// }, +// ), +// ]), +// next_account_id: BankAccount(10_004), +// transaction_depth: 0, +// gas: Gas::new(u64::MAX), +// ..Default::default() +// }; + +// { +// { +// let mut vm = +// create_simple_vm(sender, cw20_address, funds.clone(), &mut extension).unwrap(); + +// assert_matches!( +// cosmwasm_call::, OwnedWasmiVM>( +// &mut vm, +// r#"{ +// "name": "Picasso", +// "symbol": "PICA", +// "decimals": 12, +// "initial_balances": [], +// "mint": null, +// "marketing": null +// }"# +// .as_bytes(), +// ) +// .unwrap(), +// InstantiateResult(CosmwasmExecutionResult::Ok(_)) +// ); + +// for _ in 0..iter { +// cosmwasm_call::>( +// &mut vm, +// r#"{ "token_info": {} }"#.as_bytes(), +// ) +// .unwrap(); +// } +// } +// { +// let mut vm = +// create_simple_vm(sender, reflect_address, funds.clone(), &mut extension).unwrap(); +// let _ = cosmwasm_system_entrypoint::>( +// &mut vm, +// r#"{}"#.as_bytes(), +// ) +// .unwrap(); + +// for _ in 0..iter { +// let (_, events) = +// cosmwasm_system_entrypoint::>( +// &mut vm, +// r#"{ +// "reflect_sub_msg": { +// "msgs": [{ +// "id": 10, +// "msg": { +// "wasm": { +// "execute": { +// "contract_addr": "10001", +// "msg": "eyAicmVsZWFzZSI6IHt9IH0=", +// "funds": [] +// } +// } +// }, +// "gas_limit": null, +// "reply_on": "always" +// }] +// } +// }"# +// .as_bytes(), +// ) +// .unwrap(); +// } +// } + +// { +// let mut vm = +// create_simple_vm(sender, hackatom_address, funds.clone(), &mut extension).unwrap(); + +// let (_, events) = cosmwasm_system_entrypoint::( +// &mut vm, +// r#"{"verifier": "10000", "beneficiary": "10000"}"#.as_bytes(), +// ) +// .unwrap(); +// for _ in 0..iter { +// cosmwasm_call::>( +// &mut vm, +// r#"{ "recurse": { "depth": 10, "work": 10 }}"#.as_bytes(), +// ) +// .unwrap(); +// } +// } +// } +// } + +// pub fn digit_sum(input: &[u8]) -> usize { +// input.iter().map(|v| *v as usize).sum() +// } + +// pub fn riffle_shuffle(input: &[T]) -> Vec { +// assert!( +// input.len() % 2 == 0, +// "Method only defined for even number of elements" +// ); +// let mid = input.len() / 2; +// let (left, right) = input.split_at(mid); +// let mut out = Vec::::with_capacity(input.len()); +// for i in 0..mid { +// out.push(right[i].clone()); +// out.push(left[i].clone()); +// } +// out } diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 6ed63b8..b79b49a 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -1,13 +1,7 @@ [package] name = "cosmwasm-vm" -version = "0.1.0" +version = "0.2.0" edition = "2021" -authors = [ - "Hussein Ait Lahcen hussein.aitlahcen@gmail.com", - "Abdullah Eryuzlu abdullaheryuzlu@gmail.com", - "Composable Developers", -] -homepage = "https://composable.finance" [features] default = ["iterator", "stargate", "ibc3"] diff --git a/vm/src/executor.rs b/vm/src/executor.rs index fc6e684..e4a8d06 100644 --- a/vm/src/executor.rs +++ b/vm/src/executor.rs @@ -1,30 +1,6 @@ // executor.rs --- -// Copyright (C) 2022 Hussein Ait-Lahcen - -// Author: Hussein Ait-Lahcen - -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// Except as contained in this notice, the name(s) of the above copyright -// holders shall not be used in advertising or otherwise to promote the sale, -// use or other dealings in this Software without prior written authorization. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. + use crate::{ has::Has, diff --git a/vm/src/has.rs b/vm/src/has.rs index a39185b..d269149 100644 --- a/vm/src/has.rs +++ b/vm/src/has.rs @@ -1,30 +1,6 @@ // has.rs --- -// Copyright (C) 2022 Hussein Ait-Lahcen -// Author: Hussein Ait-Lahcen - -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// Except as contained in this notice, the name(s) of the above copyright -// holders shall not be used in advertising or otherwise to promote the sale, -// use or other dealings in this Software without prior written authorization. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. pub trait Has { fn get(&self) -> T; diff --git a/vm/src/input.rs b/vm/src/input.rs index e7c82d8..1ddc584 100644 --- a/vm/src/input.rs +++ b/vm/src/input.rs @@ -1,30 +1,6 @@ // input.rs --- -// Copyright (C) 2022 Hussein Ait-Lahcen -// Author: Hussein Ait-Lahcen - -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// Except as contained in this notice, the name(s) of the above copyright -// holders shall not be used in advertising or otherwise to promote the sale, -// use or other dealings in this Software without prior written authorization. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. pub type OutputOf = ::Output; diff --git a/vm/src/lib.rs b/vm/src/lib.rs index c61abd4..f177817 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -1,31 +1,3 @@ -// lib.rs --- - -// Copyright (C) 2022 Hussein Ait-Lahcen - -// Author: Hussein Ait-Lahcen - -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// Except as contained in this notice, the name(s) of the above copyright -// holders shall not be used in advertising or otherwise to promote the sale, -// use or other dealings in this Software without prior written authorization. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - #![no_std] #![feature(trait_alias)] @@ -38,6 +10,4 @@ pub mod memory; pub mod system; pub mod tagged; pub mod transaction; -pub mod vm; - -pub use cosmwasm_std; +pub mod vm; \ No newline at end of file diff --git a/vm/src/memory.rs b/vm/src/memory.rs index 2f9bed6..2a12ed0 100644 --- a/vm/src/memory.rs +++ b/vm/src/memory.rs @@ -1,30 +1,6 @@ // memory.rs --- -// Copyright (C) 2022 Hussein Ait-Lahcen -// Author: Hussein Ait-Lahcen - -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// Except as contained in this notice, the name(s) of the above copyright -// holders shall not be used in advertising or otherwise to promote the sale, -// use or other dealings in this Software without prior written authorization. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. use alloc::vec; use alloc::vec::Vec; diff --git a/vm/src/system.rs b/vm/src/system.rs index ebb35b8..2618bf1 100644 --- a/vm/src/system.rs +++ b/vm/src/system.rs @@ -1,30 +1,6 @@ // system.rs --- -// Copyright (C) 2022 Hussein Ait-Lahcen - -// Author: Hussein Ait-Lahcen - -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// Except as contained in this notice, the name(s) of the above copyright -// holders shall not be used in advertising or otherwise to promote the sale, -// use or other dealings in this Software without prior written authorization. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. + #[cfg(feature = "stargate")] use crate::executor::ibc::{ diff --git a/vm/src/tagged.rs b/vm/src/tagged.rs index a0f8559..d7c6cc8 100644 --- a/vm/src/tagged.rs +++ b/vm/src/tagged.rs @@ -1,30 +1,6 @@ // tagged.rs --- -// Copyright (C) 2022 Hussein Ait-Lahcen -// Author: Hussein Ait-Lahcen - -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// Except as contained in this notice, the name(s) of the above copyright -// holders shall not be used in advertising or otherwise to promote the sale, -// use or other dealings in this Software without prior written authorization. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. use core::marker::PhantomData; diff --git a/vm/src/transaction.rs b/vm/src/transaction.rs index 675b940..9a6e344 100644 --- a/vm/src/transaction.rs +++ b/vm/src/transaction.rs @@ -1,30 +1,6 @@ // transaction.rs --- -// Copyright (C) 2022 Hussein Ait-Lahcen -// Author: Hussein Ait-Lahcen - -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// Except as contained in this notice, the name(s) of the above copyright -// holders shall not be used in advertising or otherwise to promote the sale, -// use or other dealings in this Software without prior written authorization. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. pub type TransactionalErrorOf = ::Error; From ebf8272b1a6ed2d05246ee69a5e4ace88ed387f0 Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 8 Jun 2023 12:23:16 +0100 Subject: [PATCH 03/11] migrated all prod code --- research/Cargo.toml | 48 ++ research/bin/research.rs | 1130 ++++++++++++++++++++++++++++++++ vm-wasmi/Cargo.toml | 13 - vm-wasmi/src/bin/research.rs | 1130 -------------------------------- vm-wasmi/src/host_functions.rs | 2 + vm-wasmi/src/version.rs | 12 +- vm/src/executor.rs | 4 - vm/src/has.rs | 2 - vm/src/input.rs | 2 - vm/src/lib.rs | 2 +- vm/src/memory.rs | 2 - vm/src/system.rs | 2 - vm/src/tagged.rs | 2 - vm/src/transaction.rs | 2 - 14 files changed, 1189 insertions(+), 1164 deletions(-) create mode 100644 research/Cargo.toml create mode 100644 research/bin/research.rs delete mode 100644 vm-wasmi/src/bin/research.rs diff --git a/research/Cargo.toml b/research/Cargo.toml new file mode 100644 index 0000000..8fe4812 --- /dev/null +++ b/research/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "cosmwasm-vm-wasmi" +version = "0.2.0" +edition = "2021" + + +[[bin]] +name = "research" +test = true + +[features] +default = ["iterator", "stargate", "ibc3"] +iterator = ["cosmwasm-vm/iterator"] +stargate = ["cosmwasm-vm/stargate"] +ibc3 = ["cosmwasm-vm/ibc3"] +std = ["cosmwasm-std/std"] + +[dependencies] +serde = { workspaace = true, default-features = false, features = ["derive"] } +serde_json = { workspaace = true, default-features = false, features = ["alloc"] } +either = { version = "1.8", default-features = false } +log = { workspace = true, default-features = false } +wasmi = { version = "0.26", default-features = false } +wasmi-validation = { version = "0.5", default-features = false } +wasm-instrument = { version = "0.2", default-features = false } +cosmwasm-std = { workspace = true, default-features = false, features = [ + "iterator", + "cosmwasm_1_2" +] } +cosmwasm-vm = { path = "../vm", default-features = false } +hex = { version = "0.4", default-features = false, features = ["alloc"] } + +# benches +tracing = "0.1" +tracing-subscriber = "0.3" +tracing-opentelemetry = "*" +opentelemetry = "*" + +wyndex = { git = "https://github.com/wynddao/wynddex", rev = "a578f8b645433e108a10613e85ae49385c2fc63c", default-features = false } + +[dev-dependencies] +wat = "1.0" +env_logger = "0.9" +cosmwasm-crypto = { git = "https://github.com/ComposableFi/cosmwasm", rev = "7d288c23772d03e8cd666b76cb5bbdc5952721dd" } + +cw20-ics20 = { git = "https://github.com/CosmWasm/cw-plus", rev = "53dc88fdb81888cbd3dae8742e7318b35d3d0c0f", default-features = false, features = [ + "library", +] } diff --git a/research/bin/research.rs b/research/bin/research.rs new file mode 100644 index 0000000..0937238 --- /dev/null +++ b/research/bin/research.rs @@ -0,0 +1,1130 @@ +#![feature(trait_alias)] +#![feature(assert_matches)] +#![allow(soft_unstable)] +#![feature(test)] + +extern crate alloc; + +extern crate std; + +use cosmwasm_vm::vm::VMBase; + +use alloc::{ + collections::BTreeMap, + format, + string::{String, ToString}, + vec, + vec::Vec, +}; +use core::{ + assert_matches::assert_matches, + fmt::{Debug, Display}, + num::NonZeroU32, + str::FromStr, +}; +#[cfg(feature = "stargate")] +use cosmwasm_std::IbcTimeout; +#[cfg(feature = "iterator")] +use cosmwasm_std::Order; +use cosmwasm_std::{ + Addr, Attribute, Binary, BlockInfo, CanonicalAddr, CodeInfoResponse, Coin, ContractInfo, + ContractInfoResponse, ContractResult, Empty, Env, Event, MessageInfo, Reply, SystemResult, + Timestamp, +}; +use cosmwasm_vm::{ + executor::{ + cosmwasm_call, CosmwasmExecutionResult, CosmwasmQueryResult, ExecuteCall, ExecuteResult, + ExecutorError, InstantiateCall, InstantiateResult, MigrateCall, QueryCall, QueryResult, + ReplyCall, + }, + has::Has, + memory::{MemoryReadError, MemoryWriteError}, + system::{ + cosmwasm_system_entrypoint, cosmwasm_system_entrypoint_hook, cosmwasm_system_run, + CosmwasmCodeId, CosmwasmContractMeta, SystemError, + }, + transaction::Transactional, + vm::{VmErrorOf, VmGas, VmGasCheckpoint}, +}; +use cosmwasm_vm_wasmi::{ + code_gen, new_wasmi_vm, OwnedWasmiVM, WasmiContext, WasmiInput, WasmiModule, WasmiOutput, + WasmiVMError, +}; +use tracing::instrument::WithSubscriber; +use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt; +use wasm_instrument::gas_metering::Rules; +use wasmi::core::HostError; + +const CANONICAL_LENGTH: usize = 54; +const SHUFFLES_ENCODE: usize = 18; +const SHUFFLES_DECODE: usize = 2; + +#[derive(PartialEq, Debug)] +enum SimpleVMError { + Interpreter, + VMError(WasmiVMError), + CodeNotFound(CosmwasmCodeId), + ContractNotFound(BankAccount), + InvalidAddress, + InvalidAccountFormat, + NoCustomQuery, + NoCustomMessage, + Unsupported, + OutOfGas, + #[cfg(feature = "iterator")] + IteratorDoesNotExist, + CannotDeserialize, + Crypto, +} + +impl HostError for SimpleVMError {} + +impl From for SimpleVMError { + fn from(_: wasmi::Error) -> Self { + Self::Interpreter + } +} +impl From for SimpleVMError { + fn from(e: WasmiVMError) -> Self { + SimpleVMError::VMError(e) + } +} +impl From for SimpleVMError { + fn from(e: SystemError) -> Self { + SimpleVMError::VMError(e.into()) + } +} +impl From for SimpleVMError { + fn from(e: ExecutorError) -> Self { + SimpleVMError::VMError(e.into()) + } +} +impl From for SimpleVMError { + fn from(e: MemoryReadError) -> Self { + SimpleVMError::VMError(e.into()) + } +} +impl From for SimpleVMError { + fn from(e: MemoryWriteError) -> Self { + SimpleVMError::VMError(e.into()) + } +} +impl Display for SimpleVMError { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{self:?}") + } +} + +#[derive(Default, Clone, PartialEq, Eq, Debug)] +struct Gas { + checkpoints: Vec, +} + +impl Gas { + fn new(initial_value: u64) -> Self { + Gas { + checkpoints: vec![initial_value], + } + } + + fn current(&self) -> &u64 { + self.checkpoints.last().expect("impossible") + } + fn current_mut(&mut self) -> &mut u64 { + self.checkpoints.last_mut().expect("impossible") + } + fn push(&mut self, checkpoint: &VmGasCheckpoint) -> Result<(), SimpleVMError> { + match checkpoint { + VmGasCheckpoint::Unlimited => { + let parent = self.current_mut(); + let value = *parent; + *parent = 0; + self.checkpoints.push(value); + Ok(()) + } + VmGasCheckpoint::Limited(limit) if limit <= self.current() => { + *self.current_mut() -= limit; + self.checkpoints.push(*limit); + Ok(()) + } + VmGasCheckpoint::Limited(_) => Err(SimpleVMError::OutOfGas), + } + } + fn pop(&mut self) { + let child = self.checkpoints.pop().expect("impossible"); + let parent = self.current_mut(); + *parent += child; + } + fn charge(&mut self, value: u64) -> Result<(), SimpleVMError> { + let current = self.current_mut(); + if *current >= value { + *current -= value; + Ok(()) + } else { + Err(SimpleVMError::OutOfGas) + } + } +} + +#[cfg(feature = "iterator")] +#[derive(Default, Clone, Debug)] +struct Iter { + data: Vec<(Vec, Vec)>, + position: usize, +} + +#[derive(Default, Clone, Debug)] +struct SimpleWasmiVMStorage { + data: BTreeMap, Vec>, + #[cfg(feature = "iterator")] + iterators: BTreeMap, +} + +#[cfg(feature = "stargate")] +#[derive(Debug, Clone, PartialEq, Eq)] +struct SimpleIBCPacket { + channel_id: String, + data: Binary, + timeout: IbcTimeout, +} + +#[cfg(feature = "stargate")] +#[derive(Default, Clone, Debug, PartialEq, Eq)] +struct SimpleIBCState { + packets_sent: Vec, +} + +#[derive(Default, Clone)] +struct SimpleWasmiVMExtension { + #[cfg(feature = "stargate")] + ibc: BTreeMap, + storage: BTreeMap, + codes: BTreeMap>, + contracts: BTreeMap>, + next_account_id: BankAccount, + transaction_depth: u32, + gas: Gas, +} + +struct SimpleWasmiVM<'a> { + /// module which is in context of vm and executable now + executing_module: Option, + pub env: Env, + info: MessageInfo, + extension: &'a mut SimpleWasmiVMExtension, +} + +impl<'a> WasmiContext for SimpleWasmiVM<'a> { + fn executing_module(&self) -> Option { + self.executing_module.clone() + } + + fn set_wasmi_context(&mut self, instance: wasmi::Instance, memory: wasmi::Memory) { + self.executing_module = Some(WasmiModule { instance, memory }); + } +} + +impl<'a> SimpleWasmiVM<'a> { + pub fn load_subvm( + &mut self, + address: ::Address, + funds: Vec, + ) -> Result, VmErrorOf> { + log::debug!("Loading sub-vm, contract address: {:?}", address); + let code = (|| { + let CosmwasmContractMeta { code_id, .. } = self + .extension + .contracts + .get(&address) + .cloned() + .ok_or(SimpleVMError::ContractNotFound(address))?; + self.extension + .codes + .get(&code_id) + .ok_or(SimpleVMError::CodeNotFound(code_id)) + .cloned() + })()?; + let sub_vm = SimpleWasmiVM { + executing_module: None, + env: Env { + block: self.env.block.clone(), + transaction: self.env.transaction.clone(), + contract: ContractInfo { + address: address.into(), + }, + }, + info: MessageInfo { + sender: self.env.contract.address.clone(), + funds, + }, + extension: self.extension, + }; + let sub_vm = new_wasmi_vm::(&code, sub_vm)?; + Ok(sub_vm) + } +} + +#[derive(Debug, Clone)] +struct CanonicalAddress(pub CanonicalAddr); + +impl TryFrom> for CanonicalAddress { + type Error = SimpleVMError; + fn try_from(value: Vec) -> Result { + Ok(CanonicalAddress(CanonicalAddr(Binary::from(value)))) + } +} + +impl From for Vec { + fn from(addr: CanonicalAddress) -> Self { + addr.0.into() + } +} + +impl From for CanonicalAddr { + fn from(addr: CanonicalAddress) -> Self { + addr.0 + } +} + +impl<'a> VMBase for SimpleWasmiVM<'a> { + type Input<'x> = WasmiInput>; + type Output<'x> = WasmiOutput>; + type QueryCustom = Empty; + type MessageCustom = Empty; + type ContractMeta = CosmwasmContractMeta; + type Address = BankAccount; + type CanonicalAddress = CanonicalAddress; + type StorageKey = Vec; + type StorageValue = Vec; + type Error = SimpleVMError; + + fn running_contract_meta(&mut self) -> Result { + Ok(self + .extension + .contracts + .get( + &BankAccount::try_from(self.env.contract.address.clone()) + .expect("contract address is set by vm, this should never happen"), + ) + .cloned() + .expect("contract is inserted by vm, this should never happen")) + } + + fn set_contract_meta( + &mut self, + address: Self::Address, + contract_meta: Self::ContractMeta, + ) -> Result<(), Self::Error> { + let meta = self + .extension + .contracts + .get_mut(&address) + .ok_or(SimpleVMError::ContractNotFound(address))?; + + *meta = contract_meta; + + Ok(()) + } + + fn contract_meta(&mut self, address: Self::Address) -> Result { + self.extension + .contracts + .get_mut(&address) + .ok_or(SimpleVMError::ContractNotFound(address)) + .cloned() + } + + fn continue_query( + &mut self, + address: Self::Address, + message: &[u8], + ) -> Result { + let mut sub_vm = self.load_subvm(address, vec![])?; + cosmwasm_call::>(&mut sub_vm, message) + } + + fn continue_execute( + &mut self, + address: Self::Address, + funds: Vec, + message: &[u8], + event_handler: &mut dyn FnMut(Event), + ) -> Result, Self::Error> { + let mut sub_vm = self.load_subvm(address, funds)?; + cosmwasm_system_run::, _>( + &mut sub_vm, + message, + event_handler, + ) + } + + fn continue_instantiate( + &mut self, + contract_meta: Self::ContractMeta, + funds: Vec, + message: &[u8], + event_handler: &mut dyn FnMut(Event), + ) -> Result<(Self::Address, Option), Self::Error> { + let BankAccount(address) = self.extension.next_account_id; + self.extension.next_account_id = BankAccount(address + 1); + self.extension + .contracts + .insert(BankAccount(address), contract_meta); + + let mut sub_vm = self.load_subvm(BankAccount(address), funds)?; + cosmwasm_system_run::, _>( + &mut sub_vm, + message, + event_handler, + ) + .map(|data| (BankAccount(address), data)) + } + + fn continue_instantiate2( + &mut self, + contract_meta: Self::ContractMeta, + funds: Vec, + message: &[u8], + _salt: &[u8], + event_handler: &mut dyn FnMut(Event), + ) -> Result<(Self::Address, Option), Self::Error> { + let BankAccount(address) = self.extension.next_account_id; + self.extension.next_account_id = BankAccount(address + 1); + self.extension + .contracts + .insert(BankAccount(address), contract_meta); + + let mut sub_vm = self.load_subvm(BankAccount(address), funds)?; + cosmwasm_system_run::, _>( + &mut sub_vm, + message, + event_handler, + ) + .map(|data| (BankAccount(address), data)) + } + + fn continue_migrate( + &mut self, + address: Self::Address, + message: &[u8], + event_handler: &mut dyn FnMut(Event), + ) -> Result, Self::Error> { + let mut sub_vm = self.load_subvm(address, vec![])?; + cosmwasm_system_run::, _>( + &mut sub_vm, + message, + event_handler, + ) + } + + fn continue_reply( + &mut self, + message: Reply, + event_handler: &mut dyn FnMut(Event), + ) -> Result, Self::Error> { + let mut sub_vm = self.load_subvm( + self.env.contract.address.clone().into_string().try_into()?, + vec![], + )?; + + cosmwasm_system_run::, OwnedWasmiVM>( + &mut sub_vm, + &serde_json::to_vec(&message).map_err(|_| SimpleVMError::CannotDeserialize)?, + event_handler, + ) + } + + fn query_custom( + &mut self, + _: Self::QueryCustom, + ) -> Result, Self::Error> { + Err(SimpleVMError::NoCustomQuery) + } + + fn message_custom( + &mut self, + _: Self::MessageCustom, + _: &mut dyn FnMut(Event), + ) -> Result, Self::Error> { + Err(SimpleVMError::NoCustomMessage) + } + + fn query_raw( + &mut self, + address: Self::Address, + key: Self::StorageKey, + ) -> Result, Self::Error> { + Ok(self + .extension + .storage + .get(&address) + .unwrap_or(&SimpleWasmiVMStorage::default()) + .data + .get(&key) + .cloned()) + } + + fn transfer_from( + &mut self, + from: &Self::Address, + to: &Self::Address, + funds: &[Coin], + ) -> Result<(), Self::Error> { + log::debug!("Transfer from: {:?} -> {:?}\n{:?}", from, to, funds); + Ok(()) + } + + fn transfer(&mut self, to: &Self::Address, funds: &[Coin]) -> Result<(), Self::Error> { + log::debug!( + "Transfer: {:?} -> {:?}\n{:?}", + self.env.contract.address, + to, + funds + ); + Ok(()) + } + + fn burn(&mut self, funds: &[Coin]) -> Result<(), Self::Error> { + log::debug!("Burn: {:?}\n{:?}", self.env.contract.address, funds); + Ok(()) + } + + fn balance(&mut self, _: &Self::Address, _: String) -> Result { + log::debug!("Query balance."); + Err(SimpleVMError::Unsupported) + } + + fn supply(&mut self, _: String) -> Result { + log::debug!("Supply."); + Err(SimpleVMError::Unsupported) + } + + fn all_balance(&mut self, _: &Self::Address) -> Result, Self::Error> { + log::debug!("Query all balance."); + Ok(vec![]) + } + + fn query_contract_info( + &mut self, + _: Self::Address, + ) -> Result { + Err(SimpleVMError::Unsupported) + } + + fn query_code_info(&mut self, _: CosmwasmCodeId) -> Result { + Err(SimpleVMError::Unsupported) + } + + fn debug(&mut self, message: Vec) -> Result<(), Self::Error> { + log::info!("[contract-debug] {}", String::from_utf8_lossy(&message)); + Ok(()) + } + + #[cfg(feature = "iterator")] + #[tracing::instrument(skip(self, _order))] + fn db_scan( + &mut self, + _start: Option, + _end: Option, + _order: Order, + ) -> Result { + let contract_addr = self.env.contract.address.clone().try_into()?; + let mut empty = SimpleWasmiVMStorage::default(); + let storage = self + .extension + .storage + .get_mut(&contract_addr) + .unwrap_or(&mut empty); + + let data = storage.data.clone().into_iter().collect::>(); + // Exceeding u32 size is fatal + let last_id: u32 = storage + .iterators + .len() + .try_into() + .expect("Found more iterator IDs than supported"); + + let new_id = last_id + 1; + let iter = Iter { data, position: 0 }; + storage.iterators.insert(new_id, iter); + + Ok(new_id) + } + + #[cfg(feature = "iterator")] + #[tracing::instrument(skip(self))] + fn db_next( + &mut self, + iterator_id: u32, + ) -> Result<(Self::StorageKey, Self::StorageValue), Self::Error> { + let contract_addr = self.env.contract.address.clone().try_into()?; + let storage = self + .extension + .storage + .get_mut(&contract_addr) + .ok_or(SimpleVMError::IteratorDoesNotExist)?; + + let iterator = storage + .iterators + .get_mut(&iterator_id) + .ok_or(SimpleVMError::IteratorDoesNotExist)?; + + let position = iterator.position; + if iterator.data.len() > position { + iterator.position += 1; + Ok(iterator.data[position].clone()) + } else { + // Empty data works like `None` in rust iterators + Ok((Vec::default(), Vec::default())) + } + } + + fn secp256k1_verify( + &mut self, + message_hash: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + cosmwasm_crypto::secp256k1_verify(message_hash, signature, public_key) + .map_err(|_| SimpleVMError::Crypto) + } + + fn secp256k1_recover_pubkey( + &mut self, + message_hash: &[u8], + signature: &[u8], + recovery_param: u8, + ) -> Result, ()>, Self::Error> { + Ok( + cosmwasm_crypto::secp256k1_recover_pubkey(message_hash, signature, recovery_param) + .map_err(|_| ()), + ) + } + + fn ed25519_verify( + &mut self, + message: &[u8], + signature: &[u8], + public_key: &[u8], + ) -> Result { + cosmwasm_crypto::ed25519_verify(message, signature, public_key) + .map_err(|_| SimpleVMError::Crypto) + } + + fn ed25519_batch_verify( + &mut self, + messages: &[&[u8]], + signatures: &[&[u8]], + public_keys: &[&[u8]], + ) -> Result { + cosmwasm_crypto::ed25519_batch_verify(messages, signatures, public_keys) + .map_err(|_| SimpleVMError::Crypto) + } + + fn addr_validate(&mut self, input: &str) -> Result, Self::Error> { + let canonical = match self.addr_canonicalize(input)? { + Ok(canonical) => canonical, + Err(e) => return Ok(Err(e)), + }; + let normalized = match self.addr_humanize(&canonical)? { + Ok(canonical) => canonical, + Err(e) => return Ok(Err(e)), + }; + let account = BankAccount::try_from(input.to_string())?; + Ok(if account == normalized { + Ok(()) + } else { + Err(SimpleVMError::InvalidAddress) + }) + } + + fn addr_canonicalize( + &mut self, + input: &str, + ) -> Result, Self::Error> { + // mimicks formats like hex or bech32 where different casings are valid for one address + let normalized = input.to_lowercase(); + + // Dummy input validation. This is more sophisticated for formats like bech32, where format and checksum are validated. + if normalized.len() < 3 { + return Ok(Err(SimpleVMError::InvalidAddress)); + } + + if normalized.len() > CANONICAL_LENGTH { + return Ok(Err(SimpleVMError::InvalidAddress)); + } + + let mut out = Vec::from(normalized); + // pad to canonical length with NULL bytes + out.resize(CANONICAL_LENGTH, 0x00); + // content-dependent rotate followed by shuffle to destroy + let rotate_by = digit_sum(&out) % CANONICAL_LENGTH; + out.rotate_left(rotate_by); + for _ in 0..SHUFFLES_ENCODE { + out = riffle_shuffle(&out); + } + Ok(Ok(out.try_into()?)) + } + + fn addr_humanize( + &mut self, + addr: &Self::CanonicalAddress, + ) -> Result, Self::Error> { + if addr.0.len() != CANONICAL_LENGTH { + return Ok(Err(SimpleVMError::InvalidAddress)); + } + + let mut tmp: Vec = addr.clone().into(); + // Shuffle two more times which restored the original value (24 elements are back to original after 20 rounds) + for _ in 0..SHUFFLES_DECODE { + tmp = riffle_shuffle(&tmp); + } + // Rotate back + let rotate_by = digit_sum(&tmp) % CANONICAL_LENGTH; + tmp.rotate_right(rotate_by); + // Remove NULL bytes (i.e. the padding) + let trimmed = tmp.into_iter().filter(|&x| x != 0x00).collect(); + // decode UTF-8 bytes into string + let Ok(human) = String::from_utf8(trimmed) else { return Ok(Err(SimpleVMError::InvalidAddress)) }; + Ok( + BankAccount::try_from(Addr::unchecked(human)) + .map_err(|_| SimpleVMError::InvalidAddress), + ) + } + + #[tracing::instrument(skip(self))] + fn db_read( + &mut self, + key: Self::StorageKey, + ) -> Result, Self::Error> { + let contract_addr = self.env.contract.address.clone().try_into()?; + let empty = SimpleWasmiVMStorage::default(); + Ok(self + .extension + .storage + .get(&contract_addr) + .unwrap_or(&empty) + .data + .get(&key) + .cloned()) + } + + #[tracing::instrument(skip(self))] + fn db_write( + &mut self, + key: Self::StorageKey, + value: Self::StorageValue, + ) -> Result<(), Self::Error> { + let contract_addr = self.env.contract.address.clone().try_into()?; + self.extension + .storage + .entry(contract_addr) + .or_insert_with(SimpleWasmiVMStorage::default) + .data + .insert(key, value); + Ok(()) + } + + #[tracing::instrument(skip(self))] + fn db_remove(&mut self, key: Self::StorageKey) -> Result<(), Self::Error> { + let contract_addr = self.env.contract.address.clone().try_into()?; + self.extension + .storage + .get_mut(&contract_addr) + .map(|contract_storage| contract_storage.data.remove(&key)); + Ok(()) + } + + fn abort(&mut self, message: String) -> Result<(), Self::Error> { + log::debug!("Contract aborted: {}", message); + Err(SimpleVMError::from(WasmiVMError::from( + SystemError::ContractExecutionFailure(message), + ))) + } + + fn charge(&mut self, value: VmGas) -> Result<(), Self::Error> { + let gas_to_charge = match value { + VmGas::Instrumentation { metered } => u64::from(metered), + x => { + log::debug!("Charging gas: {:?}", x); + 1u64 + } + }; + self.extension.gas.charge(gas_to_charge)?; + Ok(()) + } + + fn gas_checkpoint_push(&mut self, checkpoint: VmGasCheckpoint) -> Result<(), Self::Error> { + log::debug!("> Gas before: {:?}", self.extension.gas); + self.extension.gas.push(&checkpoint)?; + log::debug!("> Gas after: {:?}", self.extension.gas); + Ok(()) + } + + fn gas_checkpoint_pop(&mut self) -> Result<(), Self::Error> { + log::debug!("> Gas before: {:?}", self.extension.gas); + self.extension.gas.pop(); + log::debug!("> Gas after: {:?}", self.extension.gas); + Ok(()) + } + + fn gas_ensure_available(&mut self) -> Result<(), Self::Error> { + let checkpoint = self + .extension + .gas + .checkpoints + .last() + .expect("invalis gas checkpoint state"); + if *checkpoint > 0 { + Ok(()) + } else { + Err(SimpleVMError::OutOfGas) + } + } + + #[cfg(feature = "stargate")] + fn ibc_transfer( + &mut self, + _channel_id: String, + _to_address: String, + _amount: Coin, + _timeout: IbcTimeout, + ) -> Result<(), Self::Error> { + todo!() + } + + #[cfg(feature = "stargate")] + fn ibc_send_packet( + &mut self, + channel_id: String, + data: Binary, + timeout: IbcTimeout, + ) -> Result<(), Self::Error> { + let contract_addr = self.env.contract.address.clone().try_into()?; + let entry = self.extension.ibc.entry(contract_addr).or_default(); + entry.packets_sent.push(SimpleIBCPacket { + channel_id, + data, + timeout, + }); + Ok(()) + } + + #[cfg(feature = "stargate")] + fn ibc_close_channel(&mut self, _channel_id: String) -> Result<(), Self::Error> { + todo!() + } +} + +#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +struct BankAccount(u128); + +impl TryFrom for BankAccount { + type Error = SimpleVMError; + fn try_from(value: Addr) -> Result { + value.to_string().try_into() + } +} + +impl TryFrom for BankAccount { + type Error = SimpleVMError; + fn try_from(value: String) -> Result { + Ok(BankAccount( + u128::from_str(&value).map_err(|_| SimpleVMError::InvalidAccountFormat)?, + )) + } +} + +impl From for Addr { + fn from(BankAccount(account): BankAccount) -> Self { + Addr::unchecked(format!("{account}")) + } +} + +impl<'a> Has for SimpleWasmiVM<'a> { + fn get(&self) -> Env { + self.env.clone() + } +} +impl<'a> Has for SimpleWasmiVM<'a> { + fn get(&self) -> MessageInfo { + self.info.clone() + } +} + +impl<'a> Transactional for SimpleWasmiVM<'a> { + type Error = SimpleVMError; + fn transaction_begin(&mut self) -> Result<(), Self::Error> { + self.extension.transaction_depth += 1; + log::debug!("> Transaction begin: {}", self.extension.transaction_depth); + Ok(()) + } + fn transaction_commit(&mut self) -> Result<(), Self::Error> { + self.extension.transaction_depth -= 1; + log::debug!("< Transaction end: {}", self.extension.transaction_depth); + Ok(()) + } + fn transaction_rollback(&mut self) -> Result<(), Self::Error> { + self.extension.transaction_depth -= 1; + log::debug!("< Transaction abort: {}", self.extension.transaction_depth); + Ok(()) + } +} + +struct ConstantCostRules; +impl Rules for ConstantCostRules { + fn instruction_cost( + &self, + _: &wasm_instrument::parity_wasm::elements::Instruction, + ) -> Option { + Some(42) + } + + fn memory_grow_cost(&self) -> wasm_instrument::gas_metering::MemoryGrowCost { + wasm_instrument::gas_metering::MemoryGrowCost::Linear( + NonZeroU32::new(1024).expect("impossible"), + ) + } +} + +fn instrument_contract(code: &[u8]) -> Vec { + let module = + wasm_instrument::parity_wasm::elements::Module::from_bytes(code).expect("impossible"); + let instrumented_module = + wasm_instrument::gas_metering::inject(module, &ConstantCostRules, "env") + .expect("impossible"); + instrumented_module.into_bytes().expect("impossible") +} + +pub fn initialize() { + use std::sync::Once; + static INIT: Once = Once::new(); + INIT.call_once(|| { + // setup this one to tune output + let mut builder = env_logger::builder(); + builder.format_timestamp_nanos(); + builder.try_init().unwrap(); + + let collector = tracing_subscriber::fmt() + .with_max_level(tracing::Level::TRACE) + .finish(); + let collector = tracing_subscriber::fmt::layer() + .with_level(true) + .with_line_number(true); + let tracer = opentelemetry::sdk::export::trace::stdout::new_pipeline().install_simple(); + let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); + let subscriber = tracing_subscriber::Registry::default() + .with(telemetry) + .with(collector); + tracing::subscriber::set_global_default(subscriber).unwrap(); + }); +} + +fn create_vm( + extension: &mut SimpleWasmiVMExtension, + env: Env, + info: MessageInfo, +) -> Result, SimpleVMError> { + initialize(); + let code = extension + .codes + .get( + &extension + .contracts + .get(&env.clone().contract.address.try_into().unwrap()) + .expect("contract should have been uploaded") + .code_id, + ) + .expect("contract should have been uploaded") + .clone(); + let vm = SimpleWasmiVM { + executing_module: None, + env, + info, + extension, + }; + let vm = new_wasmi_vm::(&code, vm)?; + Ok(vm) +} + +fn create_simple_vm( + sender: BankAccount, + contract: BankAccount, + funds: Vec, + extension: &mut SimpleWasmiVMExtension, +) -> Result, SimpleVMError> { + create_vm( + extension, + Env { + block: BlockInfo { + height: 0xDEAD_C0DE, + time: Timestamp::from_seconds(10000), + chain_id: "abstract-test".into(), + }, + transaction: None, + contract: ContractInfo { + address: contract.into(), + }, + }, + MessageInfo { + sender: sender.into(), + funds, + }, + ) +} + +fn main() { + let iter = 100; + let cw20_base_code = instrument_contract(include_bytes!("../../../fixtures/cw20_base.wasm")); + let hackatom_code = instrument_contract(include_bytes!("../../../fixtures/hackatom.wasm")); + let reflect_code = instrument_contract(include_bytes!("../../../fixtures/reflect.wasm")); + + let sender = BankAccount(100); + let cw20_address = BankAccount(10_000); + let hackatom_address = BankAccount(10_002); + let reflect_address = BankAccount(10_003); + let funds = vec![]; + let mut extension = SimpleWasmiVMExtension { + storage: BTreeMap::default(), + codes: BTreeMap::from([ + (0x1337, cw20_base_code), + (0x1338, hackatom_code), + (0x1339, reflect_code), + ]), + contracts: BTreeMap::from([ + ( + cw20_address, + CosmwasmContractMeta { + code_id: 0x1337, + admin: None, + label: String::new(), + }, + ), + ( + hackatom_address, + CosmwasmContractMeta { + code_id: 0x1338, + admin: None, + label: String::new(), + }, + ), + ( + reflect_address, + CosmwasmContractMeta { + code_id: 0x1339, + admin: None, + label: String::new(), + }, + ), + ]), + next_account_id: BankAccount(10_004), + transaction_depth: 0, + gas: Gas::new(u64::MAX), + ..Default::default() + }; + + { + { + let mut vm = + create_simple_vm(sender, cw20_address, funds.clone(), &mut extension).unwrap(); + + assert_matches!( + cosmwasm_call::, OwnedWasmiVM>( + &mut vm, + r#"{ + "name": "Picasso", + "symbol": "PICA", + "decimals": 12, + "initial_balances": [], + "mint": null, + "marketing": null + }"# + .as_bytes(), + ) + .unwrap(), + InstantiateResult(CosmwasmExecutionResult::Ok(_)) + ); + + for _ in 0..iter { + cosmwasm_call::>( + &mut vm, + r#"{ "token_info": {} }"#.as_bytes(), + ) + .unwrap(); + } + } + { + let mut vm = + create_simple_vm(sender, reflect_address, funds.clone(), &mut extension).unwrap(); + let _ = cosmwasm_system_entrypoint::>( + &mut vm, + r#"{}"#.as_bytes(), + ) + .unwrap(); + + for _ in 0..iter { + let (_, events) = + cosmwasm_system_entrypoint::>( + &mut vm, + r#"{ + "reflect_sub_msg": { + "msgs": [{ + "id": 10, + "msg": { + "wasm": { + "execute": { + "contract_addr": "10001", + "msg": "eyAicmVsZWFzZSI6IHt9IH0=", + "funds": [] + } + } + }, + "gas_limit": null, + "reply_on": "always" + }] + } + }"# + .as_bytes(), + ) + .unwrap(); + } + } + + { + let mut vm = + create_simple_vm(sender, hackatom_address, funds.clone(), &mut extension).unwrap(); + + let (_, events) = cosmwasm_system_entrypoint::( + &mut vm, + r#"{"verifier": "10000", "beneficiary": "10000"}"#.as_bytes(), + ) + .unwrap(); + for _ in 0..iter { + cosmwasm_call::>( + &mut vm, + r#"{ "recurse": { "depth": 10, "work": 10 }}"#.as_bytes(), + ) + .unwrap(); + } + } + } +} + +pub fn digit_sum(input: &[u8]) -> usize { + input.iter().map(|v| *v as usize).sum() +} + +pub fn riffle_shuffle(input: &[T]) -> Vec { + assert!( + input.len() % 2 == 0, + "Method only defined for even number of elements" + ); + let mid = input.len() / 2; + let (left, right) = input.split_at(mid); + let mut out = Vec::::with_capacity(input.len()); + for i in 0..mid { + out.push(right[i].clone()); + out.push(left[i].clone()); + } + out +} diff --git a/vm-wasmi/Cargo.toml b/vm-wasmi/Cargo.toml index 4248332..b66a347 100644 --- a/vm-wasmi/Cargo.toml +++ b/vm-wasmi/Cargo.toml @@ -3,11 +3,6 @@ name = "cosmwasm-vm-wasmi" version = "0.2.0" edition = "2021" - -# [[bin]] -# name = "research" -# test = true - [features] default = ["iterator", "stargate", "ibc3"] iterator = ["cosmwasm-vm/iterator"] @@ -30,14 +25,6 @@ cosmwasm-std = { workspace = true, default-features = false, features = [ cosmwasm-vm = { path = "../vm", default-features = false } hex = { version = "0.4", default-features = false, features = ["alloc"] } -# # benches -# tracing = "0.1" -# tracing-subscriber = "0.3" -# tracing-opentelemetry = "*" -# opentelemetry = "*" - -# wyndex = { git = "https://github.com/wynddao/wynddex", rev = "a578f8b645433e108a10613e85ae49385c2fc63c", default-features = false } - [dev-dependencies] wat = "1.0" env_logger = "0.9" diff --git a/vm-wasmi/src/bin/research.rs b/vm-wasmi/src/bin/research.rs deleted file mode 100644 index 3dba5b9..0000000 --- a/vm-wasmi/src/bin/research.rs +++ /dev/null @@ -1,1130 +0,0 @@ -// #![feature(trait_alias)] -// #![feature(assert_matches)] -// #![allow(soft_unstable)] -// #![feature(test)] - -// extern crate alloc; - -// extern crate std; - -// use cosmwasm_vm::vm::VMBase; - -// use alloc::{ -// collections::BTreeMap, -// format, -// string::{String, ToString}, -// vec, -// vec::Vec, -// }; -// use core::{ -// assert_matches::assert_matches, -// fmt::{Debug, Display}, -// num::NonZeroU32, -// str::FromStr, -// }; -// #[cfg(feature = "stargate")] -// use cosmwasm_std::IbcTimeout; -// #[cfg(feature = "iterator")] -// use cosmwasm_std::Order; -// use cosmwasm_std::{ -// Addr, Attribute, Binary, BlockInfo, CanonicalAddr, CodeInfoResponse, Coin, ContractInfo, -// ContractInfoResponse, ContractResult, Empty, Env, Event, MessageInfo, Reply, SystemResult, -// Timestamp, -// }; -// use cosmwasm_vm::{ -// executor::{ -// cosmwasm_call, CosmwasmExecutionResult, CosmwasmQueryResult, ExecuteCall, ExecuteResult, -// ExecutorError, InstantiateCall, InstantiateResult, MigrateCall, QueryCall, QueryResult, -// ReplyCall, -// }, -// has::Has, -// memory::{MemoryReadError, MemoryWriteError}, -// system::{ -// cosmwasm_system_entrypoint, cosmwasm_system_entrypoint_hook, cosmwasm_system_run, -// CosmwasmCodeId, CosmwasmContractMeta, SystemError, -// }, -// transaction::Transactional, -// vm::{VmErrorOf, VmGas, VmGasCheckpoint}, -// }; -// use cosmwasm_vm_wasmi::{ -// code_gen, new_wasmi_vm, OwnedWasmiVM, WasmiContext, WasmiInput, WasmiModule, WasmiOutput, -// WasmiVMError, -// }; -// use tracing::instrument::WithSubscriber; -// use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt; -// use wasm_instrument::gas_metering::Rules; -// use wasmi::core::HostError; - -// const CANONICAL_LENGTH: usize = 54; -// const SHUFFLES_ENCODE: usize = 18; -// const SHUFFLES_DECODE: usize = 2; - -// #[derive(PartialEq, Debug)] -// enum SimpleVMError { -// Interpreter, -// VMError(WasmiVMError), -// CodeNotFound(CosmwasmCodeId), -// ContractNotFound(BankAccount), -// InvalidAddress, -// InvalidAccountFormat, -// NoCustomQuery, -// NoCustomMessage, -// Unsupported, -// OutOfGas, -// #[cfg(feature = "iterator")] -// IteratorDoesNotExist, -// CannotDeserialize, -// Crypto, -// } - -// impl HostError for SimpleVMError {} - -// impl From for SimpleVMError { -// fn from(_: wasmi::Error) -> Self { -// Self::Interpreter -// } -// } -// impl From for SimpleVMError { -// fn from(e: WasmiVMError) -> Self { -// SimpleVMError::VMError(e) -// } -// } -// impl From for SimpleVMError { -// fn from(e: SystemError) -> Self { -// SimpleVMError::VMError(e.into()) -// } -// } -// impl From for SimpleVMError { -// fn from(e: ExecutorError) -> Self { -// SimpleVMError::VMError(e.into()) -// } -// } -// impl From for SimpleVMError { -// fn from(e: MemoryReadError) -> Self { -// SimpleVMError::VMError(e.into()) -// } -// } -// impl From for SimpleVMError { -// fn from(e: MemoryWriteError) -> Self { -// SimpleVMError::VMError(e.into()) -// } -// } -// impl Display for SimpleVMError { -// fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { -// write!(f, "{self:?}") -// } -// } - -// #[derive(Default, Clone, PartialEq, Eq, Debug)] -// struct Gas { -// checkpoints: Vec, -// } - -// impl Gas { -// fn new(initial_value: u64) -> Self { -// Gas { -// checkpoints: vec![initial_value], -// } -// } - -// fn current(&self) -> &u64 { -// self.checkpoints.last().expect("impossible") -// } -// fn current_mut(&mut self) -> &mut u64 { -// self.checkpoints.last_mut().expect("impossible") -// } -// fn push(&mut self, checkpoint: &VmGasCheckpoint) -> Result<(), SimpleVMError> { -// match checkpoint { -// VmGasCheckpoint::Unlimited => { -// let parent = self.current_mut(); -// let value = *parent; -// *parent = 0; -// self.checkpoints.push(value); -// Ok(()) -// } -// VmGasCheckpoint::Limited(limit) if limit <= self.current() => { -// *self.current_mut() -= limit; -// self.checkpoints.push(*limit); -// Ok(()) -// } -// VmGasCheckpoint::Limited(_) => Err(SimpleVMError::OutOfGas), -// } -// } -// fn pop(&mut self) { -// let child = self.checkpoints.pop().expect("impossible"); -// let parent = self.current_mut(); -// *parent += child; -// } -// fn charge(&mut self, value: u64) -> Result<(), SimpleVMError> { -// let current = self.current_mut(); -// if *current >= value { -// *current -= value; -// Ok(()) -// } else { -// Err(SimpleVMError::OutOfGas) -// } -// } -// } - -// #[cfg(feature = "iterator")] -// #[derive(Default, Clone, Debug)] -// struct Iter { -// data: Vec<(Vec, Vec)>, -// position: usize, -// } - -// #[derive(Default, Clone, Debug)] -// struct SimpleWasmiVMStorage { -// data: BTreeMap, Vec>, -// #[cfg(feature = "iterator")] -// iterators: BTreeMap, -// } - -// #[cfg(feature = "stargate")] -// #[derive(Debug, Clone, PartialEq, Eq)] -// struct SimpleIBCPacket { -// channel_id: String, -// data: Binary, -// timeout: IbcTimeout, -// } - -// #[cfg(feature = "stargate")] -// #[derive(Default, Clone, Debug, PartialEq, Eq)] -// struct SimpleIBCState { -// packets_sent: Vec, -// } - -// #[derive(Default, Clone)] -// struct SimpleWasmiVMExtension { -// #[cfg(feature = "stargate")] -// ibc: BTreeMap, -// storage: BTreeMap, -// codes: BTreeMap>, -// contracts: BTreeMap>, -// next_account_id: BankAccount, -// transaction_depth: u32, -// gas: Gas, -// } - -// struct SimpleWasmiVM<'a> { -// /// module which is in context of vm and executable now -// executing_module: Option, -// pub env: Env, -// info: MessageInfo, -// extension: &'a mut SimpleWasmiVMExtension, -// } - -// impl<'a> WasmiContext for SimpleWasmiVM<'a> { -// fn executing_module(&self) -> Option { -// self.executing_module.clone() -// } - -// fn set_wasmi_context(&mut self, instance: wasmi::Instance, memory: wasmi::Memory) { -// self.executing_module = Some(WasmiModule { instance, memory }); -// } -// } - -// impl<'a> SimpleWasmiVM<'a> { -// pub fn load_subvm( -// &mut self, -// address: ::Address, -// funds: Vec, -// ) -> Result, VmErrorOf> { -// log::debug!("Loading sub-vm, contract address: {:?}", address); -// let code = (|| { -// let CosmwasmContractMeta { code_id, .. } = self -// .extension -// .contracts -// .get(&address) -// .cloned() -// .ok_or(SimpleVMError::ContractNotFound(address))?; -// self.extension -// .codes -// .get(&code_id) -// .ok_or(SimpleVMError::CodeNotFound(code_id)) -// .cloned() -// })()?; -// let sub_vm = SimpleWasmiVM { -// executing_module: None, -// env: Env { -// block: self.env.block.clone(), -// transaction: self.env.transaction.clone(), -// contract: ContractInfo { -// address: address.into(), -// }, -// }, -// info: MessageInfo { -// sender: self.env.contract.address.clone(), -// funds, -// }, -// extension: self.extension, -// }; -// let sub_vm = new_wasmi_vm::(&code, sub_vm)?; -// Ok(sub_vm) -// } -// } - -// #[derive(Debug, Clone)] -// struct CanonicalAddress(pub CanonicalAddr); - -// impl TryFrom> for CanonicalAddress { -// type Error = SimpleVMError; -// fn try_from(value: Vec) -> Result { -// Ok(CanonicalAddress(CanonicalAddr(Binary::from(value)))) -// } -// } - -// impl From for Vec { -// fn from(addr: CanonicalAddress) -> Self { -// addr.0.into() -// } -// } - -// impl From for CanonicalAddr { -// fn from(addr: CanonicalAddress) -> Self { -// addr.0 -// } -// } - -// impl<'a> VMBase for SimpleWasmiVM<'a> { -// type Input<'x> = WasmiInput>; -// type Output<'x> = WasmiOutput>; -// type QueryCustom = Empty; -// type MessageCustom = Empty; -// type ContractMeta = CosmwasmContractMeta; -// type Address = BankAccount; -// type CanonicalAddress = CanonicalAddress; -// type StorageKey = Vec; -// type StorageValue = Vec; -// type Error = SimpleVMError; - -// fn running_contract_meta(&mut self) -> Result { -// Ok(self -// .extension -// .contracts -// .get( -// &BankAccount::try_from(self.env.contract.address.clone()) -// .expect("contract address is set by vm, this should never happen"), -// ) -// .cloned() -// .expect("contract is inserted by vm, this should never happen")) -// } - -// fn set_contract_meta( -// &mut self, -// address: Self::Address, -// contract_meta: Self::ContractMeta, -// ) -> Result<(), Self::Error> { -// let meta = self -// .extension -// .contracts -// .get_mut(&address) -// .ok_or(SimpleVMError::ContractNotFound(address))?; - -// *meta = contract_meta; - -// Ok(()) -// } - -// fn contract_meta(&mut self, address: Self::Address) -> Result { -// self.extension -// .contracts -// .get_mut(&address) -// .ok_or(SimpleVMError::ContractNotFound(address)) -// .cloned() -// } - -// fn continue_query( -// &mut self, -// address: Self::Address, -// message: &[u8], -// ) -> Result { -// let mut sub_vm = self.load_subvm(address, vec![])?; -// cosmwasm_call::>(&mut sub_vm, message) -// } - -// fn continue_execute( -// &mut self, -// address: Self::Address, -// funds: Vec, -// message: &[u8], -// event_handler: &mut dyn FnMut(Event), -// ) -> Result, Self::Error> { -// let mut sub_vm = self.load_subvm(address, funds)?; -// cosmwasm_system_run::, _>( -// &mut sub_vm, -// message, -// event_handler, -// ) -// } - -// fn continue_instantiate( -// &mut self, -// contract_meta: Self::ContractMeta, -// funds: Vec, -// message: &[u8], -// event_handler: &mut dyn FnMut(Event), -// ) -> Result<(Self::Address, Option), Self::Error> { -// let BankAccount(address) = self.extension.next_account_id; -// self.extension.next_account_id = BankAccount(address + 1); -// self.extension -// .contracts -// .insert(BankAccount(address), contract_meta); - -// let mut sub_vm = self.load_subvm(BankAccount(address), funds)?; -// cosmwasm_system_run::, _>( -// &mut sub_vm, -// message, -// event_handler, -// ) -// .map(|data| (BankAccount(address), data)) -// } - -// fn continue_instantiate2( -// &mut self, -// contract_meta: Self::ContractMeta, -// funds: Vec, -// message: &[u8], -// _salt: &[u8], -// event_handler: &mut dyn FnMut(Event), -// ) -> Result<(Self::Address, Option), Self::Error> { -// let BankAccount(address) = self.extension.next_account_id; -// self.extension.next_account_id = BankAccount(address + 1); -// self.extension -// .contracts -// .insert(BankAccount(address), contract_meta); - -// let mut sub_vm = self.load_subvm(BankAccount(address), funds)?; -// cosmwasm_system_run::, _>( -// &mut sub_vm, -// message, -// event_handler, -// ) -// .map(|data| (BankAccount(address), data)) -// } - -// fn continue_migrate( -// &mut self, -// address: Self::Address, -// message: &[u8], -// event_handler: &mut dyn FnMut(Event), -// ) -> Result, Self::Error> { -// let mut sub_vm = self.load_subvm(address, vec![])?; -// cosmwasm_system_run::, _>( -// &mut sub_vm, -// message, -// event_handler, -// ) -// } - -// fn continue_reply( -// &mut self, -// message: Reply, -// event_handler: &mut dyn FnMut(Event), -// ) -> Result, Self::Error> { -// let mut sub_vm = self.load_subvm( -// self.env.contract.address.clone().into_string().try_into()?, -// vec![], -// )?; - -// cosmwasm_system_run::, OwnedWasmiVM>( -// &mut sub_vm, -// &serde_json::to_vec(&message).map_err(|_| SimpleVMError::CannotDeserialize)?, -// event_handler, -// ) -// } - -// fn query_custom( -// &mut self, -// _: Self::QueryCustom, -// ) -> Result, Self::Error> { -// Err(SimpleVMError::NoCustomQuery) -// } - -// fn message_custom( -// &mut self, -// _: Self::MessageCustom, -// _: &mut dyn FnMut(Event), -// ) -> Result, Self::Error> { -// Err(SimpleVMError::NoCustomMessage) -// } - -// fn query_raw( -// &mut self, -// address: Self::Address, -// key: Self::StorageKey, -// ) -> Result, Self::Error> { -// Ok(self -// .extension -// .storage -// .get(&address) -// .unwrap_or(&SimpleWasmiVMStorage::default()) -// .data -// .get(&key) -// .cloned()) -// } - -// fn transfer_from( -// &mut self, -// from: &Self::Address, -// to: &Self::Address, -// funds: &[Coin], -// ) -> Result<(), Self::Error> { -// log::debug!("Transfer from: {:?} -> {:?}\n{:?}", from, to, funds); -// Ok(()) -// } - -// fn transfer(&mut self, to: &Self::Address, funds: &[Coin]) -> Result<(), Self::Error> { -// log::debug!( -// "Transfer: {:?} -> {:?}\n{:?}", -// self.env.contract.address, -// to, -// funds -// ); -// Ok(()) -// } - -// fn burn(&mut self, funds: &[Coin]) -> Result<(), Self::Error> { -// log::debug!("Burn: {:?}\n{:?}", self.env.contract.address, funds); -// Ok(()) -// } - -// fn balance(&mut self, _: &Self::Address, _: String) -> Result { -// log::debug!("Query balance."); -// Err(SimpleVMError::Unsupported) -// } - -// fn supply(&mut self, _: String) -> Result { -// log::debug!("Supply."); -// Err(SimpleVMError::Unsupported) -// } - -// fn all_balance(&mut self, _: &Self::Address) -> Result, Self::Error> { -// log::debug!("Query all balance."); -// Ok(vec![]) -// } - -// fn query_contract_info( -// &mut self, -// _: Self::Address, -// ) -> Result { -// Err(SimpleVMError::Unsupported) -// } - -// fn query_code_info(&mut self, _: CosmwasmCodeId) -> Result { -// Err(SimpleVMError::Unsupported) -// } - -// fn debug(&mut self, message: Vec) -> Result<(), Self::Error> { -// log::info!("[contract-debug] {}", String::from_utf8_lossy(&message)); -// Ok(()) -// } - -// #[cfg(feature = "iterator")] -// #[tracing::instrument(skip(self, _order))] -// fn db_scan( -// &mut self, -// _start: Option, -// _end: Option, -// _order: Order, -// ) -> Result { -// let contract_addr = self.env.contract.address.clone().try_into()?; -// let mut empty = SimpleWasmiVMStorage::default(); -// let storage = self -// .extension -// .storage -// .get_mut(&contract_addr) -// .unwrap_or(&mut empty); - -// let data = storage.data.clone().into_iter().collect::>(); -// // Exceeding u32 size is fatal -// let last_id: u32 = storage -// .iterators -// .len() -// .try_into() -// .expect("Found more iterator IDs than supported"); - -// let new_id = last_id + 1; -// let iter = Iter { data, position: 0 }; -// storage.iterators.insert(new_id, iter); - -// Ok(new_id) -// } - -// #[cfg(feature = "iterator")] -// #[tracing::instrument(skip(self))] -// fn db_next( -// &mut self, -// iterator_id: u32, -// ) -> Result<(Self::StorageKey, Self::StorageValue), Self::Error> { -// let contract_addr = self.env.contract.address.clone().try_into()?; -// let storage = self -// .extension -// .storage -// .get_mut(&contract_addr) -// .ok_or(SimpleVMError::IteratorDoesNotExist)?; - -// let iterator = storage -// .iterators -// .get_mut(&iterator_id) -// .ok_or(SimpleVMError::IteratorDoesNotExist)?; - -// let position = iterator.position; -// if iterator.data.len() > position { -// iterator.position += 1; -// Ok(iterator.data[position].clone()) -// } else { -// // Empty data works like `None` in rust iterators -// Ok((Vec::default(), Vec::default())) -// } -// } - -// fn secp256k1_verify( -// &mut self, -// message_hash: &[u8], -// signature: &[u8], -// public_key: &[u8], -// ) -> Result { -// cosmwasm_crypto::secp256k1_verify(message_hash, signature, public_key) -// .map_err(|_| SimpleVMError::Crypto) -// } - -// fn secp256k1_recover_pubkey( -// &mut self, -// message_hash: &[u8], -// signature: &[u8], -// recovery_param: u8, -// ) -> Result, ()>, Self::Error> { -// Ok( -// cosmwasm_crypto::secp256k1_recover_pubkey(message_hash, signature, recovery_param) -// .map_err(|_| ()), -// ) -// } - -// fn ed25519_verify( -// &mut self, -// message: &[u8], -// signature: &[u8], -// public_key: &[u8], -// ) -> Result { -// cosmwasm_crypto::ed25519_verify(message, signature, public_key) -// .map_err(|_| SimpleVMError::Crypto) -// } - -// fn ed25519_batch_verify( -// &mut self, -// messages: &[&[u8]], -// signatures: &[&[u8]], -// public_keys: &[&[u8]], -// ) -> Result { -// cosmwasm_crypto::ed25519_batch_verify(messages, signatures, public_keys) -// .map_err(|_| SimpleVMError::Crypto) -// } - -// fn addr_validate(&mut self, input: &str) -> Result, Self::Error> { -// let canonical = match self.addr_canonicalize(input)? { -// Ok(canonical) => canonical, -// Err(e) => return Ok(Err(e)), -// }; -// let normalized = match self.addr_humanize(&canonical)? { -// Ok(canonical) => canonical, -// Err(e) => return Ok(Err(e)), -// }; -// let account = BankAccount::try_from(input.to_string())?; -// Ok(if account == normalized { -// Ok(()) -// } else { -// Err(SimpleVMError::InvalidAddress) -// }) -// } - -// fn addr_canonicalize( -// &mut self, -// input: &str, -// ) -> Result, Self::Error> { -// // mimicks formats like hex or bech32 where different casings are valid for one address -// let normalized = input.to_lowercase(); - -// // Dummy input validation. This is more sophisticated for formats like bech32, where format and checksum are validated. -// if normalized.len() < 3 { -// return Ok(Err(SimpleVMError::InvalidAddress)); -// } - -// if normalized.len() > CANONICAL_LENGTH { -// return Ok(Err(SimpleVMError::InvalidAddress)); -// } - -// let mut out = Vec::from(normalized); -// // pad to canonical length with NULL bytes -// out.resize(CANONICAL_LENGTH, 0x00); -// // content-dependent rotate followed by shuffle to destroy -// let rotate_by = digit_sum(&out) % CANONICAL_LENGTH; -// out.rotate_left(rotate_by); -// for _ in 0..SHUFFLES_ENCODE { -// out = riffle_shuffle(&out); -// } -// Ok(Ok(out.try_into()?)) -// } - -// fn addr_humanize( -// &mut self, -// addr: &Self::CanonicalAddress, -// ) -> Result, Self::Error> { -// if addr.0.len() != CANONICAL_LENGTH { -// return Ok(Err(SimpleVMError::InvalidAddress)); -// } - -// let mut tmp: Vec = addr.clone().into(); -// // Shuffle two more times which restored the original value (24 elements are back to original after 20 rounds) -// for _ in 0..SHUFFLES_DECODE { -// tmp = riffle_shuffle(&tmp); -// } -// // Rotate back -// let rotate_by = digit_sum(&tmp) % CANONICAL_LENGTH; -// tmp.rotate_right(rotate_by); -// // Remove NULL bytes (i.e. the padding) -// let trimmed = tmp.into_iter().filter(|&x| x != 0x00).collect(); -// // decode UTF-8 bytes into string -// let Ok(human) = String::from_utf8(trimmed) else { return Ok(Err(SimpleVMError::InvalidAddress)) }; -// Ok( -// BankAccount::try_from(Addr::unchecked(human)) -// .map_err(|_| SimpleVMError::InvalidAddress), -// ) -// } - -// #[tracing::instrument(skip(self))] -// fn db_read( -// &mut self, -// key: Self::StorageKey, -// ) -> Result, Self::Error> { -// let contract_addr = self.env.contract.address.clone().try_into()?; -// let empty = SimpleWasmiVMStorage::default(); -// Ok(self -// .extension -// .storage -// .get(&contract_addr) -// .unwrap_or(&empty) -// .data -// .get(&key) -// .cloned()) -// } - -// #[tracing::instrument(skip(self))] -// fn db_write( -// &mut self, -// key: Self::StorageKey, -// value: Self::StorageValue, -// ) -> Result<(), Self::Error> { -// let contract_addr = self.env.contract.address.clone().try_into()?; -// self.extension -// .storage -// .entry(contract_addr) -// .or_insert_with(SimpleWasmiVMStorage::default) -// .data -// .insert(key, value); -// Ok(()) -// } - -// #[tracing::instrument(skip(self))] -// fn db_remove(&mut self, key: Self::StorageKey) -> Result<(), Self::Error> { -// let contract_addr = self.env.contract.address.clone().try_into()?; -// self.extension -// .storage -// .get_mut(&contract_addr) -// .map(|contract_storage| contract_storage.data.remove(&key)); -// Ok(()) -// } - -// fn abort(&mut self, message: String) -> Result<(), Self::Error> { -// log::debug!("Contract aborted: {}", message); -// Err(SimpleVMError::from(WasmiVMError::from( -// SystemError::ContractExecutionFailure(message), -// ))) -// } - -// fn charge(&mut self, value: VmGas) -> Result<(), Self::Error> { -// let gas_to_charge = match value { -// VmGas::Instrumentation { metered } => u64::from(metered), -// x => { -// log::debug!("Charging gas: {:?}", x); -// 1u64 -// } -// }; -// self.extension.gas.charge(gas_to_charge)?; -// Ok(()) -// } - -// fn gas_checkpoint_push(&mut self, checkpoint: VmGasCheckpoint) -> Result<(), Self::Error> { -// log::debug!("> Gas before: {:?}", self.extension.gas); -// self.extension.gas.push(&checkpoint)?; -// log::debug!("> Gas after: {:?}", self.extension.gas); -// Ok(()) -// } - -// fn gas_checkpoint_pop(&mut self) -> Result<(), Self::Error> { -// log::debug!("> Gas before: {:?}", self.extension.gas); -// self.extension.gas.pop(); -// log::debug!("> Gas after: {:?}", self.extension.gas); -// Ok(()) -// } - -// fn gas_ensure_available(&mut self) -> Result<(), Self::Error> { -// let checkpoint = self -// .extension -// .gas -// .checkpoints -// .last() -// .expect("invalis gas checkpoint state"); -// if *checkpoint > 0 { -// Ok(()) -// } else { -// Err(SimpleVMError::OutOfGas) -// } -// } - -// #[cfg(feature = "stargate")] -// fn ibc_transfer( -// &mut self, -// _channel_id: String, -// _to_address: String, -// _amount: Coin, -// _timeout: IbcTimeout, -// ) -> Result<(), Self::Error> { -// todo!() -// } - -// #[cfg(feature = "stargate")] -// fn ibc_send_packet( -// &mut self, -// channel_id: String, -// data: Binary, -// timeout: IbcTimeout, -// ) -> Result<(), Self::Error> { -// let contract_addr = self.env.contract.address.clone().try_into()?; -// let entry = self.extension.ibc.entry(contract_addr).or_default(); -// entry.packets_sent.push(SimpleIBCPacket { -// channel_id, -// data, -// timeout, -// }); -// Ok(()) -// } - -// #[cfg(feature = "stargate")] -// fn ibc_close_channel(&mut self, _channel_id: String) -> Result<(), Self::Error> { -// todo!() -// } -// } - -// #[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -// struct BankAccount(u128); - -// impl TryFrom for BankAccount { -// type Error = SimpleVMError; -// fn try_from(value: Addr) -> Result { -// value.to_string().try_into() -// } -// } - -// impl TryFrom for BankAccount { -// type Error = SimpleVMError; -// fn try_from(value: String) -> Result { -// Ok(BankAccount( -// u128::from_str(&value).map_err(|_| SimpleVMError::InvalidAccountFormat)?, -// )) -// } -// } - -// impl From for Addr { -// fn from(BankAccount(account): BankAccount) -> Self { -// Addr::unchecked(format!("{account}")) -// } -// } - -// impl<'a> Has for SimpleWasmiVM<'a> { -// fn get(&self) -> Env { -// self.env.clone() -// } -// } -// impl<'a> Has for SimpleWasmiVM<'a> { -// fn get(&self) -> MessageInfo { -// self.info.clone() -// } -// } - -// impl<'a> Transactional for SimpleWasmiVM<'a> { -// type Error = SimpleVMError; -// fn transaction_begin(&mut self) -> Result<(), Self::Error> { -// self.extension.transaction_depth += 1; -// log::debug!("> Transaction begin: {}", self.extension.transaction_depth); -// Ok(()) -// } -// fn transaction_commit(&mut self) -> Result<(), Self::Error> { -// self.extension.transaction_depth -= 1; -// log::debug!("< Transaction end: {}", self.extension.transaction_depth); -// Ok(()) -// } -// fn transaction_rollback(&mut self) -> Result<(), Self::Error> { -// self.extension.transaction_depth -= 1; -// log::debug!("< Transaction abort: {}", self.extension.transaction_depth); -// Ok(()) -// } -// } - -// struct ConstantCostRules; -// impl Rules for ConstantCostRules { -// fn instruction_cost( -// &self, -// _: &wasm_instrument::parity_wasm::elements::Instruction, -// ) -> Option { -// Some(42) -// } - -// fn memory_grow_cost(&self) -> wasm_instrument::gas_metering::MemoryGrowCost { -// wasm_instrument::gas_metering::MemoryGrowCost::Linear( -// NonZeroU32::new(1024).expect("impossible"), -// ) -// } -// } - -// fn instrument_contract(code: &[u8]) -> Vec { -// let module = -// wasm_instrument::parity_wasm::elements::Module::from_bytes(code).expect("impossible"); -// let instrumented_module = -// wasm_instrument::gas_metering::inject(module, &ConstantCostRules, "env") -// .expect("impossible"); -// instrumented_module.into_bytes().expect("impossible") -// } - -// pub fn initialize() { -// use std::sync::Once; -// static INIT: Once = Once::new(); -// INIT.call_once(|| { -// // setup this one to tune output -// let mut builder = env_logger::builder(); -// builder.format_timestamp_nanos(); -// builder.try_init().unwrap(); - -// let collector = tracing_subscriber::fmt() -// .with_max_level(tracing::Level::TRACE) -// .finish(); -// let collector = tracing_subscriber::fmt::layer() -// .with_level(true) -// .with_line_number(true); -// let tracer = opentelemetry::sdk::export::trace::stdout::new_pipeline().install_simple(); -// let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); -// let subscriber = tracing_subscriber::Registry::default() -// .with(telemetry) -// .with(collector); -// tracing::subscriber::set_global_default(subscriber).unwrap(); -// }); -// } - -// fn create_vm( -// extension: &mut SimpleWasmiVMExtension, -// env: Env, -// info: MessageInfo, -// ) -> Result, SimpleVMError> { -// initialize(); -// let code = extension -// .codes -// .get( -// &extension -// .contracts -// .get(&env.clone().contract.address.try_into().unwrap()) -// .expect("contract should have been uploaded") -// .code_id, -// ) -// .expect("contract should have been uploaded") -// .clone(); -// let vm = SimpleWasmiVM { -// executing_module: None, -// env, -// info, -// extension, -// }; -// let vm = new_wasmi_vm::(&code, vm)?; -// Ok(vm) -// } - -// fn create_simple_vm( -// sender: BankAccount, -// contract: BankAccount, -// funds: Vec, -// extension: &mut SimpleWasmiVMExtension, -// ) -> Result, SimpleVMError> { -// create_vm( -// extension, -// Env { -// block: BlockInfo { -// height: 0xDEAD_C0DE, -// time: Timestamp::from_seconds(10000), -// chain_id: "abstract-test".into(), -// }, -// transaction: None, -// contract: ContractInfo { -// address: contract.into(), -// }, -// }, -// MessageInfo { -// sender: sender.into(), -// funds, -// }, -// ) -// } - -fn main() { -// let iter = 100; -// let cw20_base_code = instrument_contract(include_bytes!("../../../fixtures/cw20_base.wasm")); -// let hackatom_code = instrument_contract(include_bytes!("../../../fixtures/hackatom.wasm")); -// let reflect_code = instrument_contract(include_bytes!("../../../fixtures/reflect.wasm")); - -// let sender = BankAccount(100); -// let cw20_address = BankAccount(10_000); -// let hackatom_address = BankAccount(10_002); -// let reflect_address = BankAccount(10_003); -// let funds = vec![]; -// let mut extension = SimpleWasmiVMExtension { -// storage: BTreeMap::default(), -// codes: BTreeMap::from([ -// (0x1337, cw20_base_code), -// (0x1338, hackatom_code), -// (0x1339, reflect_code), -// ]), -// contracts: BTreeMap::from([ -// ( -// cw20_address, -// CosmwasmContractMeta { -// code_id: 0x1337, -// admin: None, -// label: String::new(), -// }, -// ), -// ( -// hackatom_address, -// CosmwasmContractMeta { -// code_id: 0x1338, -// admin: None, -// label: String::new(), -// }, -// ), -// ( -// reflect_address, -// CosmwasmContractMeta { -// code_id: 0x1339, -// admin: None, -// label: String::new(), -// }, -// ), -// ]), -// next_account_id: BankAccount(10_004), -// transaction_depth: 0, -// gas: Gas::new(u64::MAX), -// ..Default::default() -// }; - -// { -// { -// let mut vm = -// create_simple_vm(sender, cw20_address, funds.clone(), &mut extension).unwrap(); - -// assert_matches!( -// cosmwasm_call::, OwnedWasmiVM>( -// &mut vm, -// r#"{ -// "name": "Picasso", -// "symbol": "PICA", -// "decimals": 12, -// "initial_balances": [], -// "mint": null, -// "marketing": null -// }"# -// .as_bytes(), -// ) -// .unwrap(), -// InstantiateResult(CosmwasmExecutionResult::Ok(_)) -// ); - -// for _ in 0..iter { -// cosmwasm_call::>( -// &mut vm, -// r#"{ "token_info": {} }"#.as_bytes(), -// ) -// .unwrap(); -// } -// } -// { -// let mut vm = -// create_simple_vm(sender, reflect_address, funds.clone(), &mut extension).unwrap(); -// let _ = cosmwasm_system_entrypoint::>( -// &mut vm, -// r#"{}"#.as_bytes(), -// ) -// .unwrap(); - -// for _ in 0..iter { -// let (_, events) = -// cosmwasm_system_entrypoint::>( -// &mut vm, -// r#"{ -// "reflect_sub_msg": { -// "msgs": [{ -// "id": 10, -// "msg": { -// "wasm": { -// "execute": { -// "contract_addr": "10001", -// "msg": "eyAicmVsZWFzZSI6IHt9IH0=", -// "funds": [] -// } -// } -// }, -// "gas_limit": null, -// "reply_on": "always" -// }] -// } -// }"# -// .as_bytes(), -// ) -// .unwrap(); -// } -// } - -// { -// let mut vm = -// create_simple_vm(sender, hackatom_address, funds.clone(), &mut extension).unwrap(); - -// let (_, events) = cosmwasm_system_entrypoint::( -// &mut vm, -// r#"{"verifier": "10000", "beneficiary": "10000"}"#.as_bytes(), -// ) -// .unwrap(); -// for _ in 0..iter { -// cosmwasm_call::>( -// &mut vm, -// r#"{ "recurse": { "depth": 10, "work": 10 }}"#.as_bytes(), -// ) -// .unwrap(); -// } -// } -// } -// } - -// pub fn digit_sum(input: &[u8]) -> usize { -// input.iter().map(|v| *v as usize).sum() -// } - -// pub fn riffle_shuffle(input: &[T]) -> Vec { -// assert!( -// input.len() % 2 == 0, -// "Method only defined for even number of elements" -// ); -// let mid = input.len() / 2; -// let (left, right) = input.split_at(mid); -// let mut out = Vec::::with_capacity(input.len()); -// for i in 0..mid { -// out.push(right[i].clone()); -// out.push(left[i].clone()); -// } -// out -} diff --git a/vm-wasmi/src/host_functions.rs b/vm-wasmi/src/host_functions.rs index 965ac68..4a4521e 100644 --- a/vm-wasmi/src/host_functions.rs +++ b/vm-wasmi/src/host_functions.rs @@ -560,6 +560,7 @@ pub(crate) fn define( ), ) .map_err(Into::::into)?; + #[cfg(feature = "iterator")] linker .define( "env", @@ -576,6 +577,7 @@ pub(crate) fn define( ), ) .map_err(Into::::into)?; + #[cfg(feature = "iterator")] linker .define( "env", diff --git a/vm-wasmi/src/version.rs b/vm-wasmi/src/version.rs index 446cecd..fb299e6 100644 --- a/vm-wasmi/src/version.rs +++ b/vm-wasmi/src/version.rs @@ -1,9 +1,11 @@ use super::validation::ExportRequirement; +#[cfg(feature = "ibc3")] +use cosmwasm_vm::executor::ibc::{ + IbcChannelCloseCall, IbcChannelConnectCall, IbcChannelOpenCall, IbcPacketAckCall, + IbcPacketReceiveCall, IbcPacketTimeoutCall, +}; + use cosmwasm_vm::executor::{ - ibc::{ - IbcChannelCloseCall, IbcChannelConnectCall, IbcChannelOpenCall, IbcPacketAckCall, - IbcPacketReceiveCall, IbcPacketTimeoutCall, - }, AllocateCall, AsFunctionName, DeallocateCall, ExecuteCall, InstantiateCall, MigrateCall, QueryCall, ReplyCall, }; @@ -17,6 +19,7 @@ pub trait Version { const ENV_MODULE: &'static str = "env"; const ENV_GAS: &'static str = "gas"; const EXPORTS: &'static [Export]; + #[cfg(feature = "ibc3")] const IBC_EXPORTS: &'static [Export]; } @@ -85,6 +88,7 @@ impl Version for Version1x { // extern "C" fn ibc_packet_receive(env_ptr: u32, msg_ptr: u32) -> u32; // extern "C" fn ibc_packet_ack(env_ptr: u32, msg_ptr: u32) -> u32; // extern "C" fn ibc_packet_timeout(env_ptr: u32, msg_ptr: u32) -> u32; + #[cfg(feature = "ibc3")] const IBC_EXPORTS: &'static [Export] = &[ ( ExportRequirement::Mandatory, diff --git a/vm/src/executor.rs b/vm/src/executor.rs index e4a8d06..4cd3c8a 100644 --- a/vm/src/executor.rs +++ b/vm/src/executor.rs @@ -1,7 +1,3 @@ -// executor.rs --- - - - use crate::{ has::Has, input::Input, diff --git a/vm/src/has.rs b/vm/src/has.rs index d269149..d2727e3 100644 --- a/vm/src/has.rs +++ b/vm/src/has.rs @@ -1,7 +1,5 @@ // has.rs --- - - pub trait Has { fn get(&self) -> T; } diff --git a/vm/src/input.rs b/vm/src/input.rs index 1ddc584..ee49200 100644 --- a/vm/src/input.rs +++ b/vm/src/input.rs @@ -1,7 +1,5 @@ // input.rs --- - - pub type OutputOf = ::Output; pub trait Input { diff --git a/vm/src/lib.rs b/vm/src/lib.rs index f177817..478d456 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -10,4 +10,4 @@ pub mod memory; pub mod system; pub mod tagged; pub mod transaction; -pub mod vm; \ No newline at end of file +pub mod vm; diff --git a/vm/src/memory.rs b/vm/src/memory.rs index 2a12ed0..8453328 100644 --- a/vm/src/memory.rs +++ b/vm/src/memory.rs @@ -1,7 +1,5 @@ // memory.rs --- - - use alloc::vec; use alloc::vec::Vec; use core::fmt::Debug; diff --git a/vm/src/system.rs b/vm/src/system.rs index 2618bf1..7e491c9 100644 --- a/vm/src/system.rs +++ b/vm/src/system.rs @@ -1,7 +1,5 @@ // system.rs --- - - #[cfg(feature = "stargate")] use crate::executor::ibc::{ IbcChannelCloseCall, IbcChannelConnectCall, IbcPacketAckCall, IbcPacketReceiveCall, diff --git a/vm/src/tagged.rs b/vm/src/tagged.rs index d7c6cc8..a1fea6d 100644 --- a/vm/src/tagged.rs +++ b/vm/src/tagged.rs @@ -1,7 +1,5 @@ // tagged.rs --- - - use core::marker::PhantomData; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] diff --git a/vm/src/transaction.rs b/vm/src/transaction.rs index 9a6e344..807dc27 100644 --- a/vm/src/transaction.rs +++ b/vm/src/transaction.rs @@ -1,7 +1,5 @@ // transaction.rs --- - - pub type TransactionalErrorOf = ::Error; pub trait Transactional { From b4635eb81395875ae0cfde92bf8934934b685abf Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 8 Jun 2023 12:40:36 +0100 Subject: [PATCH 04/11] oh --- Cargo.lock | 50 +----------------------------------------- orchestrate/Cargo.toml | 8 +++---- 2 files changed, 5 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2097dca..7045152 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -187,18 +187,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cosmwasm-crypto" -version = "1.2.0" -source = "git+https://github.com/ComposableFi/cosmwasm?rev=34af48221c90e6818fe341d6d5b15116dfeab671#34af48221c90e6818fe341d6d5b15116dfeab671" -dependencies = [ - "digest 0.10.6", - "ed25519-zebra", - "k256", - "rand_core 0.6.4", - "thiserror", -] - [[package]] name = "cosmwasm-derive" version = "1.1.9" @@ -208,14 +196,6 @@ dependencies = [ "syn", ] -[[package]] -name = "cosmwasm-derive" -version = "1.2.0" -source = "git+https://github.com/ComposableFi/cosmwasm?rev=34af48221c90e6818fe341d6d5b15116dfeab671#34af48221c90e6818fe341d6d5b15116dfeab671" -dependencies = [ - "syn", -] - [[package]] name = "cosmwasm-derive" version = "1.2.5" @@ -232,7 +212,7 @@ dependencies = [ "base64", "bech32", "bs58", - "cosmwasm-std 1.2.0", + "cosmwasm-std 1.2.5", "cosmwasm-vm", "cosmwasm-vm-wasmi", "ed25519-zebra", @@ -294,25 +274,6 @@ dependencies = [ "uint", ] -[[package]] -name = "cosmwasm-std" -version = "1.2.0" -source = "git+https://github.com/ComposableFi/cosmwasm?rev=34af48221c90e6818fe341d6d5b15116dfeab671#34af48221c90e6818fe341d6d5b15116dfeab671" -dependencies = [ - "base64", - "cosmwasm-crypto 1.2.0", - "cosmwasm-derive 1.2.0", - "derivative", - "forward_ref", - "hex", - "schemars", - "serde", - "serde-json-wasm 0.5.0", - "sha2 0.10.6", - "thiserror", - "uint", -] - [[package]] name = "cosmwasm-std" version = "1.2.5" @@ -1601,15 +1562,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde-json-wasm" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" -dependencies = [ - "serde", -] - [[package]] name = "serde-json-wasm" version = "0.5.1" diff --git a/orchestrate/Cargo.toml b/orchestrate/Cargo.toml index c4437bf..b296328 100644 --- a/orchestrate/Cargo.toml +++ b/orchestrate/Cargo.toml @@ -5,12 +5,12 @@ edition = "2021" [features] default = ["std"] -std = ["reqwest", "cosmwasm-std/std"] +std = ["reqwest", "cosmwasm-std/std", "cosmwasm-vm/std", "cosmwasm-vm-wasmi/std"] [dependencies] cosmwasm-vm = { path = "../vm" } cosmwasm-vm-wasmi = { path = "../vm-wasmi" } -cosmwasm-std = { git = "https://github.com/ComposableFi/cosmwasm", rev = "34af48221c90e6818fe341d6d5b15116dfeab671", default-features = false, features = [ +cosmwasm-std = {workspace = true, default-features = false, features = [ "stargate", "ibc3", "staking", @@ -18,8 +18,8 @@ cosmwasm-std = { git = "https://github.com/ComposableFi/cosmwasm", rev = "34af48 ] } ed25519-zebra = { version = "3.1.0", default-features = false } libsecp256k1 = { version = "0.7.1", default-features = false, features = [ "hmac", "static-context" ] } -serde_json = { version = "1.0", default-features = false, features = [ "alloc" ] } -serde = { version = "1.0", default-features = false, features = [ "derive", "alloc" ] } +serde_json = { workspace = true, default-features = false, features = [ "alloc" ] } +serde = { workspace = true, default-features = false, features = [ "derive", "alloc" ] } wasmi = { version = "0.26", default-features = false } wasm-instrument = { version = "0.2", default-features = false } log = "0.4" From 5120f9fe585a7b02f67b00d215b4c2289b9747aa Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 8 Jun 2023 15:25:32 +0100 Subject: [PATCH 05/11] fixed --- Cargo.lock | 74 +++++++++++++++++++++++---------------------- Cargo.toml | 4 ++- research/Cargo.toml | 6 ++-- vm-wasmi/Cargo.toml | 4 +-- 4 files changed, 46 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7045152..b18fb33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -164,8 +164,8 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cosmwasm-crypto" -version = "1.1.5" -source = "git+https://github.com/ComposableFi/cosmwasm?rev=7d288c23772d03e8cd666b76cb5bbdc5952721dd#7d288c23772d03e8cd666b76cb5bbdc5952721dd" +version = "1.2.5" +source = "git+https://github.com/dzmitry-lahoda-forks/cosmwasm?rev=677fa9c04b07a4934db82a6a9aa9e68fa13fcff9#677fa9c04b07a4934db82a6a9aa9e68fa13fcff9" dependencies = [ "digest 0.10.6", "ed25519-zebra", @@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "cosmwasm-crypto" -version = "1.1.9" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227315dc11f0bb22a273d0c43d3ba8ef52041c42cf959f09045388a89c57e661" +checksum = "41c0e41be7e6c7d7ab3c61cdc32fcfaa14f948491a401cbc1c74bb33b6f4b851" dependencies = [ "digest 0.10.6", "ed25519-zebra", @@ -189,17 +189,17 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fca30d51f7e5fbfa6440d8b10d7df0231bdf77e97fd3fe5d0cb79cc4822e50c" +version = "1.2.5" +source = "git+https://github.com/dzmitry-lahoda-forks/cosmwasm?rev=677fa9c04b07a4934db82a6a9aa9e68fa13fcff9#677fa9c04b07a4934db82a6a9aa9e68fa13fcff9" dependencies = [ "syn", ] [[package]] name = "cosmwasm-derive" -version = "1.2.5" -source = "git+https://github.com/dzmitry-lahoda-forks/cosmwasm?rev=f483c3c4695fcb094539b5aead223d54cb0e23b2#f483c3c4695fcb094539b5aead223d54cb0e23b2" +version = "1.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a7ee2798c92c00dd17bebb4210f81d5f647e5e92d847959b7977e0fd29a3500" dependencies = [ "syn", ] @@ -233,9 +233,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema" -version = "1.1.9" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04135971e2c3b867eb793ca4e832543c077dbf72edaef7672699190f8fcdb619" +checksum = "407aca6f1671a08b60db8167f03bb7cb6b2378f0ddd9a030367b66ba33c2fd41" dependencies = [ "cosmwasm-schema-derive", "schemars", @@ -246,9 +246,9 @@ dependencies = [ [[package]] name = "cosmwasm-schema-derive" -version = "1.1.9" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06c8f516a13ae481016aa35f0b5c4652459e8aee65b15b6fb51547a07cea5a0" +checksum = "e6d1e00b8fd27ff923c10303023626358e23a6f9079f8ebec23a8b4b0bfcd4b3" dependencies = [ "proc-macro2", "quote", @@ -257,38 +257,40 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13d5a84d15cf7be17dc249a21588cdb0f7ef308907c50ce2723316a7d79c3dc" +version = "1.2.5" +source = "git+https://github.com/dzmitry-lahoda-forks/cosmwasm?rev=677fa9c04b07a4934db82a6a9aa9e68fa13fcff9#677fa9c04b07a4934db82a6a9aa9e68fa13fcff9" dependencies = [ "base64", - "cosmwasm-crypto 1.1.9", - "cosmwasm-derive 1.1.9", + "cosmwasm-crypto 1.2.5", + "cosmwasm-derive 1.2.5", "derivative", "forward_ref", "hex", "schemars", "serde", - "serde-json-wasm 0.4.1", - "thiserror", + "serde-json-wasm 0.5.1 (git+https://github.com/dzmitry-lahoda-forks/serde-json-wasm?rev=8a7e522c0e4de36a6dfb535766f26a9941017d81)", + "sha2 0.10.6", + "thiserror-core", "uint", ] [[package]] name = "cosmwasm-std" -version = "1.2.5" -source = "git+https://github.com/dzmitry-lahoda-forks/cosmwasm?rev=f483c3c4695fcb094539b5aead223d54cb0e23b2#f483c3c4695fcb094539b5aead223d54cb0e23b2" +version = "1.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d5fdfd112b070055f068fad079d490117c8e905a588b92a5a7c9276d029930" dependencies = [ "base64", - "cosmwasm-derive 1.2.5", + "cosmwasm-crypto 1.2.6", + "cosmwasm-derive 1.2.6", "derivative", "forward_ref", "hex", "schemars", "serde", - "serde-json-wasm 0.5.1", + "serde-json-wasm 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.10.6", - "thiserror-core", + "thiserror", "uint", ] @@ -309,7 +311,7 @@ dependencies = [ name = "cosmwasm-vm-wasmi" version = "0.2.0" dependencies = [ - "cosmwasm-crypto 1.1.5", + "cosmwasm-crypto 1.2.5", "cosmwasm-std 1.2.5", "cosmwasm-vm", "cw20-ics20", @@ -391,7 +393,7 @@ version = "0.16.0" source = "git+https://github.com/CosmWasm/cw-plus?rev=53dc88fdb81888cbd3dae8742e7318b35d3d0c0f#53dc88fdb81888cbd3dae8742e7318b35d3d0c0f" dependencies = [ "cosmwasm-schema", - "cosmwasm-std 1.1.9", + "cosmwasm-std 1.2.6", "cw-storage-plus", "cw-utils", "schemars", @@ -404,7 +406,7 @@ name = "cw-storage-plus" version = "0.16.0" source = "git+https://github.com/CosmWasm/cw-plus?rev=53dc88fdb81888cbd3dae8742e7318b35d3d0c0f#53dc88fdb81888cbd3dae8742e7318b35d3d0c0f" dependencies = [ - "cosmwasm-std 1.1.9", + "cosmwasm-std 1.2.6", "schemars", "serde", ] @@ -415,7 +417,7 @@ version = "0.16.0" source = "git+https://github.com/CosmWasm/cw-plus?rev=53dc88fdb81888cbd3dae8742e7318b35d3d0c0f#53dc88fdb81888cbd3dae8742e7318b35d3d0c0f" dependencies = [ "cosmwasm-schema", - "cosmwasm-std 1.1.9", + "cosmwasm-std 1.2.6", "cw2", "schemars", "semver", @@ -429,7 +431,7 @@ version = "0.16.0" source = "git+https://github.com/CosmWasm/cw-plus?rev=53dc88fdb81888cbd3dae8742e7318b35d3d0c0f#53dc88fdb81888cbd3dae8742e7318b35d3d0c0f" dependencies = [ "cosmwasm-schema", - "cosmwasm-std 1.1.9", + "cosmwasm-std 1.2.6", "cw-storage-plus", "schemars", "serde", @@ -441,7 +443,7 @@ version = "0.16.0" source = "git+https://github.com/CosmWasm/cw-plus?rev=53dc88fdb81888cbd3dae8742e7318b35d3d0c0f#53dc88fdb81888cbd3dae8742e7318b35d3d0c0f" dependencies = [ "cosmwasm-schema", - "cosmwasm-std 1.1.9", + "cosmwasm-std 1.2.6", "cw-utils", "schemars", "serde", @@ -453,7 +455,7 @@ version = "0.16.0" source = "git+https://github.com/CosmWasm/cw-plus?rev=53dc88fdb81888cbd3dae8742e7318b35d3d0c0f#53dc88fdb81888cbd3dae8742e7318b35d3d0c0f" dependencies = [ "cosmwasm-schema", - "cosmwasm-std 1.1.9", + "cosmwasm-std 1.2.6", "cw-controllers", "cw-storage-plus", "cw-utils", @@ -1540,9 +1542,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" @@ -1555,9 +1557,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137" dependencies = [ "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 1a36541..09d63b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,10 +5,12 @@ resolver = "2" [workspace.dependencies] -cosmwasm-std = { git = "https://github.com/dzmitry-lahoda-forks/cosmwasm", rev = "f483c3c4695fcb094539b5aead223d54cb0e23b2", default-features = false, features = [ +cosmwasm-std = { git = "https://github.com/dzmitry-lahoda-forks/cosmwasm", rev = "677fa9c04b07a4934db82a6a9aa9e68fa13fcff9", default-features = false, features = [ "iterator", "cosmwasm_1_2", ] } +cosmwasm-crypto = { git = "https://github.com/dzmitry-lahoda-forks/cosmwasm", rev = "677fa9c04b07a4934db82a6a9aa9e68fa13fcff9" } + serde = { version = "1", default-features = false, features = ["derive"] } serde_json = { version = "1", default-features = false, features = ["alloc"] } log = { version = "0.4", default-features = false } diff --git a/research/Cargo.toml b/research/Cargo.toml index 8fe4812..7fbfa39 100644 --- a/research/Cargo.toml +++ b/research/Cargo.toml @@ -43,6 +43,6 @@ wat = "1.0" env_logger = "0.9" cosmwasm-crypto = { git = "https://github.com/ComposableFi/cosmwasm", rev = "7d288c23772d03e8cd666b76cb5bbdc5952721dd" } -cw20-ics20 = { git = "https://github.com/CosmWasm/cw-plus", rev = "53dc88fdb81888cbd3dae8742e7318b35d3d0c0f", default-features = false, features = [ - "library", -] } +# cw20-ics20 = { git = "https://github.com/CosmWasm/cw-plus", rev = "53dc88fdb81888cbd3dae8742e7318b35d3d0c0f", default-features = false, features = [ +# "library", +# ] } diff --git a/vm-wasmi/Cargo.toml b/vm-wasmi/Cargo.toml index b66a347..d4b603c 100644 --- a/vm-wasmi/Cargo.toml +++ b/vm-wasmi/Cargo.toml @@ -8,7 +8,7 @@ default = ["iterator", "stargate", "ibc3"] iterator = ["cosmwasm-vm/iterator"] stargate = ["cosmwasm-vm/stargate"] ibc3 = ["cosmwasm-vm/ibc3"] -std = ["cosmwasm-std/std"] +std = ["cosmwasm-std/std", "cosmwasm-vm/std"] [dependencies] serde = { workspaace = true, default-features = false, features = ["derive"] } @@ -28,7 +28,7 @@ hex = { version = "0.4", default-features = false, features = ["alloc"] } [dev-dependencies] wat = "1.0" env_logger = "0.9" -cosmwasm-crypto = { git = "https://github.com/ComposableFi/cosmwasm", rev = "7d288c23772d03e8cd666b76cb5bbdc5952721dd" } +cosmwasm-crypto = { workspace = true } cw20-ics20 = { git = "https://github.com/CosmWasm/cw-plus", rev = "53dc88fdb81888cbd3dae8742e7318b35d3d0c0f", default-features = false, features = [ "library", From 5fa220380decea2c0b8d84f7319e15a1110232ed Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 8 Jun 2023 15:33:09 +0100 Subject: [PATCH 06/11] shared wasmi dep --- Cargo.toml | 5 ++++- orchestrate/Cargo.toml | 4 ++-- research/Cargo.toml | 6 +++--- vm-wasmi/Cargo.toml | 6 +++--- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 09d63b4..f002dab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,7 @@ cosmwasm-crypto = { git = "https://github.com/dzmitry-lahoda-forks/cosmwasm", re serde = { version = "1", default-features = false, features = ["derive"] } serde_json = { version = "1", default-features = false, features = ["alloc"] } log = { version = "0.4", default-features = false } -num = { version = "0.4", default-features = false } \ No newline at end of file +num = { version = "0.4", default-features = false } +wasmi = { version = "0.26", default-features = false } +wasm-instrument = { version = "0.2", default-features = false } +wasmi-validation = { version = "0.5", default-features = false } \ No newline at end of file diff --git a/orchestrate/Cargo.toml b/orchestrate/Cargo.toml index b296328..4f6b170 100644 --- a/orchestrate/Cargo.toml +++ b/orchestrate/Cargo.toml @@ -20,8 +20,8 @@ ed25519-zebra = { version = "3.1.0", default-features = false } libsecp256k1 = { version = "0.7.1", default-features = false, features = [ "hmac", "static-context" ] } serde_json = { workspace = true, default-features = false, features = [ "alloc" ] } serde = { workspace = true, default-features = false, features = [ "derive", "alloc" ] } -wasmi = { version = "0.26", default-features = false } -wasm-instrument = { version = "0.2", default-features = false } +wasmi = { workspace = true, default-features = false } +wasm-instrument = { workspace = true, default-features = false } log = "0.4" sha2 = { version = "0.10", default-features = false } reqwest = { version = "0.11", optional = true } diff --git a/research/Cargo.toml b/research/Cargo.toml index 7fbfa39..33e21ed 100644 --- a/research/Cargo.toml +++ b/research/Cargo.toml @@ -20,9 +20,9 @@ serde = { workspaace = true, default-features = false, features = ["derive"] } serde_json = { workspaace = true, default-features = false, features = ["alloc"] } either = { version = "1.8", default-features = false } log = { workspace = true, default-features = false } -wasmi = { version = "0.26", default-features = false } -wasmi-validation = { version = "0.5", default-features = false } -wasm-instrument = { version = "0.2", default-features = false } +wasmi = { workspace = true, default-features = false } +wasmi-validation = { workspace = true, default-features = false } +wasm-instrument = { workspace = true, default-features = false } cosmwasm-std = { workspace = true, default-features = false, features = [ "iterator", "cosmwasm_1_2" diff --git a/vm-wasmi/Cargo.toml b/vm-wasmi/Cargo.toml index d4b603c..d48562e 100644 --- a/vm-wasmi/Cargo.toml +++ b/vm-wasmi/Cargo.toml @@ -15,9 +15,9 @@ serde = { workspaace = true, default-features = false, features = ["derive"] } serde_json = { workspaace = true, default-features = false, features = ["alloc"] } either = { version = "1.8", default-features = false } log = { workspace = true, default-features = false } -wasmi = { version = "0.26", default-features = false } -wasmi-validation = { version = "0.5", default-features = false } -wasm-instrument = { version = "0.2", default-features = false } +wasmi = { workspace = true, default-features = false } +wasmi-validation = { workspace = true, default-features = false } +wasm-instrument = { workspace = true, default-features = false } cosmwasm-std = { workspace = true, default-features = false, features = [ "iterator", "cosmwasm_1_2" From 556cb35c93a304ba849ebfa861c361516839d561 Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 8 Jun 2023 15:35:35 +0100 Subject: [PATCH 07/11] readme --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index ed77b61..94d5995 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # CosmWasm VM Experimental, minimalistic, `no_std` friendly abstract virtual machine for CosmWasm contracts execution. @@ -25,3 +26,10 @@ Install `flamegraph` (in nix shell already installed) Modify `research.rs` as needed. +## Authors + "Hussein Ait Lahcen hussein.aitlahcen@gmail.com" + "Abdullah Eryuzlu abdullaheryuzlu@gmail.com" + "Composable Developers" +## homepage + +https://composable.finance From e8666ef5bf9eae2d8f716814259da10d3df3ad40 Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 8 Jun 2023 15:38:05 +0100 Subject: [PATCH 08/11] who cares if it is obsolete? --- SPEC.md | 112 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/SPEC.md b/SPEC.md index 8aabe18..2ec7428 100644 --- a/SPEC.md +++ b/SPEC.md @@ -20,68 +20,71 @@ It describes the semantics of the VM in a slightly more structured way than the - [Abstract](#abstract) - [Status of This Memo](#status-of-this-memo) -- [Copyright Notice](#copyright-notice) -- [Table of Contents](#table-of-contents) +- [Table of contents](#table-of-contents) - [1. Overview](#1-overview) - [1.1. Document Structure](#11-document-structure) - [1.2. Terms and Definitions](#12-terms-and-definitions) - - [1.3. Notational Conventions](#13-notational-conventions) + - [1.3. Notational Conventions](#13--notational-conventions) - [2. Smart Contracts](#2-smart-contracts) - - [2.1. Exports](#21-exports) - - [2.1.1. Base exports](#211-base-exports) - - [2.1.2. IBC exports](#212-ibc-exports) - - [2.2. Interface Version](#22-interface-version) - - [2.3. Allocating](#23-allocating) - - [2.4. Deallocating](#24-deallocating) - - [2.5. Instantiation](#25-instantiation) - - [2.5.1. Environment Pointer](#251-environment-pointer) - - [2.5.2. Information Pointer](#252-information-pointer) - - [2.5.3. Regions](#253-regions) - - [2.6. Execute](#26-execute) - - [2.7. Query](#27-query) - - [2.8. Migrate](#28-migrate) - - [2.9. Reply](#29-reply) - - [2.10. Sudo](#210-sudo) - - [2.11. IBC Channel Open](#211-ibc-channel-open) - - [2.12. IBC Channel Connect](#212-ibc-channel-connect) - - [2.13. IBC Channel Close](#213-ibc-channel-close) - - [2.14. IBC Packet Receive](#214-ibc-packet-receive) - - [2.15. IBC Packet Ack](#215-ibc-packet-ack) - - [2.16. IBC Packet Timeout](#216-ibc-packet-timeout) + - [2.1. Exports](#21-exports) + - [2.1.1. Base exports](#211-base-exports) + - [2.1.2. IBC exports](#212-ibc-exports) + - [2.2. Interface Version](#22-interface-version) + - [2.3. Allocating](#23-allocating) + - [2.4. Deallocating](#24-deallocating) + - [2.5. Instantiation](#25-instantiation) + - [2.5.1. Environment Pointer](#251-environment-pointer) + - [2.5.2. Information Pointer](#252-information-pointer) + - [2.5.2.1. Block Info](#2521-block-info) + - [2.5.2.2. Transaction Info](#2522-transaction-info) + - [2.5.2.3. Contract Info](#2523-contract-info) + - [2.5.2.4. Message Info](#2524-message-info) + - [2.5.3. Regions](#253-regions) + - [2.6. Execute](#26-execute) + - [2.7. Query](#27-query) + - [2.8. Migrate](#28-migrate) + - [2.9. Reply](#29-reply) + - [2.10. Sudo](#210-sudo) + - [2.11. IBC Channel Open](#211-ibc-channel-open) + - [2.12. IBC Channel Connect](#212-ibc-channel-connect) + - [2.13. IBC Channel Close](#213-ibc-channel-close) + - [2.14. IBC Packet Receive](#214-ibc-packet-receive) + - [2.15. IBC Packet Ack](#215-ibc-packet-ack) + - [2.16. IBC Packet Timeout](#216-ibc-packet-timeout) - [3. Host Functions](#3-host-functions) - - [3.1. DB Read](#31-db-read) - - [3.2. DB Write](#32-db-write) - - [3.3. DB Remove](#33-db-remove) - - [3.4. DB Scan](#34-db-scan) - - [3.5. DB Next](#35-db-next) - - [3.6. Address Validate](#36-address-validate) - - [3.7. Address Canonicalize](#37-address-canonicalize) - - [3.8. Address Humanize](#38-address-humanize) - - [3.9. Secp256k1 Verify](#39-secp256k1-verify) - - [3.10. Secp256k1 Recovery](#310-secp256k1-recovery) - - [3.11. Ed25519 Verify](#311-ed25519-verify) - - [3.12. Ed25519 Batch Verify](#312-ed25519-batch-verify) - - [3.13. Debug](#313-debug) - - [3.14. Query Chain](#314-query-chain) - - [3.14.1 Bank Query](#3141-bank-query) - - [3.14.2 Wasm Query](#3142-wasm-query) + - [3.1. DB Read](#31-db-read) + - [3.2. DB Write](#32-db-write) + - [3.3. DB Remove](#33-db-remove) + - [3.4. DB Scan](#34-db-scan) + - [3.5. DB Next](#35-db-next) + - [3.6. Address Validate](#36-address-validate) + - [3.7. Address Canonicalize](#37-address-canonicalize) + - [3.8. Address Humanize](#38-address-humanize) + - [3.9. Secp256k1 Verify](#39-secp256k1-verify) + - [3.10. Secp256k1 Recovery](#310-secp256k1-recovery) + - [3.11. Ed25519 Verify](#311-ed25519-verify) + - [3.12. Ed25519 Batch Verify](#312-ed25519-batch-verify) + - [3.13. Debug](#313-debug) + - [3.14. Query Chain](#314-query-chain) + - [3.14.1 Bank Query](#3141-bank-query) + - [3.14.2 Wasm Query](#3142-wasm-query) - [4. Virtual Machine](#4-virtual-machine) - - [4.1. Gas Metering](#41-gas-metering) - - [4.1.1. Gas to Weight](#411-gas-to-weight) - - [4.2. Messaging](#42-messaging) - - [4.2.1 Submessages](#421-submessages) - - [4.2.2 Query](#422-query) - - [4.3. Calling a Contract](#43-calling-a-contract) - - [4.4. Contract Call Graph](#44-contract-call-graph) - - [4.5. Custom Message](#45-custom-message) - - [4.6. Custom Query](#46-custom-query) + - [4.1. Gas Metering](#41-gas-metering) + - [4.1.1. Gas to Weight](#411-gas-to-weight) + - [4.2. Messaging](#42-messaging) + - [4.2.1 Submessages](#421-submessages) + - [4.2.2 Query](#422-query) + - [4.3. Calling a Contract](#43-calling-a-contract) + - [4.4. Contract Call Graph](#44-contract-call-graph) + - [4.5. Custom Message](#45-custom-message) + - [4.6. Custom Query](#46-custom-query) - [5. Serialization Format](#5-serialization-format) - [6. IBC](#6-ibc) - - [6.1. Enabling IBC](#61-enabling-ibc) - - [6.2. Host Functions](#62-host-functions) - - [6.2.1. IBC Transfer](#621-ibc-transfer) - - [6.2.2. IBC Packet Send](#622-ibc-packet-send) - - [6.2.3. IBC Channel Close](#623-ibc-channel-close) + - [6.1. Enabling IBC](#61-enabling-ibc) + - [6.2. Host Functions](#62-host-functions) + - [6.2.1. IBC Transfer](#621-ibc-transfer) + - [6.2.2. IBC Packet Send](#622-ibc-packet-send) + - [6.2.3. IBC Channel Close](#623-ibc-channel-close) - [7. Contributors](#7-contributors) # 1. Overview @@ -1227,7 +1230,6 @@ Contributors that made our CosmWasm implementation possible are here listed in a - Hussein Ait Lahcen - XCVM Principal Engineering - Composable Finance - Abdullah Eryuzlu - Rust Developer - Composable Finance -- Dzmitry Lahoda - Rust Developer - Composable Finance - Cor Pruijs - Rust Developer - Composable Finance [2.5.1.]: #251-environment-pointer From da7f0a8e55f4d930bd90abca00f473008f7e4833 Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 8 Jun 2023 16:48:14 +0100 Subject: [PATCH 09/11] wasmi --- .gitignore | 1 + Cargo.lock | 26 ++++++++++++++++++++------ Cargo.toml | 6 +++--- orchestrate/src/vm/mod.rs | 4 ++++ vm-wasmi/src/host_functions.rs | 10 +++++++--- vm-wasmi/src/lib.rs | 2 +- vm-wasmi/src/semantic.rs | 17 +++++++++++++---- 7 files changed, 49 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 9b55c4a..cd51d6b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ flamegraph.svg *.log *.data *.data.old +.vscode/setting.json diff --git a/Cargo.lock b/Cargo.lock index b18fb33..f4b19fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -949,6 +949,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "intx" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f38a50a899dc47a6d0ed5508e7f601a2e34c3a85303514b5d137f3c10a0c75" + [[package]] name = "io-lifetimes" version = "1.0.3" @@ -1660,6 +1666,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + [[package]] name = "socket2" version = "0.4.7" @@ -2033,19 +2045,21 @@ dependencies = [ [[package]] name = "wasm-instrument" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bca81f5279342b38b17d9acbf007a46ddeb73144e2bd5f0a21bfa9fc5d4ab3e" +checksum = "2a47ecb37b9734d1085eaa5ae1a81e60801fd8c28d4cabdd8aedb982021918bc" dependencies = [ "parity-wasm", ] [[package]] name = "wasmi" -version = "0.26.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ad19edb5ccf561b5a01c9e37bd1ff38b2c2443c778aa2ff65e993205189c33" +checksum = "e51fb5c61993e71158abf5bb863df2674ca3ec39ed6471c64f07aeaf751d67b4" dependencies = [ + "intx", + "smallvec", "spin", "wasmi_arena", "wasmi_core", @@ -2069,9 +2083,9 @@ checksum = "401c1f35e413fac1846d4843745589d9ec678977ab35a384db8ae7830525d468" [[package]] name = "wasmi_core" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2bde97906bbc49ad61184db16e5c905e946e747f6febd09b583fc321d70af0" +checksum = "624e6333e861ef49095d2d678b76ebf30b06bf37effca845be7e5b87c90071b7" dependencies = [ "downcast-rs", "libm", diff --git a/Cargo.toml b/Cargo.toml index f002dab..dab9bb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,6 @@ serde = { version = "1", default-features = false, features = ["derive"] } serde_json = { version = "1", default-features = false, features = ["alloc"] } log = { version = "0.4", default-features = false } num = { version = "0.4", default-features = false } -wasmi = { version = "0.26", default-features = false } -wasm-instrument = { version = "0.2", default-features = false } -wasmi-validation = { version = "0.5", default-features = false } \ No newline at end of file +wasmi = { version = "0.30", default-features = false } +wasm-instrument = { version = "0.4.0", default-features = false } +wasmi-validation = { version = "0.5.0", default-features = false } \ No newline at end of file diff --git a/orchestrate/src/vm/mod.rs b/orchestrate/src/vm/mod.rs index 7ba634f..4c58749 100644 --- a/orchestrate/src/vm/mod.rs +++ b/orchestrate/src/vm/mod.rs @@ -928,4 +928,8 @@ impl Rules for ConstantCostRules { NonZeroU32::new(1024).expect("impossible"), ) } + + fn call_per_local_cost(&self) -> u32 { + 0 + } } diff --git a/vm-wasmi/src/host_functions.rs b/vm-wasmi/src/host_functions.rs index 4a4521e..335945f 100644 --- a/vm-wasmi/src/host_functions.rs +++ b/vm-wasmi/src/host_functions.rs @@ -5,8 +5,12 @@ )] use super::{ format, AsContextMut, String, Tagged, VMBase, Vec, VmErrorOf, VmGas, VmQueryCustomOf, - WasmiBaseVM, WasmiVM, WasmiVMError, + WasmiBaseVM, WasmiVM, }; + +#[cfg(feature = "iterator")] +use super::WasmiVMError; + #[cfg(feature = "iterator")] use cosmwasm_std::Order; use cosmwasm_std::QueryRequest; @@ -453,7 +457,7 @@ where } /// Charges `value` amount of gas. -pub fn env_gas(mut vm: WasmiVM, value: i32) -> Result<(), VmErrorOf> +pub fn env_gas(mut vm: WasmiVM, value: i64) -> Result<(), VmErrorOf> where V: WasmiBaseVM, S: AsContextMut, @@ -764,7 +768,7 @@ pub(crate) fn define( "gas", Func::wrap( ctx.as_context_mut(), - |caller: Caller<'_, V>, value: i32| -> Result<(), Trap> { + |caller: Caller<'_, V>, value: i64| -> Result<(), Trap> { env_gas(WasmiVM(caller), value).map_err(Into::into) }, ), diff --git a/vm-wasmi/src/lib.rs b/vm-wasmi/src/lib.rs index 7f71c2f..b0d03dd 100644 --- a/vm-wasmi/src/lib.rs +++ b/vm-wasmi/src/lib.rs @@ -249,7 +249,7 @@ pub fn new_wasmi_vm(code: &[u8], data: V) -> Result::into)?; let mut store = Store::new(&engine, data); - let mut linker = >::new(); + let mut linker = >::new(&engine); host_functions::define(store.as_context_mut(), &mut linker)?; diff --git a/vm-wasmi/src/semantic.rs b/vm-wasmi/src/semantic.rs index 42015b0..1cbe489 100644 --- a/vm-wasmi/src/semantic.rs +++ b/vm-wasmi/src/semantic.rs @@ -1,5 +1,7 @@ extern crate std; +use crate::version::{Version, Version1x}; + use super::{ code_gen, new_wasmi_vm, OwnedWasmiVM, VMBase, WasmiContext, WasmiInput, WasmiModule, WasmiOutput, WasmiVMError, @@ -41,7 +43,7 @@ use cosmwasm_vm::{ transaction::Transactional, vm::{VmErrorOf, VmGas, VmGasCheckpoint}, }; -use wasm_instrument::gas_metering::Rules; +use wasm_instrument::gas_metering::{host_function, Rules}; use wasmi::core::HostError; const CANONICAL_LENGTH: usize = 54; @@ -881,14 +883,21 @@ impl Rules for ConstantCostRules { NonZeroU32::new(1024).expect("impossible"), ) } + + fn call_per_local_cost(&self) -> u32 { + 0 + } } fn instrument_contract(code: &[u8]) -> Vec { let module = wasm_instrument::parity_wasm::elements::Module::from_bytes(code).expect("impossible"); - let instrumented_module = - wasm_instrument::gas_metering::inject(module, &ConstantCostRules, "env") - .expect("impossible"); + let instrumented_module = wasm_instrument::gas_metering::inject( + module, + host_function::Injector::new(Version1x::ENV_MODULE, Version1x::ENV_GAS), + &ConstantCostRules, + ) + .expect("impossible"); instrumented_module.into_bytes().expect("impossible") } From 82e1f20debbfbf0c6cacae9da36d720cad527bcf Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 8 Jun 2023 17:15:45 +0100 Subject: [PATCH 10/11] Update .gitignore Co-authored-by: Michal Nazarewicz Signed-off-by: dzmitry-lahoda --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index cd51d6b..ea1686b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ flamegraph.svg *.log *.data *.data.old -.vscode/setting.json +.vscode/ From d1f1a356b299386dd4b962d93f314763e1c0db3a Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Thu, 8 Jun 2023 17:34:13 +0100 Subject: [PATCH 11/11] clean up --- SPEC.md | 71 --------------------------------------------------------- 1 file changed, 71 deletions(-) diff --git a/SPEC.md b/SPEC.md index 2ec7428..226585b 100644 --- a/SPEC.md +++ b/SPEC.md @@ -16,77 +16,6 @@ It has been authored and approved by the core Composable team. It describes the semantics of the VM in a slightly more structured way than the original [spec](https://github.com/CosmWasm/wasmvm/blob/main/spec/Specification.md) by Confio. -# Table of contents - -- [Abstract](#abstract) -- [Status of This Memo](#status-of-this-memo) -- [Table of contents](#table-of-contents) -- [1. Overview](#1-overview) - - [1.1. Document Structure](#11-document-structure) - - [1.2. Terms and Definitions](#12-terms-and-definitions) - - [1.3. Notational Conventions](#13--notational-conventions) -- [2. Smart Contracts](#2-smart-contracts) - - [2.1. Exports](#21-exports) - - [2.1.1. Base exports](#211-base-exports) - - [2.1.2. IBC exports](#212-ibc-exports) - - [2.2. Interface Version](#22-interface-version) - - [2.3. Allocating](#23-allocating) - - [2.4. Deallocating](#24-deallocating) - - [2.5. Instantiation](#25-instantiation) - - [2.5.1. Environment Pointer](#251-environment-pointer) - - [2.5.2. Information Pointer](#252-information-pointer) - - [2.5.2.1. Block Info](#2521-block-info) - - [2.5.2.2. Transaction Info](#2522-transaction-info) - - [2.5.2.3. Contract Info](#2523-contract-info) - - [2.5.2.4. Message Info](#2524-message-info) - - [2.5.3. Regions](#253-regions) - - [2.6. Execute](#26-execute) - - [2.7. Query](#27-query) - - [2.8. Migrate](#28-migrate) - - [2.9. Reply](#29-reply) - - [2.10. Sudo](#210-sudo) - - [2.11. IBC Channel Open](#211-ibc-channel-open) - - [2.12. IBC Channel Connect](#212-ibc-channel-connect) - - [2.13. IBC Channel Close](#213-ibc-channel-close) - - [2.14. IBC Packet Receive](#214-ibc-packet-receive) - - [2.15. IBC Packet Ack](#215-ibc-packet-ack) - - [2.16. IBC Packet Timeout](#216-ibc-packet-timeout) -- [3. Host Functions](#3-host-functions) - - [3.1. DB Read](#31-db-read) - - [3.2. DB Write](#32-db-write) - - [3.3. DB Remove](#33-db-remove) - - [3.4. DB Scan](#34-db-scan) - - [3.5. DB Next](#35-db-next) - - [3.6. Address Validate](#36-address-validate) - - [3.7. Address Canonicalize](#37-address-canonicalize) - - [3.8. Address Humanize](#38-address-humanize) - - [3.9. Secp256k1 Verify](#39-secp256k1-verify) - - [3.10. Secp256k1 Recovery](#310-secp256k1-recovery) - - [3.11. Ed25519 Verify](#311-ed25519-verify) - - [3.12. Ed25519 Batch Verify](#312-ed25519-batch-verify) - - [3.13. Debug](#313-debug) - - [3.14. Query Chain](#314-query-chain) - - [3.14.1 Bank Query](#3141-bank-query) - - [3.14.2 Wasm Query](#3142-wasm-query) -- [4. Virtual Machine](#4-virtual-machine) - - [4.1. Gas Metering](#41-gas-metering) - - [4.1.1. Gas to Weight](#411-gas-to-weight) - - [4.2. Messaging](#42-messaging) - - [4.2.1 Submessages](#421-submessages) - - [4.2.2 Query](#422-query) - - [4.3. Calling a Contract](#43-calling-a-contract) - - [4.4. Contract Call Graph](#44-contract-call-graph) - - [4.5. Custom Message](#45-custom-message) - - [4.6. Custom Query](#46-custom-query) -- [5. Serialization Format](#5-serialization-format) -- [6. IBC](#6-ibc) - - [6.1. Enabling IBC](#61-enabling-ibc) - - [6.2. Host Functions](#62-host-functions) - - [6.2.1. IBC Transfer](#621-ibc-transfer) - - [6.2.2. IBC Packet Send](#622-ibc-packet-send) - - [6.2.3. IBC Channel Close](#623-ibc-channel-close) -- [7. Contributors](#7-contributors) - # 1. Overview CosmWasm is a web assembly (wasm) based standard for smart contracts. In this document, we define and provide a specification for our implementation of CosmWasm.