class Replay: def __init__(self, node, seed, bundle, replay_callback=None, depth=7, min_weight_magnitude=14): self.api = Iota(node, seed) self.depth = depth self.min_weight_magnitude = min_weight_magnitude if replay_callback: self.replay_callback = replay_callback self.replay(bundle) def fetch_tail_transaction(self, bundle_hash): ft_result = self.api.find_transactions(bundles=[bundle_hash]) transaction_hashes = ft_result['hashes'] gt_result = self.api.get_trytes(transaction_hashes) bundle = Bundle.from_tryte_strings(gt_result['trytes']) return bundle.tail_transaction.hash def replay(self, bundle): tail_transaction = self.fetch_tail_transaction(bundle) try: self.api.replay_bundle( transaction=tail_transaction, depth=self.depth, min_weight_magnitude=self.min_weight_magnitude) if callable(self.replay_callback): self.replay_callback( 'Successfully replayed your specified bundle!') except: if callable(self.replay_callback): self.replay_callback( 'Something went wrong while replaying your bundle! Please try again.' )
def test_wireup(self): """ Verify that the command is wired up correctly. (sync) The API method indeed calls the appropiate command. """ with patch('iota.commands.extended.replay_bundle.ReplayBundleCommand.__call__', MagicMock(return_value=async_return('You found me!')) ) as mocked_command: api = Iota(self.adapter) # Don't need to call with proper args here. response = api.replay_bundle('transaction') self.assertTrue(mocked_command.called) self.assertEqual( response, 'You found me!' )
from iota import Iota from config import NODE_URL import json TXN_HASH = "XHADQXMPFWJCFCLZOVFYRFDQCNFLJFKVDRLCDACAOQBBQMMOUIVTPLASLOQAFRC9MUSUEFWPZJRMZ9999" api = Iota(NODE_URL) print(api.replay_bundle(TXN_HASH))
class Wallet: """docstring for Wallet""" def __init__(self, uri: str, seed: Optional[str] = None) -> None: self._iota_api = Iota(uri, seed) self._account: _Account @property def account(self) -> _Account: try: return self._account except AttributeError: # We get an attibute error if we check this property before ever # calling refresh_account. self.refresh_account() return self._account @property def addresses(self) -> List[Address]: return self.account.addresses @property def balance(self) -> int: return self.account.balance @property def bundles(self) -> Dict[str, Iterable[Bundle]]: return { 'confirmed': self.account.confirmed_bundles, 'unconfirmed': self.account.unconfirmed_bundles, 'duplicate': self.account.duplicate_bundles, } def _is_above_max_depth(self, transaction: Transaction) -> bool: current_millis = time.time() * 1000 max_age = 11 * 60 * 1000 # 11 minutes diff = current_millis - cast(float, transaction.attachment_timestamp) return (0 < diff < max_age) def _is_promotable(self, bundle: Bundle) -> bool: return (self._is_above_max_depth(bundle.tail_transaction) and self._iota_api.helpers.is_promotable( bundle.tail_transaction.hash)) def _promote(self, bundle: Bundle) -> Bundle: tail_hash = bundle.tail_transaction.hash response = self._iota_api.get_latest_inclusion([tail_hash]) if response['states'][tail_hash]: raise BundleAlreadyPromoted() response = self._iota_api.promote_transaction(transaction=tail_hash, depth=DEPTH) return response['bundle'] def _reattach(self, bundle: Bundle) -> Bundle: response = self._iota_api.replay_bundle( bundle.tail_transaction.hash, DEPTH, ) return Bundle.from_tryte_strings(response['trytes']) def create_new_address(self) -> Address: response = self._iota_api.get_new_addresses(count=None) address = response['addresses'][0] # Attach the address self._iota_api.send_transfer( depth=DEPTH, transfers=[ProposedTransaction(address, value=0)], ) return address def refresh_account(self) -> None: response = self._iota_api.get_account_data(inclusion_states=True) addresses = response['addresses'] balance = response['balance'] bundles = response['bundles'] self._account = _Account(addresses, balance, bundles) def retry_unconfirmed_bundles(self, *bundles: Bundle) -> None: if len(bundles) == 0: bundles = tuple(self.bundles['unconfirmed']) for bundle in bundles: print(f'Retrying bundle: {bundle.hash}') if not self._is_promotable(bundle): bundle = self._reattach(bundle) while True: time.sleep(2) if self._is_promotable(bundle): break for attempt in range(5): try: promote_bundle = self._promote(bundle) except BundleAlreadyPromoted: break else: print( f'Promotion attempt ({attempt}): Bundle {promote_bundle.hash}' ) def send(self, address: str, value: int) -> None: print(f'Sending {value} iota to {address}...') response = self._iota_api.send_transfer( depth=DEPTH, transfers=[ProposedTransaction(Address(address), value=value)]) bundle = response['bundle'] print(f'Iota sent! Bundle hash: {bundle.hash}')
'interruptAttachingToTangle', LOCAL_NODE)) bundle_hash = input('Paste bundle hash: ') """ API.replay_bundle does not accept a bundle hash as argument. You have to pass the transaction hash with a currentIndex of 0 (= the first transaction or "tail transaction" of a bundle). That's why we have to get the transaction hashes of the bundle with API.find_transactions. Then we have to find out which of the returned transactions has a currentIndex of 0. """ print('Fetching transaction hashes...') transaction_hashes = API.find_transactions(bundles=[bundle_hash])['hashes'] print('Received transaction hashes.') print('Fetching transaction trytes...') bundle_trytes = API.get_trytes(transaction_hashes)['trytes'] print('Received transaction trytes.') from iota import Transaction for transaction_trytes in bundle_trytes: transaction = Transaction.from_tryte_string(transaction_trytes) if transaction.is_tail: print('Reattaching...') API.replay_bundle(transaction.hash, 3) print('Reattached') break