From 88f63d88b34365aed2cceffdef87f0502b28898b Mon Sep 17 00:00:00 2001 From: Virgil Date: Mon, 23 Sep 2024 18:48:32 +0300 Subject: [PATCH 1/2] Implement require! --- mx-rust-semantics/main/calls.md | 2 + mx-rust-semantics/main/calls/macros.md | 22 +++++++++ mx-rust-semantics/main/glue.md | 5 +++ mx-rust-semantics/test/execution.md | 8 ++++ mx-semantics/main/accounts/tools.md | 4 ++ mx-semantics/main/errors/hooks.md | 10 +++++ mx-semantics/main/errors/tools.md | 27 +++++++++++ mx-semantics/main/mx-common.md | 4 ++ mx-semantics/main/syntax.md | 1 + tests/mx-rust-contracts/require.1.args | 0 tests/mx-rust-contracts/require.1.run | 13 ++++++ tests/mx-rust-contracts/require.2.args | 0 tests/mx-rust-contracts/require.2.run | 12 +++++ tests/mx-rust-contracts/require.3.args | 0 tests/mx-rust-contracts/require.3.run | 13 ++++++ tests/mx-rust-contracts/require.4.args | 0 tests/mx-rust-contracts/require.4.run | 12 +++++ tests/mx-rust-contracts/require.5.args | 0 tests/mx-rust-contracts/require.5.run | 24 ++++++++++ tests/mx-rust-contracts/require.6.args | 0 tests/mx-rust-contracts/require.6.run | 24 ++++++++++ tests/mx-rust-contracts/require.rs | 62 ++++++++++++++++++++++++++ 22 files changed, 243 insertions(+) create mode 100644 mx-rust-semantics/main/calls/macros.md create mode 100644 mx-semantics/main/errors/hooks.md create mode 100644 mx-semantics/main/errors/tools.md create mode 100644 tests/mx-rust-contracts/require.1.args create mode 100644 tests/mx-rust-contracts/require.1.run create mode 100644 tests/mx-rust-contracts/require.2.args create mode 100644 tests/mx-rust-contracts/require.2.run create mode 100644 tests/mx-rust-contracts/require.3.args create mode 100644 tests/mx-rust-contracts/require.3.run create mode 100644 tests/mx-rust-contracts/require.4.args create mode 100644 tests/mx-rust-contracts/require.4.run create mode 100644 tests/mx-rust-contracts/require.5.args create mode 100644 tests/mx-rust-contracts/require.5.run create mode 100644 tests/mx-rust-contracts/require.6.args create mode 100644 tests/mx-rust-contracts/require.6.run create mode 100644 tests/mx-rust-contracts/require.rs diff --git a/mx-rust-semantics/main/calls.md b/mx-rust-semantics/main/calls.md index f0b6c1c..f5fbfc4 100644 --- a/mx-rust-semantics/main/calls.md +++ b/mx-rust-semantics/main/calls.md @@ -1,9 +1,11 @@ ```k requires "calls/implementation.md" +requires "calls/macros.md" module MX-RUST-CALLS imports private MX-RUST-CALLS-IMPLEMENTATION + imports private MX-RUST-CALLS-MACROS endmodule ``` \ No newline at end of file diff --git a/mx-rust-semantics/main/calls/macros.md b/mx-rust-semantics/main/calls/macros.md new file mode 100644 index 0000000..63b3778 --- /dev/null +++ b/mx-rust-semantics/main/calls/macros.md @@ -0,0 +1,22 @@ +```k + +module MX-RUST-CALLS-MACROS + imports private RUST-SHARED-SYNTAX + imports private RUST-VALUE-SYNTAX + imports private MX-COMMON-SYNTAX + + syntax MxRustInstruction ::= requireMacro(condition:Expression, message:Expression) + [seqstrict] + + rule ( #token("require", "Identifier") :: .SimplePathList ! + ( Condition:Expression, Message:Expression, .CallParamsList ) ; + ):MacroInvocationSemi:KItem + => requireMacro(... condition:Condition, message:Message) + + rule requireMacro(... condition: ptrValue(_, true), message: _:PtrValue) => .K + rule requireMacro(... condition: ptrValue(_, false), message: ptrValue(_, Message:String)) + => MX#signalError(mxStringValue(Message)) + +endmodule + +``` diff --git a/mx-rust-semantics/main/glue.md b/mx-rust-semantics/main/glue.md index ec4bb20..0299c94 100644 --- a/mx-rust-semantics/main/glue.md +++ b/mx-rust-semantics/main/glue.md @@ -62,6 +62,11 @@ module MX-RUST-GLUE rule ptrValue(_, V) ~> rustValueToMx => rustValueToMx(V) + rule rustValueToMx(tuple(.ValueList)) => mxUnitValue() + + rule rustValueToMx(V:Value) => mxIntValue({valueToInteger(V)}:>Int) + requires notBool isSemanticsError(valueToInteger(V)) + endmodule ``` diff --git a/mx-rust-semantics/test/execution.md b/mx-rust-semantics/test/execution.md index 4837597..6abc760 100644 --- a/mx-rust-semantics/test/execution.md +++ b/mx-rust-semantics/test/execution.md @@ -11,6 +11,7 @@ module MX-RUST-TESTING-PARSING-SYNTAX syntax MxRustTest ::= ExecutionTest syntax ExecutionItem ::= "set_named" String | "push_named" String + | "catch_error" String | "get_bigint_from_struct" | "check_eq" Int | TestInstruction @@ -19,6 +20,7 @@ endmodule module MX-RUST-TEST imports private COMMON-K-CELL + imports private K-EQUAL-SYNTAX imports private MX-RUST-EXECUTION-TEST-CONFIGURATION imports private MX-RUST-TESTING-PARSING-SYNTAX imports private RUST-EXECUTION-CONFIGURATION @@ -43,6 +45,12 @@ module MX-RUST-TEST ) ~> get_bigint_from_struct => mxRustGetBigIntFromStruct(S) + + rule #exception(_, Message) ~> catch_error Message => .K [priority(30)] + rule (#exception(_, Message1) #as E:MxInstructions) ~> (catch_error Message2 #as C) + => catch_error C ~> E + requires Message1 =/=K Message2 + [priority(30)] endmodule ``` diff --git a/mx-semantics/main/accounts/tools.md b/mx-semantics/main/accounts/tools.md index 0d24921..ee38eba 100644 --- a/mx-semantics/main/accounts/tools.md +++ b/mx-semantics/main/accounts/tools.md @@ -145,6 +145,10 @@ module MX-ACCOUNTS-TOOLS rule [dropWorldState]: dropWorldState => .K ... (ListItem(_) => .List) ... + rule [popWorldState]: + popWorldState => .K ... + (ListItem(ACCTDATA) => .List) ... + _ => ACCTDATA // ------------------------------------------------------ rule transferFunds(... from: From:String, to: To:String, amount: 0) diff --git a/mx-semantics/main/errors/hooks.md b/mx-semantics/main/errors/hooks.md new file mode 100644 index 0000000..3ab1db9 --- /dev/null +++ b/mx-semantics/main/errors/hooks.md @@ -0,0 +1,10 @@ +```k + +module MX-ERRORS-HOOKS + imports private MX-COMMON-SYNTAX + + rule MX#signalError(mxStringValue(Message:String)) => #exception(UserError, Message) + +endmodule + +``` diff --git a/mx-semantics/main/errors/tools.md b/mx-semantics/main/errors/tools.md new file mode 100644 index 0000000..7886a16 --- /dev/null +++ b/mx-semantics/main/errors/tools.md @@ -0,0 +1,27 @@ +```k + +module MX-ERRORS-TOOLS + imports private COMMON-K-CELL + imports private K-EQUAL-SYNTAX + imports private MX-CALL-RESULT-CONFIGURATION + imports private MX-COMMON-SYNTAX + + syntax MxInstructions ::= setErrorVMOutput(ExceptionCode, String) + + rule #exception(_, _) ~> (Next:KItem => .K) + requires Next =/=K endCall + rule #exception(Code, Message) ~> endCall + => setErrorVMOutput(Code, Message) ~> popCallState ~> popWorldState + + rule [setErrorVMOutput]: + setErrorVMOutput(Code, Message) => .K ... + + _ => mxCallResult + (... returnCode: Code + , returnMessage: Message + , out: mxListValue(.MxValueList) + ) + +endmodule + +``` diff --git a/mx-semantics/main/mx-common.md b/mx-semantics/main/mx-common.md index 0510f20..104091a 100644 --- a/mx-semantics/main/mx-common.md +++ b/mx-semantics/main/mx-common.md @@ -11,6 +11,8 @@ requires "blocks/hooks.md" requires "call-state/tools.md" requires "calls/hooks.md" requires "calls/tools.md" +requires "errors/hooks.md" +requires "errors/tools.md" requires "tools.md" module MX-COMMON @@ -23,6 +25,8 @@ module MX-COMMON imports private MX-CALL-STATE-TOOLS imports private MX-CALLS-HOOKS imports private MX-CALLS-TOOLS + imports private MX-ERRORS-HOOKS + imports private MX-ERRORS-TOOLS imports private MX-STORAGE-HOOKS imports private MX-STORAGE-TOOLS imports private MX-TOOLS diff --git a/mx-semantics/main/syntax.md b/mx-semantics/main/syntax.md index 60407ff..b9a1e22 100644 --- a/mx-semantics/main/syntax.md +++ b/mx-semantics/main/syntax.md @@ -41,6 +41,7 @@ module MX-COMMON-SYNTAX | "resetCallState" [symbol(resetCallState)] | "pushWorldState" [symbol(pushWorldState)] | "dropWorldState" [symbol(dropWorldState)] + | "popWorldState" [symbol(popWorldState)] | "clearBigInts" [symbol(clearBigInts)] | "endCall" [symbol(endCall)] | "finishExecuteOnDestContext" [symbol(finishExecuteOnDestContext)] diff --git a/tests/mx-rust-contracts/require.1.args b/tests/mx-rust-contracts/require.1.args new file mode 100644 index 0000000..e69de29 diff --git a/tests/mx-rust-contracts/require.1.run b/tests/mx-rust-contracts/require.1.run new file mode 100644 index 0000000..6d7480d --- /dev/null +++ b/tests/mx-rust-contracts/require.1.run @@ -0,0 +1,13 @@ +setCallee("Owner"); + +push mxListValue(); +push mxStringValue("callRequirePassesRetv"); +push mxIntValue(0); +push mxTransfersValue(); +push mxIntValue(0); +push mxStringValue("TestContract"); +call 6 MX#managedExecuteOnDestContext; +check_eq mxIntValue(0); + +push_return_value; +check_eq mxIntValue(3) diff --git a/tests/mx-rust-contracts/require.2.args b/tests/mx-rust-contracts/require.2.args new file mode 100644 index 0000000..e69de29 diff --git a/tests/mx-rust-contracts/require.2.run b/tests/mx-rust-contracts/require.2.run new file mode 100644 index 0000000..373d93f --- /dev/null +++ b/tests/mx-rust-contracts/require.2.run @@ -0,0 +1,12 @@ +setCallee("Owner"); + +push mxListValue(); +push mxStringValue("callRequireFailsRetv"); +push mxIntValue(0); +push mxTransfersValue(); +push mxIntValue(0); +push mxStringValue("TestContract"); +call 6 MX#managedExecuteOnDestContext; +check_eq mxIntValue(7000); + +catch_error "error signalled by smartcontract: Require failure" diff --git a/tests/mx-rust-contracts/require.3.args b/tests/mx-rust-contracts/require.3.args new file mode 100644 index 0000000..e69de29 diff --git a/tests/mx-rust-contracts/require.3.run b/tests/mx-rust-contracts/require.3.run new file mode 100644 index 0000000..226ddc1 --- /dev/null +++ b/tests/mx-rust-contracts/require.3.run @@ -0,0 +1,13 @@ +setCallee("Owner"); + +push mxListValue(); +push mxStringValue("callRequirePassesInstr"); +push mxIntValue(0); +push mxTransfersValue(); +push mxIntValue(0); +push mxStringValue("TestContract"); +call 6 MX#managedExecuteOnDestContext; +check_eq mxIntValue(0); + +push_return_value; +check_eq mxUnitValue() diff --git a/tests/mx-rust-contracts/require.4.args b/tests/mx-rust-contracts/require.4.args new file mode 100644 index 0000000..e69de29 diff --git a/tests/mx-rust-contracts/require.4.run b/tests/mx-rust-contracts/require.4.run new file mode 100644 index 0000000..9aa8805 --- /dev/null +++ b/tests/mx-rust-contracts/require.4.run @@ -0,0 +1,12 @@ +setCallee("Owner"); + +push mxListValue(); +push mxStringValue("callRequireFailsInstr"); +push mxIntValue(0); +push mxTransfersValue(); +push mxIntValue(0); +push mxStringValue("TestContract"); +call 6 MX#managedExecuteOnDestContext; +check_eq mxIntValue(7000); + +catch_error "error signalled by smartcontract: Require failure" diff --git a/tests/mx-rust-contracts/require.5.args b/tests/mx-rust-contracts/require.5.args new file mode 100644 index 0000000..e69de29 diff --git a/tests/mx-rust-contracts/require.5.run b/tests/mx-rust-contracts/require.5.run new file mode 100644 index 0000000..f6ca3a0 --- /dev/null +++ b/tests/mx-rust-contracts/require.5.run @@ -0,0 +1,24 @@ +setCallee("Owner"); + +push mxListValue(); +push mxStringValue("callRequireFailsUndoRetv"); +push mxIntValue(0); +push mxTransfersValue(); +push mxIntValue(0); +push mxStringValue("TestContract"); +call 6 MX#managedExecuteOnDestContext; +check_eq mxIntValue(7000); + +catch_error "error signalled by smartcontract: Require failure"; + +push mxListValue(); +push mxStringValue("getMyStorage"); +push mxIntValue(0); +push mxTransfersValue(); +push mxIntValue(0); +push mxStringValue("TestContract"); +call 6 MX#managedExecuteOnDestContext; +check_eq mxIntValue(0); + +push_return_value; +check_eq mxIntValue(10) diff --git a/tests/mx-rust-contracts/require.6.args b/tests/mx-rust-contracts/require.6.args new file mode 100644 index 0000000..e69de29 diff --git a/tests/mx-rust-contracts/require.6.run b/tests/mx-rust-contracts/require.6.run new file mode 100644 index 0000000..8836ea2 --- /dev/null +++ b/tests/mx-rust-contracts/require.6.run @@ -0,0 +1,24 @@ +setCallee("Owner"); + +push mxListValue(); +push mxStringValue("callRequireFailsUndoInstr"); +push mxIntValue(0); +push mxTransfersValue(); +push mxIntValue(0); +push mxStringValue("TestContract"); +call 6 MX#managedExecuteOnDestContext; +check_eq mxIntValue(7000); + +catch_error "error signalled by smartcontract: Require failure"; + +push mxListValue(); +push mxStringValue("getMyStorage"); +push mxIntValue(0); +push mxTransfersValue(); +push mxIntValue(0); +push mxStringValue("TestContract"); +call 6 MX#managedExecuteOnDestContext; +check_eq mxIntValue(0); + +push_return_value; +check_eq mxIntValue(10) diff --git a/tests/mx-rust-contracts/require.rs b/tests/mx-rust-contracts/require.rs new file mode 100644 index 0000000..2bb2007 --- /dev/null +++ b/tests/mx-rust-contracts/require.rs @@ -0,0 +1,62 @@ +#![no_std] + +#[allow(unused_imports)] +use multiversx_sc::imports::*; + +#[multiversx_sc::contract] +pub trait RequireContract { + #[view(noArg)] + #[storage_mapper("my_value")] + fn my_storage(&self) -> SingleValueMapper; + + #[init] + fn init(&self) { + self.my_storage().set_if_empty(BigUint::from(10)) + } + + #[upgrade] + fn upgrade(&self) {} + + #[endpoint(callRequirePassesRetv)] + fn call_require_passes_retv(&self) -> u64 { + require!(5_u64 > 4_u64, "Require failure"); + 3_u64 + } + + #[endpoint(callRequireFailsRetv)] + fn call_require_fails_retv(&self) -> u64 { + require!(5_u64 > 6_u64, "Require failure"); + 3_u64 + } + + #[endpoint(callRequirePassesInstr)] + fn call_require_passes_Instr(&self) { + require!(5_u64 > 4_u64, "Require failure"); + 3_u64; + } + + #[endpoint(callRequireFailsInstr)] + fn call_require_fails_instr(&self) -> u64 { + require!(5_u64 > 6_u64, "Require failure"); + 3_u64; + } + + #[endpoint(callRequireFailsUndoRetv)] + fn call_require_fails_undo_retv(&self) { + self.my_storage().set(BigUint::from(100_u64)); + require!(5_u64 > 6_u64, "Require failure"); + self.my_storage().set(BigUint::from(100_u64)) + } + + #[endpoint(callRequireFailsUndoInstr)] + fn call_require_fails_undo_instr(&self) -> u64 { + self.my_storage().set(BigUint::from(100_u64)); + require!(5_u64 > 6_u64, "Require failure"); + self.my_storage().set(BigUint::from(100_u64)); + } + + #[endpoint(getMyStorage)] + fn get_my_storage(&self) -> BigUint { + self.my_storage().get() + } +} From b8d67876118b413a275557d827b9c054d09be172 Mon Sep 17 00:00:00 2001 From: Virgil Date: Tue, 24 Sep 2024 19:43:48 +0300 Subject: [PATCH 2/2] Remove redundant rule --- mx-rust-semantics/main/calls/implementation.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/mx-rust-semantics/main/calls/implementation.md b/mx-rust-semantics/main/calls/implementation.md index bb50c33..6f2ddb5 100644 --- a/mx-rust-semantics/main/calls/implementation.md +++ b/mx-rust-semantics/main/calls/implementation.md @@ -13,8 +13,6 @@ module MX-RUST-CALLS-IMPLEMENTATION imports private RUST-REPRESENTATION imports private RUST-SHARED-SYNTAX - rule rustValueToMx(tuple(.ValueList)) => mxUnitValue() - rule (.K => rustValueToMx(V)) ~> rustValuesToMx((V:Value , L:ValueList => L), _:MxValueList) rule (V:MxValue => .K)