Skip to content

Commit

Permalink
Merge pull request #338 from dusk-network/empty-argument-ctor-316
Browse files Browse the repository at this point in the history
piecrust: allow passing no argument when constructor exist
  • Loading branch information
Eduardo Leegwater Simões authored Feb 22, 2024
2 parents 9113a27 + 0dc4c06 commit 648f68d
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 24 deletions.
1 change: 1 addition & 0 deletions contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"counter",
"debugger",
"double_counter",
"empty_constructor",
"eventer",
"everest",
"fallible_counter",
Expand Down
15 changes: 15 additions & 0 deletions contracts/empty_constructor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "empty_constructor"
version = "0.1.0"
authors = [
"Eduardo Leegwater Simões <[email protected]>",
]
edition = "2021"

license = "MPL-2.0"

[dependencies]
piecrust-uplink = { path = "../../piecrust-uplink", features = ["abi", "dlmalloc"] }

[lib]
crate-type = ["cdylib", "rlib"]
56 changes: 56 additions & 0 deletions contracts/empty_constructor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) DUSK NETWORK. All rights reserved.

//! Contract that provides and example use of the constructor.
#![no_std]

use piecrust_uplink as uplink;

/// Struct that describes the state of the Constructor contract
pub struct EmptyConstructor {
value: u8,
}

impl EmptyConstructor {
pub fn init(&mut self) {
self.value = 0x10;
}
}

/// State of the EmptyConstructor contract
static mut STATE: EmptyConstructor = EmptyConstructor { value: 0x00 };

impl EmptyConstructor {
/// Read the value of the constructor contract state
pub fn read_value(&self) -> u8 {
self.value
}

/// Increment the value by 1
pub fn increment(&mut self) {
let value = self.value + 1;
self.value = value;
}
}

/// Expose `EmptyConstructor::read_value()` to the host
#[no_mangle]
unsafe fn read_value(arg_len: u32) -> u32 {
uplink::wrap_call(arg_len, |_: ()| STATE.read_value())
}

/// Expose `EmptyConstructor::increment()` to the host
#[no_mangle]
unsafe fn increment(arg_len: u32) -> u32 {
uplink::wrap_call(arg_len, |_: ()| STATE.increment())
}

/// Expose `EmptyConstructor::init()` to the host
#[no_mangle]
unsafe fn init(arg_len: u32) -> u32 {
uplink::wrap_call(arg_len, |()| STATE.init())
}
2 changes: 2 additions & 0 deletions piecrust/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Use empty constructor arguments by default [#316]
- Upgrade `dusk-wasmtime` to version `18`

## [0.16.0] - 2024-02-14
Expand Down Expand Up @@ -366,6 +367,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- ISSUES -->
[#325]: https://github.com/dusk-network/piecrust/issues/325
[#324]: https://github.com/dusk-network/piecrust/issues/324
[#316]: https://github.com/dusk-network/piecrust/issues/316
[#301]: https://github.com/dusk-network/piecrust/issues/313
[#301]: https://github.com/dusk-network/piecrust/issues/301
[#296]: https://github.com/dusk-network/piecrust/issues/296
Expand Down
23 changes: 7 additions & 16 deletions piecrust/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,22 +289,13 @@ impl Session {
let instance =
self.instance(&contract_id).expect("instance should exist");

let has_init = instance.is_function_exported(INIT_METHOD);
if has_init && arg.is_none() {
return Err(InitalizationError(
"Contract has constructor but no argument was provided"
.into(),
));
}

if let Some(arg) = arg {
if !has_init {
return Err(InitalizationError(
"Argument was provided but contract has no constructor"
.into(),
));
}

if instance.is_function_exported(INIT_METHOD) {
// If no argument was provided, we call the constructor anyway,
// but with an empty argument. The alternative is to panic, but
// that assumes that the caller of `deploy` knows that the
// contract has a constructor in the first place, which might
// not be the case, such as when ingesting untrusted bytecode.
let arg = arg.unwrap_or_default();
self.call_inner(contract_id, INIT_METHOD, arg, gas_limit)?;
}

Expand Down
16 changes: 8 additions & 8 deletions piecrust/tests/constructor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,20 @@ fn constructor() -> Result<(), Error> {
}

#[test]
fn missing_init() -> Result<(), Error> {
fn empty_constructor_argument() -> Result<(), Error> {
let vm = VM::ephemeral()?;

let mut session = vm.session(SessionData::builder())?;

let result = session.deploy(
contract_bytecode!("counter"),
ContractData::builder(OWNER).constructor_arg(&0xabu8),
let id = session.deploy(
contract_bytecode!("empty_constructor"),
ContractData::builder(OWNER),
LIMIT,
);
)?;

assert!(
result.is_err(),
"deploy with data when the 'init' method is not exported should fail with an error"
assert_eq!(
session.call::<_, u8>(id, "read_value", &(), LIMIT)?.data,
0x10
);

Ok(())
Expand Down

0 comments on commit 648f68d

Please sign in to comment.