def _remove_from_index(self, tx: BaseTransaction, index: int) -> None: """ Remove tx from mint/melt indexes and total amount """ assert tx.hash is not None tx_output = tx.outputs[index] token_uid = tx.get_token_uid(tx_output.get_token_index()) if tx_output.is_token_authority(): if tx_output.can_mint_token(): # remove from mint index self.tokens[token_uid].mint.discard((tx.hash, index)) if tx_output.can_melt_token(): # remove from melt index self.tokens[token_uid].melt.discard((tx.hash, index)) else: self.tokens[token_uid].total -= tx_output.value
def _add_to_index(self, tx: BaseTransaction, index: int) -> None: """ Add tx to mint/melt indexes and total amount """ assert tx.hash is not None tx_output = tx.outputs[index] token_uid = tx.get_token_uid(tx_output.get_token_index()) if tx_output.is_token_authority(): if tx_output.can_mint_token(): # add to mint index self.tokens[token_uid].mint.add((tx.hash, index)) if tx_output.can_melt_token(): # add to melt index self.tokens[token_uid].melt.add((tx.hash, index)) else: self.tokens[token_uid].total += tx_output.value
def _remove_utxo(self, tx: BaseTransaction, index: int) -> None: """ Remove tx from mint/melt indexes and total amount """ assert tx.hash is not None tx_output = tx.outputs[index] token_uid = tx.get_token_uid(tx_output.get_token_index()) if tx_output.is_token_authority(): if tx_output.can_mint_token(): # remove from mint index self._remove_authority_utxo(token_uid, tx.hash, index, is_mint=True) if tx_output.can_melt_token(): # remove from melt index self._remove_authority_utxo(token_uid, tx.hash, index, is_mint=False) else: self._subtract_from_total(token_uid, tx_output.value)
def _add_utxo(self, tx: BaseTransaction, index: int) -> None: """ Add tx to mint/melt indexes and total amount """ assert tx.hash is not None tx_output = tx.outputs[index] token_uid = tx.get_token_uid(tx_output.get_token_index()) if tx_output.is_token_authority(): if tx_output.can_mint_token(): # add to mint index self._add_authority_utxo(token_uid, tx.hash, index, is_mint=True) if tx_output.can_melt_token(): # add to melt index self._add_authority_utxo(token_uid, tx.hash, index, is_mint=False) else: self._add_to_total(token_uid, tx_output.value)
def on_new_tx(self, tx: BaseTransaction) -> None: """Checks the inputs and outputs of a transaction for matching keys. If an output matches, will add it to the unspent_txs dict. If an input matches, removes from unspent_txs dict and adds to spent_txs dict. """ assert tx.hash is not None updated = False # check outputs for index, output in enumerate(tx.outputs): script_type_out = parse_address_script(output.script) if script_type_out: if script_type_out.address in self.keys: token_id = tx.get_token_uid(output.get_token_index()) # this wallet received tokens utxo = UnspentTx(tx.hash, index, output.value, tx.timestamp, script_type_out.address, output.token_data, timelock=script_type_out.timelock) self.unspent_txs[token_id][(tx.hash, index)] = utxo # mark key as used self.tokens_received(script_type_out.address) updated = True # publish new output and new balance self.publish_update(HathorEvents.WALLET_OUTPUT_RECEIVED, total=self.get_total_tx(), output=utxo) else: # it's the only one we know, so log warning self.log.warn('unknown script') # check inputs for _input in tx.inputs: assert tx.storage is not None output_tx = tx.storage.get_transaction(_input.tx_id) output = output_tx.outputs[_input.index] token_id = output_tx.get_token_uid(output.get_token_index()) script_type_out = parse_address_script(output.script) if script_type_out: if script_type_out.address in self.keys: # this wallet spent tokens # remove from unspent_txs key = (_input.tx_id, _input.index) old_utxo = self.unspent_txs[token_id].pop(key, None) if old_utxo is None: old_utxo = self.maybe_spent_txs[token_id].pop( key, None) if old_utxo: # add to spent_txs spent = SpentTx(tx.hash, _input.tx_id, _input.index, old_utxo.value, tx.timestamp) self.spent_txs[key].append(spent) updated = True # publish spent output and new balance self.publish_update(HathorEvents.WALLET_INPUT_SPENT, output_spent=spent) else: # If we dont have it in the unspent_txs, it must be in the spent_txs # So we append this spent with the others if key in self.spent_txs: output_tx = tx.storage.get_transaction( _input.tx_id) output = output_tx.outputs[_input.index] spent = SpentTx(tx.hash, _input.tx_id, _input.index, output.value, tx.timestamp) self.spent_txs[key].append(spent) else: self.log.warn('unknown input data') if updated: # TODO update history file? # XXX should wallet always update it or it will be called externally? self.update_balance()