diff --git a/examples/map.nim b/examples/map.nim index 08afa1c..11fee6c 100644 --- a/examples/map.nim +++ b/examples/map.nim @@ -56,3 +56,6 @@ contract("MapStorage"): # tx = contract_.functions.set_name(b"key", b"value").buildTransaction({'from': acct.address, 'nonce': w3.eth.getTransactionCount(acct.address)}) +# signed = acct.signTransaction(tx) +# tx_hash = w3.eth.sendRawTransaction(signed.rawTransaction) +# receipt = w3.eth.waitForTransactionReceipt(tx_hash) diff --git a/examples/registry.nim b/examples/registry.nim index ea1f39f..e716656 100644 --- a/examples/registry.nim +++ b/examples/registry.nim @@ -5,8 +5,8 @@ contract("Registry"): names: StorageTable[bytes32, bytes32] - proc set_name*(k: bytes32, v: bytes32) {.self,msg.} = + proc set_name*(k: bytes32, v: bytes32) {.self.} = self.names[k] = v - # proc get_name(k: bytes32) {.self.} = - # self.names[k] + proc get_name*(k: bytes32): bytes32 {.self.} = + self.names[k] diff --git a/nimplay/builtin_keywords.nim b/nimplay/builtin_keywords.nim index 2805561..4b2bc46 100644 --- a/nimplay/builtin_keywords.nim +++ b/nimplay/builtin_keywords.nim @@ -55,14 +55,14 @@ proc is_log_statement(node: NimNode, global_ctx: GlobalContext): bool = ) -proc has_self_assignment(node: NimNode, global_ctx: GlobalContext): bool = +proc has_self_assignment(node: NimNode): bool = if node.kind == nnkAsgn: if is_dot_variable(node[0]) and node[0][0].strVal == "self": return true return false -proc has_self_storage_table(node: NimNode, global_ctx: GlobalContext): bool = +proc has_self_storage_table_set(node: NimNode): bool = if node.kind == nnkAsgn and node[0].kind == nnkBracketExpr: if is_dot_variable(node[0][0]) and node[0][0][0].strVal == "self": echo treeRepr(node) @@ -70,14 +70,22 @@ proc has_self_storage_table(node: NimNode, global_ctx: GlobalContext): bool = return false +proc has_self_storage_table_get(node: NimNode): bool = + if node.kind == nnkBracketExpr and is_dot_variable(node[0]): + return true + return false + + proc is_keyword(node: NimNode, global_ctx: GlobalContext): (bool, string) = if is_message_sender(node): return (true, "msg.sender") if is_message_value(node): return (true, "msg.value") - elif has_self_storage_table(node, global_ctx): - return (true, "set_table_self."& strVal(node[0][0][1])) - elif has_self_assignment(node, global_ctx): + elif has_self_storage_table_set(node): + return (true, "set_table_self." & strVal(node[0][0][1])) + elif has_self_storage_table_get(node): + return (true, "get_table_self." & strVal(node[0][1])) + elif has_self_assignment(node): return (true, "set_self." & strVal(node[0][1])) elif has_self(node, global_ctx): return (true, "self." & strVal(node[1])) @@ -90,8 +98,14 @@ proc is_keyword(node: NimNode, global_ctx: GlobalContext): (bool, string) = proc find_builtin_keywords(func_body: NimNode, used_keywords: var seq[string], global_ctx: GlobalContext) = for child in func_body: let (is_kw, kw_key_name) = is_keyword(child, global_ctx) - var setter_kw = false - for proposed_setter_kw in @["set_" & kw_key_name, "set_table_" & kw_key_name]: + var + setter_kw = false + setter_exemption_list = @[ + "set_" & kw_key_name, + "set_table_" & kw_key_name, + "get_table_" & kw_key_name, + ] + for proposed_setter_kw in setter_exemption_list: if proposed_setter_kw in used_keywords: setter_kw = true if is_kw and not setter_kw: @@ -141,7 +155,11 @@ proc generate_defines(keywords: seq[string], global_ctx: GlobalContext): (NimNod tmp_vars[kw] = new_proc_name stmts.add(new_proc) elif kw.startsWith("set_table_self."): - var (new_proc, new_proc_name) = generate_storage_table_func(kw, global_ctx) + var (new_proc, new_proc_name) = generate_storage_table_set_func(kw, global_ctx) + tmp_vars[kw] = new_proc_name + stmts.add(new_proc) + elif kw.startsWith("get_table_self."): + var (new_proc, new_proc_name) = generate_storage_table_get_func(kw, global_ctx) tmp_vars[kw] = new_proc_name stmts.add(new_proc) elif kw.startsWith("self."): @@ -153,7 +171,7 @@ proc generate_defines(keywords: seq[string], global_ctx: GlobalContext): (NimNod proc check_keyword_defines(keywords_used: seq[string], local_ctx: LocalContext) = for keyword in keywords_used: - var base = keyword.replace("set_", "").replace("table_", "") + var base = keyword.replace("set_", "").replace("get_", "").replace("table_", "") if "." in base: base = base.split(".")[0] if not (base in local_ctx.sig.pragma_base_keywords): @@ -167,13 +185,12 @@ proc get_keyword_defines*(proc_def: NimNode, global_ctx: GlobalContext, local_ct var keywords_used: seq[string] find_builtin_keywords(proc_def, keywords_used, global_ctx) - echo keywords_used - echo "%^%^%^%^%^" keywords_used = deduplicate(keywords_used) check_keyword_defines(keywords_used, local_ctx) let (global_define_stmts, global_keyword_map) = generate_defines(keywords_used, global_ctx) return (global_define_stmts, global_keyword_map) + proc get_next_storage_node(kw_key_name: string, global_keyword_map: Table[string, string], current_node: NimNode): NimNode = if kw_key_name.startsWith("self."): return nnkCall.newTree( @@ -183,7 +200,15 @@ proc get_next_storage_node(kw_key_name: string, global_keyword_map: Table[string return nnkCall.newTree( newIdentNode(global_keyword_map[kw_key_name]), current_node[1] + ) + elif kw_key_name.startsWith("get_table_self."): + var call_func = nnkCall.newTree( + newIdentNode(global_keyword_map[kw_key_name]), ) + echo treeRepr(current_node) + for param in current_node[1..current_node.len - 1]: # key params + call_func.add(param) + return call_func elif kw_key_name.startsWith("set_table_self."): var call_func = nnkCall.newTree( newIdentNode(global_keyword_map[kw_key_name]), @@ -191,10 +216,8 @@ proc get_next_storage_node(kw_key_name: string, global_keyword_map: Table[string for param in current_node[0][1..current_node.len - 1]: # key params call_func.add(param) call_func.add(current_node[1]) # val param - echo treeRepr(call_func) return call_func else: - raise newException(ParserError, "Unknown global self keyword") diff --git a/nimplay/nimplay_macros.nim b/nimplay/nimplay_macros.nim index ac84c18..5cc337c 100644 --- a/nimplay/nimplay_macros.nim +++ b/nimplay/nimplay_macros.nim @@ -238,22 +238,21 @@ template get_util_functions() {.dirty.} = if Uint128.fromBytesBE(b) > 0.stuint(128): revert(nil, 0) - proc exit_message(s: string) = + proc exitMessage(s: string) = revert(cstring(s), s.len.int32) proc concat[I1, I2: static[int]; T](a: array[I1, T], b: array[I2, T]): array[I1 + I2, T] = result[0..a.high] = a result[a.len..result.high] = b - proc setTableValue[N](table_id: int32, key: array[N, byte], value: var bytes32) = + proc getHashedKey[N](table_id: int32, key: array[N, byte]): bytes32 = type CombinedKey {.packed.} = object table_id: int32 key: array[N, byte] - var - sha256_address: array[20, byte] + hashed_key {.noinit.}: bytes32 combined_key: CombinedKey - hashed_key: bytes32 + sha256_address: array[20, byte] sha256_address[19] = 2'u8 combined_key.table_id = table_id @@ -267,14 +266,25 @@ template get_util_functions() {.dirty.} = sizeof(combined_key).int32, # dataLength ) if res == 1: # call failed - exit_message("Could not call sha256 in setTableValue") + exitMessage("Could not call sha256 in setTableValue") # raise newException(Exception, "Could not call sha256 in setTableValue") if getReturnDataSize() != 32.int32: - exit_message("Could not call sha256, Incorrect return size") - + exitMessage("Could not call sha256, Incorrect return size") returnDataCopy(addr hashed_key, 0.int32, 32.int32) + + hashed_key # return + + proc setTableValue[N](table_id: int32, key: array[N, byte], value: var bytes32) = + var hashed_key = getHashedKey(table_id, key) storageStore(hashed_key, addr value) + proc getTableValue[N](table_id: int32, key: array[N, byte], ): bytes32 = + var + value: bytes32 + hashed_key: bytes32 = getHashedKey(table_id, key) + storageLoad(hashed_key, addr value) + value # return + proc get_getter_func(var_struct: VariableType): NimNode = let diff --git a/nimplay/storage.nim b/nimplay/storage.nim index 983eed7..64cc99e 100644 --- a/nimplay/storage.nim +++ b/nimplay/storage.nim @@ -6,9 +6,9 @@ import tables import ./types -proc generate_storage_get_func*(storage_keword: string, global_ctx: GlobalContext): (NimNode, string) = +proc generate_storage_get_func*(storage_keyword: string, global_ctx: GlobalContext): (NimNode, string) = var - global_var_name = storage_keword.split(".")[1] + global_var_name = storage_keyword.split(".")[1] new_proc_name = fmt"get_{global_var_name}_from_storage" var_info = global_ctx.global_variables[global_var_name] slot_number = var_info.slot @@ -61,27 +61,6 @@ proc generate_storage_get_func*(storage_keword: string, global_ctx: GlobalContex return tmp """) return (new_proc, new_proc_name) - # elif var_info.var_type == "StorageTable": - # var - # key_param_arr: seq[string] - # value_type = var_info.key_types[^1] - # table_id = var_info.slot - # key_count = 0 - # for x in var_info.key_types[0..^1]: - # key_param_arr.add( - # fmt"key{key_count}:" & x - # ) - # inc(key_count) - - # var new_proc = parseStmt(fmt""" - # proc {new_proc_name}({key_param_arr.join(",")}): {value_type} = - # var - # tmp {{.noinit.}}: bytes32 - # pos = {$slot_number}.stuint(32).toByteArrayBE - # storageLoad(pos, addr tmp) - # return tmp - # """) - # return (new_proc, new_proc_name) else: raise newException(ParserError, var_info.var_type & " storage is not supported at the moment.") @@ -136,12 +115,12 @@ proc generate_storage_set_func*(storage_keyword: string, global_ctx: GlobalConte raise newException(ParserError, var_info.var_type & " storage is not supported at the moment.") -proc generate_storage_table_func*(storage_keyword: string, global_ctx: GlobalContext): (NimNode, string) = +proc generate_storage_table_set_func*(storage_keyword: string, global_ctx: GlobalContext): (NimNode, string) = var key_param_arr: seq[string] global_var_name = storage_keyword.split(".")[1] var_info = global_ctx.global_variables[global_var_name] - new_proc_name = fmt"set_{global_var_name}_in_storage" + new_proc_name = fmt"set_{global_var_name}_in_storage_table" value_type = var_info.key_types[^1] table_id = var_info.slot key_count = 0 @@ -159,8 +138,37 @@ proc generate_storage_table_func*(storage_keyword: string, global_ctx: GlobalCon raise newException(ParserError, "Only one key storage is supported at the moment.") var new_proc = parseStmt(fmt""" - proc {new_proc_name}({key_param_arr.join(",")}, val: {var_info.key_types[^1]}) = + proc {new_proc_name}({key_param_arr.join(",")}, val: {value_type}) = var tmp_val = val setTableValue({table_id}.int32, {combined_key}, tmp_val) """) return (new_proc, new_proc_name) + + +proc generate_storage_table_get_func*(storage_keyword: string, global_ctx: GlobalContext): (NimNode, string) = + var + key_param_arr: seq[string] + global_var_name = storage_keyword.split(".")[1] + new_proc_name = fmt"get_{global_var_name}_in_storage_table" + var_info = global_ctx.global_variables[global_var_name] + value_type = var_info.key_types[^1] + table_id = var_info.slot + key_count = 0 + combined_key = "" + + for x in var_info.key_types[0..^2]: + key_param_arr.add( + fmt"key{key_count}: " & x + ) + inc(key_count) + + if key_param_arr.len == 1: + combined_key = "key0" + else: + raise newException(ParserError, "Only one key storage is supported at the moment.") + + var new_proc = parseStmt(fmt""" + proc {new_proc_name}({key_param_arr.join(",")}): {value_type} = + getTableValue({table_id}.int32, {combined_key}) + """) + return (new_proc, new_proc_name)