Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change constructor to init(ializer) #381

Merged
merged 1 commit into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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",
Neotamandua marked this conversation as resolved.
Show resolved Hide resolved
"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