diff --git a/rust-semantics/error.md b/rust-semantics/error.md index 96ae8365..5c7b59b0 100644 --- a/rust-semantics/error.md +++ b/rust-semantics/error.md @@ -12,6 +12,7 @@ module RUST-ERROR-SYNTAX syntax TypePathOrError ::= injectOrError(TypePathSegmentsOrError) [function, total] syntax TypePathSegmentsOrError ::= concat(TypePathSegment, TypePathSegmentsOrError) [function, total] syntax ExpressionOrError ::= andOrError(ExpressionOrError, ExpressionOrError) [function, total] + syntax ExpressionOrError ::= addOrError(ExpressionOrError, ExpressionOrError) [function, total] syntax ValueOrError ::= tupleOrError(ValueListOrError) [function, total] endmodule @@ -52,6 +53,10 @@ module RUST-ERROR rule andOrError(e(E:SemanticsError), v(_:Expression)) => e(E) rule andOrError(v(E1:Expression), v(E2:Expression)) => v(E1 && E2) + rule addOrError(_:ExpressionOrError, e(E:SemanticsError)) => e(E) + rule addOrError(e(E:SemanticsError), v(_:Expression)) => e(E) + rule addOrError(v(E1:Expression), v(E2:Expression)) => v(E1 + E2) + rule tupleOrError(L:ValueList) => tuple(L) rule tupleOrError(E:SemanticsError) => E endmodule diff --git a/tests/ulm-contracts/bytes_hooks.rs b/tests/ulm-contracts/bytes_hooks.rs index 74c8a43b..9ec9a902 100644 --- a/tests/ulm-contracts/bytes_hooks.rs +++ b/tests/ulm-contracts/bytes_hooks.rs @@ -13,6 +13,8 @@ extern "C" { fn append_bool(bytes_id: u64, value: bool) -> u64; fn append_str(bytes_id: u64, value: &str) -> u64; + fn append_bytes_raw(bytes_id: u64, to_append: u64) -> u64; + fn decode_u256(bytes_id: u64) -> (u64, u256); fn decode_u160(bytes_id: u64) -> (u64, u160); fn decode_u128(bytes_id: u64) -> (u64, u128); @@ -20,6 +22,7 @@ extern "C" { fn decode_u32(bytes_id: u64) -> (u64, u32); fn decode_u16(bytes_id: u64) -> (u64, u16); fn decode_u8(bytes_id: u64) -> (u64, u8); + fn decode_str(bytes_id: u64) -> (u64, str); fn decode_signature(bytes_id: u64) -> (u64, u64); fn hash(bytes_id: u64) -> u256; diff --git a/tests/ulm-contracts/test_helpers.rs b/tests/ulm-contracts/test_helpers.rs index 5d7ba179..10785bfd 100644 --- a/tests/ulm-contracts/test_helpers.rs +++ b/tests/ulm-contracts/test_helpers.rs @@ -14,3 +14,15 @@ fn decode_single_u256(bytes_id: u64) -> u256 { }; value } + +fn decode_single_str(bytes_id: u64) -> str { + let (remaining_id, prefix_size) = :: bytes_hooks :: decode_u256(bytes_id); + if prefix_size != 32_u256 { + fail(); + }; + let (remaining_id, value) = :: bytes_hooks :: decode_str(remaining_id); + if :: bytes_hooks :: length(remaining_id) > 0_u32 { + fail(); + }; + value +} diff --git a/tests/ulm-no-contract/test_bytes_hooks.appendstr.run b/tests/ulm-no-contract/test_bytes_hooks.appendstr.run index 400b52c2..f49ebb8b 100644 --- a/tests/ulm-no-contract/test_bytes_hooks.appendstr.run +++ b/tests/ulm-no-contract/test_bytes_hooks.appendstr.run @@ -3,11 +3,11 @@ call :: test_bytes_hooks :: append_str; return_value_to_arg; call :: bytes_hooks :: length; return_value; -check_eq 7_u32; +check_eq 64_u32; -push "Everyone"; +push "Everyone12345678901234567890123456789012"; call :: test_bytes_hooks :: append_str; return_value_to_arg; call :: bytes_hooks :: length; return_value; -check_eq 10_u32 +check_eq 96_u32 diff --git a/tests/ulm-with-contract/erc_20_token.1.run b/tests/ulm-with-contract/erc_20_token.1.run index f5c63e56..72953e0e 100644 --- a/tests/ulm-with-contract/erc_20_token.1.run +++ b/tests/ulm-with-contract/erc_20_token.1.run @@ -1,28 +1,28 @@ -list_mock GetAccountStorageHook ( 11059124170230400219182520145867018696635045254189466511817698468614930762963 ) ulmIntResult(0, u256); -list_mock SetAccountStorageHook ( 11059124170230400219182520145867018696635045254189466511817698468614930762963 , 10000 ) ulmNoResult(); -list_mock GetAccountStorageHook ( 115494845046723600673943990597816811669707739681772931244236289759170204726560 ) ulmIntResult(0, u256); -list_mock SetAccountStorageHook ( 115494845046723600673943990597816811669707739681772931244236289759170204726560 , 10000 ) ulmNoResult(); -list_mock GetAccountStorageHook ( 115494845046723600673943990597816811669707739681772931244236289759170204726560 ) ulmIntResult(10000, u256); -list_mock GetAccountStorageHook ( 115494845046723600673943990597816811669707739681772931244236289759170204726560 ) ulmIntResult(10000, u256); -list_mock GetAccountStorageHook ( 115494845046723600673943990597816811669707739681772931244236289759170204726560 ) ulmIntResult(10000, u256); -list_mock SetAccountStorageHook ( 115494845046723600673943990597816811669707739681772931244236289759170204726560 , 9900 ) ulmNoResult(); -list_mock GetAccountStorageHook ( 17171626450567201640701347902808840427582371480602455275836469707331258301780 ) ulmIntResult(0, u256); -list_mock SetAccountStorageHook ( 17171626450567201640701347902808840427582371480602455275836469707331258301780 , 100 ) ulmNoResult(); +list_mock GetAccountStorageHook ( 13032332009337290780939164280742955473285243463246449969298152790977293574652 ) ulmIntResult(0, u256); +list_mock SetAccountStorageHook ( 13032332009337290780939164280742955473285243463246449969298152790977293574652 , 10000 ) ulmNoResult(); +list_mock GetAccountStorageHook ( 61159765391625381932700807532824927387505868579121206115135228514320059425645 ) ulmIntResult(0, u256); +list_mock SetAccountStorageHook ( 61159765391625381932700807532824927387505868579121206115135228514320059425645 , 10000 ) ulmNoResult(); +list_mock GetAccountStorageHook ( 61159765391625381932700807532824927387505868579121206115135228514320059425645 ) ulmIntResult(10000, u256); +list_mock GetAccountStorageHook ( 61159765391625381932700807532824927387505868579121206115135228514320059425645 ) ulmIntResult(10000, u256); +list_mock GetAccountStorageHook ( 61159765391625381932700807532824927387505868579121206115135228514320059425645 ) ulmIntResult(10000, u256); +list_mock SetAccountStorageHook ( 61159765391625381932700807532824927387505868579121206115135228514320059425645 , 9900 ) ulmNoResult(); +list_mock GetAccountStorageHook ( 107935355587284645605585039702009686485686559005730386557515578263121021727641 ) ulmIntResult(0, u256); +list_mock SetAccountStorageHook ( 107935355587284645605585039702009686485686559005730386557515578263121021727641 , 100 ) ulmNoResult(); list_mock Log3Hook ( 100389287136786176327247604509743168900146139575972864366142685224231313322991 , 1010101 , 2020202 , b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d" ) ulmNoResult(); -list_mock GetAccountStorageHook ( 115494845046723600673943990597816811669707739681772931244236289759170204726560 ) ulmIntResult(9900, u256); -list_mock GetAccountStorageHook ( 17171626450567201640701347902808840427582371480602455275836469707331258301780 ) ulmIntResult(100, u256); -list_mock SetAccountStorageHook ( 97321503972240892886219376522881926110074550168465622121824657360422868161783 , 200 ) ulmNoResult(); +list_mock GetAccountStorageHook ( 61159765391625381932700807532824927387505868579121206115135228514320059425645 ) ulmIntResult(9900, u256); +list_mock GetAccountStorageHook ( 107935355587284645605585039702009686485686559005730386557515578263121021727641 ) ulmIntResult(100, u256); +list_mock SetAccountStorageHook ( 6299478510657022222390882510197411465571447485061513230872540120223652878023 , 200 ) ulmNoResult(); list_mock Log3Hook ( 63486140976153616755203102783360879283472101686154884697241723088393386309925 , 1010101 , 3030303 , b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8" ) ulmNoResult(); -list_mock GetAccountStorageHook ( 97321503972240892886219376522881926110074550168465622121824657360422868161783 ) ulmIntResult(200, u256); -list_mock SetAccountStorageHook ( 97321503972240892886219376522881926110074550168465622121824657360422868161783 , 0 ) ulmNoResult(); -list_mock GetAccountStorageHook ( 115494845046723600673943990597816811669707739681772931244236289759170204726560 ) ulmIntResult(9900, u256); -list_mock GetAccountStorageHook ( 115494845046723600673943990597816811669707739681772931244236289759170204726560 ) ulmIntResult(9900, u256); -list_mock SetAccountStorageHook ( 115494845046723600673943990597816811669707739681772931244236289759170204726560 , 9700 ) ulmNoResult(); -list_mock GetAccountStorageHook ( 17171626450567201640701347902808840427582371480602455275836469707331258301780 ) ulmIntResult(100, u256); -list_mock SetAccountStorageHook ( 17171626450567201640701347902808840427582371480602455275836469707331258301780 , 300 ) ulmNoResult(); +list_mock GetAccountStorageHook ( 6299478510657022222390882510197411465571447485061513230872540120223652878023 ) ulmIntResult(200, u256); +list_mock SetAccountStorageHook ( 6299478510657022222390882510197411465571447485061513230872540120223652878023 , 0 ) ulmNoResult(); +list_mock GetAccountStorageHook ( 61159765391625381932700807532824927387505868579121206115135228514320059425645 ) ulmIntResult(9900, u256); +list_mock GetAccountStorageHook ( 61159765391625381932700807532824927387505868579121206115135228514320059425645 ) ulmIntResult(9900, u256); +list_mock SetAccountStorageHook ( 61159765391625381932700807532824927387505868579121206115135228514320059425645 , 9700 ) ulmNoResult(); +list_mock GetAccountStorageHook ( 107935355587284645605585039702009686485686559005730386557515578263121021727641 ) ulmIntResult(100, u256); +list_mock SetAccountStorageHook ( 107935355587284645605585039702009686485686559005730386557515578263121021727641 , 300 ) ulmNoResult(); list_mock Log3Hook ( 100389287136786176327247604509743168900146139575972864366142685224231313322991 , 1010101 , 2020202 , b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8" ) ulmNoResult(); -list_mock GetAccountStorageHook ( 115494845046723600673943990597816811669707739681772931244236289759170204726560 ) ulmIntResult(9700, u256); -list_mock GetAccountStorageHook ( 17171626450567201640701347902808840427582371480602455275836469707331258301780 ) ulmIntResult(300, u256); +list_mock GetAccountStorageHook ( 61159765391625381932700807532824927387505868579121206115135228514320059425645 ) ulmIntResult(9700, u256); +list_mock GetAccountStorageHook ( 107935355587284645605585039702009686485686559005730386557515578263121021727641 ) ulmIntResult(300, u256); push "uint256"; hold_list_values_from_test_stack; diff --git a/tests/ulm-with-contract/storage.256.run b/tests/ulm-with-contract/storage.256.run index b5b52615..f20b63a9 100644 --- a/tests/ulm-with-contract/storage.256.run +++ b/tests/ulm-with-contract/storage.256.run @@ -1,5 +1,5 @@ -mock SetAccountStorageHook ( 47586510880955265726688953653028435069486243252926274554489699639913455891751 , 1000000000000000000000000000000000000000000000000000000000000 ) ulmNoResult(); -mock GetAccountStorageHook ( 47586510880955265726688953653028435069486243252926274554489699639913455891751 ) ulmIntResult(1000000000000000000000000000000000000000000000000000000000000, u256); +mock SetAccountStorageHook ( 81899343944223093934060911023235694134954301913235101281428181165721203435003 , 1000000000000000000000000000000000000000000000000000000000000 ) ulmNoResult(); +mock GetAccountStorageHook ( 81899343944223093934060911023235694134954301913235101281428181165721203435003 ) ulmIntResult(1000000000000000000000000000000000000000000000000000000000000, u256); push "setMyData256"; hold_string_from_test_stack; diff --git a/tests/ulm-with-contract/storage.key.run b/tests/ulm-with-contract/storage.key.run index e89191c8..2f9d282f 100644 --- a/tests/ulm-with-contract/storage.key.run +++ b/tests/ulm-with-contract/storage.key.run @@ -1,5 +1,5 @@ -mock SetAccountStorageHook ( 10244917065751466042072482011607924022453580028001931068470547844249081769915 , 123 ) ulmNoResult(); -mock GetAccountStorageHook ( 10244917065751466042072482011607924022453580028001931068470547844249081769915 ) ulmIntResult(123, u256); +mock SetAccountStorageHook ( 89307555350153532481150451243271458944170707741354029868021544305102042370102 , 123 ) ulmNoResult(); +mock GetAccountStorageHook ( 89307555350153532481150451243271458944170707741354029868021544305102042370102 ) ulmIntResult(123, u256); push "setMyDataKey"; hold_string_from_test_stack; diff --git a/tests/ulm-with-contract/storage.simple.run b/tests/ulm-with-contract/storage.simple.run index 6ad0b98e..67d06534 100644 --- a/tests/ulm-with-contract/storage.simple.run +++ b/tests/ulm-with-contract/storage.simple.run @@ -1,5 +1,5 @@ -mock SetAccountStorageHook ( 73866358942311723187445361469509963283744060252826659833950887638461707973283 , 123 ) ulmNoResult(); -mock GetAccountStorageHook ( 73866358942311723187445361469509963283744060252826659833950887638461707973283 ) ulmIntResult(123, u256); +mock SetAccountStorageHook ( 2566766180763832229052383091904627608042490431692515280991237530682175269032 , 123 ) ulmNoResult(); +mock GetAccountStorageHook ( 2566766180763832229052383091904627608042490431692515280991237530682175269032 ) ulmIntResult(123, u256); push "setMyData"; hold_string_from_test_stack; diff --git a/tests/ulm-with-contract/types.rs b/tests/ulm-with-contract/types.rs new file mode 100644 index 00000000..b0963fe7 --- /dev/null +++ b/tests/ulm-with-contract/types.rs @@ -0,0 +1,15 @@ +#![no_std] + +#[allow(unused_imports)] +use ulm::*; + +#[ulm::contract] +pub trait Types { + #[init] + fn init(&self) {} + + #[endpoint(strEndpoint)] + fn str_endpoint(&self) -> str { + "Hello" + } +} diff --git a/tests/ulm-with-contract/types.str-raw.run b/tests/ulm-with-contract/types.str-raw.run new file mode 100644 index 00000000..a53a467c --- /dev/null +++ b/tests/ulm-with-contract/types.str-raw.run @@ -0,0 +1,21 @@ +push "strEndpoint"; +hold_string_from_test_stack; +hold_list_values_from_test_stack; +hold_list_values_from_test_stack; +encode_call_data; + +return_value; +mock CallData; + +call_contract 12345; +return_value; +check_eq (); + +push_status; +check_eq 2; + +check_raw_output + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05" + + b"Hello\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + diff --git a/tests/ulm-with-contract/types.str.run b/tests/ulm-with-contract/types.str.run new file mode 100644 index 00000000..384e17ac --- /dev/null +++ b/tests/ulm-with-contract/types.str.run @@ -0,0 +1,19 @@ +push "strEndpoint"; +hold_string_from_test_stack; +hold_list_values_from_test_stack; +hold_list_values_from_test_stack; +encode_call_data; + +return_value; +mock CallData; + +call_contract 12345; +return_value; +check_eq (); + +push_status; +check_eq 2; +output_to_arg; +call :: test_helpers :: decode_single_str; +return_value; +check_eq "Hello" diff --git a/ulm-semantics/main/encoding/encoder.md b/ulm-semantics/main/encoding/encoder.md index f769b9ce..fc37d305 100644 --- a/ulm-semantics/main/encoding/encoder.md +++ b/ulm-semantics/main/encoding/encoder.md @@ -59,6 +59,7 @@ module ULM-CALLDATA-ENCODER imports private ULM-ENCODING-HELPER syntax Identifier ::= "bytes_hooks" [token] + | "append_bytes_raw" [token] | "append_u8" [token] | "append_u16" [token] | "append_u32" [token] @@ -67,6 +68,9 @@ module ULM-CALLDATA-ENCODER | "append_u160" [token] | "append_u256" [token] | "append_bool" [token] + | "append_str" [token] + | "empty" [token] + | "length" [token] rule encodeFunctionSignatureAsBytes(FS) @@ -105,25 +109,146 @@ module ULM-CALLDATA-ENCODER rule encodeFunctionParams(.List, .List, B:Bytes) => B - rule appendValue(BufferId:Identifier, Value:Identifier, u8) - => v(:: bytes_hooks :: append_u8 ( BufferId , Value , .CallParamsList )) - rule appendValue(BufferId:Identifier, Value:Identifier, u16) - => v(:: bytes_hooks :: append_u16 ( BufferId , Value , .CallParamsList )) - rule appendValue(BufferId:Identifier, Value:Identifier, u32) - => v(:: bytes_hooks :: append_u32 ( BufferId , Value , .CallParamsList )) - rule appendValue(BufferId:Identifier, Value:Identifier, u64) - => v(:: bytes_hooks :: append_u64 ( BufferId , Value , .CallParamsList )) - rule appendValue(BufferId:Identifier, Value:Identifier, u128) - => v(:: bytes_hooks :: append_u128 ( BufferId , Value , .CallParamsList )) - rule appendValue(BufferId:Identifier, Value:Identifier, u160) - => v(:: bytes_hooks :: append_u160 ( BufferId , Value , .CallParamsList )) - rule appendValue(BufferId:Identifier, Value:Identifier, u256) - => v(:: bytes_hooks :: append_u256 ( BufferId , Value , .CallParamsList )) - rule appendValue(BufferId:Identifier, Value:Identifier, bool) - => v(:: bytes_hooks :: append_bool ( BufferId , Value , .CallParamsList )) - rule appendValue(BufferId:Identifier, _Value:Identifier, ()) => v(BufferId) - rule appendValue(BufferId:Identifier, Value:Identifier, T:Type) - => e(error("appendValue: unrecognized type", ListItem(BufferId) ListItem(Value) ListItem(T))) + syntax Identifier ::= "ulm#head_size" [token] + | "ulm#head" [token] + | "ulm#tail" [token] + + syntax NonEmptyStatementsOrError ::= #codegenValuesEncoder + ( bufferId: Identifier + , headSize: ExpressionOrError + , append: NonEmptyStatementsOrError + ) [function, total] + + rule codegenValuesEncoder(... bufferId: BufferId:Identifier, values: Values:EncodeValues) + => #codegenValuesEncoder(BufferId, totalHeadSize(Values), appendValues(Values, ulm#head_size, ulm#head, ulm#tail)) + + rule #codegenValuesEncoder(_BufferId:Identifier, e(HeadSize:SemanticsError), _AppendValues:NonEmptyStatementsOrError) + => HeadSize + rule #codegenValuesEncoder(_BufferId:Identifier, v(_HeadSize:Expression), AppendValues:SemanticsError) + => AppendValues + rule #codegenValuesEncoder(BufferId:Identifier, v(HeadSize:Expression), AppendValues:NonEmptyStatements) + => concatNonEmptyStatements + ( let ulm#head_size = HeadSize; + let ulm#head = :: bytes_hooks :: empty ( .CallParamsList ); + let ulm#tail = :: bytes_hooks :: empty ( .CallParamsList ); + AppendValues + , let BufferId = :: bytes_hooks :: append_bytes_raw ( BufferId, ulm#head , .CallParamsList); + let BufferId = :: bytes_hooks :: append_bytes_raw ( BufferId, ulm#tail , .CallParamsList); + .NonEmptyStatements + ) + + syntax ExpressionOrError ::= totalHeadSize(EncodeValues) [function, total] + rule totalHeadSize(.EncodeValues) => v(ptrValue(null, u32(0p32))) + rule totalHeadSize(_:Expression : T:Type , Evs:EncodeValues) + => addOrError(headSize(T), totalHeadSize(Evs)) + + syntax NonEmptyStatementsOrError ::= appendValues + ( values: EncodeValues + , headSize: Expression + , head: Expression + , tail: Expression + ) [function, total] + rule appendValues(.EncodeValues, _HeadSize:Expression, _Head:Expression, _Tail:Expression) + => .NonEmptyStatements + rule appendValues + ( V:Expression : T:Type , Evs:EncodeValues + , HeadSize:Expression + , Head:Expression + , Tail:Expression + ) + => concat( + appendValue + ( V + , HeadSize + , Head, Tail + , appendType(T) + ) + , appendValues(Evs, HeadSize, Head, Tail) + ) + + syntax AppendType ::= fixedSize(PathInExpression) + | variableSize(PathInExpression) + | "empty" + syntax AppendTypeOrError ::= AppendType | SemanticsError + syntax AppendTypeOrError ::= appendType(Type) [function, total] + + rule appendType(u8 ) => fixedSize(:: bytes_hooks :: append_u8) + rule appendType(u16 ) => fixedSize(:: bytes_hooks :: append_u16) + rule appendType(u32 ) => fixedSize(:: bytes_hooks :: append_u32) + rule appendType(u64 ) => fixedSize(:: bytes_hooks :: append_u64) + rule appendType(u128) => fixedSize(:: bytes_hooks :: append_u128) + rule appendType(u160) => fixedSize(:: bytes_hooks :: append_u160) + rule appendType(u256) => fixedSize(:: bytes_hooks :: append_u256) + + rule appendType(bool) => fixedSize(:: bytes_hooks :: append_bool) + rule appendType(()) => empty + rule appendType(str) => variableSize(:: bytes_hooks :: append_str) + rule appendType(T:Type) + => error("appendType: unrecognized type", ListItem(T)) + [owise] + + syntax NonEmptyStatementsOrError ::= appendValue + ( value: Expression + , headSize: Expression + , head: Identifier + , tail: Identifier + , appendFn: AppendTypeOrError + ) [function, total] + + rule appendValue + (... value: _Value:Expression + , headSize: _HeadSize:Expression + , head: _Head:Identifier + , tail: _Tail:Identifier + , appendFn: E:SemanticsError + ) + => E + rule appendValue + (... value: Value:Expression + , headSize: _HeadSize:Expression + , head: Head:Identifier + , tail: _Tail:Identifier + , appendFn: fixedSize(P:PathInExpression) + ) + => let Head = P ( Head , Value , .CallParamsList ); + .NonEmptyStatements + rule appendValue + (... value: Value:Expression + , headSize: HeadSize:Expression + , head: Head:Identifier + , tail: Tail:Identifier + , appendFn: variableSize(P:PathInExpression) + ) + => let Head = :: bytes_hooks :: append_u32 + ( Head + , HeadSize + (:: bytes_hooks :: length( Tail, .CallParamsList )) + , .CallParamsList + ); + let Tail = P ( Tail , Value , .CallParamsList ); + .NonEmptyStatements + rule appendValue + (... value: _Value:Expression + , headSize: _HeadSize:Expression + , head: _Head:Identifier + , tail: _Tail:Identifier + , appendFn: empty + ) + => .NonEmptyStatements + + syntax ExpressionOrError ::= headSize(Type) [function, total] + rule headSize(u8 ) => v(ptrValue(null, u32(32p32))) + rule headSize(u16 ) => v(ptrValue(null, u32(32p32))) + rule headSize(u32 ) => v(ptrValue(null, u32(32p32))) + rule headSize(u64 ) => v(ptrValue(null, u32(32p32))) + rule headSize(u128) => v(ptrValue(null, u32(32p32))) + rule headSize(u160) => v(ptrValue(null, u32(32p32))) + rule headSize(u256) => v(ptrValue(null, u32(32p32))) + + rule headSize(bool) => v(ptrValue(null, u32(32p32))) + rule headSize(()) => v(ptrValue(null, u32(0p32))) + rule headSize(str) => v(ptrValue(null, u32(32p32))) + rule headSize(T:Type) + => e(error("headSize: unrecognized type", ListItem(T:Type:KItem))) [owise] rule methodSignature(S:String, Ps:NormalizedFunctionParameterList) @@ -160,6 +285,14 @@ module ULM-CALLDATA-ENCODER rule signatureType(T) => error("Unknown type in signatureType:", ListItem(T)) [owise] + rule paramToEncodeValue(I:Identifier : T:Type) => I : T + rule paramToEncodeValue(I:SelfSort : T:Type) => I : T + + rule paramsToEncodeValues(.NormalizedFunctionParameterList) => .EncodeValues + rule paramsToEncodeValues(P:NormalizedFunctionParameter , Ps:NormalizedFunctionParameterList) + => paramToEncodeValue(P) , paramsToEncodeValues(Ps) + + endmodule ``` \ No newline at end of file diff --git a/ulm-semantics/main/encoding/syntax.md b/ulm-semantics/main/encoding/syntax.md index 9ec34ae4..d7688cb9 100644 --- a/ulm-semantics/main/encoding/syntax.md +++ b/ulm-semantics/main/encoding/syntax.md @@ -21,8 +21,14 @@ module ULM-ENCODING-SYNTAX syntax BytesOrError ::= methodSignature(String, NormalizedFunctionParameterList) [function, total] syntax ValueOrError ::= eventSignature(String, NormalizedFunctionParameterList) [function, total] - syntax ExpressionOrError ::= appendValue(bufferId: Identifier, value: Identifier, Type) [function, total] + syntax EncodeValue ::= Expression ":" Type + syntax EncodeValues ::= List{EncodeValue, ","} + // assumes that bufferId points to an empty buffer. + syntax NonEmptyStatementsOrError ::= codegenValuesEncoder(bufferId: Identifier, values: EncodeValues) [function, total] + + syntax EncodeValue ::= paramToEncodeValue(NormalizedFunctionParameter) [function, total] + syntax EncodeValues ::= paramsToEncodeValues(NormalizedFunctionParameterList) [function, total] endmodule module ULM-ENCODING-HELPER-SYNTAX diff --git a/ulm-semantics/main/hooks/bytes.md b/ulm-semantics/main/hooks/bytes.md index 32380b59..5111ea00 100644 --- a/ulm-semantics/main/hooks/bytes.md +++ b/ulm-semantics/main/hooks/bytes.md @@ -31,6 +31,7 @@ module ULM-SEMANTICS-HOOKS-BYTES | "length" [token] | "equals" [token] | "append_bool" [token] + | "append_bytes_raw" [token] | "append_u256" [token] | "append_u160" [token] | "append_u128" [token] @@ -144,6 +145,13 @@ module ULM-SEMANTICS-HOOKS-BYTES ) => ulmBytesAppendStr(BufferIdId, StrId) + rule + normalizedFunctionCall + ( :: bytes_hooks :: append_bytes_raw :: .PathExprSegments + , BufferIdId:Ptr, ToAppendId:Ptr, .PtrList + ) + => ulmBytesAppendBytesRaw(BufferIdId, ToAppendId) + rule normalizedFunctionCall ( :: bytes_hooks :: decode_u256 :: .PathExprSegments @@ -232,6 +240,8 @@ module ULM-SEMANTICS-HOOKS-BYTES | ulmBytesAppendInt(Expression, Expression) [seqstrict] | ulmBytesAppendInt(UlmExpression, Int) [strict(1)] | ulmBytesAppendBool(Expression, Expression) [seqstrict] + | ulmBytesAppendBytesRaw(Expression, Expression) [seqstrict] + | ulmBytesAppendBytesRaw(UlmExpression, UlmExpression) [seqstrict] | ulmBytesAppendStr(Expression, Expression) [seqstrict] | ulmBytesAppendBytes(UlmExpression, Bytes) [strict(1)] | ulmBytesAppendLenAndBytes(UlmExpression, Bytes) [strict(1)] @@ -297,11 +307,24 @@ module ULM-SEMANTICS-HOOKS-BYTES rule ulmBytesAppendStr(ptrValue(_, u64(BytesId)), ptrValue(_, Value:String)) => ulmBytesAppendLenAndBytes(ulmBytesId(BytesId), String2Bytes(Value)) + rule ulmBytesAppendBytesRaw(ptrValue(_, u64(BytesId)), ptrValue(_, u64(ToAppendId))) + => ulmBytesAppendBytesRaw(ulmBytesId(BytesId), ulmBytesId(ToAppendId)) + rule ulmBytesAppendBytesRaw(ulmBytesValue(B:Bytes), ulmBytesValue(ToAppend)) + => ulmBytesNew(B +Bytes ToAppend) + rule ulmBytesAppendBytes(ulmBytesValue(B:Bytes), Value:Bytes) => ulmBytesNew(B +Bytes Value) rule ulmBytesAppendLenAndBytes(ulmBytesValue(First:Bytes), Second:Bytes) - => ulmBytesNew(First +Bytes Int2Bytes(2, lengthBytes(Second), BE) +Bytes Second) + => ulmBytesNew + ( First + +Bytes Int2Bytes(32, lengthBytes(Second), BE) + +Bytes padRightBytes + ( Second + , ((lengthBytes(Second) +Int 31) /Int 32) *Int 32 + , 0 + ) + ) requires lengthBytes(Second) ulmBytesDecodeStr - ( Bytes2Int(substrBytes(B, 0, 2), BE, Signed) - , substrBytes(B, 2, lengthBytes(B)) + ( Bytes2Int(substrBytes(B, 0, 32), BE, Signed) + , substrBytes(B, 32, lengthBytes(B)) ) requires 2 <=Int lengthBytes(B) rule ulmBytesDecodeInt(Value:Int, B:Bytes, T:Type) => ulmBytesDecode(integerToValue(Value, T), B) rule ulmBytesDecodeStr(Len:Int, B:Bytes) - => ulmBytesDecode(Bytes2String(substrBytes(B, 0, Len)), substrBytes(B, Len, lengthBytes(B))) + => ulmBytesDecode + ( Bytes2String(substrBytes(B, 0, Len)) + , substrBytes(B, ((Len +Int 31) /Int 32) *Int 32, lengthBytes(B)) + ) requires 0 <=Int Len andBool Len <=Int lengthBytes(B) rule ulmBytesDecode(Value:Value, B:Bytes) diff --git a/ulm-semantics/main/preprocessing/endpoints.md b/ulm-semantics/main/preprocessing/endpoints.md index ee261139..1e4dda88 100644 --- a/ulm-semantics/main/preprocessing/endpoints.md +++ b/ulm-semantics/main/preprocessing/endpoints.md @@ -48,7 +48,7 @@ module ULM-PREPROCESSING-ENDPOINTS (... wrapperMethod: WrapperMethod , params: Params , method: ImplementationMethod - , appendReturn: appendValue(buffer_id, return_value, ReturnType) + , appendReturn: codegenValuesEncoder(buffer_id, (return_value : ReturnType , .EncodeValues)) , decodeStatements: decodeParams(0, Params) ) @@ -58,7 +58,7 @@ module ULM-PREPROCESSING-ENDPOINTS (... wrapperMethod: WrapperMethod:PathInExpression , params: Params:NormalizedFunctionParameterList , method: ImplementationMethod:Identifier - , appendReturn: v(Append:Expression) + , appendReturn: Append:NonEmptyStatements , decodeStatements: Decode:NonEmptyStatements ) => .K ... @@ -77,11 +77,14 @@ module ULM-PREPROCESSING-ENDPOINTS :: state_hooks :: setGasLeft(gas , .CallParamsList); concatNonEmptyStatements ( Decode - , let return_value = callMethod(ImplementationMethod, Params); - let buffer_id = :: bytes_hooks :: empty(.CallParamsList); - let buffer_id = Append; - :: state_hooks :: setOutput(buffer_id , .CallParamsList); - :: state_hooks :: setStatus(:: ulm :: EVMC_SUCCESS , .CallParamsList); + , concatNonEmptyStatements + ( let return_value = callMethod(ImplementationMethod, Params); + let buffer_id = :: bytes_hooks :: empty(.CallParamsList); + Append + , :: state_hooks :: setOutput(buffer_id , .CallParamsList); + :: state_hooks :: setStatus(:: ulm :: EVMC_SUCCESS , .CallParamsList); + .NonEmptyStatements + ) ) }) @@ -164,6 +167,7 @@ module ULM-PREPROCESSING-ENDPOINTS | "append_u160" [token] | "append_u256" [token] | "append_bool" [token] + | "append_str" [token] | "decode_u8" [token] | "decode_u16" [token] | "decode_u32" [token] @@ -246,15 +250,15 @@ module ULM-PREPROCESSING-ENDPOINTS rule decodeForType(u256) => v(:: bytes_hooks :: decode_u256 ( buffer_id , .CallParamsList )) syntax Expression ::= callMethod(Identifier, NormalizedFunctionParameterList) [function, total] - syntax Expression ::= callMethod(Identifier, CallParamsList) [function, total] + syntax Expression ::= #callMethod(Identifier, CallParamsList) [function, total] syntax CallParamsList ::= buildArgs(Int, NormalizedFunctionParameterList) [function, total] rule callMethod(Method:Identifier, Ps:NormalizedFunctionParameterList) - => callMethod(Method, buildArgs(0, Ps)) + => #callMethod(Method, buildArgs(0, Ps)) - rule callMethod(Method:Identifier, .CallParamsList) + rule #callMethod(Method:Identifier, .CallParamsList) => self . Method ( ) - rule callMethod(Method:Identifier, (_ , _:CallParamsList) #as Ps:CallParamsList) + rule #callMethod(Method:Identifier, (_ , _:CallParamsList) #as Ps:CallParamsList) => self . Method ( Ps ) rule buildArgs(_:Int, .NormalizedFunctionParameterList) => .CallParamsList diff --git a/ulm-semantics/main/preprocessing/events.md b/ulm-semantics/main/preprocessing/events.md index d0c4288d..475a9029 100644 --- a/ulm-semantics/main/preprocessing/events.md +++ b/ulm-semantics/main/preprocessing/events.md @@ -8,7 +8,7 @@ module ULM-PREPROCESSING-EVENTS imports private ULM-PREPROCESSING-SYNTAX-PRIVATE syntax Identifier ::= "bytes_hooks" [token] - | "data" [token] + | "log_buffer" [token] | "empty" [token] | "Log0" [token] | "Log1" [token] @@ -19,7 +19,7 @@ module ULM-PREPROCESSING-EVENTS syntax UkmInstruction ::= #ulmPreprocessEvent ( method: PathInExpression - , appendLastParam: ExpressionOrError + , appendLastParam: NonEmptyStatementsOrError , logIdentifier: IdentifierOrError , eventSignature: ValueOrError ) @@ -34,7 +34,13 @@ module ULM-PREPROCESSING-EVENTS // but the last one are indexed. We should handle generic events. => #ulmPreprocessEvent ( Method - , appendParamToBytes(data, last(Param, Params)) + , codegenValuesEncoder + ( log_buffer + , paramsToEncodeValues + ( last(Param, Params) + , .NormalizedFunctionParameterList + ) + ) , findLogIdentifier(1 +Int length(Params)) , eventSignature(EventName, (Param , Params)) ) @@ -49,7 +55,7 @@ module ULM-PREPROCESSING-EVENTS #ulmPreprocessEvent (... method: Method:PathInExpression - , appendLastParam: v(AppendLast:Expression) + , appendLastParam: AppendLast:NonEmptyStatements , logIdentifier: LogIdentifier:Identifier , eventSignature: EventSignature:Value ) @@ -61,29 +67,22 @@ module ULM-PREPROCESSING-EVENTS empty => block({ .InnerAttributes - let data = :: bytes_hooks :: empty ( .CallParamsList ); - let data = AppendLast; - :: ulm :: LogIdentifier - ( ptrValue(null, EventSignature) - , concatCallParamsList - ( paramsToArgs(allButLast(Param, Params)) - , (data , .CallParamsList) - ) - ); - .NonEmptyStatements + concatNonEmptyStatements + ( let log_buffer = :: bytes_hooks :: empty ( .CallParamsList ); + AppendLast + , :: ulm :: LogIdentifier + ( ptrValue(null, EventSignature) + , concatCallParamsList + ( paramsToArgs(allButLast(Param, Params)) + , (log_buffer , .CallParamsList) + ) + ); + .NonEmptyStatements + ) }) () - syntax ExpressionOrError ::= appendParamToBytes - ( bufferId: Identifier - , NormalizedFunctionParameter - ) [function, total] - rule appendParamToBytes(B:Identifier, (I:Identifier : T:Type)) => appendValue(B, I, T) - rule appendParamToBytes(B, P) - => e(error("appendParamToBytes: unrecognized param", ListItem(B) ListItem(P))) - [owise] - syntax IdentifierOrError ::= findLogIdentifier(Int) [function, total] rule findLogIdentifier(1) => Log1 rule findLogIdentifier(2) => Log2 diff --git a/ulm-semantics/main/preprocessing/syntax.md b/ulm-semantics/main/preprocessing/syntax.md index 0a34d8a9..5e80e05e 100644 --- a/ulm-semantics/main/preprocessing/syntax.md +++ b/ulm-semantics/main/preprocessing/syntax.md @@ -32,7 +32,7 @@ module ULM-PREPROCESSING-SYNTAX-PRIVATE ( wrapperMethod: PathInExpression , params: NormalizedFunctionParameterList , method: Identifier - , appendReturn: ExpressionOrError + , appendReturn: NonEmptyStatementsOrError , decodeStatements: NonEmptyStatementsOrError ) | ulmAddEndpointSignature(signature: BytesOrError, method: Identifier) diff --git a/ulm-semantics/test/execution.md b/ulm-semantics/test/execution.md index 7ad6ef31..7f22cbb2 100644 --- a/ulm-semantics/test/execution.md +++ b/ulm-semantics/test/execution.md @@ -18,6 +18,7 @@ module ULM-TEST-SYNTAX | "list_values_holder" List syntax ULMTestTypeHolderList ::= List{ULMTestTypeHolder, ","} + syntax BytesList ::= NeList{Bytes, "+"} syntax ExecutionItem ::= "mock" "CallData" | "mock" "Caller" @@ -36,6 +37,7 @@ module ULM-TEST-SYNTAX | "hold_string_from_test_stack" | "hold_list_values_from_test_stack" | "expect_cancel" + | "check_raw_output" BytesList syntax Identifier ::= "u8" [token] | "u16" [token] @@ -49,6 +51,7 @@ endmodule module ULM-TEST-EXECUTION imports private BYTES imports private COMMON-K-CELL + imports private K-EQUAL-SYNTAX imports private RUST-EXECUTION-TEST-CONFIGURATION imports private RUST-SHARED-SYNTAX imports private ULM-ENCODING-SYNTAX @@ -59,8 +62,6 @@ module ULM-TEST-EXECUTION imports private ULM-SEMANTICS-HOOKS-ULM-SYNTAX imports private ULM-REPRESENTATION imports private ULM-TEST-SYNTAX - imports private RUST-SHARED-SYNTAX - imports private BYTES syntax Mockable ::= UlmHook @@ -178,6 +179,26 @@ module ULM-TEST-EXECUTION rule (ulmCancel ~> expect_cancel) => .K + // BytesList is used to define bytes concatenation in tests, so the "+" + // uses below represent the test AST concatenation, which we are + // evaluating by concatenating the bytes. + syntax Bytes ::= concat(BytesList) [function, total] + rule concat(.BytesList) => b"" + rule concat(B:Bytes + Bs:BytesList) => B +Bytes concat(Bs) + + syntax Int ::= size(BytesList) [function, total] + rule size(.BytesList) => 0 + rule size(_:Bytes + Bs:BytesList) => 1 +Int size(Bs) + + rule check_raw_output (L:BytesList => concat(L) + .BytesList) + requires size(L) >Int 1 + rule + + check_raw_output B:Bytes + .BytesList => .K + ... + + B:Bytes + endmodule ```