Skip to content

Commit

Permalink
constructor with arguments
Browse files Browse the repository at this point in the history
Closes: diem#177
  • Loading branch information
rahxephon89 authored and bors-diem committed Apr 4, 2022
1 parent 42a69f1 commit 6d2afae
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 43 deletions.
23 changes: 21 additions & 2 deletions language/evm/hardhat-examples/contracts/Token.abi.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
[
{
"inputs": [],
"name": "create",
"inputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"name": "",
"outputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
Expand All @@ -25,6 +31,19 @@
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
Expand Down
12 changes: 10 additions & 2 deletions language/evm/hardhat-examples/contracts/Token.move
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,28 @@ module Evm::Token {
struct State has key {
total_supply: U256,
balances: Table<address, U256>,
name: vector<u8>,
}

#[create]
public fun create() acquires State {
#[create(sig=b"constructor(string)")]
public fun create(name: vector<u8>) acquires State {
move_to<State>(
&sign(self()),
State {
total_supply: U256::zero(),
balances: Table::empty<address, U256>(),
name
}
);
mint(sender(), U256::u256_from_u128(42));
}

#[callable(sig=b"name() returns (string)"), view]
/// Returns the name of the token
public fun name(): vector<u8> acquires State {
*&borrow_global<State>(self()).name
}

#[callable(sig=b"totalSupply() returns (uint256)"), view]
public fun totalSupply(): U256 acquires State {
*&borrow_global<State>(self()).total_supply
Expand Down
9 changes: 8 additions & 1 deletion language/evm/hardhat-examples/test/Token.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { expect } = require("chai");
describe("Token", function () {
before(async function () {
this.Token = await ethers.getContractFactory("Token");
this.token = await this.Token.deploy();
this.token = await this.Token.deploy("user");
await this.token.deployed();
});

Expand Down Expand Up @@ -41,4 +41,11 @@ describe("Token", function () {
// total supply should not change
expect(await this.token.totalSupply()).to.be.equal(169);
});

it("test name", async function () {
const accounts = await ethers.getSigners();
deployer = accounts[0];
expect(await this.token.name()).to.be.equal("user");
});

});
19 changes: 11 additions & 8 deletions language/evm/move-to-yul/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,16 @@ fn extract_attr_value_str(
}

/// Extract the solidity signature from the callable attribute
pub fn extract_callable_signature(fun: &FunctionEnv<'_>) -> Option<String> {
extract_attr_value_str(
fun.module_env.env,
fun.get_attributes(),
CALLABLE_ATTR,
SIGNATURE,
)
pub fn extract_callable_or_create_signature(
fun: &FunctionEnv<'_>,
callable_flag: bool,
) -> Option<String> {
let attr = if callable_flag {
CALLABLE_ATTR
} else {
CREATE_ATTR
};
extract_attr_value_str(fun.module_env.env, fun.get_attributes(), attr, SIGNATURE)
}

/// Extract the solidity signature from the callable attribute
Expand Down Expand Up @@ -113,7 +116,7 @@ pub fn is_callable_fun(fun: &FunctionEnv<'_>) -> bool {

/// Check whether the function has a `#[create]` attribute.
pub fn is_create_fun(fun: &FunctionEnv<'_>) -> bool {
has_attr(fun.module_env.env, fun.get_attributes(), CREATE_ATTR, true)
has_attr(fun.module_env.env, fun.get_attributes(), CREATE_ATTR, false)
}

/// Check whether the function has a `#[payable]` attribute.
Expand Down
6 changes: 4 additions & 2 deletions language/evm/move-to-yul/src/dispatcher_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl Generator {
);
continue;
}
let sig = self.get_solidity_signature(ctx, fun);
let sig = self.get_solidity_signature(ctx, fun, true);
self.generate_dispatch_item(ctx, fun, &sig, &mut selectors);
}
emitln!(ctx.writer, "default {}");
Expand All @@ -97,8 +97,10 @@ impl Generator {
&self,
ctx: &Context,
fun: &FunctionEnv,
callable_flag: bool,
) -> SoliditySignature {
let extracted_sig_opt = attributes::extract_callable_signature(fun);
let extracted_sig_opt =
attributes::extract_callable_or_create_signature(fun, callable_flag);
let mut sig = SoliditySignature::create_default_solidity_signature(ctx, fun);
if let Some(extracted_sig) = extracted_sig_opt {
let parsed_sig_opt = SoliditySignature::parse_into_solidity_signature(&extracted_sig);
Expand Down
48 changes: 42 additions & 6 deletions language/evm/move-to-yul/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl Generator {
ctx.emit_block(|| {
// Generate the deployment code block
self.begin_code_block(ctx);
self.optional_creator(ctx);
self.optional_creator(ctx, contract_name);
let contract_deployed_name = format!("{}_deployed", contract_name);
emitln!(
ctx.writer,
Expand Down Expand Up @@ -266,7 +266,7 @@ impl Generator {
}

/// Generate optional creator (contract constructor).
fn optional_creator(&mut self, ctx: &Context) {
fn optional_creator(&mut self, ctx: &Context, contract_name: &str) {
let mut creators = ctx.get_target_functions(attributes::is_create_fun);
if creators.len() > 1 {
ctx.env
Expand Down Expand Up @@ -295,23 +295,59 @@ impl Generator {
// Translate call to the constructor function
let fun_id = creator.get_qualified_id().instantiate(vec![]);
let function_name = ctx.make_function_name(&fun_id);
let solidity_sig = self.get_solidity_signature(ctx, &creator);
let solidity_sig = self.get_solidity_signature(ctx, &creator, false);
let param_count = solidity_sig.para_types.len();
let mut params = "".to_string();
if param_count > 0 {
let program_size_str = "program_size".to_string();
let arg_size_str = "arg_size".to_string();
let memory_data_offset_str = "memory_data_offset".to_string();
emitln!(
ctx.writer,
"let {} := datasize(\"{}\")",
program_size_str,
contract_name
);
emitln!(
ctx.writer,
"let {} := sub(codesize(), {})",
arg_size_str,
program_size_str
);
let malloc_call = self.call_builtin_str(
ctx,
YulFunction::Malloc,
std::iter::once(arg_size_str.clone()),
);
emitln!(
ctx.writer,
"let {} := {}",
memory_data_offset_str,
malloc_call
);
emitln!(
ctx.writer,
"codecopy({}, {}, {})",
memory_data_offset_str,
program_size_str,
arg_size_str
);
let decoding_fun_name = self.generate_abi_tuple_decoding_para(
ctx,
&solidity_sig,
creator.get_parameter_types(),
false,
true,
);
params = (0..param_count).map(|i| format!("param_{}", i)).join(", ");
let let_params = format!("let {} := ", params);
emitln!(
ctx.writer,
"{}{}(4, calldatasize())",
"{}{}({}, add({}, {}))",
let_params,
decoding_fun_name
decoding_fun_name,
memory_data_offset_str,
memory_data_offset_str,
arg_size_str
);
}

Expand Down
63 changes: 44 additions & 19 deletions language/evm/move-to-yul/tests/ConstructorTest.exp
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,42 @@
object "A2_ConstructorTest" {
code {
mstore(0, memoryguard(160))
A2_ConstructorTest_init()
let program_size := datasize("A2_ConstructorTest")
let arg_size := sub(codesize(), program_size)
let memory_data_offset := $Malloc(arg_size)
codecopy(memory_data_offset, program_size, arg_size)
let param_0, param_1 := abi_decode_tuple_$uint64_uint64$_$u64_u64$_from_memory(memory_data_offset, add(memory_data_offset, arg_size))
A2_ConstructorTest_init(param_0, param_1)
codecopy(0, dataoffset("A2_ConstructorTest_deployed"), datasize("A2_ConstructorTest_deployed"))
return(0, datasize("A2_ConstructorTest_deployed"))
function A2_ConstructorTest_init() {
let $t1, $t2, $t3, $t4
function A2_ConstructorTest_init(value, value2) {
let $t3, $t4, $t5
let $locals := $Malloc(32)
// $t1 := 0x42
$t1 := 0x42
// $t0 := Evm::sign($t1)
mstore($locals, A2_Evm_sign($t1))
// $t2 := borrow_local($t0)
$t2 := $MakePtr(false, $locals)
// $t3 := 43
$t3 := 43
// $t4 := pack ConstructorTest::Balance($t3)
// $t3 := 0x42
$t3 := 0x42
// $t2 := Evm::sign($t3)
mstore($locals, A2_Evm_sign($t3))
// $t4 := borrow_local($t2)
$t4 := $MakePtr(false, $locals)
// $t5 := pack ConstructorTest::Balance($t0, $t1)
{
let $mem := $Malloc(8)
$MemoryStoreU64(add($mem, 0), $t3)
$t4 := $mem
let $mem := $Malloc(16)
$MemoryStoreU64(add($mem, 0), value)
$MemoryStoreU64(add($mem, 8), value2)
$t5 := $mem
}
// move_to<ConstructorTest::Balance>($t4, $t2)
// move_to<ConstructorTest::Balance>($t5, $t4)
{
let $base_offset := $MakeTypeStorageBase(0, 0x91d9463a, $LoadU256($t2))
let $base_offset := $MakeTypeStorageBase(0, 0x91d9463a, $LoadU256($t4))
if $AlignedStorageLoad($base_offset) {
$AbortBuiltin()
}
$AlignedStorageStore($base_offset, true)
{
let $dst := add($base_offset, 32)
let $src := $t4
let $src := $t5
$AlignedStorageStore(add($dst, 0), mload(add($src, 0)))
$Free($src, 8)
$Free($src, 16)
}
}
// return ()
Expand All @@ -47,6 +51,27 @@ object "A2_ConstructorTest" {
function A2_Evm_sign(addr) -> signer {
signer := addr
}
function abi_decode_tuple_$uint64_uint64$_$u64_u64$_from_memory(headStart, dataEnd) -> value_0, value_1 {
if slt(sub(dataEnd, headStart), 64) { $Abort(96) }
{
let offset := 0
value_0 := abi_decode_uint64_from_memory(add(headStart, offset), dataEnd)
}
{
let offset := 32
value_1 := abi_decode_uint64_from_memory(add(headStart, offset), dataEnd)
}
}
function abi_decode_uint64_from_memory(offset, end) -> value {
value := mload(offset)
validator_uint64(value)
}
function validator_uint64(value) {
if iszero(eq(value, cleanup_uint64(value))) { $Abort(95) }
}
function cleanup_uint64(value) -> cleaned {
cleaned := and(value, 0xffffffffffffffff)
}
function $Abort(code) {
mstore(0, code)
revert(24, 8) // TODO: store code as a string?
Expand Down
7 changes: 4 additions & 3 deletions language/evm/move-to-yul/tests/ConstructorTest.move
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ module 0x2::ConstructorTest {
use Evm::Evm::sign;

struct Balance has key, drop {
value: u64
value: u64,
value2: u64
}

#[create]
fun init() {
move_to(&sign(@0x42), Balance { value: 43 });
fun init(value: u64, value2: u64) {
move_to(&sign(@0x42), Balance { value, value2});
}

#[callable]
Expand Down

0 comments on commit 6d2afae

Please sign in to comment.