def test_constants_fail(bad_code): if isinstance(bad_code, tuple): with raises(bad_code[1]): compiler.compile_code(bad_code[0]) else: with raises(StructureException): compiler.compile_code(bad_code)
def test_varname_validity_fail(bad_code): if isinstance(bad_code, tuple): with raises(bad_code[1]): compiler.compile_code(bad_code[0]) else: with raises(EventDeclarationException): compiler.compile_code(bad_code)
def test_tuple_assign_fail(bad_code): if isinstance(bad_code, tuple): with raises(bad_code[1]): compiler.compile_code(bad_code[0]) else: with raises(TypeMismatch): compiler.compile_code(bad_code)
def test_as_wei_fail(bad_code): if isinstance(bad_code, tuple): with raises(bad_code[1]): compiler.compile_code(bad_code[0]) else: with raises(VariableDeclarationException): compiler.compile_code(bad_code)
def test_chain_fail(bad_code): if isinstance(bad_code, tuple): with raises(bad_code[1]): compiler.compile_code(bad_code[0], evm_version="istanbul") else: with raises(TypeMismatch): compiler.compile_code(bad_code, evm_version="istanbul")
def test_undef_toplevel(): code = """ @public def foo(): x = bar(55) """ with raises(StructureException) as ex: compiler.compile_code(code) assert "Not a top-level function: bar" in str(ex.value)
def test_json_interface_implements(type_str): code = interface_test_code.format(type_str) abi = compile_code(code, ['abi'])['abi'] code = f"import jsonabi as jsonabi\nimplements: jsonabi\n{code}" compile_code(code, interface_codes={'jsonabi': { 'type': 'json', 'code': abi }})
def test_evm_version(evm_version): code = """ @public def foo(): a: uint256 = chain.id """ if EVM_VERSIONS[evm_version] < 2: with raises(EvmVersionException): compiler.compile_code(code, evm_version=evm_version) else: compiler.compile_code(code, evm_version=evm_version)
def test_undef_suggestion(): code = """ @public def bar(x: int128) -> int128: return 3 * x @public def foo() -> int128: return bar(20) """ with raises(StructureException) as ex: compiler.compile_code(code) assert "Not a top-level function: bar" in str(ex.value) assert "Did you mean self.bar?" in str(ex.value)
def test_external_interface_parsing(assert_compile_failed): interface_code = """ @public def foo() -> uint256: pass @public def bar() -> uint256: pass """ interface_codes = { 'FooBarInterface': { 'type': 'srilang', 'code': interface_code } } code = """ import a as FooBarInterface implements: FooBarInterface @public def foo() -> uint256: return 1 @public def bar() -> uint256: return 2 """ assert compile_code(code, interface_codes=interface_codes) not_implemented_code = """ import a as FooBarInterface implements: FooBarInterface @public def foo() -> uint256: return 1 """ assert_compile_failed( lambda: compile_code(not_implemented_code, interface_codes=interface_codes), StructureException)
def test_imports_and_implements_within_interface(): interface_code = """ from srilang.interfaces import ERC20 import foo.bar as Baz implements: Baz @public def foobar(): pass """ code = """ import foo as Foo implements: Foo @public def foobar(): pass """ assert compiler.compile_code( code, interface_codes={'Foo': { 'type': "srilang", 'code': interface_code }}) is not None
def _get_contract(w3, source_code, *args, **kwargs): out = compiler.compile_code( source_code, ['abi', 'bytecode'], interface_codes=kwargs.pop('interface_codes', None), evm_version=kwargs.pop('evm_version', None), ) LARK_GRAMMAR.parse(source_code + "\n") # Test grammar. abi = out['abi'] bytecode = out['bytecode'] value = kwargs.pop('value_in_eth', 0) * 10**18 # Handle deploying with an eth value. c = w3.eth.contract(abi=abi, bytecode=bytecode) deploy_transaction = c.constructor(*args) tx_info = { 'from': w3.eth.accounts[0], 'value': value, 'gasPrice': 0, } tx_info.update(kwargs) tx_hash = deploy_transaction.transact(tx_info) address = w3.eth.getTransactionReceipt(tx_hash)['contractAddress'] contract = w3.eth.contract( address, abi=abi, bytecode=bytecode, ContractFactoryClass=srilangContract, ) return contract
def test_get_extcodehash(get_contract, evm_version): code = """ a: address @public def __init__(): self.a = self @public def foo(x: address) -> bytes32: return x.codehash @public def foo2(x: address) -> bytes32: b: address = x return b.codehash @public def foo3() -> bytes32: return self.codehash @public def foo4() -> bytes32: return self.a.codehash """ if evm_version in ("byzantium", "atlantis"): with pytest.raises(EvmVersionException): compile_code(code, evm_version=evm_version) return compiled = compile_code(code, ['bytecode_runtime'], evm_version=evm_version) bytecode = bytes.fromhex(compiled['bytecode_runtime'][2:]) hash_ = keccak256(bytecode) c = get_contract(code, evm_version=evm_version) assert c.foo(c.address) == hash_ assert not int(c.foo("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF").hex(), 16) assert c.foo2(c.address) == hash_ assert not int(c.foo2("0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF").hex(), 16) assert c.foo3() == hash_ assert c.foo4() == hash_
def test_bitwise_opcodes(evm_version): opcodes = compile_code(code, ['opcodes'], evm_version=evm_version)['opcodes'] if evm_version in ("byzantium", "atlantis"): assert "SHL" not in opcodes assert "SHR" not in opcodes else: assert "SHL" in opcodes assert "SHR" in opcodes
def test_ast_to_dict_node_id(): code = """ @public def test() -> int128: a: uint256 = 100 return 123 """ dict_out = compiler.compile_code(code, ['ast_dict']) node_ids = get_node_ids(dict_out) assert len(node_ids) == len(set(node_ids))
def test_basic_interface_implements(assert_compile_failed): code = """ from srilang.interfaces import ERC20 implements: ERC20 @public def test() -> bool: return True """ assert_compile_failed(lambda: compile_code(code), StructureException)
def test_self_interface_cannot_compile(assert_compile_failed): code = """ contract Bar: def foo() -> uint256: constant @public def foo() -> uint256 : return 42 @public def bar() -> uint256: return Bar(self).foo() """ assert_compile_failed(lambda: compile_code(code), StructureException)
def test_constant_folds(search_for_sublist): some_prime = 10013677 code = f""" SOME_CONSTANT: constant(uint256) = 11 + 1 SOME_PRIME: constant(uint256) = {some_prime} @public def test() -> uint256: # calculate some constant which is really unlikely to be randomly # in bytecode return 2**SOME_CONSTANT * SOME_PRIME """ lll = compile_code(code, ['ir'])['ir'] assert search_for_sublist(lll, ['mstore', [0], [2**12 * some_prime]])
def test_jump_map(): source_map = compile_code(TEST_CODE, ['source_map'])['source_map'] pos_map = source_map['pc_pos_map'] jump_map = source_map['pc_jump_map'] assert len([v for v in jump_map.values() if v == "o"]) == 3 assert len([v for v in jump_map.values() if v == "i"]) == 2 code_lines = [i + "\n" for i in TEST_CODE.split("\n")] for pc in [k for k, v in jump_map.items() if v == "o"]: lineno, col_offset, _, end_col_offset = pos_map[pc] assert code_lines[lineno - 1][col_offset:end_col_offset].startswith("return") for pc in [k for k, v in jump_map.items() if v == "i"]: lineno, col_offset, _, end_col_offset = pos_map[pc] assert code_lines[lineno - 1][col_offset:end_col_offset].startswith("self.")
def test_method_identifiers(): code = """ x: public(int128) @public def foo(x: uint256) -> bytes[100]: return b"hello" """ out = compile_code( code, output_formats=['method_identifiers'], ) assert out['method_identifiers'] == { 'foo(uint256)': '0x2fbebd38', 'x()': '0xc55699c' }
def test_json_interface_calls(get_contract, type_str, value): code = interface_test_code.format(type_str) abi = compile_code(code, ['abi'])['abi'] c1 = get_contract(code) code = f""" import jsonabi as jsonabi @public @constant def test_call(a: address, b: {type_str}) -> {type_str}: return jsonabi(a).test_json(b) """ c2 = get_contract( code, interface_codes={'jsonabi': { 'type': 'json', 'code': abi }}) assert c2.test_call(c1.address, value) == value
def test_struct_return_abi(get_contract_with_gas_estimation): code = """ struct Voter: weight: int128 voted: bool @public def test() -> Voter: a: Voter = Voter({weight: 123, voted: True}) return a """ out = compile_code(code, ['abi']) abi = out['abi'][0] assert abi['name'] == 'test' c = get_contract_with_gas_estimation(code) assert c.test() == (123, True)
def test_basic_extract_interface(): code = """ # Events Transfer: event({_from: address, _to: address, _value: uint256}) # Functions @constant @public def allowance(_owner: address, _spender: address) -> (uint256, uint256): return 1, 2 """ out = compile_code(code, ['interface']) out = out['interface'] code_pass = '******'.join(code.split('\n')[:-2] + [' pass']) # replace with a pass statement. assert code_pass.strip() == out.strip()
def test_pos_map_offsets(): source_map = compile_code(TEST_CODE, ['source_map'])['source_map'] expanded = expand_source_map(source_map['pc_pos_map_compressed']) pc_iter = iter(source_map['pc_pos_map'][i] for i in sorted(source_map['pc_pos_map'])) jump_iter = iter(source_map['pc_jump_map'][i] for i in sorted(source_map['pc_jump_map'])) code_lines = [i + "\n" for i in TEST_CODE.split("\n")] for item in expanded: if item[-1] is not None: assert next(jump_iter) == item[-1] if item[:2] != [-1, -1]: start, length = item[:2] lineno, col_offset, end_lineno, end_col_offset = next(pc_iter) assert code_lines[lineno - 1][col_offset] == TEST_CODE[start] assert length == ( sum(len(i) for i in code_lines[lineno - 1:end_lineno]) - col_offset - (len(code_lines[end_lineno - 1]) - end_col_offset))
def test_basic_ast(): code = """ a: int128 """ dict_out = compiler.compile_code(code, ['ast_dict']) assert dict_out['ast_dict']['ast']['body'][0] == { 'annotation': { 'ast_type': 'Name', 'col_offset': 3, 'end_col_offset': 9, 'end_lineno': 2, 'id': 'int128', 'lineno': 2, 'node_id': 4, 'src': "4:6:0", }, 'ast_type': 'AnnAssign', 'col_offset': 0, 'end_col_offset': 9, 'end_lineno': 2, 'lineno': 2, 'node_id': 1, 'simple': 1, 'src': '1:9:0', 'target': { 'ast_type': 'Name', 'col_offset': 0, 'end_col_offset': 1, 'end_lineno': 2, 'id': 'a', 'lineno': 2, 'node_id': 2, 'src': '1:1:0', }, 'value': None }
def test_varname_validity_success(good_code): assert compiler.compile_code(good_code) is not None
def test_varname_validity_fail(bad_code): with raises(FunctionDeclarationException): compiler.compile_code(bad_code)
def test_block_fail(bad_code): with raises(TypeMismatch): compiler.compile_code(bad_code)
def test_syntax_exception(bad_code): with raises(SyntaxException): compiler.compile_code(bad_code)
def test_block_success(good_code): assert compiler.compile_code(good_code) is not None