Skip to content

Commit

Permalink
Call data encoding and decoding (#171)
Browse files Browse the repository at this point in the history
* Call data encoding and decoding

* Making spliting the encoding to helpers and main module. Adding TODOs.

---------

Co-authored-by: ACassimiro <[email protected]>
  • Loading branch information
virgil-serbanuta and ACassimiro authored Oct 24, 2024
1 parent 076c304 commit 115fd63
Show file tree
Hide file tree
Showing 17 changed files with 193 additions and 138 deletions.
4 changes: 2 additions & 2 deletions tests/ukm-contracts/bytes_hooks.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
extern "C" {
fn empty() -> u64;
fn length(bytes_id: u64) -> u32;
fn equals(bytes_id_1: u64, bytes_id_2: u64) -> bool;

fn append_u256(bytes_id: u64, value: u256) -> u64;
fn append_u160(bytes_id: u64, value: u160) -> u64;
Expand All @@ -19,8 +20,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, str);
fn decode_signature(bytes_id: u64) -> (u64, u64);
fn hash(bytes_id: u64) -> u64;
}
4 changes: 2 additions & 2 deletions tests/ukm-no-contract/test_bytes_hooks.append32.run
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ call :: test_bytes_hooks :: append_u32;
return_value_to_arg;
call :: bytes_hooks :: length;
return_value;
check_eq 3_u32;
check_eq 32_u32;

push 1000_u32;
call :: test_bytes_hooks :: append_u32;
return_value_to_arg;
call :: bytes_hooks :: length;
return_value;
check_eq 4_u32
check_eq 32_u32
4 changes: 2 additions & 2 deletions tests/ukm-no-contract/test_bytes_hooks.append64.run
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ call :: test_bytes_hooks :: append_u64;
return_value_to_arg;
call :: bytes_hooks :: length;
return_value;
check_eq 3_u32;
check_eq 32_u32;

push 1000_u64;
call :: test_bytes_hooks :: append_u64;
return_value_to_arg;
call :: bytes_hooks :: length;
return_value;
check_eq 4_u32
check_eq 32_u32
2 changes: 1 addition & 1 deletion tests/ukm-with-contract/endpoints.2.run
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ push 1_u64;
hold_list_values_from_test_stack;
encode_call_data_to_string;
return_value;
check_eq "81922854\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\x01"
check_eq "\x00\x81\x00\x92\x00(\x00T\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\x01"
40 changes: 20 additions & 20 deletions tests/ukm-with-contract/erc_20_token.1.run
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
list_mock GetAccountStorageHook ( 7809087261546347641 ) ukmIntResult(0, u256);
list_mock SetAccountStorageHook ( 7809087261546347641 , 10000 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7162266444907899391 ) ukmIntResult(0, u256);
list_mock SetAccountStorageHook ( 7162266444907899391 , 10000 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7162266444907899391 ) ukmIntResult(10000, u256);
list_mock GetAccountStorageHook ( 7162266444907899391 ) ukmIntResult(10000, u256);
list_mock GetAccountStorageHook ( 7162266444907899391 ) ukmIntResult(10000, u256);
list_mock SetAccountStorageHook ( 7162266444907899391 , 9900 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7162266444908917614 ) ukmIntResult(0, u256);
list_mock SetAccountStorageHook ( 7162266444908917614 , 100 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7162266444907899391 ) ukmIntResult(9900, u256);
list_mock GetAccountStorageHook ( 7162266444908917614 ) ukmIntResult(100, u256);
list_mock SetAccountStorageHook ( 8028228613167873919 , 200 ) ukmNoResult();
list_mock GetAccountStorageHook ( 8028228613167873919 ) ukmIntResult(200, u256);
list_mock SetAccountStorageHook ( 8028228613167873919 , 0 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7162266444907899391 ) ukmIntResult(9900, u256);
list_mock GetAccountStorageHook ( 7162266444907899391 ) ukmIntResult(9900, u256);
list_mock SetAccountStorageHook ( 7162266444907899391 , 9700 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7162266444908917614 ) ukmIntResult(100, u256);
list_mock SetAccountStorageHook ( 7162266444908917614 , 300 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7162266444907899391 ) ukmIntResult(9700, u256);
list_mock GetAccountStorageHook ( 7162266444908917614 ) ukmIntResult(300, u256);
list_mock GetAccountStorageHook ( 7089066454178295295 ) ukmIntResult(0, u256);
list_mock SetAccountStorageHook ( 7089066454178295295 , 10000 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7089066454178295295 ) ukmIntResult(10000, u256);
list_mock GetAccountStorageHook ( 7089066454178295295 ) ukmIntResult(10000, u256);
list_mock GetAccountStorageHook ( 7089066454178295295 ) ukmIntResult(10000, u256);
list_mock SetAccountStorageHook ( 7089066454178295295 , 9900 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7089066454179379067 ) ukmIntResult(0, u256);
list_mock SetAccountStorageHook ( 7089066454179379067 , 100 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7089066454178295295 ) ukmIntResult(9900, u256);
list_mock GetAccountStorageHook ( 7089066454179379067 ) ukmIntResult(100, u256);
list_mock SetAccountStorageHook ( 7089066454178299391 , 200 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7089066454178299391 ) ukmIntResult(200, u256);
list_mock SetAccountStorageHook ( 7089066454178299391 , 0 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7089066454178295295 ) ukmIntResult(9900, u256);
list_mock GetAccountStorageHook ( 7089066454178295295 ) ukmIntResult(9900, u256);
list_mock SetAccountStorageHook ( 7089066454178295295 , 9700 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7089066454179379067 ) ukmIntResult(100, u256);
list_mock SetAccountStorageHook ( 7089066454179379067 , 300 ) ukmNoResult();
list_mock GetAccountStorageHook ( 7089066454178295295 ) ukmIntResult(9700, u256);
list_mock GetAccountStorageHook ( 7089066454179379067 ) ukmIntResult(300, u256);

push "#init";
hold_string_from_test_stack;
Expand Down
4 changes: 2 additions & 2 deletions tests/ukm-with-contract/storage.key.run
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mock SetAccountStorageHook ( 7010817630605304703 , 123 ) ukmNoResult();
mock GetAccountStorageHook ( 7010817630605304703 ) ukmIntResult(123, u64);
mock SetAccountStorageHook ( 8738216329482039167 , 123 ) ukmNoResult();
mock GetAccountStorageHook ( 8738216329482039167 ) ukmIntResult(123, u64);

push "setMyDataKey";
hold_string_from_test_stack;
Expand Down
1 change: 1 addition & 0 deletions ukm-semantics/main/encoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
requires "encoding/encoder.md"
requires "encoding/impl.md"
requires "encoding/syntax.md"
requires "encoding/encoder.md"
module UKM-ENCODING
imports private UKM-CALLDATA-ENCODER
Expand Down
100 changes: 61 additions & 39 deletions ukm-semantics/main/encoding/encoder.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,91 @@
```k
requires "plugin/krypto.md"
module UKM-ENCODING-HELPER
imports private BYTES
imports private INT-SYNTAX
imports private KRYPTO
imports private STRING
imports private UKM-ENCODING-HELPER-SYNTAX
// TODO: Error for argument of length 1 or string not hex
rule encodeHexBytes(_:String) => .Bytes
[owise]
rule encodeHexBytes(S:String)
=> Int2Bytes(2, String2Base(substrString(S, 0, 2), 16), BE)
+Bytes encodeHexBytes(substrString(S, 2, lengthString(S)))
requires 2 <=Int lengthString(S) andBool isHex(substrString(S, 0, 2), 0)
syntax Bool ::= isHex(String, idx:Int) [function, total]
rule isHex(S:String, I:Int) => true
requires I <Int 0 orBool lengthString(S) <=Int I
rule isHex(S:String, I:Int)
=> isHexDigit(substrString(S, I, I +Int 1)) andBool isHex(S, I +Int 1)
requires 0 <=Int I andBool I <Int lengthString(S)
syntax Bool ::= isHexDigit(String) [function, total]
rule isHexDigit(S)
=> ("0" <=String S andBool S <=String "9")
orBool ("a" <=String S andBool S <=String "f")
orBool ("A" <=String S andBool S <=String "F")
// Encoding of individual types
rule convertToKBytes(i8(V) , "int8") => Int2Bytes(32, MInt2Signed(V), BE:Endianness)
rule convertToKBytes(u8(V) , "uint8") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(i16(V), "int16") => Int2Bytes(32, MInt2Signed(V), BE:Endianness)
rule convertToKBytes(u16(V), "uint16") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(i32(V), "int32") => Int2Bytes(32, MInt2Signed(V), BE:Endianness)
rule convertToKBytes(u32(V), "uint32") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(i64(V), "int64") => Int2Bytes(32, MInt2Signed(V), BE:Endianness)
rule convertToKBytes(u64(V), "uint64") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(u128(V), "uint128") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(true, "bool") => Int2Bytes(32, 1, BE:Endianness)
rule convertToKBytes(false, "bool") => Int2Bytes(32, 0, BE:Endianness)
rule convertToKBytes(u256(V), "uint256") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(u160(V), "uint160") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(u160(V), "address") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
endmodule
module UKM-CALLDATA-ENCODER
imports private COMMON-K-CELL
imports private BYTES
imports private INT-SYNTAX
imports private KRYPTO
imports private STRING
imports private UKM-ENCODING-SYNTAX
imports private UKM-PREPROCESSING-ENDPOINTS
imports STRING
imports BYTES
imports INT
imports KRYPTO
imports private UKM-ENCODING-HELPER-SYNTAX
imports private UKM-ENCODING-HELPER
rule encodeFunctionSignatureAsBytes(FS)
=> encodeHexBytes(substrString(Keccak256(String2Bytes(FS)), 0, 8))
rule encodeFunctionSignatureAsBytes(E:SemanticsError) => E
// TODO: Properly encode the call data. Currently, we are returning the
// representation of the encoded function signature from a string using
// two characters to represent a byte in hexadecimal. We need to return the
// correct four bytes representation of signature.
// TODO: it may be worth extracting the substrString(Keccak256(String2Bytes(FS)), 0, 8)
// thing to a function that takes a String and produces a String or Bytes (as opposed to
// taking a StringOrError as below) (perhaps with an encodeAsBytes(...) on top of it) and
// then use it here and in the rules below.
rule encodeCallData(FN:String, FAT:List, FAL:List) =>
encodeFunctionSignature(FN, FAT) +Bytes encodeFunctionParams(FAL, FAT, b"")
encodeFunctionSignature(FN, FAT) +Bytes encodeFunctionParams(FAL, FAT, b"")
// Function signature encoding
rule encodeFunctionSignature(FuncName:String, RL:List) =>
encodeFunctionSignatureHelper(RL:List, FuncName +String "(") [priority(40)]
rule encodeFunctionSignatureHelper(ListItem(FuncParam:String) RL:List, FS) =>
encodeFunctionSignatureHelper(RL, FS +String FuncParam +String ",") [owise]
encodeFunctionSignatureHelper(RL, FS +String FuncParam +String ",") [owise]
// The last param does not have a follow up comma
rule encodeFunctionSignatureHelper(ListItem(FuncParam:String) .List, FS) =>
encodeFunctionSignatureHelper(.List, FS +String FuncParam )
rule encodeFunctionSignatureHelper(.List, FS) => String2Bytes(substrString(Keccak256(String2Bytes(FS +String ")")), 0, 8))
encodeFunctionSignatureHelper(.List, FS +String FuncParam )
// TODO: Implement helper functions and break down encodeFunctionSignatureAsString
// into smaller productions. Trigger errors for each of the
// possible functions which can be failure causes.
rule encodeFunctionSignatureAsString(FS) => substrString(Keccak256(String2Bytes(FS)), 0, 8)
rule encodeFunctionSignatureAsString(FS) => error("Failed to apply the Keccak256 of function signature.", FS) [owise]
rule encodeFunctionSignatureHelper(.List, FS) => encodeHexBytes(substrString(Keccak256(String2Bytes(FS +String ")")), 0, 8))
// Function parameters encoding
rule encodeFunctionParams(ListItem(V:Value) ARGS:List, ListItem(T:String) PTYPES:List, B:Bytes) =>
encodeFunctionParams(ARGS:List, PTYPES:List, B:Bytes +Bytes convertToKBytes(V, T))
rule encodeFunctionParams(.List, .List, B:Bytes) => B
// Encoding of individual types
rule convertToKBytes(i8(V) , "int8") => Int2Bytes(32, MInt2Signed(V), BE:Endianness)
rule convertToKBytes(u8(V) , "uint8") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(i16(V), "int16") => Int2Bytes(32, MInt2Signed(V), BE:Endianness)
rule convertToKBytes(u16(V), "uint16") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(i32(V), "int32") => Int2Bytes(32, MInt2Signed(V), BE:Endianness)
rule convertToKBytes(u32(V), "uint32") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(i64(V), "int64") => Int2Bytes(32, MInt2Signed(V), BE:Endianness)
rule convertToKBytes(u64(V), "uint64") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(u128(V), "uint128") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(true, "bool") => Int2Bytes(32, 1, BE:Endianness)
rule convertToKBytes(false, "bool") => Int2Bytes(32, 0, BE:Endianness)
rule convertToKBytes(u256(V), "uint256") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(u160(V), "uint160") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
rule convertToKBytes(u160(V), "address") => Int2Bytes(32, MInt2Unsigned(V), BE:Endianness)
endmodule
```
18 changes: 15 additions & 3 deletions ukm-semantics/main/encoding/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,26 @@ module UKM-ENCODING-SYNTAX
syntax UKMInstruction ::= "ukmEncodePreprocessedCell"
| ukmEncodedPreprocessedCell(Bytes)
// TODO: Make these functions total and returning BytesOrError
syntax Bytes ::= encodeCallData (String, List, List) [function] //Function name, argument types, argument list
| encodeFunctionSignature (String, List) [function]
| encodeFunctionSignatureHelper (List, String) [function]
| encodeFunctionParams (List, List, Bytes) [function]
| convertToKBytes ( Value , String ) [function]
syntax StringOrError ::= encodeFunctionSignatureAsString(StringOrError) [function, total]
syntax BytesOrError ::= encodeFunctionSignatureAsBytes(StringOrError) [function, total]
endmodule
module UKM-ENCODING-HELPER-SYNTAX
imports BYTES-SYNTAX
imports LIST
imports RUST-REPRESENTATION
imports UKM-REPRESENTATION
// TODO: Make convertToKBytes total
syntax Bytes ::= encodeHexBytes(String) [function, total]
| convertToKBytes ( Value , String ) [function]
endmodule
```
```
Loading

0 comments on commit 115fd63

Please sign in to comment.