Skip to content

Commit 648f68d

Browse files
author
Eduardo Leegwater Simões
authored
Merge pull request #338 from dusk-network/empty-argument-ctor-316
piecrust: allow passing no argument when constructor exist
2 parents 9113a27 + 0dc4c06 commit 648f68d

File tree

6 files changed

+89
-24
lines changed

6 files changed

+89
-24
lines changed

contracts/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ members = [
77
"counter",
88
"debugger",
99
"double_counter",
10+
"empty_constructor",
1011
"eventer",
1112
"everest",
1213
"fallible_counter",
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "empty_constructor"
3+
version = "0.1.0"
4+
authors = [
5+
"Eduardo Leegwater Simões <[email protected]>",
6+
]
7+
edition = "2021"
8+
9+
license = "MPL-2.0"
10+
11+
[dependencies]
12+
piecrust-uplink = { path = "../../piecrust-uplink", features = ["abi", "dlmalloc"] }
13+
14+
[lib]
15+
crate-type = ["cdylib", "rlib"]
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
//
5+
// Copyright (c) DUSK NETWORK. All rights reserved.
6+
7+
//! Contract that provides and example use of the constructor.
8+
9+
#![no_std]
10+
11+
use piecrust_uplink as uplink;
12+
13+
/// Struct that describes the state of the Constructor contract
14+
pub struct EmptyConstructor {
15+
value: u8,
16+
}
17+
18+
impl EmptyConstructor {
19+
pub fn init(&mut self) {
20+
self.value = 0x10;
21+
}
22+
}
23+
24+
/// State of the EmptyConstructor contract
25+
static mut STATE: EmptyConstructor = EmptyConstructor { value: 0x00 };
26+
27+
impl EmptyConstructor {
28+
/// Read the value of the constructor contract state
29+
pub fn read_value(&self) -> u8 {
30+
self.value
31+
}
32+
33+
/// Increment the value by 1
34+
pub fn increment(&mut self) {
35+
let value = self.value + 1;
36+
self.value = value;
37+
}
38+
}
39+
40+
/// Expose `EmptyConstructor::read_value()` to the host
41+
#[no_mangle]
42+
unsafe fn read_value(arg_len: u32) -> u32 {
43+
uplink::wrap_call(arg_len, |_: ()| STATE.read_value())
44+
}
45+
46+
/// Expose `EmptyConstructor::increment()` to the host
47+
#[no_mangle]
48+
unsafe fn increment(arg_len: u32) -> u32 {
49+
uplink::wrap_call(arg_len, |_: ()| STATE.increment())
50+
}
51+
52+
/// Expose `EmptyConstructor::init()` to the host
53+
#[no_mangle]
54+
unsafe fn init(arg_len: u32) -> u32 {
55+
uplink::wrap_call(arg_len, |()| STATE.init())
56+
}

piecrust/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Changed
1111

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

1415
## [0.16.0] - 2024-02-14
@@ -366,6 +367,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
366367
<!-- ISSUES -->
367368
[#325]: https://github.com/dusk-network/piecrust/issues/325
368369
[#324]: https://github.com/dusk-network/piecrust/issues/324
370+
[#316]: https://github.com/dusk-network/piecrust/issues/316
369371
[#301]: https://github.com/dusk-network/piecrust/issues/313
370372
[#301]: https://github.com/dusk-network/piecrust/issues/301
371373
[#296]: https://github.com/dusk-network/piecrust/issues/296

piecrust/src/session.rs

+7-16
Original file line numberDiff line numberDiff line change
@@ -289,22 +289,13 @@ impl Session {
289289
let instance =
290290
self.instance(&contract_id).expect("instance should exist");
291291

292-
let has_init = instance.is_function_exported(INIT_METHOD);
293-
if has_init && arg.is_none() {
294-
return Err(InitalizationError(
295-
"Contract has constructor but no argument was provided"
296-
.into(),
297-
));
298-
}
299-
300-
if let Some(arg) = arg {
301-
if !has_init {
302-
return Err(InitalizationError(
303-
"Argument was provided but contract has no constructor"
304-
.into(),
305-
));
306-
}
307-
292+
if instance.is_function_exported(INIT_METHOD) {
293+
// If no argument was provided, we call the constructor anyway,
294+
// but with an empty argument. The alternative is to panic, but
295+
// that assumes that the caller of `deploy` knows that the
296+
// contract has a constructor in the first place, which might
297+
// not be the case, such as when ingesting untrusted bytecode.
298+
let arg = arg.unwrap_or_default();
308299
self.call_inner(contract_id, INIT_METHOD, arg, gas_limit)?;
309300
}
310301

piecrust/tests/constructor.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,20 @@ fn constructor() -> Result<(), Error> {
7373
}
7474

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

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

81-
let result = session.deploy(
82-
contract_bytecode!("counter"),
83-
ContractData::builder(OWNER).constructor_arg(&0xabu8),
81+
let id = session.deploy(
82+
contract_bytecode!("empty_constructor"),
83+
ContractData::builder(OWNER),
8484
LIMIT,
85-
);
85+
)?;
8686

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

9292
Ok(())

0 commit comments

Comments
 (0)