Skip to content

Commit

Permalink
piecrust: change constructor to init(ializer)
Browse files Browse the repository at this point in the history
- Add deprecation notice for constructor_arg
  • Loading branch information
Neotamandua committed Aug 22, 2024
1 parent 6ce487f commit 57e3711
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 56 deletions.
4 changes: 2 additions & 2 deletions contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ members = [
"box",
"c-example",
"callcenter",
"constructor",
"initializer",
"counter",
"debugger",
"double_counter",
"empty_constructor",
"empty_initializer",
"eventer",
"everest",
"fallible_counter",
Expand Down
3 changes: 2 additions & 1 deletion contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ This workspace contains individual contract examples. These examples demonstrate

- [Box](box/): A contract for managing a boxed i16 value with set and get operations.
- [Callcenter](callcenter/): Inter-contract call example.
- [Constructor](constructor/): Contract with a constructor.
- [Initializer](initializer/): Contract that makes use of the init method.
- [Empty Initializer](empty_initializer/): Contract that makes use of an init method without arguments.
- [Counter](counter/): Counter contract that both reads and writes state.
- [Crossover](crossover/): Bi-directional inter-contract call example.
- [Debugger](debugger/): Example of in-contract debug calls.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "empty_constructor"
name = "empty_initializer"
version = "0.1.0"
authors = [
"Eduardo Leegwater Simões <[email protected]>",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,31 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

//! Contract that provides and example use of the constructor.
//! Contract that provides an example use of the init method.
//! The init method provides a way to initialize the state of the contract and execute other logic only once at the time of deployment.
//!
//! The init method can be partially compared to the functionality of a constructor in other languages.
#![no_std]

use piecrust_uplink as uplink;

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

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

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

impl EmptyConstructor {
/// Read the value of the constructor contract state
impl EmptyInitializer {
/// Read the value of the contract state
pub fn read_value(&self) -> u8 {
self.value
}
Expand All @@ -37,19 +40,19 @@ impl EmptyConstructor {
}
}

/// Expose `EmptyConstructor::read_value()` to the host
/// Expose `EmptyInitializer::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
/// Expose `EmptyInitializer::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
/// Expose `EmptyInitializer::init()` to the host
#[no_mangle]
unsafe fn init(arg_len: u32) -> u32 {
uplink::wrap_call(arg_len, |()| STATE.init())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "constructor"
name = "initializer"
version = "0.1.0"
authors = [
"Milosz Muszynski <[email protected]>",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,31 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

//! Contract that provides and example use of the constructor.
//! Contract that provides an example use of the init method.
//! The init method provides a way to initialize the state of the contract and execute other logic only once at the time of deployment.
//!
//! The init method can be partially compared to the functionality of a constructor in other languages.
#![no_std]

use piecrust_uplink as uplink;

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

impl Constructor {
impl Initializer {
pub fn init(&mut self, value: u8) {
self.value = value;
}
}

/// State of the Constructor contract
static mut STATE: Constructor = Constructor { value: 0x50 };
/// State of the Initializer contract
static mut STATE: Initializer = Initializer { value: 0x50 };

impl Constructor {
/// Read the value of the constructor contract state
impl Initializer {
/// Read the value of the contract state
pub fn read_value(&self) -> u8 {
self.value
}
Expand All @@ -36,19 +39,19 @@ impl Constructor {
}
}

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

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

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

- Change `callee` import to return an integer
- Change `constructor_arg` to `init_arg`
- Change all references to `constructor` either to `init` or `initializer`

## [0.22.0] - 2024-07-03

Expand Down
24 changes: 16 additions & 8 deletions piecrust/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ use crate::error::Error;

pub struct ContractData<'a, A> {
pub(crate) contract_id: Option<ContractId>,
pub(crate) constructor_arg: Option<&'a A>,
pub(crate) init_arg: Option<&'a A>,
pub(crate) owner: Option<Vec<u8>>,
}

// `()` is done on purpose, since by default it should be that the constructor
// `()` is done on purpose, since by default it should be that the initializer
// takes no argument.
impl<'a> ContractData<'a, ()> {
/// Build a deploy data structure.
Expand All @@ -29,7 +29,7 @@ impl<'a> ContractData<'a, ()> {
pub fn builder() -> ContractDataBuilder<'a, ()> {
ContractDataBuilder {
contract_id: None,
constructor_arg: None,
init_arg: None,
owner: None,
}
}
Expand All @@ -44,7 +44,7 @@ impl<'a, A> From<ContractDataBuilder<'a, A>> for ContractData<'a, A> {
pub struct ContractDataBuilder<'a, A> {
contract_id: Option<ContractId>,
owner: Option<Vec<u8>>,
constructor_arg: Option<&'a A>,
init_arg: Option<&'a A>,
}

impl<'a, A> ContractDataBuilder<'a, A> {
Expand All @@ -54,15 +54,23 @@ impl<'a, A> ContractDataBuilder<'a, A> {
self
}

/// Set the constructor argument for deployment.
pub fn constructor_arg<B>(self, arg: &B) -> ContractDataBuilder<B> {
/// Set the initializer argument for deployment.
/// This is the argument that will be passed to the contract's `init`
/// function.
pub fn init_arg<B>(self, arg: &B) -> ContractDataBuilder<B> {
ContractDataBuilder {
contract_id: self.contract_id,
owner: self.owner,
constructor_arg: Some(arg),
init_arg: Some(arg),
}
}

/// Deprecated: Use `init_arg` instead.
#[deprecated(note = "Use `init_arg` instead of `constructor_arg`")]
pub fn constructor_arg<B>(self, arg: &B) -> ContractDataBuilder<B> {
self.init_arg(arg)
}

/// Set the owner of the contract.
pub fn owner(mut self, owner: impl Into<Vec<u8>>) -> Self {
self.owner = Some(owner.into());
Expand All @@ -72,7 +80,7 @@ impl<'a, A> ContractDataBuilder<'a, A> {
pub fn build(self) -> ContractData<'a, A> {
ContractData {
contract_id: self.contract_id,
constructor_arg: self.constructor_arg,
init_arg: self.init_arg,
owner: self.owner,
}
}
Expand Down
22 changes: 8 additions & 14 deletions piecrust/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,8 @@ impl Session {
{
let deploy_data = deploy_data.into();

let mut constructor_arg = None;
if let Some(arg) = deploy_data.constructor_arg {
let mut init_arg = None;
if let Some(arg) = deploy_data.init_arg {
let mut sbuf = [0u8; SCRATCH_BUF_BYTES];
let scratch = BufferScratch::new(&mut sbuf);
let ser = BufferSerializer::new(&mut self.inner.buffer[..]);
Expand All @@ -236,13 +236,13 @@ impl Session {
ser.serialize_value(arg)?;
let pos = ser.pos();

constructor_arg = Some(self.inner.buffer[0..pos].to_vec());
init_arg = Some(self.inner.buffer[0..pos].to_vec());
}

self.deploy_raw(
deploy_data.contract_id,
bytecode,
constructor_arg,
init_arg,
deploy_data
.owner
.expect("Owner must be specified when deploying a contract"),
Expand Down Expand Up @@ -272,21 +272,15 @@ impl Session {
&mut self,
contract_id: Option<ContractId>,
bytecode: &[u8],
constructor_arg: Option<Vec<u8>>,
init_arg: Option<Vec<u8>>,
owner: Vec<u8>,
gas_limit: u64,
) -> Result<ContractId, Error> {
let contract_id = contract_id.unwrap_or({
let hash = blake3::hash(bytecode);
ContractId::from_bytes(hash.into())
});
self.do_deploy(
contract_id,
bytecode,
constructor_arg,
owner,
gas_limit,
)?;
self.do_deploy(contract_id, bytecode, init_arg, owner, gas_limit)?;

Ok(contract_id)
}
Expand Down Expand Up @@ -328,10 +322,10 @@ impl Session {
self.instance(&contract_id).expect("instance should exist");

if instance.is_function_exported(INIT_METHOD) {
// If no argument was provided, we call the constructor anyway,
// If no argument was provided, we call the init method 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
// contract has an init method 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
12 changes: 5 additions & 7 deletions piecrust/tests/constructor.rs → piecrust/tests/initializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,14 @@ const OWNER: [u8; 32] = [0u8; 32];
const LIMIT: u64 = 1_000_000;

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

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

let id = session.deploy(
contract_bytecode!("constructor"),
ContractData::builder()
.owner(OWNER)
.constructor_arg(&0xabu8),
contract_bytecode!("initializer"),
ContractData::builder().owner(OWNER).init_arg(&0xabu8),
LIMIT,
)?;

Expand Down Expand Up @@ -75,13 +73,13 @@ fn constructor() -> Result<(), Error> {
}

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

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

let id = session.deploy(
contract_bytecode!("empty_constructor"),
contract_bytecode!("empty_initializer"),
ContractData::builder().owner(OWNER),
LIMIT,
)?;
Expand Down

0 comments on commit 57e3711

Please sign in to comment.