diff --git a/contracts/erc725.v.py b/contracts/erc725.v.py new file mode 100644 index 0000000..39efd72 --- /dev/null +++ b/contracts/erc725.v.py @@ -0,0 +1,102 @@ + +keys: address[20] +key_types: num[20] +key_count: num + + +def __init__(): + self.keys[0] = msg.sender + self.key_types[0] = 1 + self.key_count = 1 + + +@constant +def getKeyType(_key: address) -> num256: + + for i in range(0, 20): + + if i >= self.key_count: + break + + if self.keys[i] == _key: + return as_num256(self.key_types[i]) + + return as_num256(0) + + +def getKeysByType(_type: num(num256)) -> address[20]: + assert _type >= 1 + + outarr: address[20] + + j = 0 + for i in range(0, 20): + + if i >= self.key_count: + break + + if self.key_types[i] == _type: + outarr[j] = self.keys[i] + j += 1 + + return outarr + +# Permission check function. +# Any modifying of keys should be handled by key holder of type 1 only. +@internal +def from_key_type1(_from: address) -> bool: + + for i in range(0, 20): + + if self.keys[i] == _from and self.key_types[i] == 1: + return True + + return False + + +def addKey(_key: address, _type: num(num256)) -> bool: + assert _type >= 1 + assert self.key_count <= 20 + + if not self.from_key_type1(msg.sender): + return False + + self.key_count += 1 + self.keys[self.key_count] = _key + self.key_types[self.key_count] = 1 + + return True + + +def removeKey(_key: address) -> bool: + + if not self.from_key_type1(msg.sender): + return False + + for i in range(0, 20): + + if i >= self.key_count: + break + + if self.keys[i] == _key: + self.keys[i] = 0x0000000000000000000000000000000000000000 + return True + + return False + + +def replaceKey(_oldKey: address, _newKey: address) -> bool: + + if not self.from_key_type1(msg.sender): + return False + + for i in range(0, 20): + + if i >= self.key_count: + break + + if self.keys[i] == _oldKey: + self.keys[i] = _newKey + return True + + return False diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/setup_transaction_tests.py b/tests/setup_transaction_tests.py new file mode 100644 index 0000000..073d47e --- /dev/null +++ b/tests/setup_transaction_tests.py @@ -0,0 +1,135 @@ +import pytest +from functools import wraps + +from viper import parser, compile_lll, utils +from viper import compiler +from ethereum.tools import tester +from ethereum import transactions, messages +from ethereum import utils as ethereum_utils +import rlp +from ethereum.slogging import LogRecorder, configure_logging, set_level +config_string = ':info,eth.vm.log:trace,eth.vm.op:trace,eth.vm.stack:trace,eth.vm.exit:trace,eth.pb.msg:trace,eth.pb.tx:debug' +#configure_logging(config_string=config_string) + +chain = tester.Chain() +tester.languages['viper'] = compiler.Compiler() + +def inject_tx(txhex): + tx = rlp.decode(ethereum_utils.decode_hex(txhex[2:]), transactions.Transaction) + chain.head_state.set_balance(tx.sender, tx.startgas * tx.gasprice) + chain.chain.state.set_balance(tx.sender, tx.startgas * tx.gasprice) + messages.apply_transaction(chain.head_state, tx) + chain.block.transactions.append(tx) + contract_address = ethereum_utils.sha3(rlp.encode([tx.sender, 0]))[12:] + assert chain.head_state.get_code(contract_address) + chain.mine(1) + return contract_address + +_rlp_decoder_address = inject_tx( "0xf90237808506fc23ac00830330888080b902246102128061000e60003961022056600060007f010000000000000000000000000000000000000000000000000000000000000060003504600060c082121515585760f882121561004d5760bf820336141558576001905061006e565b600181013560f783036020035260005160f6830301361415585760f6820390505b5b368112156101c2577f010000000000000000000000000000000000000000000000000000000000000081350483602086026040015260018501945060808112156100d55760018461044001526001828561046001376001820191506021840193506101bc565b60b881121561014357608081038461044001526080810360018301856104600137608181141561012e5760807f010000000000000000000000000000000000000000000000000000000000000060018401350412151558575b607f81038201915060608103840193506101bb565b60c08112156101b857600182013560b782036020035260005160388112157f010000000000000000000000000000000000000000000000000000000000000060018501350402155857808561044001528060b6838501038661046001378060b6830301830192506020810185019450506101ba565bfe5b5b5b5061006f565b601f841315155857602060208502016020810391505b6000821215156101fc578082604001510182826104400301526020820391506101d8565b808401610420528381018161044003f350505050505b6000f31b2d4f") +assert utils.bytes_to_int(_rlp_decoder_address) == utils.RLP_DECODER_ADDRESS + +chain.head_state.gas_limit = 10**9 + +def check_gas(code, function=None, num_txs=1): + if function: + gas_estimate = tester.languages['viper'].gas_estimate(code)[function] + else: + gas_estimate = sum(tester.languages['viper'].gas_estimate(code).values()) + + gas_actual = chain.head_state.receipts[-1].gas_used \ + - chain.head_state.receipts[-1-num_txs].gas_used \ + - chain.last_tx.intrinsic_gas_used*num_txs + #Computed upper bound on the gas consumption should + #be greater than or equal to the amount of gas used + if gas_estimate < gas_actual: + raise Exception("Gas upper bound fail: bound %d actual %d" % (gas_estimate, gas_actual)) + + print('Function name: {} - Gas estimate {}, Actual: {}'.format( + function, gas_estimate, gas_actual) + ) + + +def gas_estimation_decorator(fn, source_code, func): + def decorator(*args, **kwargs): + @wraps(fn) + def decorated_function(*args, **kwargs): + result = fn(*args, **kwargs) + check_gas(source_code, func) + return result + return decorated_function(*args, **kwargs) + return decorator + + +def set_decorator_to_contract_function(contract, source_code, func): + func_definition = getattr(contract, func) + func_with_decorator = gas_estimation_decorator( + func_definition, source_code, func + ) + setattr(contract, func, func_with_decorator) + + +def get_contract_with_gas_estimation( + source_code, + *args, **kwargs): + contract = chain.contract(source_code, language="viper", *args, **kwargs) + + for func_name in contract.translator.function_data: + set_decorator_to_contract_function( + contract, source_code, func_name + ) + + return contract + + +def get_contract(source_code, *args, **kwargs): + return chain.contract(source_code, language="viper", *args, **kwargs) + +G1 = [1, 2] + +G1_times_two = [ + 1368015179489954701390400359078579693043519447331113978918064868415326638035, + 9918110051302171585080402603319702774565515993150576347155970296011118125764 +] + +G1_times_three = [ + 3353031288059533942658390886683067124040920775575537747144343083137631628272, + 19321533766552368860946552437480515441416830039777911637913418824951667761761 +] + +negative_G1 = [ + 1, + 21888242871839275222246405745257275088696311157297823662689037894645226208581 +] + +curve_order = 21888242871839275222246405745257275088548364400416034343698204186575808495617 + +@pytest.fixture +def get_log(): + def get_log(chain, contract, event_name): + event_ids_w_name = [k for k, v in \ + contract.translator.event_data.items() if v["name"] == event_name] + assert len(event_ids_w_name) == 1, \ + "Contract doesn't have event {}!".format(event_name) + event_id = event_ids_w_name[0] + + # Get the last logged event + logs = chain.head_state.receipts[-1].logs[-1] + + # Ensure it has the event we are looking to decode + assert logs.address == contract.address, \ + "This contract didn't originate the last event!" + assert logs.topics[0] == event_id, \ + "The last event wasn't {}!".format(event_name) + + # Return the decoded event data + return contract.translator.decode_event(logs.topics, logs.data) + return get_log + +@pytest.fixture +def assert_tx_failed(): + def assert_tx_failed(tester, function_to_test, exception = tester.TransactionFailed): + initial_state = tester.s.snapshot() + with pytest.raises(exception): + function_to_test() + tester.s.revert(initial_state) + return assert_tx_failed