From e8b47b6049584201de0fcf23ad6e758842f3bbf6 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Wed, 29 May 2024 12:59:02 +0200 Subject: [PATCH 1/6] piecrust: metadata support for free hint and price hint --- contracts/metadata/src/lib.rs | 22 ++++++ piecrust/CHANGELOG.md | 2 + piecrust/src/contract.rs | 24 +++++++ piecrust/src/imports.rs | 79 +++++++++++++++++--- piecrust/src/imports/wasm32.rs | 14 ++++ piecrust/src/imports/wasm64.rs | 14 ++++ piecrust/src/session.rs | 14 +++- piecrust/src/store/session.rs | 2 + piecrust/tests/metadata.rs | 128 +++++++++++++++++++++++++++++++++ 9 files changed, 288 insertions(+), 11 deletions(-) diff --git a/contracts/metadata/src/lib.rs b/contracts/metadata/src/lib.rs index 162dfcb4..0b35b2a2 100644 --- a/contracts/metadata/src/lib.rs +++ b/contracts/metadata/src/lib.rs @@ -32,6 +32,16 @@ impl Metadata { pub fn read_owner_of(&self, id: ContractId) -> Option<[u8; 33]> { uplink::owner(id) } + + /// Read the value of the given contract's free limit + pub fn read_free_limit_of(&self, id: ContractId) -> Option { + uplink::free_limit(id) + } + + /// Read the value of the given contract's free price hint + pub fn read_free_price_hint_of(&self, id: ContractId) -> Option<(u64, u64)> { + uplink::free_price_hint(id) + } } /// Expose `Metadata::read_owner()` to the host @@ -51,3 +61,15 @@ unsafe fn read_id(arg_len: u32) -> u32 { unsafe fn read_owner_of(arg_len: u32) -> u32 { uplink::wrap_call(arg_len, |id| STATE.read_owner_of(id)) } + +/// Expose `Metadata::read_free_limit_of()` to the host +#[no_mangle] +unsafe fn read_free_limit_of(arg_len: u32) -> u32 { + uplink::wrap_call(arg_len, |id| STATE.read_free_limit_of(id)) +} + +/// Expose `Metadata::read_free_price_hint_of()` to the host +#[no_mangle] +unsafe fn read_free_price_hint_of(arg_len: u32) -> u32 { + uplink::wrap_call(arg_len, |id| STATE.read_free_price_hint_of(id)) +} diff --git a/piecrust/CHANGELOG.md b/piecrust/CHANGELOG.md index 79900196..6c7a70d1 100644 --- a/piecrust/CHANGELOG.md +++ b/piecrust/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Apply charging mechanism for host queries [#359] - Add `HostQuery::execute` and `HostQuery::deserialize_and_price` [#359] +- Add support for metadata elements: free limit and free price hint [#357] ## Changed @@ -425,6 +426,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#359]: https://github.com/dusk-network/piecrust/issues/359 +[#357]: https://github.com/dusk-network/piecrust/issues/357 [#353]: https://github.com/dusk-network/piecrust/issues/353 [#350]: https://github.com/dusk-network/piecrust/issues/350 [#347]: https://github.com/dusk-network/piecrust/issues/347 diff --git a/piecrust/src/contract.rs b/piecrust/src/contract.rs index ab7d4824..49306bdc 100644 --- a/piecrust/src/contract.rs +++ b/piecrust/src/contract.rs @@ -17,6 +17,8 @@ pub struct ContractData<'a, A> { pub(crate) contract_id: Option, pub(crate) constructor_arg: Option<&'a A>, pub(crate) owner: Option>, + pub(crate) free_limit: Option, + pub(crate) free_price_hint: Option<(u64, u64)>, } // `()` is done on purpose, since by default it should be that the constructor @@ -31,6 +33,8 @@ impl<'a> ContractData<'a, ()> { contract_id: None, constructor_arg: None, owner: None, + free_limit: None, + free_price_hint: None, } } } @@ -45,6 +49,8 @@ pub struct ContractDataBuilder<'a, A> { contract_id: Option, owner: Option>, constructor_arg: Option<&'a A>, + free_limit: Option, + free_price_hint: Option<(u64, u64)>, } impl<'a, A> ContractDataBuilder<'a, A> { @@ -60,6 +66,8 @@ impl<'a, A> ContractDataBuilder<'a, A> { contract_id: self.contract_id, owner: self.owner, constructor_arg: Some(arg), + free_limit: self.free_limit, + free_price_hint: self.free_price_hint, } } @@ -69,11 +77,25 @@ impl<'a, A> ContractDataBuilder<'a, A> { self } + /// Set the gas limit for the the free execution of contract's methods. + pub fn free_limit(mut self, free_limit: u64) -> Self { + self.free_limit = Some(free_limit); + self + } + + /// Set the gas price hint for the the free execution of contract's methods. + pub fn free_price_hint(mut self, price_hint: (u64, u64)) -> Self { + self.free_price_hint = Some(price_hint); + self + } + pub fn build(self) -> ContractData<'a, A> { ContractData { contract_id: self.contract_id, constructor_arg: self.constructor_arg, owner: self.owner, + free_limit: self.free_limit, + free_price_hint: self.free_price_hint, } } } @@ -83,6 +105,8 @@ impl<'a, A> ContractDataBuilder<'a, A> { pub struct ContractMetadata { pub contract_id: ContractId, pub owner: Vec, + pub free_limit: Option, + pub free_price_hint: Option<(u64, u64)>, } #[derive(Clone)] diff --git a/piecrust/src/imports.rs b/piecrust/src/imports.rs index c9574af4..8cc3bd62 100644 --- a/piecrust/src/imports.rs +++ b/piecrust/src/imports.rs @@ -10,6 +10,7 @@ mod wasm64; use std::any::Any; use std::sync::Arc; +use crate::contract::ContractMetadata; use dusk_wasmtime::{ Caller, Extern, Func, Module, Result as WasmtimeResult, Store, }; @@ -78,6 +79,14 @@ impl Imports { false => Func::wrap(store, wasm32::owner), true => Func::wrap(store, wasm64::owner), }, + "free_limit" => match is_64 { + false => Func::wrap(store, wasm32::free_limit), + true => Func::wrap(store, wasm64::free_limit), + }, + "free_price_hint" => match is_64 { + false => Func::wrap(store, wasm32::free_price_hint), + true => Func::wrap(store, wasm64::free_price_hint), + }, "self_id" => Func::wrap(store, self_id), #[cfg(feature = "debug")] "hdebug" => Func::wrap(store, hdebug), @@ -426,14 +435,10 @@ fn panic(fenv: Caller, arg_len: u32) -> WasmtimeResult<()> { })?) } -fn owner(fenv: Caller, mod_id_ofs: usize) -> WasmtimeResult { - check_ptr(fenv.data().self_instance(), mod_id_ofs, CONTRACT_ID_BYTES)?; - - let env = fenv.data(); - +fn get_metadata(env: &mut Env, mod_id_ofs: usize) -> Option<&ContractMetadata> { // The null pointer is always zero, so we can use this to check if the // caller wants their own ID. - let metadata = if mod_id_ofs == 0 { + if mod_id_ofs == 0 { let self_id = env.self_contract_id(); let contract_metadata = env @@ -452,15 +457,24 @@ fn owner(fenv: Caller, mod_id_ofs: usize) -> WasmtimeResult { mod_id }); + if env.instance(&mod_id).is_none() { + let _ = env.create_instance(mod_id); + } + env.contract_metadata(&mod_id) - }; + } +} - match metadata { +fn owner(mut fenv: Caller, mod_id_ofs: usize) -> WasmtimeResult { + let instance = fenv.data().self_instance(); + check_ptr(instance, mod_id_ofs, CONTRACT_ID_BYTES)?; + let env = fenv.data_mut(); + match get_metadata(env, mod_id_ofs) { None => Ok(0), Some(metadata) => { let owner = metadata.owner.as_slice(); - env.self_instance().with_arg_buf_mut(|arg| { + instance.with_arg_buf_mut(|arg| { arg[..owner.len()].copy_from_slice(owner) }); @@ -469,6 +483,53 @@ fn owner(fenv: Caller, mod_id_ofs: usize) -> WasmtimeResult { } } +fn free_limit(mut fenv: Caller, mod_id_ofs: usize) -> WasmtimeResult { + let instance = fenv.data().self_instance(); + check_ptr(instance, mod_id_ofs, CONTRACT_ID_BYTES)?; + let env = fenv.data_mut(); + match get_metadata(env, mod_id_ofs) { + None => Ok(0), + Some(metadata) => { + let free_limit = metadata.free_limit; + + let len = instance.with_arg_buf_mut(|arg| { + let vec = rkyv::to_bytes::<_, 8>(&free_limit) + .expect("Serialization should succeed"); + let slice = vec.as_slice(); + arg[..slice.len()].copy_from_slice(slice); + slice.len() + }); + + Ok(len as i32) + } + } +} + +fn free_price_hint( + mut fenv: Caller, + mod_id_ofs: usize, +) -> WasmtimeResult { + let instance = fenv.data().self_instance(); + check_ptr(instance, mod_id_ofs, CONTRACT_ID_BYTES)?; + let env = fenv.data_mut(); + match get_metadata(env, mod_id_ofs) { + None => Ok(0), + Some(metadata) => { + let free_price_hint = metadata.free_price_hint; + + let len = instance.with_arg_buf_mut(|arg| { + let vec = rkyv::to_bytes::<_, 16>(&free_price_hint) + .expect("Serialization should succeed"); + let slice = vec.as_slice(); + arg[..slice.len()].copy_from_slice(slice); + slice.len() + }); + + Ok(len as i32) + } + } +} + fn self_id(fenv: Caller) { let env = fenv.data(); let self_id = env.self_contract_id(); diff --git a/piecrust/src/imports/wasm32.rs b/piecrust/src/imports/wasm32.rs index 4963f461..98f22d4b 100644 --- a/piecrust/src/imports/wasm32.rs +++ b/piecrust/src/imports/wasm32.rs @@ -56,3 +56,17 @@ pub(crate) fn emit( pub(crate) fn owner(fenv: Caller, mod_id_ofs: u32) -> WasmtimeResult { imports::owner(fenv, mod_id_ofs as usize) } + +pub(crate) fn free_limit( + fenv: Caller, + mod_id_ofs: u32, +) -> WasmtimeResult { + imports::free_limit(fenv, mod_id_ofs as usize) +} + +pub(crate) fn free_price_hint( + fenv: Caller, + mod_id_ofs: u32, +) -> WasmtimeResult { + imports::free_price_hint(fenv, mod_id_ofs as usize) +} diff --git a/piecrust/src/imports/wasm64.rs b/piecrust/src/imports/wasm64.rs index 06f729db..76ea610e 100644 --- a/piecrust/src/imports/wasm64.rs +++ b/piecrust/src/imports/wasm64.rs @@ -56,3 +56,17 @@ pub(crate) fn emit( pub(crate) fn owner(fenv: Caller, mod_id_ofs: u64) -> WasmtimeResult { imports::owner(fenv, mod_id_ofs as usize) } + +pub(crate) fn free_limit( + fenv: Caller, + mod_id_ofs: u64, +) -> WasmtimeResult { + imports::free_limit(fenv, mod_id_ofs as usize) +} + +pub(crate) fn free_price_hint( + fenv: Caller, + mod_id_ofs: u64, +) -> WasmtimeResult { + imports::free_price_hint(fenv, mod_id_ofs as usize) +} diff --git a/piecrust/src/session.rs b/piecrust/src/session.rs index 1b381b35..0cd33f5c 100644 --- a/piecrust/src/session.rs +++ b/piecrust/src/session.rs @@ -257,11 +257,14 @@ impl Session { .owner .expect("Owner must be specified when deploying a contract"), gas_limit, + deploy_data.free_limit, + deploy_data.free_price_hint, )?; Ok(contract_id) } + #[allow(clippy::too_many_arguments)] fn do_deploy( &mut self, contract_id: ContractId, @@ -269,6 +272,8 @@ impl Session { arg: Option>, owner: Vec, gas_limit: u64, + free_limit: Option, + free_price_hint: Option<(u64, u64)>, ) -> Result<(), Error> { if self.inner.contract_session.contract_deployed(contract_id) { return Err(InitalizationError( @@ -278,7 +283,12 @@ impl Session { let wrapped_contract = WrappedContract::new(&self.engine, bytecode, None::<&[u8]>)?; - let contract_metadata = ContractMetadata { contract_id, owner }; + let contract_metadata = ContractMetadata { + contract_id, + owner, + free_limit, + free_price_hint, + }; let metadata_bytes = Self::serialize_data(&contract_metadata)?; self.inner @@ -622,7 +632,7 @@ impl Session { /// Creates a new instance of the given contract, returning its memory /// length. - fn create_instance( + pub(crate) fn create_instance( &mut self, contract: ContractId, ) -> Result { diff --git a/piecrust/src/store/session.rs b/piecrust/src/store/session.rs index 88716184..b484d512 100644 --- a/piecrust/src/store/session.rs +++ b/piecrust/src/store/session.rs @@ -327,6 +327,8 @@ impl ContractSession { new_contract_data.metadata.set_data(ContractMetadata { contract_id: old_contract, owner: new_contract_data.metadata.data().owner.clone(), + free_limit: new_contract_data.metadata.data().free_limit, + free_price_hint: new_contract_data.metadata.data().free_price_hint, })?; self.contracts.insert(old_contract, new_contract_data); diff --git a/piecrust/tests/metadata.rs b/piecrust/tests/metadata.rs index 1c70e02b..2b33f44a 100644 --- a/piecrust/tests/metadata.rs +++ b/piecrust/tests/metadata.rs @@ -123,3 +123,131 @@ fn owner_of() -> Result<(), Error> { Ok(()) } + +#[test] +fn free_limit_and_price_hint_of() -> Result<(), Error> { + const OWNER_0: [u8; 33] = [3u8; 33]; + const OWNER_1: [u8; 33] = [4u8; 33]; + + const EXPECTED_FREE_LIMIT_0: u64 = 10_000_000; + const EXPECTED_FREE_LIMIT_1: u64 = 20_000_000; + const EXPECTED_FREE_PRICE_HINT_0: (u64, u64) = (2, 1); + const EXPECTED_FREE_PRICE_HINT_1: (u64, u64) = (3, 1); + + const CONTRACT_ID_0: ContractId = ContractId::from_bytes([1; 32]); + const CONTRACT_ID_1: ContractId = ContractId::from_bytes([2; 32]); + const CONTRACT_ID_2: ContractId = ContractId::from_bytes([3; 32]); + + let vm = VM::ephemeral()?; + + let mut session = vm.session(SessionData::builder())?; + + session.deploy( + contract_bytecode!("metadata"), + ContractData::builder() + .owner(OWNER_0) + .contract_id(CONTRACT_ID_0) + .free_limit(EXPECTED_FREE_LIMIT_0) + .free_price_hint(EXPECTED_FREE_PRICE_HINT_0), + LIMIT, + )?; + session.deploy( + contract_bytecode!("metadata"), + ContractData::builder() + .owner(OWNER_1) + .contract_id(CONTRACT_ID_1) + .free_limit(EXPECTED_FREE_LIMIT_1) + .free_price_hint(EXPECTED_FREE_PRICE_HINT_1), + LIMIT, + )?; + + let free_limit = session + .call::<_, Option>( + CONTRACT_ID_0, + "read_free_limit_of", + &CONTRACT_ID_1, + LIMIT, + )? + .data; + + assert_eq!( + free_limit, + Some(EXPECTED_FREE_LIMIT_1), + "contract 0 should think that contract 1 has the correct free limit" + ); + + let free_limit = session + .call::<_, Option>( + CONTRACT_ID_1, + "read_free_limit_of", + &CONTRACT_ID_0, + LIMIT, + )? + .data; + + assert_eq!( + free_limit, + Some(EXPECTED_FREE_LIMIT_0), + "contract 1 should think that contract 0 has the correct free limit" + ); + + let free_limit = session + .call::<_, Option>( + CONTRACT_ID_0, + "read_free_limit_of", + &CONTRACT_ID_2, + LIMIT, + )? + .data; + + assert_eq!( + free_limit, + None, + "contract 0 should think that the free_limit of a non-existing contract is None" ); + + let free_price_hint = session + .call::<_, Option<(u64, u64)>>( + CONTRACT_ID_0, + "read_free_price_hint_of", + &CONTRACT_ID_1, + LIMIT, + )? + .data; + + assert_eq!( + free_price_hint, + Some(EXPECTED_FREE_PRICE_HINT_1), + "contract 0 should think that contract 1 has the correct free price hint" ); + + let free_price_hint = session + .call::<_, Option<(u64, u64)>>( + CONTRACT_ID_1, + "read_free_price_hint_of", + &CONTRACT_ID_0, + LIMIT, + )? + .data; + + assert_eq!( + free_price_hint, + Some(EXPECTED_FREE_PRICE_HINT_0), + "contract 1 should think that contract 0 has the correct free price + hint" + ); + + let free_price_hint = session + .call::<_, Option<(u64, u64)>>( + CONTRACT_ID_0, + "read_free_price_hint_of", + &CONTRACT_ID_2, + LIMIT, + )? + .data; + + assert_eq!( + free_price_hint, + None, + "contract 0 should think that the free price hint of a non-existing contract is none" ); + + Ok(()) +} From ce772d8a1ca39fdb48e9e628d94f8694d0d51a9c Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Wed, 29 May 2024 12:59:37 +0200 Subject: [PATCH 2/6] uplink: metadata support for free hint and price hint --- piecrust-uplink/CHANGELOG.md | 2 ++ piecrust-uplink/src/abi/state.rs | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/piecrust-uplink/CHANGELOG.md b/piecrust-uplink/CHANGELOG.md index b951a591..c4a11650 100644 --- a/piecrust-uplink/CHANGELOG.md +++ b/piecrust-uplink/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Add support for metadata elements: free limit and free price hint [#357] - Add contract charge setting method [#353] - Add contract allowance setting method and a corresponding passing mechanism [#350] @@ -169,6 +170,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - First `piecrust-uplink` release +[#357]: https://github.com/dusk-network/piecrust/issues/357 [#353]: https://github.com/dusk-network/piecrust/issues/353 [#350]: https://github.com/dusk-network/piecrust/issues/350 [#324]: https://github.com/dusk-network/piecrust/issues/324 diff --git a/piecrust-uplink/src/abi/state.rs b/piecrust-uplink/src/abi/state.rs index b1a76616..46896dec 100644 --- a/piecrust-uplink/src/abi/state.rs +++ b/piecrust-uplink/src/abi/state.rs @@ -76,6 +76,8 @@ mod ext { pub fn limit() -> u64; pub fn spent() -> u64; pub fn owner(contract_id: *const u8) -> i32; + pub fn free_limit(contract_id: *const u8) -> i32; + pub fn free_price_hint(contract_id: *const u8) -> i32; pub fn self_id(); } } @@ -292,6 +294,37 @@ pub fn owner(contract: ContractId) -> Option<[u8; N]> { } } +/// Returns given contract's free limit, if the contract exists and if it +/// has a free limit set. +pub fn free_limit(contract: ContractId) -> Option { + let contract_id_ptr = contract.as_bytes().as_ptr(); + unsafe { + match ext::free_limit(contract_id_ptr) as usize { + 0 => None, + arg_pos => with_arg_buf(|buf, _| { + let ret = archived_root::>(&buf[..arg_pos]); + ret.deserialize(&mut Infallible).expect("Infallible") + }), + } + } +} + +/// Returns given contract's free gas price hint, if the contract exists and +/// if it has a free price hint set. +pub fn free_price_hint(contract: ContractId) -> Option<(u64, u64)> { + let contract_id_ptr = contract.as_bytes().as_ptr(); + + unsafe { + match ext::free_price_hint(contract_id_ptr) as usize { + 0 => None, + arg_pos => with_arg_buf(|buf, _| { + let ret = archived_root::>(&buf[..arg_pos]); + ret.deserialize(&mut Infallible).expect("Infallible") + }), + } + } +} + /// Returns the current contract's owner. pub fn self_owner() -> [u8; N] { unsafe { ext::owner(ptr::null()) }; From a36937f6ecea069377a0eb00b2d1533ed11642f8 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Fri, 31 May 2024 12:10:30 +0200 Subject: [PATCH 3/6] uplink: serializing free limit and gas hint w/o rkyv --- piecrust-uplink/src/abi/state.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/piecrust-uplink/src/abi/state.rs b/piecrust-uplink/src/abi/state.rs index 46896dec..746eb729 100644 --- a/piecrust-uplink/src/abi/state.rs +++ b/piecrust-uplink/src/abi/state.rs @@ -18,6 +18,8 @@ use crate::{ CONTRACT_ID_BYTES, ECO_MODE_BUF_LEN, ECO_MODE_LEN, SCRATCH_BUF_BYTES, }; +const LEN_U64: usize = core::mem::size_of::(); + pub mod arg_buf { use crate::{EconomicMode, ARGBUF_LEN, ECO_MODE_BUF_LEN, ECO_MODE_LEN}; use core::ptr; @@ -301,9 +303,14 @@ pub fn free_limit(contract: ContractId) -> Option { unsafe { match ext::free_limit(contract_id_ptr) as usize { 0 => None, - arg_pos => with_arg_buf(|buf, _| { - let ret = archived_root::>(&buf[..arg_pos]); - ret.deserialize(&mut Infallible).expect("Infallible") + _ => with_arg_buf(|buf, _| { + if buf[0] == 0 { + None + } else { + let mut value_bytes = [0; LEN_U64]; + value_bytes.copy_from_slice(&buf[1..LEN_U64 + 1]); + Some(u64::from_le_bytes(value_bytes)) + } }), } } @@ -317,9 +324,18 @@ pub fn free_price_hint(contract: ContractId) -> Option<(u64, u64)> { unsafe { match ext::free_price_hint(contract_id_ptr) as usize { 0 => None, - arg_pos => with_arg_buf(|buf, _| { - let ret = archived_root::>(&buf[..arg_pos]); - ret.deserialize(&mut Infallible).expect("Infallible") + _ => with_arg_buf(|buf, _| { + if buf[0] == 0 { + None + } else { + let mut value_bytes = [0; LEN_U64]; + value_bytes.copy_from_slice(&buf[1..LEN_U64 + 1]); + let num = u64::from_le_bytes(value_bytes); + value_bytes + .copy_from_slice(&buf[LEN_U64 + 1..LEN_U64 * 2 + 1]); + let denom = u64::from_le_bytes(value_bytes); + Some((num, denom)) + } }), } } From 38d31adffb993030f898e3ad8d7491ffcc68eb11 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Fri, 31 May 2024 12:10:47 +0200 Subject: [PATCH 4/6] piecrust: serializing free limit and gas hint w/o rkyv --- piecrust/src/imports.rs | 42 +++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/piecrust/src/imports.rs b/piecrust/src/imports.rs index 8cc3bd62..30cd6863 100644 --- a/piecrust/src/imports.rs +++ b/piecrust/src/imports.rs @@ -24,6 +24,8 @@ use crate::Error; pub const GAS_PASS_PCT: u64 = 93; +const LEN_U64: usize = core::mem::size_of::(); + pub(crate) struct Imports; impl Imports { @@ -490,14 +492,19 @@ fn free_limit(mut fenv: Caller, mod_id_ofs: usize) -> WasmtimeResult { match get_metadata(env, mod_id_ofs) { None => Ok(0), Some(metadata) => { - let free_limit = metadata.free_limit; - let len = instance.with_arg_buf_mut(|arg| { - let vec = rkyv::to_bytes::<_, 8>(&free_limit) - .expect("Serialization should succeed"); - let slice = vec.as_slice(); - arg[..slice.len()].copy_from_slice(slice); - slice.len() + match metadata.free_limit { + Some(free_limit) => { + arg[0] = 1; + arg[1..LEN_U64 + 1] + .copy_from_slice(&free_limit.to_le_bytes()[..]); + } + _ => { + arg[0] = 0; + arg[1..LEN_U64 + 1].fill(0); + } + } + LEN_U64 + 1 }); Ok(len as i32) @@ -515,14 +522,21 @@ fn free_price_hint( match get_metadata(env, mod_id_ofs) { None => Ok(0), Some(metadata) => { - let free_price_hint = metadata.free_price_hint; - let len = instance.with_arg_buf_mut(|arg| { - let vec = rkyv::to_bytes::<_, 16>(&free_price_hint) - .expect("Serialization should succeed"); - let slice = vec.as_slice(); - arg[..slice.len()].copy_from_slice(slice); - slice.len() + match metadata.free_price_hint { + Some((num, denom)) => { + arg[0] = 1; + arg[1..LEN_U64 + 1] + .copy_from_slice(&num.to_le_bytes()[..]); + arg[LEN_U64 + 1..LEN_U64 * 2 + 1] + .copy_from_slice(&denom.to_le_bytes()[..]); + } + _ => { + arg[0] = 0; + arg[1..LEN_U64 * 2 + 1].fill(0); + } + } + LEN_U64 * 2 + 1 }); Ok(len as i32) From 9434ccc3d51f3c7b8a57ce073f0024c776d29325 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Mon, 3 Jun 2024 12:40:20 +0200 Subject: [PATCH 5/6] uplink: removed superfluous casts --- piecrust-uplink/src/abi/state.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/piecrust-uplink/src/abi/state.rs b/piecrust-uplink/src/abi/state.rs index 746eb729..bd9b0f2e 100644 --- a/piecrust-uplink/src/abi/state.rs +++ b/piecrust-uplink/src/abi/state.rs @@ -301,7 +301,7 @@ pub fn owner(contract: ContractId) -> Option<[u8; N]> { pub fn free_limit(contract: ContractId) -> Option { let contract_id_ptr = contract.as_bytes().as_ptr(); unsafe { - match ext::free_limit(contract_id_ptr) as usize { + match ext::free_limit(contract_id_ptr) { 0 => None, _ => with_arg_buf(|buf, _| { if buf[0] == 0 { @@ -322,7 +322,7 @@ pub fn free_price_hint(contract: ContractId) -> Option<(u64, u64)> { let contract_id_ptr = contract.as_bytes().as_ptr(); unsafe { - match ext::free_price_hint(contract_id_ptr) as usize { + match ext::free_price_hint(contract_id_ptr) { 0 => None, _ => with_arg_buf(|buf, _| { if buf[0] == 0 { From 76e0917c7c26e8e14fe64557202e5d210d9f1872 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Mon, 3 Jun 2024 12:41:13 +0200 Subject: [PATCH 6/6] piecrust: pre-loading metadata on demand --- piecrust/src/imports.rs | 20 ++++++++------------ piecrust/src/session.rs | 2 +- piecrust/src/store/session.rs | 3 ++- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/piecrust/src/imports.rs b/piecrust/src/imports.rs index 30cd6863..575a37d1 100644 --- a/piecrust/src/imports.rs +++ b/piecrust/src/imports.rs @@ -441,10 +441,10 @@ fn get_metadata(env: &mut Env, mod_id_ofs: usize) -> Option<&ContractMetadata> { // The null pointer is always zero, so we can use this to check if the // caller wants their own ID. if mod_id_ofs == 0 { - let self_id = env.self_contract_id(); + let self_id = env.self_contract_id().to_owned(); let contract_metadata = env - .contract_metadata(self_id) + .contract_metadata(&self_id) .expect("contract metadata should exist"); Some(contract_metadata) @@ -459,10 +459,6 @@ fn get_metadata(env: &mut Env, mod_id_ofs: usize) -> Option<&ContractMetadata> { mod_id }); - if env.instance(&mod_id).is_none() { - let _ = env.create_instance(mod_id); - } - env.contract_metadata(&mod_id) } } @@ -544,14 +540,14 @@ fn free_price_hint( } } -fn self_id(fenv: Caller) { - let env = fenv.data(); - let self_id = env.self_contract_id(); +fn self_id(mut fenv: Caller) { + let env = fenv.data_mut(); + let self_id = env.self_contract_id().to_owned(); let contract_metadata = env - .contract_metadata(self_id) + .contract_metadata(&self_id) .expect("contract metadata should exist"); - let slice = contract_metadata.contract_id.as_bytes(); + let slice = contract_metadata.contract_id.to_bytes(); let len = slice.len(); env.self_instance() - .with_arg_buf_mut(|arg| arg[..len].copy_from_slice(slice)); + .with_arg_buf_mut(|arg| arg[..len].copy_from_slice(&slice)); } diff --git a/piecrust/src/session.rs b/piecrust/src/session.rs index 0cd33f5c..5551e305 100644 --- a/piecrust/src/session.rs +++ b/piecrust/src/session.rs @@ -811,7 +811,7 @@ impl Session { } pub fn contract_metadata( - &self, + &mut self, contract_id: &ContractId, ) -> Option<&ContractMetadata> { self.inner.contract_session.contract_metadata(contract_id) diff --git a/piecrust/src/store/session.rs b/piecrust/src/store/session.rs index b484d512..5c454b2d 100644 --- a/piecrust/src/store/session.rs +++ b/piecrust/src/store/session.rs @@ -338,9 +338,10 @@ impl ContractSession { /// Provides metadata of the contract with a given `contract_id`. pub fn contract_metadata( - &self, + &mut self, contract_id: &ContractId, ) -> Option<&ContractMetadata> { + let _ = self.contract(*contract_id); self.contracts .get(contract_id) .map(|store_data| store_data.metadata.data())