def add_receivable_transaction(self, address, transaction_hash, sender_block_hash): validate_canonical_address(address, title="Storage Address") validate_is_bytes(transaction_hash, title="Transaction Hash") validate_is_bytes(sender_block_hash, title="Sender Block Hash") #this is the wallet address people send money to when slashed. It is a sink if address == SLASH_WALLET_ADDRESS: return #first lets make sure we don't already have the transaction if self.get_receivable_transaction(address, transaction_hash) is not False: raise ValueError( "Tried to save a receivable transaction that was already saved" ) account = self._get_account(address) receivable_transactions = account.receivable_transactions new_receivable_transactions = receivable_transactions + ( TransactionKey(transaction_hash, sender_block_hash), ) self.logger.debug( "adding receivable transaction {}".format(transaction_hash)) #self.logger.debug(new_receivable_transactions) self._set_account( address, account.copy(receivable_transactions=new_receivable_transactions))
def delete_receivable_transaction(self, address, transaction_hash): validate_canonical_address(address, title="Storage Address") validate_is_bytes(transaction_hash, title="Transaction Hash") self.logger.debug("deleting receivable tx {}".format(transaction_hash)) account = self._get_account(address) receivable_transactions = list( self.get_receivable_transactions(address)) i = 0 found = False for tx_key in receivable_transactions: if tx_key.transaction_hash == transaction_hash: found = True break i += 1 if found == True: del receivable_transactions[i] else: raise ValueError( "transaction hash {0} not found in receivable_transactions database for wallet {1}" .format(transaction_hash, address)) self._set_account( address, account.copy( receivable_transactions=tuple(receivable_transactions)))
def add_receivable_transaction(self, address: Address, transaction_hash: Hash32, sender_block_hash: Hash32, is_contract_deploy:bool = False) -> None: validate_canonical_address(address, title="Wallet Address") validate_is_bytes(transaction_hash, title="Transaction Hash") validate_is_bytes(sender_block_hash, title="Sender Block Hash") #this is the wallet address people send money to when slashed. It is a sink if address == SLASH_WALLET_ADDRESS: return account = self._get_account(address) receivable_transactions = account.receivable_transactions # first lets make sure we don't already have the transaction for tx_key in receivable_transactions: if tx_key.transaction_hash == transaction_hash: raise ValueError("Tried to save a receivable transaction that was already saved. TX HASH = {}".format(encode_hex(transaction_hash))) new_receivable_transactions = receivable_transactions + (TransactionKey(transaction_hash, sender_block_hash), ) #self.logger.debug(new_receivable_transactions) self.logger.debug("Adding receivable transaction {} to account {}".format(encode_hex(transaction_hash), encode_hex(address))) self._set_account(address, account.copy(receivable_transactions=new_receivable_transactions)) #finally, if this is a smart contract, lets add it to the list of smart contracts with pending transactions if is_contract_deploy or self.get_code_hash(address) != EMPTY_SHA3: self.logger.debug("Adding address to list of smart contracts with pending transactions") #we only need to run this when adding the first one. self._add_address_to_smart_contracts_with_pending_transactions(address)
def delete_chain(self, address, delete_from_historical_root_hashes: bool = True): validate_canonical_address(address, title="Wallet Address") self.delete_chain_head_hash(address) if delete_from_historical_root_hashes: self.add_block_hash_to_timestamp(address, BLANK_HASH, 0)
def persist(self, save_account_hash=False, wallet_address=None) -> None: self._journaldb.persist() self._batchdb.commit(apply_deletes=True) if save_account_hash: validate_canonical_address(wallet_address, title="Address") self.save_current_account_with_hash_lookup(wallet_address)
def delete_receivable_transaction(self, address: Address, transaction_hash: Hash32) -> None: validate_canonical_address(address, title="Storage Address") validate_is_bytes(transaction_hash, title="Transaction Hash") self.logger.debug("deleting receivable tx {} from account {}".format(encode_hex(transaction_hash), encode_hex(address))) account = self._get_account(address) receivable_transactions = list(self.get_receivable_transactions(address)) i = 0 found = False for tx_key in receivable_transactions: if tx_key.transaction_hash == transaction_hash: found = True break i +=1 if found == True: del receivable_transactions[i] else: raise ReceivableTransactionNotFound("transaction hash {0} not found in receivable_transactions database for wallet {1}".format(transaction_hash, address)) self._set_account(address, account.copy(receivable_transactions=tuple(receivable_transactions))) if self.get_code_hash(address) != EMPTY_SHA3: if len(receivable_transactions) == 0: self.logger.debug("Removing address from list of smart contracts with pending transactions") self._remove_address_from_smart_contracts_with_pending_transactions(address)
def get_code(self, address): validate_canonical_address(address, title="Storage Address") try: return self._journaldb[self.get_code_hash(address)] except KeyError: return b""
def get_chain_head_hash_at_timestamp(self, address, timestamp): validate_canonical_address(address, title="Wallet Address") validate_uint256(timestamp, title='timestamp') #make sure it isnt in the future if timestamp > int(time.time()): raise InvalidHeadRootTimestamp() #first make sure the timestamp is correct. if timestamp % TIME_BETWEEN_HEAD_HASH_SAVE != 0: raise InvalidHeadRootTimestamp() historical_roots = self.get_historical_root_hashes() if historical_roots is None: return None if timestamp < historical_roots[0][0]: return None historical_roots_dict = dict(historical_roots) try: historical_root = historical_roots_dict[timestamp] except KeyError: historical_root = historical_roots[-1][1] new_chain_head_db = ChainHeadDB(self.db, historical_root) head_hash = new_chain_head_db._trie_cache.get(address) return head_hash
def add_log_entry(self, account: Address, topics: List[int], data: bytes) -> None: validate_canonical_address(account, title="Log entry address") for topic in topics: validate_uint256(topic, title="Log entry topic") validate_is_bytes(data, title="Log entry data") self._log_entries.append( (self.transaction_context.get_next_log_counter(), account, topics, data))
def save_current_account_with_hash_lookup(self, wallet_address): validate_canonical_address(wallet_address, title="Address") account_hash = self.get_account_hash(wallet_address) account = self._get_account(wallet_address) rlp_account = rlp.encode(account, sedes=Account) lookup_key = SchemaV1.make_account_by_hash_lookup_key(account_hash) self.db[lookup_key] = rlp_account
def persist(self, save_account_hash = False, wallet_address = None) -> None: self.logger.debug('Persisting account db. save_account_hash {} | wallet_address {}'.format(save_account_hash, wallet_address)) self._journaldb.persist() self._batchdb.commit(apply_deletes=True) if save_account_hash: validate_canonical_address(wallet_address, title="Address") self.save_current_account_with_hash_lookup(wallet_address)
def register_account_for_deletion(self, beneficiary: Address) -> None: validate_canonical_address(beneficiary, title="Self destruct beneficiary address") if self.msg.storage_address in self.accounts_to_delete: raise ValueError( "Invariant. Should be impossible for an account to be " "registered for deletion multiple times" ) self.accounts_to_delete[self.msg.storage_address] = beneficiary
def set_code(self, address, code): validate_canonical_address(address, title="Storage Address") validate_is_bytes(code, title="Code") account = self._get_account(address) code_hash = keccak(code) self._journaldb[code_hash] = code self._set_account(address, account.copy(code_hash=code_hash))
def revert_to_account_from_hash(self, account_hash, wallet_address): validate_canonical_address(wallet_address, title="Address") validate_is_bytes(account_hash, title="account_hash") lookup_key = SchemaV1.make_account_by_hash_lookup_key(account_hash) try: rlp_encoded = self.db[lookup_key] account = rlp.decode(rlp_encoded, sedes=Account) self._set_account(wallet_address, account) except KeyError: raise StateRootNotFound()
def get_storage(self, address, slot): validate_canonical_address(address, title="Storage Address") validate_uint256(slot, title="Storage Slot") account = self._get_account(address) storage = HashTrie(HexaryTrie(self._journaldb, account.storage_root)) slot_as_key = pad32(int_to_big_endian(slot)) if slot_as_key in storage: encoded_value = storage[slot_as_key] return rlp.decode(encoded_value, sedes=rlp.sedes.big_endian_int) else: return 0
def _get_peer_node_health( self, peer_wallet_address: Address, after_block_number: BlockNumber) -> PeerNodeHealth: validate_canonical_address(peer_wallet_address, title="Value") validate_uint64(after_block_number, 'block_number') key = SchemaV1.make_peer_node_health_lookup(peer_wallet_address, after_block_number) try: rlp_peer_node_health = self.db[key] peer_node_health = rlp.decode(rlp_peer_node_health, sedes=PeerNodeHealth) except KeyError: peer_node_health = PeerNodeHealth() return peer_node_health
def set_storage(self, address, slot, value): validate_uint256(value, title="Storage Value") validate_uint256(slot, title="Storage Slot") validate_canonical_address(address, title="Storage Address") account = self._get_account(address) storage = HashTrie(HexaryTrie(self._journaldb, account.storage_root)) slot_as_key = pad32(int_to_big_endian(slot)) if value: encoded_value = rlp.encode(value) storage[slot_as_key] = encoded_value else: del storage[slot_as_key] self._set_account(address, account.copy(storage_root=storage.root_hash))
def __init__(self, gas, to, sender, value, data, code, depth=0, create_address=None, code_address=None, should_transfer_value=True, is_static=False, refund_amount=0): validate_uint256(gas, title="Message.gas") self.gas = gas # type: int if to != CREATE_CONTRACT_ADDRESS: validate_canonical_address(to, title="Message.to") self.to = to validate_canonical_address(sender, title="Message.sender") self.sender = sender validate_uint256(value, title="Message.value") self.value = value validate_is_bytes(data, title="Message.data") self.data = data validate_is_integer(depth, title="Message.depth") validate_gte(depth, minimum=0, title="Message.depth") self.depth = depth validate_is_bytes(code, title="Message.code") self.code = code if create_address is not None: validate_canonical_address(create_address, title="Message.storage_address") self.storage_address = create_address if code_address is not None: validate_canonical_address(code_address, title="Message.code_address") self.code_address = code_address validate_is_boolean(should_transfer_value, title="Message.should_transfer_value") self.should_transfer_value = should_transfer_value validate_is_integer(depth, title="Message.refund_amount") self.refund_amount = refund_amount validate_is_boolean(is_static, title="Message.is_static") self.is_static = is_static
def __init__(self, origin: Address, send_tx_hash: Hash32, caller_chain_address:Address, gas_price: int = None, receive_tx_hash: Hash32 = None, is_receive: bool = False, is_refund: bool = False): if gas_price is not None: validate_uint256(gas_price, title="TransactionContext.gas_price") self._gas_price = gas_price validate_canonical_address(origin, title="TransactionContext.origin") self._origin = origin validate_canonical_address(caller_chain_address, title='caller_chain_address') self._caller_chain_address = caller_chain_address validate_is_boolean(is_receive, title="is_receive") self._is_receive = is_receive validate_is_boolean(is_refund, title="is_from_refund") self._is_refund = is_refund validate_word(send_tx_hash, title="send_tx_hash") self._send_tx_hash = send_tx_hash if receive_tx_hash is not None: validate_word(receive_tx_hash, title="receive_tx_hash") self._receive_tx_hash = receive_tx_hash self._log_counter = itertools.count()
def calculate_final_reward_type_1_amount( self, wallet_address: Address, at_timestamp: Timestamp = None) -> int: ''' :param wallet_address: :return: ''' validate_canonical_address(wallet_address, 'wallet_address') if at_timestamp == None: at_timestamp = int(time.time()) fractional_interest = self.reward_type_1_amount_factor amount = self.calculate_reward_based_on_fractional_interest( wallet_address, fractional_interest, at_timestamp) return amount
def validate(self): validate_canonical_address(self.recipient_node_wallet_address, title="recipient_node_wallet_address") validate_uint256(self.score, title="score") validate_uint256(self.since_block_number, title="since_block_number") validate_uint256(self.timestamp, title="timestamp") validate_uint256(self.v, title="v") validate_uint256(self.r, title="r") validate_uint256(self.s, title="s") validate_lt_secpk1n(self.r, title="r") validate_gte(self.r, minimum=1, title="r") validate_lt_secpk1n(self.s, title="s") validate_gte(self.s, minimum=1, title="s") validate_gte(self.v, minimum=self.v_min, title="v") validate_lte(self.v, maximum=self.v_max, title="v") validate_lt_secpk1n2(self.s, title="s")
def validate(self): validate_uint256(self.nonce, title="Transaction.nonce") validate_uint256(self.gas_price, title="Transaction.gas_price") validate_uint256(self.gas, title="Transaction.gas") if self.to != CREATE_CONTRACT_ADDRESS: validate_canonical_address(self.to, title="Transaction.to") validate_uint256(self.value, title="Transaction.value") validate_is_bytes(self.data, title="Transaction.data") validate_uint256(self.v, title="Transaction.v") validate_uint256(self.r, title="Transaction.r") validate_uint256(self.s, title="Transaction.s") validate_lt_secpk1n(self.r, title="Transaction.r") validate_gte(self.r, minimum=1, title="Transaction.r") validate_lt_secpk1n(self.s, title="Transaction.s") validate_gte(self.s, minimum=1, title="Transaction.s") validate_gte(self.v, minimum=self.v_min, title="Transaction.v") validate_lte(self.v, maximum=self.v_max, title="Transaction.v") super(FrontierTransaction, self).validate()
def get_receivable_transactions(self, address: Address) -> List[TransactionKey]: validate_canonical_address(address, title="Storage Address") account = self._get_account(address) return account.receivable_transactions
def get_code_hash(self, address): validate_canonical_address(address, title="Storage Address") account = self._get_account(address) return account.code_hash
def add_receivable_transactions(self, address: Address, transaction_keys: TransactionKey) -> None: validate_canonical_address(address, title="Wallet Address") for tx_key in transaction_keys: self.add_receivable_transaction(address, tx_key.transaction_hash, tx_key.sender_block_hash)
def touch_account(self, address): validate_canonical_address(address, title="Storage Address") account = self._get_account(address) self._set_account(address, account)
def account_exists(self, address): validate_canonical_address(address, title="Storage Address") account_lookup_key = SchemaV1.make_account_lookup_key(address) return self._journaldb.get(account_lookup_key, b'') != b''
def delete_account(self, address): validate_canonical_address(address, title="Storage Address") account_lookup_key = SchemaV1.make_account_lookup_key(address) #try: del self._journaldb[account_lookup_key]
def has_pending_smart_contract_transactions(self, address: Address) -> bool: validate_canonical_address(address, title="Storage Address") address_set = set(self.get_smart_contracts_with_pending_transactions()) return address in address_set
def delete_code(self, address): validate_canonical_address(address, title="Storage Address") account = self._get_account(address) self._set_account(address, account.copy(code_hash=EMPTY_SHA3))