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

Call data encoding and decoding #171

Merged
merged 3 commits into from
Oct 24, 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 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
Loading