def _refresh_storage(self, addr: Address = None): """ Helper function that refreshes the displayed storage table widget with values for the specified address. """ self._clear_table_widget(TableWidgetEnum.STORAGE) if addr is None: return self.ui.storage_address_label.setText("Address: 0x" + addr.hex()) self.ui.storage_address_label.setToolTip( "Showing storage for address: 0x" + addr.hex()) lkp = self.storage_lookup.get(addr) if lkp is not None: for i in range(0, len(lkp.keys())): self.ui.storage_table_widget.insertRow(i) for slot in lkp.keys(): value = hex(self.evm_handler.get_storage_at( addr, int(slot, 0))) k = QTableWidgetItem() v = QTableWidgetItem() k.setText(slot) v.setText(value) v.setTextAlignment(130) self.ui.storage_table_widget.setItem(lkp.get(slot), 0, k) self.ui.storage_table_widget.setItem(lkp.get(slot), 1, v)
def _log_pending_accounts(self) -> None: # This entire method is about debug2 logging, so skip it if debug2 is disabled if not self.logger.show_debug2: return diff = self._journaltrie.diff() for address in sorted(diff.pending_keys()): account = self._get_account(Address(address)) self.logger.debug2( "Pending Account %s: balance %d, nonce %d, storage root %s, code hash %s", to_checksum_address(address), account.balance, account.nonce, encode_hex(account.storage_root), encode_hex(account.code_hash), ) for deleted_address in sorted(diff.deleted_keys()): # Check if the account was accessed before accessing/logging info about the address was_account_accessed = deleted_address in self._accessed_accounts cast_deleted_address = Address(deleted_address) self.logger.debug2( "Deleted Account %s, empty? %s, exists? %s", to_checksum_address(deleted_address), self.account_is_empty(cast_deleted_address), self.account_exists(cast_deleted_address), ) # If the account was not accessed previous to the log, (re)mark it as not accessed if not was_account_accessed: self._accessed_accounts.remove(cast_deleted_address)
def check_log_matches_filter(params: FilterParams, log: Log) -> None: header = log.receipt.blocktransaction.block.header # Check address matches if isinstance(params.address, tuple): assert any( is_same_address(Address(log.address), Address(address)) for address in params.address ) elif params.address is not None: assert is_same_address(Address(log.address), Address(params.address)) # Check block number in range if isinstance(params.from_block, int): assert header.block_number >= params.from_block if isinstance(params.to_block, int): assert header.block_number <= params.to_block # Check topics zipped_topics = itertools.zip_longest( params.topics, log.topics, fillvalue=None # type: ignore ) for expected_topic, actual_topic in zipped_topics: if expected_topic is None: assert actual_topic is not None elif actual_topic is None: assert expected_topic is None elif isinstance(expected_topic, tuple): assert any(topic == actual_topic.topic for topic in expected_topic) elif isinstance(expected_topic, bytes): assert expected_topic == actual_topic.topic else: raise Exception("Invariant")
def set_code(self, code: bytes, addr: Address = Address(b'')) -> Address: """ Sets the code of an address. :param addr: The address to set the code of. :param code: The code to set. This should not be constructor bytecode. :return: """ if addr == Address(b''): addr = self.get_random_address() self.vm.state.set_code(addr, code) self._mine_block_dirty() return addr
def configure_homestead_header(vm: "HomesteadVM", **header_params: Any) -> BlockHeader: validate_header_params_for_configuration(header_params) with vm.header.build_changeset(**header_params) as changeset: if 'timestamp' in header_params and changeset.block_number > 0: parent_header = get_parent_header(changeset.build_rlp(), vm.chaindb) changeset.difficulty = compute_homestead_difficulty( parent_header, header_params['timestamp'], ) # In geth the modification of the state in the DAO fork block is performed # before any transactions are applied, so doing it here is the closest we # get to that. Another alternative would be to do it in Block.mine(), but # there we'd need to manually instantiate the State and update # header.state_root after we're done. if vm.support_dao_fork and changeset.block_number == vm.get_dao_fork_block_number(): state = vm.state for account in dao_drain_list: address = Address(decode_hex(account)) balance = state.get_balance(address) state.delta_balance(dao_refund_contract, balance) state.set_balance(address, 0) # Persist the changes to the database state.persist() # Update state_root manually changeset.state_root = state.state_root header = changeset.commit() return header
def test_state_does_not_revert_on_reserved_0xEF_byte_for_create_transaction_pre_london( pre_london_miner, funded_address, funded_address_private_key, data): chain = pre_london_miner vm = chain.get_vm() initial_balance = vm.state.get_balance(funded_address) # test the parametrized negative cases create_contract_txn_0xef_byte = new_transaction( vm=vm, from_=funded_address, to=Address(b''), amount=0, private_key=funded_address_private_key, gas=60000, nonce=0, data=data, ) block_import, _, computations = chain.mine_all( [create_contract_txn_0xef_byte], gas_limit=99904) computation = computations[0] mined_header = block_import.imported_block.header txn = block_import.imported_block.transactions[0] end_balance = computation.state.get_balance(funded_address) assert computation.is_success assert computation.state.get_nonce(funded_address) == 1 # txn consumes gas and fees assert end_balance == initial_balance - (txn.gas_price * mined_header.gas_used)
def test_register_token_without_balance( api_server_test_instance, token_amount, raiden_network: List[RaidenService], contract_manager, retry_timeout, ): app0 = raiden_network[0] contract_proxy, _ = app0.rpc_client.deploy_single_contract( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, contract=contract_manager.get_contract(CONTRACT_HUMAN_STANDARD_TOKEN), constructor_parameters=(token_amount, 2, "raiden", "Rd2"), ) new_token_address = Address(to_canonical_address(contract_proxy.address)) # Wait until Raiden can start using the token contract. # Here, the block at which the contract was deployed should be confirmed by Raiden. # Therefore, until that block is received. wait_for_block( raiden=app0, block_number=BlockNumber(app0.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1), retry_timeout=retry_timeout, ) # Burn all the eth and then make sure we get the appropriate API error burn_eth(app0.rpc_client) poor_request = grequests.put( api_url_for( api_server_test_instance, "registertokenresource", token_address=to_checksum_address(new_token_address), )) poor_response = poor_request.send().response assert_response_with_error(poor_response, HTTPStatus.PAYMENT_REQUIRED)
async def filterAddressesWithReceivableTransactions( self, chain_addresses, after_timestamp=0): # # Checks all of the given chain_addresses for receivable transactions, and returns a list of chain addresses that have any. # if len(chain_addresses) < 1: raise BaseRPCError( "Must provide at least one chain address when calling getAddressesWithReceivableTransactions" ) earliest_chronological_timestamp = int( int(time.time()) - TIME_BETWEEN_HEAD_HASH_SAVE * NUMBER_OF_HEAD_HASH_TO_SAVE * 0.95) # create new chain for all requests chain = self.get_new_chain() chain_addresses = [Address(decode_hex(x)) for x in chain_addresses] if isinstance( after_timestamp, int) and after_timestamp > earliest_chronological_timestamp: # cycle through all chronological windows _, addresses_with_receivable_transactions = await chain.coro_get_receivable_transaction_hashes_from_chronological( after_timestamp, chain_addresses) else: addresses_with_receivable_transactions = await chain.coro_filter_accounts_with_receivable_transactions( chain_addresses) addresses_with_receivable_transactions = [ to_checksum_address(x) for x in addresses_with_receivable_transactions ] return addresses_with_receivable_transactions
class Erc20Token(Currency): address: Address = Address(b"") supply: int = 10**21 def __post_init__(self): if self.address == Address(b""): raise TokenError( "Erc20Token should not get initialized without an address") @staticmethod def find_by_ticker(ticker, network_name): major, minor, _ = CONTRACTS_VERSION.split(".", 2) version_string = f"{major}.{minor}" token_list_version = { "0.25": TokensV25, "0.33": TokensV33, "0.36": TokensV36, "0.37": TokensV37, }.get(version_string, Tokens) try: token_data = token_list_version[ticker].value address = token_data.addresses[network_name] except KeyError as exc: raise TokenError( f"{ticker} is not deployed on {network_name}") from exc return Erc20Token(ticker=token_data.ticker, wei_ticker=token_data.wei_ticker, address=to_canonical_address(address))
def get_balance(self, addr: bytes) -> int: """ Gets the balance of an address. :param addr: Address to query the balance of. :return: The address balance. """ return self.vm.state.get_balance(Address(addr))
def create_contract(self, data: str, value: int = 0, debug: int = 0, **kwargs) -> Address: """ Creates a new smart contract. :param data: The data field. Must include constructor code in order for new contract to be created. :param value: The value to be sent alongside the transaction. :param debug: Signalizes whether the user wants the current transaction to be debugged or just send it out. :return: The address under which the newly created contract is located. """ nonce = self.vm.state.get_nonce(MASTER_ADDRESS) MyComputation.debug_mode = debug MyComputation.kwargs = kwargs MyComputation.call_depth = 0 block, receipt, computation = self._make_transaction( nonce, DEFAULT_GAS_PRICE, DEFAULT_TRANSACTION_GAS_AMOUNT, constants.CREATE_CONTRACT_ADDRESS, value, decode_hex(data)) logger.info( "Created contract with {b}, receipt {r}, and computation {c}". format(b=block, r=receipt, c=computation)) self._mine_block() if computation.is_error: return Address(b'') else: return generate_contract_address(MASTER_ADDRESS, nonce)
def get_random_address(self) -> Address: """ :return: A random address. Initial seed is the timestamp of initialization of the instance. Not really cryptographically secure but enough for our use case. """ addr = Address(decode_hex(self.seed[:40])) self.seed = keccak_256(self.seed.encode("utf-8")).hexdigest() return addr
def force_bytes_to_address(value: bytes) -> Address: """ Take any byte value and force it into becoming a valid address by padding it to 20 bytes or returning the first 20 bytes in case the provided value is longer than 20 bytes. """ trimmed_value = value[-20:] padded_value = trimmed_value.rjust(20, b'\x00') return Address(padded_value)
def get_code(self, addr: bytes) -> bytes: """ Gets the code of an address. We can distinguish between normal addresses and smart contracts by looking if the code is equal to b'', in which case it is a normal address, or anything else which means that <param>addr</param> holds a smart contract. :param addr: Address to query the code of. :return: The address code. """ return self.vm.state.get_code(Address(addr))
def contract_selected(self): self.ui.select_function_combobox.clear() self.current_contract = self.relevant_addresses.get( self.ui.select_address_combobox.currentText()) self.ui.select_function_combobox.addItems( self.current_contract.signatures) self._refresh_storage( Address( decode_hex(self.ui.select_address_combobox.currentText()[2:])))
def test_selfdestruct(self): """ Creates a contract with inital value of 1 wei which then selfdestructs onto address 0x00...01 whose vale is then asserted to be 1. :return: """ destroy_contract = get_contract("SelfDestruct") self.create_contract_and_set_address(destroy_contract, True) assert 0 == self.evm_handler.get_balance( Address(decode_hex("0000000000000000000000000000000000000001"))) _, _, comp = self.evm_handler.call_contract_function( destroy_contract.get_typed_address(), "destroy()", [], 0, 0, set_storage=self.dummy) assert comp.is_success assert 1 == self.evm_handler.get_balance( Address(decode_hex("0000000000000000000000000000000000000001")))
def test_set_code_and_get_code(self): """ Tries setting the code section of an address dirtily by omitting block validation. :return: """ addr1 = Address(decode_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) code = decode_hex(SAMPLE_CONTRACT_STRING) self.evm_handler.set_code(code, addr1) actual = self.evm_handler.get_code(addr1) assert code == actual
def contract_created_signal_cb(self, addr: Address): cb: QComboBox = self.ui.select_address_combobox if addr != b'': self.current_contract.set_address(addr.hex()) a = self.current_contract.get_readable_address() self.relevant_addresses[a] = self.current_contract self._refresh_statusbar("Mined new Contract at address " + a) cb.currentIndexChanged.disconnect() cb.clear() for addr in self.relevant_addresses.values(): if self.evm_handler.get_code(addr.get_typed_address()) != b'': cb.addItem(addr.get_readable_address()) cb.currentIndexChanged.connect(self.contract_selected) cb.setCurrentIndex(cb.count() - 1) if cb.count() == 1: self.contract_selected() else: self._refresh_statusbar("Error processing transaction.") self.post_transaction_handling()
def test_set_storage_and_get_storage(self): """ Tries setting the storage of a contract dirtily by omitting block validation. :return: """ addr1 = Address(decode_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) val = 1 self.evm_handler.set_storage(addr1, 0, val) actual = self.evm_handler.get_storage_at(addr1, 0) assert val == actual
def create_monitor(eth1_rpc: str, dep_contract_addr: str) -> DepositMonitor: w3prov = Web3.HTTPProvider(eth1_rpc) if eth1_rpc.startswith( "http") else Web3.WebsocketProvider(eth1_rpc) w3: Web3 = Web3(w3prov) # Handle POA Goerli style "extraData" in Web3 # inject the poa compatibility middleware to the innermost layer w3.middleware_onion.inject(geth_poa_middleware, layer=0) contract_addr = Address(bytes.fromhex(dep_contract_addr.replace("0x", ""))) return DepositMonitor(w3, contract_addr, deposit_contract_abi)
def extract_genesis_params(genesis_config: RawEIP1085Dict) -> GenesisParams: raw_params = genesis_config['genesis'] return GenesisParams( nonce=decode_hex(raw_params['nonce']), difficulty=to_int(hexstr=raw_params['difficulty']), extra_data=Hash32(decode_hex(raw_params['extraData'])), gas_limit=to_int(hexstr=raw_params['gasLimit']), coinbase=Address(decode_hex(raw_params['author'])), timestamp=to_int(hexstr=raw_params['timestamp']), )
def _log_pending_accounts(self) -> None: diff = self._journaltrie.diff() for address in sorted(diff.pending_keys()): account = self._get_account(Address(address)) self.logger.debug2( "Pending Account %s: balance %d, nonce %d, storage root %s, code hash %s", to_checksum_address(address), account.balance, account.nonce, encode_hex(account.storage_root), encode_hex(account.code_hash), ) for deleted_address in sorted(diff.deleted_keys()): cast_deleted_address = Address(deleted_address) self.logger.debug2( "Deleted Account %s, empty? %s, exists? %s", to_checksum_address(deleted_address), self.account_is_empty(cast_deleted_address), self.account_exists(cast_deleted_address), )
def show_set_contract_dialog(self): AddContractDialog = QDialog() ui = Ui_AddContractDialog() ui.setupUi(AddContractDialog) ui.info_label_2.linkActivated.connect( lambda link: QDesktopServices.openUrl(QUrl(link))) ui.info_label.linkActivated.connect( lambda link: QDesktopServices.openUrl(QUrl(link))) AddContractDialog.setFixedSize(AddContractDialog.size()) AddContractDialog.show() if AddContractDialog.exec_() == QDialog.Accepted: try: if ui.tabWidget.currentIndex() == 0: self.pre_transaction_handling() step_duration = float(self.ui.step_duration_le.text()) abi = ui.abi_te.toPlainText() abi = "[]" if abi == "" else abi byte_code = ui.bytecode_te_2.toPlainText() if byte_code == "": raise ValueError("Please enter a valid contract.") self.current_contract = MyContract(abi, byte_code) self._clear_table_widget(TableWidgetEnum.STORAGE) qApp.processEvents() wei = self._parse_string(self.ui.value_le.text(), int, [(operator.ge, [0])]) if wei is None: wei = 0 self._refresh_statusbar( "Invalid amount. Continue with " + str(wei)) worker = ContractWorker( self.evm_handler.create_contract, self.current_contract.bytecode.object, wei, self._current_debug_mode(), storage_lookup=self.storage_lookup, init_lock=self.init_lock, step_lock=self.step_lock, storage_lock=self.storage_lock, step_semaphore=self.step_semaphore, step_duration=step_duration) self._connect_signals_and_start_worker(worker) else: self.current_contract = MyContract( "[]", ui.bytecode_te.toPlainText()) addr = Address(decode_hex(ui.contract_le.text())) addr = self.evm_handler.set_code( addr=addr, code=decode_hex(self.current_contract.bytecode.object)) self.storage_lookup[addr] = {} self.contract_created_signal_cb(addr) except (TypeError, json.JSONDecodeError, ValueError) as e: self._refresh_statusbar(str(e)) self.post_transaction_handling()
def test_send_wei_and_get_balance_and_set_balance(self): """ Tries to set the balance of a contract with 1) normal transactions and 2) dirtily by setting the value and omitting block validation. The actual value is compared with the expected :return: """ addr1 = Address(decode_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) addr2 = Address(decode_hex("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")) addr3 = Address(decode_hex("9742421b7279129e6791e67921d9787df9779fa7")) assert 0 == self.evm_handler.get_balance(addr1) assert 0 == self.evm_handler.get_balance(addr2) assert 0 == self.evm_handler.get_balance(addr3) self.evm_handler.send_wei(addr1, to_wei(20, "finney")) self.evm_handler.send_wei(addr2, to_wei(30, "ether")) self.evm_handler.send_wei(addr3, to_wei(10, "wei")) assert units.get("finney") * 20 == self.evm_handler.get_balance(addr1) assert units.get("ether") * 30 == self.evm_handler.get_balance(addr2) assert units.get("wei") * 10 == self.evm_handler.get_balance(addr3) self.evm_handler.set_balance(addr1, 0) self.evm_handler.set_balance(addr2, 0) self.evm_handler.set_balance(addr3, 0) assert 0 == self.evm_handler.get_balance(addr1) assert 0 == self.evm_handler.get_balance(addr2) assert 0 == self.evm_handler.get_balance(addr3)
def post_transaction_handling(self): """ Post transaction processes. """ self._refresh_relevant_addresses() addr = self.ui.select_address_combobox.currentText() if addr != "Load a contract first!": self._refresh_storage(Address(decode_hex(addr[2:]))) self.ui.debug_checkbox.setDisabled(False) self.ui.automode_checkbox.setDisabled(False) self.ui.send_transaction_button.setDisabled(False) self.ui.step_duration_label.setDisabled(False) self.ui.step_duration_le.setDisabled(False) self.ui.select_address_combobox.setDisabled(False) self.ui.select_function_combobox.setDisabled(False) self.ui.abort_automode_button.hide()
def get_signers_at_checkpoint(header: BlockHeaderAPI) -> Iterable[Address]: """ Read the list of signers from a checkpoint header. """ signers_length = len(header.extra_data) - VANITY_LENGTH - SIGNATURE_LENGTH if signers_length % COMMON_ADDRESS_LENGTH != 0: raise ValidationError("Checkpoint header must contain list of signers") signer_count = int( (len(header.extra_data) - VANITY_LENGTH - SIGNATURE_LENGTH) / COMMON_ADDRESS_LENGTH) for i in range(signer_count): yield Address( header.extra_data[VANITY_LENGTH + i * COMMON_ADDRESS_LENGTH:][:COMMON_ADDRESS_LENGTH])
def _log_pending_accounts(self) -> None: accounts_displayed = set() # type: Set[bytes] queued_changes = self._journaltrie.journal.journal_data.items() # mypy bug for ordered dict reversibility: https://github.com/python/typeshed/issues/2078 for _, accounts in reversed(queued_changes): for address in accounts: if address in accounts_displayed: continue else: accounts_displayed.add(address) account = self._get_account(Address(address)) self.logger.debug2( "Account %s: balance %d, nonce %d, storage root %s, code hash %s", encode_hex(address), account.balance, account.nonce, encode_hex(account.storage_root), encode_hex(account.code_hash), )
def make_sample_tx(sender_pri_key_hex, recv_address, data="sample tx data".encode('utf-8'), nonce=None, value=0): assert isinstance(data, bytes), "data must be of type bytes" sender_pri_key = keys.PrivateKey(decode_hex(sender_pri_key_hex)) sender_address = Address(sender_pri_key.public_key.to_canonical_address()) vm = shard_driver.shard.vm if nonce is None: nonce = vm.state.account_db.get_nonce(sender_address) tx = vm.create_unsigned_transaction( nonce=nonce, gas_price=0, gas=100000, to=recv_address, value=value, data=data, ) return tx.as_signed_transaction(sender_pri_key)
def test_register_token_mainnet( api_server_test_instance: APIServer, token_amount, raiden_network: List[RaidenService], contract_manager, ): app0 = raiden_network[0] contract_proxy, _ = app0.rpc_client.deploy_single_contract( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, contract=contract_manager.get_contract(CONTRACT_HUMAN_STANDARD_TOKEN), constructor_parameters=(token_amount, 2, "raiden", "Rd"), ) new_token_address = Address(to_canonical_address(contract_proxy.address)) register_request = grequests.put( api_url_for( api_server_test_instance, "registertokenresource", token_address=to_checksum_address(new_token_address), )) response = register_request.send().response assert response is not None and response.status_code == HTTPStatus.NOT_IMPLEMENTED
def send_wei(self, addr: bytes, value: int) -> Address: """ Will send wei from the MASTER_ADDRESS to another address. :param addr: The receiver address of the transaction. :param value: The amount of wei to be sent. :return: The receiver address. """ logger.info("Sending {v} wei to {a} ".format(v=value, a=addr.hex())) dbg = MyComputation.debug_mode MyComputation.debug_mode = MODE_NONE receiver = Address(addr) self.used_addresses.add(receiver) nonce = self.vm.state.get_nonce(MASTER_ADDRESS) block, receipt, computation = self._make_transaction( nonce, DEFAULT_GAS_PRICE, DEFAULT_TRANSACTION_GAS_AMOUNT, receiver, value, b'') logger.info("Mined {b} with receipt {r}, and computation {c}".format( b=block, r=receipt, c=computation)) self._mine_block() MyComputation.debug_mode = dbg return receiver