Skip to content

Commit

Permalink
fix: codegen for hashmaps with string keys (#3384)
Browse files Browse the repository at this point in the history
this commit fixes a regression introduced in 3abe588, where the
codegen in parse_Subscript would handle string keys as non-bytestrings
(thus treating the value of the string as word loaded by the string
 pointer - its length value). it also cleans up the logic a little bit,
avoiding a redundant unwrap_location (since get_element_ptr calls
unwrap_location itself), and removing a dead argument from
keccak256_helper.
charles-cooper authored May 5, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 5ae0a07 commit d62125c
Showing 5 changed files with 35 additions and 11 deletions.
25 changes: 25 additions & 0 deletions tests/parser/features/test_string_map_keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
def test_string_map_keys(get_contract):
code = """
f:HashMap[String[1], bool]
@external
def test() -> bool:
a:String[1] = "a"
b:String[1] = "b"
self.f[a] = True
return self.f[b] # should return False
"""
c = get_contract(code)
c.test()
assert c.test() is False


def test_string_map_keys_literals(get_contract):
code = """
f:HashMap[String[1], bool]
@external
def test() -> bool:
self.f["a"] = True
return self.f["b"] # should return False
"""
c = get_contract(code)
assert c.test() is False
2 changes: 1 addition & 1 deletion vyper/builtins/functions.py
Original file line number Diff line number Diff line change
@@ -611,7 +611,7 @@ def infer_arg_types(self, node):
@process_inputs
def build_IR(self, expr, args, kwargs, context):
assert len(args) == 1
return keccak256_helper(expr, args[0], context)
return keccak256_helper(args[0], context)


def _make_sha256_call(inp_start, inp_len, out_start, out_len):
2 changes: 1 addition & 1 deletion vyper/codegen/events.py
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ def _encode_log_topics(expr, event_id, arg_nodes, context):
value = unwrap_location(arg)

elif isinstance(arg.typ, _BytestringT):
value = keccak256_helper(expr, arg, context=context)
value = keccak256_helper(arg, context=context)
else:
# TODO block at higher level
raise TypeMismatch("Event indexes may only be value types", expr)
11 changes: 5 additions & 6 deletions vyper/codegen/expr.py
Original file line number Diff line number Diff line change
@@ -338,11 +338,10 @@ def parse_Subscript(self):

if isinstance(sub.typ, HashMapT):
# TODO sanity check we are in a self.my_map[i] situation
index = Expr.parse_value_expr(self.expr.slice.value, self.context)
if isinstance(index.typ, BytesT):
index = Expr(self.expr.slice.value, self.context).ir_node
if isinstance(index.typ, _BytestringT):
# we have to hash the key to get a storage location
assert len(index.args) == 1
index = keccak256_helper(self.expr.slice.value, index.args[0], self.context)
index = keccak256_helper(index, self.context)

elif is_array_like(sub.typ):
index = Expr.parse_value_expr(self.expr.slice.value, self.context)
@@ -528,8 +527,8 @@ def parse_Compare(self):
left = Expr(self.expr.left, self.context).ir_node
right = Expr(self.expr.right, self.context).ir_node

left_keccak = keccak256_helper(self.expr, left, self.context)
right_keccak = keccak256_helper(self.expr, right, self.context)
left_keccak = keccak256_helper(left, self.context)
right_keccak = keccak256_helper(right, self.context)

if op not in ("eq", "ne"):
return # raises
6 changes: 3 additions & 3 deletions vyper/codegen/keccak256_helper.py
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
from vyper.utils import SHA3_BASE, SHA3_PER_WORD, MemoryPositions, bytes_to_int, keccak256


def _check_byteslike(typ, _expr):
def _check_byteslike(typ):
if not isinstance(typ, _BytestringT) and typ != BYTES32_T:
# NOTE this may be checked at a higher level, but just be safe
raise CompilerPanic("keccak256 only accepts bytes-like objects")
@@ -18,8 +18,8 @@ def _gas_bound(num_words):
return SHA3_BASE + num_words * SHA3_PER_WORD


def keccak256_helper(expr, to_hash, context):
_check_byteslike(to_hash.typ, expr)
def keccak256_helper(to_hash, context):
_check_byteslike(to_hash.typ)

# Can hash literals
# TODO this is dead code.

0 comments on commit d62125c

Please sign in to comment.