def test_happy_path(self): """ Successfully promoting a bundle. """ self.adapter.seed_response('checkConsistency', { 'state': True, }) result_bundle = Bundle.from_tryte_strings([ TransactionTrytes(self.trytes1), TransactionTrytes(self.trytes2), ]) mock_send_transfer = mock.Mock(return_value={ 'bundle': result_bundle, }) with mock.patch( 'iota.commands.extended.send_transfer.SendTransferCommand._execute', mock_send_transfer, ): response = self.command( transaction=self.hash1, depth=3, minWeightMagnitude=16, ) self.assertDictEqual(response, { 'bundle': result_bundle, })
async def test_happy_path_multiple_bundles(self): """ Get two bundles with multiple transactions. """ # We will fetch the same two bundle for _ in range(2): for txn_trytes in self.bundle_trytes: self.adapter.seed_response('getTrytes', { 'trytes': [txn_trytes], }) self.adapter.seed_response('getTrytes', { 'trytes': [self.spam_trytes], }) response = await self.command(transactions = [self.tx_hash, self.tx_hash]) self.maxDiff = None original_bundle = Bundle.from_tryte_strings(self.bundle_trytes) self.assertListEqual( response['bundles'][0].as_json_compatible(), original_bundle.as_json_compatible(), ) self.assertListEqual( response['bundles'][1].as_json_compatible(), original_bundle.as_json_compatible(), )
async def _execute(self, request: dict) -> dict: change_address: Optional[Address] = request['changeAddress'] depth: int = request['depth'] inputs: Optional[List[Address]] = request['inputs'] min_weight_magnitude: int = request['minWeightMagnitude'] seed: Seed = request['seed'] transfers: List[ProposedTransaction] = request['transfers'] reference: Optional[TransactionHash] = request['reference'] security_level: int = request['securityLevel'] pt_response = await PrepareTransferCommand(self.adapter)( changeAddress=change_address, inputs=inputs, seed=seed, transfers=transfers, securityLevel=security_level, ) st_response = await SendTrytesCommand(self.adapter)( depth=depth, minWeightMagnitude=min_weight_magnitude, trytes=pt_response['trytes'], reference=reference, ) return { 'bundle': Bundle.from_tryte_strings(st_response['trytes']), }
def _execute(self, request): change_address = request['changeAddress'] # type: Optional[Address] depth = request['depth'] # type: int inputs = request['inputs'] # type: Optional[List[Address]] min_weight_magnitude = request['minWeightMagnitude'] # type: int seed = request['seed'] # type: Seed transfers = request['transfers'] # type: List[ProposedTransaction] reference = request['reference'] # type: Optional[TransactionHash] pt_response = PrepareTransferCommand(self.adapter)( changeAddress = change_address, inputs = inputs, seed = seed, transfers = transfers, ) st_response = SendTrytesCommand(self.adapter)( depth = depth, minWeightMagnitude = min_weight_magnitude, trytes = pt_response['trytes'], reference = reference, ) return { 'bundle': Bundle.from_tryte_strings(st_response['trytes']), }
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 custom_attach( trytes: List[TransactionTrytes], mwm: int, ): """ Custom attach to to tangle. Takes already attached bundle trytes, and except for the the head transaction, updates `attachment_timestamp` and re-does the pow, resulting in a new nonce and transaction hash. The head transaction remains the same as in the original bundle. """ # Install the pow package together with pyota: # $ pip install pyota[pow] from pow.ccurl_interface import get_powed_tx_trytes, get_hash_trytes, \ get_current_ms previoustx = None # Construct bundle object bundle = Bundle.from_tryte_strings(trytes) # and we need the head tx first for txn in reversed(bundle.transactions): if (not previoustx): # this is the head transaction # head tx stays the same, it is the original previoustx = txn.hash continue #we only want to mess with tx at index 1 if txn.current_index != 1: continue # set any old tx so that this bundles head.trunk != tx txn.branch_transaction_hash = 'TBLBTVTHAMPGMGQBUETQSOYHXLCDKSFRTLECTRKSTCHCEHJLCCRPGCUK9VUJNWGQCQNZCUM9IVVIOB999' # the previous transaction txn.attachment_timestamp = get_current_ms() # Let's do the pow locally txn_string = txn.as_tryte_string().__str__() # returns a python unicode string powed_txn_string = get_powed_tx_trytes(txn_string, mwm) # construct trytestring from python string powed_txn_trytes = TryteString(powed_txn_string) # compute transaction hash hash_string = get_hash_trytes(powed_txn_string) hash_trytes = TryteString(hash_string) hash_ = TransactionHash(hash_trytes) # Create powed txn object powed_txn = Transaction.from_tryte_string(trytes=powed_txn_trytes, hash_=hash_) previoustx = powed_txn.hash # put that back in the bundle bundle.transactions[txn.current_index] = powed_txn return bundle.as_tryte_strings()
def send_bundle(trytes): gtta = api.get_transactions_to_approve(depth=3) trunk = str(gtta['trunkTransaction']) # set a non-tail to fail rule 1 branch = str(gtta['branchTransaction']) #set a non-tail to fail rule 1 attached_trytes = api.attach_to_tangle(trunk, branch, trytes, 9).get('trytes') api.broadcast_and_store(attached_trytes) bundle = Bundle.from_tryte_strings(attached_trytes) pprint('Bundle is:') pprint(bundle.as_json_compatible()) return attached_trytes
async def test_validator_error(self): """ TraverseBundleCommand returns bundle but it is invalid. """ # Make the returned bundle invalid bundle = Bundle.from_tryte_strings(self.bundle_trytes) bundle.transactions[0].value = 999 # Unbalanced bundle for txn in bundle.transactions: self.adapter.seed_response('getTrytes', { 'trytes': [txn.as_tryte_string()], }) self.adapter.seed_response('getTrytes', { 'trytes': [self.spam_trytes], }) with self.assertRaises(BadApiResponse): response = await self.command(transactions = [self.tx_hash])
def test_happy_path(self): """ Get a bundle with multiple transactions. """ for txn_trytes in self.bundle_trytes: self.adapter.seed_response('getTrytes', { 'trytes': [txn_trytes], }) self.adapter.seed_response('getTrytes', { 'trytes': [self.spam_trytes], }) response = self.command(transactions = [self.tx_hash]) self.maxDiff = None original_bundle = Bundle.from_tryte_strings(self.bundle_trytes) self.assertListEqual( response['bundles'][0].as_json_compatible(), original_bundle.as_json_compatible(), )
def test_wrongly_ordered_bundle(self): """ Supply bundle trytes in wrong order. `attach_to_tangle` constructs a bundle object from the trytes, that should reorder transactions in correct order based on index. """ wrong_bundle_trytes = [] for txn in reversed(self.bundle.as_tryte_strings()): wrong_bundle_trytes.append(txn) test_trytes = ccurl_interface.attach_to_tangle(wrong_bundle_trytes, self.branch, self.trunk, mwm=14) test_bundle = Bundle.from_tryte_strings(test_trytes) validator = BundleValidator(test_bundle) if not validator.is_valid(): raise ValueError( 'Bundle failed validation:\n{errors}'.format(errors='\n'.join( (' - ' + e) for e in validator.errors), ), ) self.assertTrue(validator.is_valid())
def _execute(self, request): change_address = request['changeAddress'] # type: Optional[Address] depth = request['depth'] # type: int inputs = request['inputs'] # type: Optional[List[Address]] min_weight_magnitude = request['minWeightMagnitude'] # type: int seed = request['seed'] # type: Seed transfers = request['transfers'] # type: List[ProposedTransaction] pt_response = PrepareTransferCommand(self.adapter)( changeAddress = change_address, inputs = inputs, seed = seed, transfers = transfers, ) st_response = SendTrytesCommand(self.adapter)( depth = depth, minWeightMagnitude = min_weight_magnitude, trytes = pt_response['trytes'], ) return { 'bundle': Bundle.from_tryte_strings(st_response['trytes']), }
https://github.com/iotaledger/wiki/blob/master/multisigs.md#how-m-of-n-works For this example, the structure of the bundle looks like this: - Transaction 0: Spend IOTAs. - Transactions 1-8: Transactions that will hold the signature fragments for the multisig input: - 1-3: Generated from ``digest_1`` (security level 3). - 4-6: Generated from ``digest_2`` (security level 3). - 7-8: Generated from ``digest_3`` (security level 2). Note that transactions 1-8 don't have signatures yet; we need the corresponding private keys in order to create those! """ bundle = Bundle.from_tryte_strings(prepared_trytes) # Note that we must use the same parameters that we provided to the # ``get_digests`` method, in order to generate the correct value to # sign the input! gpk_result = api_1.get_private_keys(index=0, count=1, security_level=3) private_key_1 = gpk_result['keys'][0] # type: PrivateKey private_key_1.sign_input_transactions(bundle, 1) gpk_result = api_2.get_private_keys(index=42, count=1, security_level=3) private_key_2 = gpk_result['keys'][0] # type: PrivateKey private_key_2.sign_input_transactions(bundle, 4) gpk_result = api_3.get_private_keys(index=8, count=1, security_level=2) private_key_3 = gpk_result['keys'][0] # type: PrivateKey private_key_3.sign_input_transactions(bundle, 7)
]).get('trytes') gtta_response = api.get_transactions_to_approve(3) trunk = gtta_response.get('trunkTransaction') branch = gtta_response.get('branchTransaction') attached_original_trytes = api.attach_to_tangle(trunk, branch, original_trytes).get('trytes') # So we have the original bundle attached, time to construct the new one # We need to re-attach, but take special care, so we dont use the api, rather we do it ourself re_attached_trytes = custom_attach(attached_original_trytes, 9) original_bundle = Bundle.from_tryte_strings(attached_original_trytes) re_attached_bundle = Bundle.from_tryte_strings(re_attached_trytes) pprint('Original bundle is:') pprint(original_bundle.as_json_compatible()) pprint('Reattached bundle is:') pprint(re_attached_bundle.as_json_compatible()) #api.broadcast_and_store(attached_original_trytes) api.broadcast_and_store(re_attached_trytes) # bundles # BJRYHWKLREEUQCAZSUQFDNQAIL9LFRBZVEFFWPQZ99GNKATZBUZKFJYJIRYTFBPPESFJYDQRAYHNHH9LW good # UYBVN9EZKNA9KGGCSILJJGRTNGI9ZHVIUEYB9VXZXHLKZBTFGPHGJPJ9OHCUILSRBAA9XYSDKIXHYVLJW bad
def test_multiple_transactions(self): """ Getting a bundle that contains multiple transactions. """ bundle = Bundle.from_tryte_strings([ TransactionTrytes( b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999WUQXEGBVIECGIWO9IGSYKWWPYCIVUJJGSJPWGIAFJPYSF9NSQOHWAHS9P' b'9PWQHOBXNNQIF9IRHVQXKPZW999999999999999999999999999XZUIENOTTBKJMDP' b'RXWGQYG9PWGTHNLFMVD99A99999999A99999999PDQWLVVDPUU9VIBODGMRIAZPGQX' b'DOGSEXIHKIBWSLDAWUKZCZMK9Z9YZSPCKBDJSVDPRQLJSTKUMTNVSXBGUEHHGAIWWQ' b'BCJZHZAQOWZMAIDAFUZBVMUVPWQJLUGGQKNKLMGTWXXNZKUCBJLEDAMYVRGABAWBY9' b'999MYIYBTGIOQYYZFJBLIAWMPSZEFFTXUZPCDIXSLLQDQSFYGQSQOGSPKCZNLVSZ9L' b'MCUWVNGEN9EJEW9999XZUIENOTTBKJMDPRXWGQYG9PWGTXUO9AXMP9FLMDRMADLRPW' b'CZCJBROYCDRJMYU9HDYJM9NDBFUPIZVTR'), # Well, it was bound to happen sooner or later... the ASCII # representation of this tryte sequence contains a very naughty # phrase. But I don't feel like doing another POW, so... enjoy. TransactionTrytes( b'NBTCPCFDEACCPCBDVC9DTCQAJ9RBTC9D9DCDQAEAKDCDFD9DSCFAJ9VBCDJDTCQAJ9' b'ZBMDYBCCKB99999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999SYRABNN9JD9PNDL' b'IKUNCECUELTOHNLFMVD99999999999A99999999PDQWLVVDPUU9VIBODGMRIAZPGQX' b'DOGSEXIHKIBWSLDAWUKZCZMK9Z9YZSPCKBDJSVDPRQLJSTKUMTNVSXFSEWUNJOEGNU' b'I9QOCRFMYSIFAZLJHKZBPQZZYFG9ORYCRDX9TOMJPFCRB9R9KPUUGFPVOWYXFIWEW9' b'999BGUEHHGAIWWQBCJZHZAQOWZMAIDAFUZBVMUVPWQJLUGGQKNKLMGTWXXNZKUCBJL' b'EDAMYVRGABAWBY9999SYRABNN9JD9PNDLIKUNCECUELTOQZPSBDILVHJQVCEOICFAD' b'YKZVGMOAXJRQNTCKMHGTAUMPGJJMX9LNF'), ]) for txn in bundle: self.adapter.seed_response('getTrytes', { 'trytes': [txn.as_tryte_string()], }) self.adapter.seed_response( 'getTrytes', { 'trytes': [ 'SPAMSPAMSPAM999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999JECDITWO9999999' '999999999999ONLFMVD99999999999999999999VVCHSQSRVFKSBONDWB9EAQEMQOY' 'YRBIZHTBJLYNAVDHZPUZAZ9LYHXWKBEJ9IPR9FAMFLT9EEOHVYWUPRHHSRCILCLWFD' 'GBYBFFOKMCSAPVD9VGZZRRGBLGMZMXD9RMZQDBLMGN9BATWZGULRBCYQEIKIRBPHC9' '999KTLTRSYOWBD9HVNP9GCUABARNGMYXUZKXWRPGOPETZLKYYC9Z9EYXIWVARUBMBM' 'BPXGORN9WPBLY99999ZRBVQWULRFXDNDYZKRKIXPZQT9JJJH9FZU9PVWZJWLXBPODP' 'EHMKTTAGEPLPHUQCZNLDSHERONOMHJCOI' ], }) response = self.command(transaction=TransactionHash( b'TOYJPHKMLQNDVLDHDILARUJCCIUMQBLUSWPCTIVA' b'DRXICGYDGSVPXFTILFFGAPICYHGGJ9OHXINFX9999'), ) self.maxDiff = None self.assertListEqual( response['bundles'][0].as_json_compatible(), bundle.as_json_compatible(), )
async def test_unspent_inputs_with_change_address(self): """ The bundle has unspent inputs, so it uses the provided change address. """ self.adapter.seed_response( command=GetBalancesCommand.command, response={ 'balances': [101], 'duration': 86, }, ) pmt_result =\ await self.command( transfers = [ ProposedTransaction( address = Address(self.trytes_1), value = 42, ), ], multisigInput = MultisigAddress( digests = [self.digest_1, self.digest_2], trytes = self.trytes_2, ), changeAddress = Address(self.trytes_3), ) bundle = Bundle.from_tryte_strings(pmt_result['trytes']) self.assertEqual(len(bundle), 6) # Spend Transaction txn_1 = bundle[0] self.assertEqual(txn_1.address, self.trytes_1) self.assertEqual(txn_1.value, 42) # Input 1, Part 1 of 4 txn_2 = bundle[1] self.assertEqual(txn_2.address, self.trytes_2) self.assertEqual(txn_2.value, -101) self.assertEqual(txn_2.signature_message_fragment, Fragment(b'')) # Input 1, Part 2 of 4 txn_3 = bundle[2] self.assertEqual(txn_3.address, self.trytes_2) self.assertEqual(txn_3.value, 0) self.assertEqual(txn_3.signature_message_fragment, Fragment(b'')) # Input 1, Part 3 of 4 txn_4 = bundle[3] self.assertEqual(txn_4.address, self.trytes_2) self.assertEqual(txn_4.value, 0) self.assertEqual(txn_4.signature_message_fragment, Fragment(b'')) # Input 1, Part 4 of 4 txn_5 = bundle[4] self.assertEqual(txn_5.address, self.trytes_2) self.assertEqual(txn_5.value, 0) self.assertEqual(txn_5.signature_message_fragment, Fragment(b'')) # Change txn_6 = bundle[5] self.assertEqual(txn_6.address, self.trytes_3) self.assertEqual(txn_6.value, 59)
async def test_happy_path(self): """ Preparing a bundle with a multisig input. """ self.adapter.seed_response( command=GetBalancesCommand.command, response={ 'balances': [42], # Would it be cheeky to put "7½ million years" here? 'duration': 86, }, ) pmt_result =\ await self.command( transfers = [ ProposedTransaction( address = Address(self.trytes_1), value = 42, ), ], multisigInput = MultisigAddress( digests = [self.digest_1, self.digest_2], trytes = self.trytes_2, ), ) # The command returns the raw trytes. This is useful in a # real-world scenario because trytes are easier to transfer between # each entity that needs to apply their signature. # # However, for purposes of this test, we will convert the trytes # back into a bundle so that we can inspect the end result more # easily. bundle = Bundle.from_tryte_strings(pmt_result['trytes']) # # This bundle looks almost identical to what you would expect from # :py:meth:`iota.api.Iota.prepare_transfer`, except: # - There are 4 inputs (to hold all of the signature fragments). # - The inputs are unsigned. # self.assertEqual(len(bundle), 5) # Spend Transaction txn_1 = bundle[0] self.assertEqual(txn_1.address, self.trytes_1) self.assertEqual(txn_1.value, 42) # Input 1, Part 1 of 4 txn_2 = bundle[1] self.assertEqual(txn_2.address, self.trytes_2) self.assertEqual(txn_2.value, -42) self.assertEqual(txn_2.signature_message_fragment, Fragment(b'')) # Input 1, Part 2 of 4 txn_3 = bundle[2] self.assertEqual(txn_3.address, self.trytes_2) self.assertEqual(txn_3.value, 0) self.assertEqual(txn_3.signature_message_fragment, Fragment(b'')) # Input 1, Part 3 of 4 txn_4 = bundle[3] self.assertEqual(txn_4.address, self.trytes_2) self.assertEqual(txn_4.value, 0) self.assertEqual(txn_4.signature_message_fragment, Fragment(b'')) # Input 1, Part 4 of 4 txn_5 = bundle[4] self.assertEqual(txn_5.address, self.trytes_2) self.assertEqual(txn_5.value, 0) self.assertEqual(txn_5.signature_message_fragment, Fragment(b''))
def execute(self, api, **arguments): # type: (Iota, ...) -> int channel_key_index = arguments['channel_key_index'] # type: int count = arguments['count'] # type: int depth = arguments['depth'] # type: int dry_run = arguments['dry_run'] # type: bool mam_encrypt_path = arguments['mam_encrypt_path'] # type: Text min_weight_magnitude = arguments['min_weight_magnitude'] # type: int message_encoding = arguments['message_encoding'] # type: Text message_file = arguments['message_file'] # type: Optional[Text] security_level = arguments['security_level'] # type: int start = arguments['start'] # type: int if message_file: with codecs.open( message_file, 'r', message_encoding) as f_: # type: codecs.StreamReaderWriter message = f_.read() else: self.stdout.write( 'Enter message to send. Press Ctrl-D on a blank line when done.\n\n', ) message = self.stdin.read().strip() self.stdout.write('\n') # Generating the encrypted message may take a little while, so we # should provide some feedback to the user so that they know that # their input is being processed (this is especially important if # the user typed in their message, so that they don't press ^D # again, thinking that the program didn't register the first one). self.stdout.write('Encrypting message...\n') proc =\ run( args = [ # mam_encrypt.js mam_encrypt_path, # Required arguments binary_type(api.seed), message, # Options '--channel-key-index', text_type(channel_key_index), '--start', text_type(start), '--count', text_type(count), '--security-level', text_type(security_level), ], check = True, stdout = PIPE, stderr = self.stderr, ) # The output of the JS script is a collection of transaction # trytes, encoded as JSON. filter_ =\ f.FilterRunner( starting_filter = f.Required | f.Unicode | f.JsonDecode | f.Array | f.FilterRepeater( f.ByteString(encoding='ascii') | Trytes(result_type=TransactionTrytes) ), incoming_data = proc.stdout, ) if not filter_.is_valid(): self.stderr.write( 'Invalid output from {mam_encrypt_path}:\n' '\n' 'Output:\n' '{output}\n' '\n' 'Errors:\n' '{errors}\n'.format( errors=pformat(filter_.get_errors(with_context=True)), mam_encrypt_path=mam_encrypt_path, output=proc.stdout, ), ) return 2 transaction_trytes = filter_.cleaned_data # type: List[TransactionTrytes] bundle = Bundle.from_tryte_strings(transaction_trytes) if dry_run: self.stdout.write('Transactions:\n\n') self.stdout.write(json.dumps(bundle, cls=JsonEncoder, indent=2)) else: api.send_trytes( depth=depth, trytes=transaction_trytes, min_weight_magnitude=min_weight_magnitude, ) self.stdout.write('Message broadcast successfully!\n') self.stdout.write( 'Bundle ID: {bundle_hash}\n'.format( bundle_hash=bundle.hash, ), ) return 0
def setUpClass(self): # This is a valid bundle taken from the Tangle self.bundle = Bundle.from_tryte_strings([ TransactionTrytes( '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999GTSOCZLYYATDVK9FYRZXRFEHYUWTSXNALBGHO9T9GHANN' '9YTJIZHOBWZHYSLDRTIVSYRRBUJZFUKWVNJAJSNA99999999999999999999999FBNGLE9BE' 'AT9CYCLUX999999999RFAVOBD99999999999B99999999BGNBAIUZAHWWAIHAWHXIDGYQYKI' 'LEWDCBQXYBNQBFNPOIICLCJKHSX9KLPECYBGWW9CGILRKTVEYTL99AAVSD99RCNCYGIVIRVI' 'TNVOVQNQE9RFJIRAXCEXQEHEXQEKFXSDQVBQGJQWBRTRSAUPMXJLMFKUJKZ9999UIBLZWXJQ' 'DMZCPEQRLSFYJLEPIFTOCY9ODVKIYAMXMKYKHFWKEHNGLVKEYDGR9GOXWWNXLOCQFD999999' 'TANGLE9BEAT9CYCLUX999999999FIAMTJGOF999999999MMMMMMMMMZCJOZALASXIERYTDLY' 'WMZTJF9HQ'), TransactionTrytes( '9PTKKTOZFZBKCJTYHMKZZDRHCOYXHOTDQY9ALYIBNGD9UDPTUKPHJBORIICRNLDTECKLGPOGE' 'VQIVFHIYI9UUYWYEKGRDDGAAXD9EMFSKX9TDWGGPKTIXBCWQKPERPUIRYEEYXYPXGHBSRGQAH' 'ZOIBPERAWSCMIFJZGYAFQ9XBVYDXVJAXXX9XPTXJTSDMJSLNCBACGQ9CHVCYMEKOKSEBRUGTX' 'KMU9HLWRNWOZJGIOIKLPZEHDZKCQXFDMYOA9DRK9CJVRQSWZSDUWDCXWFPZIL9PJDQUQNMMBM' 'STGMOFCXKKCRZKDCRCBYSVDSKXTDKFBYIRVSTIVHGWTBFRGNNAYXZBVNSZDQDQRSJBNMBRZTG' 'VDWYAHHFEMSWF9CLSZPQYKFD9MOIR9CUZCPQAGBZSPSCRHSYVDKX9ZVEQONHOO9EAAHZSTHAW' 'SLSVI9HSOYKIGDWSKXCHHPFXMKCIBEASGQXHEIGOAETCBLHWPUBSLMELCUVARTPHGOG9BEQTM' 'NHA9MJHCRVNKXZTZTMEMSHFKJMWNBXLBLMVJDONO9JDYALFCBQ9GELAXSOEGOLNCPYGSKWRFF' 'IZNUGVHECQKRIZ9NTCPAXEKIAZLTXCBM9PJCOKSFDL99YPEVKOMWEXED9IAAOVPZLLFBZHVAM' 'DXEXCAZBGKWVQCXPFSEUNTPYVSLPEYKCTTGPVBSXQYFVWFUCGYLARMB9HA9PTRXAXKEOQLVXQ' 'TTHYZEXSOLFSEHMVJ9QOLMBGFHPTEQAYDZWSAPADJSSHTBWOZGVSLLPTMOLFZWUQFVKJZQPMZ' 'T9QACMCOEKJVWBOSKQHUTGLHAWMQHPDHCZEDKVUTYVMZCSMR9YPLRJGLUNTRGSEXLNBYJXLAR' 'MWWAWVPLZXYAYACMJCNYWISCHBMQAAMGTCFOZN9OZCITSFGBUJVERM9FRYHJYVKXLBALTHKWM' 'JMECDKGPKNWFWNHXAFQ9UEWBTUJADYFFMD9WAWE9PYEZIHGO9DSRBLLHCKIIVLHRPYR9UIYRN' 'VDYAL9Y9AEPVYOKBEDXJDYYBKEOLOAZCNLSBOULLOHEYAAJBZDNTNKVULUSUAME9LTAIEEUJV' 'QRVFXSDDTNDMNRSLAXKZTRCAGLIDVJJVGEJWSGDIH9HGVHDKLXVEEFTHAMLSUVEDMMVSDRPOI' 'UJTSNZJVMGBCFZYOMUSARYNXTRMFVMZOCZYPTBSOZUXXSYBRKKLZEAQDPNGLYAKAWTSEJKLBK' 'NASQQPZAB9MKOUZN9TO9ZYUVSTAPWGTMGO9ZARUWBVQT9ZLHAYEVJM9FNJCQNSBIRZ9AIXZEX' 'N9QMLPZBHTVNVKRPIXMQIA9OAWQFPNHMXOOPEUJQCKXZQOOYLMMJXXQAIVHRLGDKLGBOSKERQ' 'ZYNQOTVJW9IKMWZSORHMXFNOLSR9SIKBNTOANAZBGPGIPVVIFYWTUMATZAJPMUGYVITWCBBSQ' 'RVAY9MXJCECVTYASSAVUGKKQBDXYVWLTSL9HCAD9NUEWEHQXQUCDJC9WPVAZEDLTGTLZXUUOH' 'WCEUXCDYHATVRSJXJNLWCPEOENOBLXHTDOXSQCIDSEOHZHWBAYJV9ALDOBYMLXKNUQYQTEYAW' 'ZFSWGQOAHFXHZDBNCJDIJXRJDGRIOPCLPGPLG9AVFGQQBWPKNJROPIQDLXHNDGWGZOVBXHRBP' 'JQ9YHIJ9MNJFFLDTVLXJA9EBVPGVIAIHCDDHHTNX9KZARELDIZVQYUQGCPPCRTU9CDUXCVBYZ' 'RAUJDUMGGTKKOFQQTEGXRQKYPQTGHBGRCJ9IENKLNBIZNRSPVQ9VBKQLCG9YPYBEKJEYNAIDJ' 'PHABZJXBWHZLMADR9SDEWICFGRRTVAGZYCMJ9CANUSGIUKKHWUSWBQIBC9TXONXYDURJJWWE9' 'FKPPRWEJVWVJVKFKLMD9HCYASRUYCZPKM9VUCLOUVBYSMWIRFYJMTNOYXNKLNDWZJSRRZKLQL' 'YCODRSAKLMIRSPFYOANY9DUCYZYLEXDTGEJAKUDFWZNEGIBLMXZTW9OKF9SQGNNMHMUWIICFX' 'LFQMSLLSVJIMDEEWGOG9PDAPTZCRAL9TJRFPIOPMSFJOTLPRMEOUWGLTTXODGD9LSDJBTKX9Y' '9JNNIYNERDRQWJGICGHUFJCMGBBUZWLHQJUSUMUXNWRNIVHSFSRGMBMO9VTBGBBFOMHGNZQYI' 'OIIITMJDZLCJGNUWRJPJKOSSKRLUMGDXNRZFUFTZTSKXEZOCHUEWBONL9OBRYNWLPKSGCFE9W' 'TBVEXQHMZ99999999999999999999999999999999999999999999999999RFAVOBD99A9999' '9999B99999999BGNBAIUZAHWWAIHAWHXIDGYQYKILEWDCBQXYBNQBFNPOIICLCJKHSX9KLPEC' 'YBGWW9CGILRKTVEYTL99AYUMYMXIZRU9IIWNDROROZOINKOLXPOFCRZZTXAWDXUKVV9LMEMNG' 'HYZUMAPCESBINZGITBMIOQYX99999UIBLZWXJQDMZCPEQRLSFYJLEPIFTOCY9ODVKIYAMXMKY' 'KHFWKEHNGLVKEYDGR9GOXWWNXLOCQFD999999999999999999999999999999999ZS9MTJGOF' '999999999MMMMMMMMMMJVAHLRNJKJGTOLKSKNZWBTJNQP'), TransactionTrytes( 'M9STFJDJXSROWSPZTZXDYCWQDOQPBPAGATRY9SOXIXJOQL99OMWXPNXKCKJHHRPGWEDBLT9EO' 'IBTFDKZYXFMELEBQABMPIXUKYZKONEQESB9XHXYMQBULQVQLEEPHCZSFSMJKDGKEDRVBKLFKZ' 'JFNKLZWQPMTQGJKWQNAN9NQRKGWHEMIVZNODTNQNPXOTISDNWT9WZKC9DGLYWHUD9EQ9VTZRF' 'YUYU9BDHZULDGNUGUOUUXQTXZJVCBPZWYVTBEWVUJAOCZVNUJNMSMSVN9CPXWDSFCMRSWAMLP' 'AJRAEGSCOPLWYEGWPKKSXYJSBNLGMBLDEQ9NQEM9XDCSYZLUHLLEICKFHBFPIYDNGEZJEJXBE' '9HJGFRMHAHNXIGDDZRPAOTUZPEEUGLZYDEJYIYFCMOUNRLZFBYC9BDPWUVIR9DE9QGBEPVMDL' 'J9HUDJMGVDQNIDQQTCRXLCPNSLZXSUUPNKUCDHKWCMQ9HPVWXSZXKGXCDKX9BXNOFDUYUBBGD' 'DOJEZISFJLFUMKJJHXNBMLUWZWBQ9QDITUUZWHFEXQVAAKBUEXCO9XFBPAD9IKEODAPALAGSG' 'XFDLORKHCXSPINKO9HSJF9BXUIBRXNUX9APPTPIUYXVVWIYXGARPKDYNEGQXPWYCRAPZMZYKW' 'ICPYJWUEBIBPTXNJTBSSQDFKH9ZFQXNNH9MUTVKEYQIYOJTLFJLAQOFZFIVMTHESCNDLGXZXA' 'OWHXPEDVVBFJHIKCNFGPLUZQBYVRRMYCIAJOOJINAHSATUVCLQNMOAERIAJESBZOABTMBMJVQ' 'DVBMLDBBONGRW9QJUAXS9LQWRRKH9PLQUEVUDHWRZFP9FPYSWOQQRINOCHSJYPVKEUQPDOHXQ' 'WZFKOLZFXYQF9WDHKTHBVMACJMNUVYFLDBCCCHKTBJINNBPKVXYTVLVGADMYEYVLYROARFBWE' 'ATEIHEENZVRNOJRJYIMQJRAOFKUWSDKFTNNDTLCFHXQNRFEUFJN9GFFJXWDPKIQUQBXDARMRK' 'LSGUSATHVZMJSXFTWIJPCWNG9UWDGQYUGPMSGJSZBCSUPAKQKIHP9EGIXNRNMDGUVJNVMW9RL' 'TOHXUXI9UZTCRLVMMREWFSRUOBKFVQYH9PUVOWATYNDULLZ9RCBHDUVNJDMOJETQ9H9RKOSQF' 'XEVDVVJNZZSMFMLLQJTYXAALRIHQJWDCZYFZBLODYGYUP9XGPZVILG9WBGOVVYRUTHDGF9TRZ' 'GSFIYHAAAGXJTJKRG9ZYBFDSRQPQAOIJHDENVQAPJMBLOIVUZIGHMVXHBKZOFUJVEWCZJNCTS' 'TDEPQTYCPGGG9ZEDEYTSDBOMLOO9QO9LMJKNRXHLWNJUOLVNGXMLNHXZVKTRJGDD9CERBOTKR' 'EDGEGUQDBFIKPYPOXXF9KLYAX9SDCCDTCFULSOZRYJSORRZUUN9CCNRQKTCDCOGIYHAHWYBUX' 'EYVIJTGXCPGIGBFQWOTJX9APYNDCPQ9FSNXUZF9MDRLZIJSYDGYKBQGWTQLEKZSATDKVWFFMH' 'QNTMNWWJNBKVGI9QDXYYWOFAKI9OZRBOWMZZHLXUJQKIICFTBZAHUTZFIZIAUO9CWSTYMGZPO' 'PBKIO9ZYNSRHXCCIMKD9SPDQNXALFLNTXWVVYDAFHWLD9YSDGGRQJUBWZXQHVULYVDON9WADY' 'XPEVAGKTXIUTDRMLE9TTKD9TSHXFHQSOLHOCQ9SYWJWTOC99GAKHRSREJKHCBLYSHPOEYJNYX' 'IYNSQITTFSMKFL9HRNEKDZSJSYEBJACGTVBRVQGUREAYZEIQQIGWVRWIWSDGBRLAMPKQGZCEO' 'JPHANGFVYRXZJCDO9MGKBPYPQYVHQWDJVSUKA9VGLJELXFJKTNMQYZYGBHNFLGETZ9SWLDRNO' 'OUCAWNFOTBFICNEQJNPAZABLPOR99DPWTZZWLIRA9MFPXXHMJL9QWVJOAPYA9REAHBATJYJYJ' 'DYAGCKFDRSVTXMFFIBDPIBXBINGXTWMM9PSRVAKQEEQGRDJNOHKJDCCFBZZRLIVXPGEZYAV9G' 'CUGCATAQLMSOABNYLSNSTRPOGIRMKCGDDITKO9TEVOWPRGQHJDYWPZTZ9RVLPWGFDZOZICSUZ' 'AUPZJVTXCMUEADAKPZMNOTHLMGDJKTQWJQBK9TIGUTLDWYEPNDLJLDDYHQUWNLLH9MJUFAQYI' 'OIIITMJDZLCJGNUWRJPJKOSSKRLUMGDXNRZFUFTZTSKXEZOCHUEWBONL9OBRYNWLPKSGCFE9W' 'TBVEX999999999999999999999999999999999999999999999999999999RFAVOBD99B9999' '9999B99999999BGNBAIUZAHWWAIHAWHXIDGYQYKILEWDCBQXYBNQBFNPOIICLCJKHSX9KLPEC' 'YBGWW9CGILRKTVEYTL99AUIBLZWXJQDMZCPEQRLSFYJLEPIFTOCY9ODVKIYAMXMKYKHFWKEHN' 'GLVKEYDGR9GOXWWNXLOCQFD999999IFJ9JLPZON9CZJWMKJWPMUWHKOYTUOSBWQYCTCGBXAJG' 'T9KRVDDLBCNXFYKRXDEKJYQMTAMYJXJRA9999999999999999999999999999999BGYMTJGOF' '999999999MMMMMMMMMOGZMHCGFJIGGC9JYILNUCHZSDGV') ]) self.single_tx_bundle = Bundle.from_tryte_strings([ TransactionTrytes( 'VBCDFDTCADEAXCDDGDIDADEASCCD9DCDFDEAGDXCHDEAPCADTCHDQAEARCCDBDGDTCRCHDTCH' 'DIDFDEAPCSCXCDDXCGDRCXCBDVCEATC9DXCHDSAEASBBDEABDCDBDEA9DXCQCTCFDCDEAXCSC' 'EABDXCQCWCEAUCPCRCXC9DXCGDXCGDEAXCADDDTCFDSCXCTCHDEATCIDEAGDTCSCEAGDPCDDX' 'CTCBDSAEABCTCSCEASCXCVCBDXCGDGDXCADEA9DXCVCID9DPCEAXCBDEATCGDHDEAADPC9DTC' 'GDIDPCSCPCEA9DCDQCCDFDHDXCGDSAEAOBHDXCPCADEAJDPCFDXCIDGDEAADCD9DTCGDHDXCT' 'CEABDID9D9DPCEADDFDTCHDXCIDADEAHDXCBDRCXCSCIDBDHDSAEAXBPCADEAJDTCWCXCRCID' '9DPCEA9DPCRCXCBDXCPCEA9DXCQCTCFDCDSAEAMBIDFDPCQCXCHDIDFDEAXCBDEACDFDBDPCF' 'DTCEA9DTCCDSAEAMBFDPCGDEATCIDEASCCD9DCDFDEAEDIDXCGDEAHDCDFDHDCDFDEAXCADDD' 'TCFDSCXCTCHDEAPC9DXCEDIDTCHDSAEANBCDBDTCRCEAPCEAHDTC9D9DIDGDEATCFDPCHDSAE' 'AXBIDBDRCEAXCSCEAXCPCRCID9DXCGDEASCIDXCSA99999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999MZW' 'YYLQNAKEWITJSJZJCPFZWMEYGOVYOKUZYUWMUDLGAAAHTBYNQQNGHLUMSGZNQCJCHOULIZSDC' 'ATEXD999999999999999999999999999VHURLINTERFACE9TEST9TX999999KGVOBD9999999' '9999999999999DLWTLGSTHZKRDSIRWCZ9HCJWNUJBKTWHCBZGRIFTASCTBIBZZNNWFVGHEGJB' 'EWWXKRFOXD9GLTXPFGRBY9999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999CCURLINTERFACE9TEST9TX99999999999999' '999999999999999999999999999999999999999999999') ]) self.trunk = TransactionHash('TRUNKTXHASH9TESTVALUEONLY') self.branch = TransactionHash('BRANCHTXHASH9TESTVALUEONLY') # Result is reused accross tests, no need to calculate it # multiple times. # Mock away current time calculation, timestamps are imaginary from # this point on. self.before = 99 with patch('pow.ccurl_interface.get_current_ms', MagicMock(return_value=100)): self.powed = ccurl_interface.attach_to_tangle( self.bundle.as_tryte_strings(), self.branch, self.trunk, mwm=14) self.after = 101 self.powed_bundle = Bundle.from_tryte_strings(self.powed)
def attach_to_tangle( bundle_trytes, # Iterable[TryteString] trunk_transaction_hash, # TransactionHash branch_transaction_hash, # TransactionHash mwm=14): # Int """ Attaches the bundle to the Tangle by doing Proof-of-Work locally. No connection to the Tangle is needed in this step. :param bundle_trytes: List of TryteString(s) that contain raw transaction trytes. :param trunk_transaction_hash: Trunk transaction hash obtained from an iota node. Result of the tip selection process. :param branch_transaction_hash: Branch transaction hash obtained from an iota node. Result of the tip selection process. :param mwm: Minimum Weight Magnitude to be used during the PoW. Number of trailing zero trits in transaction hash. :returns: The bundle as a list of transaction trytes (TryteStrings). Attachment timestamp and nonce included. """ previoustx = None # Construct bundle object bundle = Bundle.from_tryte_strings(bundle_trytes) # reversed, beause pyota bundles look like [...tx2,tx1,tx0] # and we need the tail tx first (tx0) for txn in reversed(bundle.transactions): txn.attachment_timestamp = get_current_ms() txn.attachment_timestamp_upper_bound = (math.pow(3, 27) - 1) // 2 if (not previoustx): # this is the tail transaction if txn.current_index == txn.last_index: txn.branch_transaction_hash = branch_transaction_hash txn.trunk_transaction_hash = trunk_transaction_hash else: raise ValueError('Tail transaction is inconsistent in bundle') else: # It is not a tail transaction txn.branch_transaction_hash = trunk_transaction_hash txn.trunk_transaction_hash = previoustx # the previous transaction # Let's do the pow locally txn_string = txn.as_tryte_string().__str__() # returns a python unicode string powed_txn_string = get_powed_tx_trytes(txn_string, mwm) # construct trytestring from python string powed_txn_trytes = TryteString(powed_txn_string) # compute transaction hash hash_string = get_hash_trytes(powed_txn_string) hash_trytes = TryteString(hash_string) hash_ = TransactionHash(hash_trytes) # Create powed txn object powed_txn = Transaction.from_tryte_string(trytes=powed_txn_trytes, hash_=hash_) previoustx = powed_txn.hash # put that back in the bundle bundle.transactions[txn.current_index] = powed_txn return bundle.as_tryte_strings()
def attach_to_tangle( bundle_trytes, # Iterable[TryteString] trunk_transaction_hash, # TransactionHash branch_transaction_hash, # TransactionHash mwm=14): # Int """ Attaches the bundle to the Tangle by doing Proof-of-Work locally. No connection to the Tangle is needed in this step. :param bundle_trytes: List of TryteString(s) that contain raw transaction trytes. :param trunk_transaction_hash: Trunk transaction hash obtained from an iota node. Result of the tip selection process. :param branch_transaction_hash: Branch transaction hash obtained from an iota node. Result of the tip selection process. :param mwm: Minimum Weight Magnitude to be used during the PoW. Number of trailing zero trits in transaction hash. :returns: The bundle as a list of transaction trytes (TryteStrings). Attachment timestamp and nonce included. """ previoustx = None # Construct bundle object bundle = Bundle.from_tryte_strings(bundle_trytes) # Used for checking hash trailing_zeros = [0] * mwm # reversed, beause pyota bundles look like [tx0,tx1,...] # and we need the head (last) tx first for txn in reversed(bundle.transactions): # Ccurl lib sometimes needs a kick to return the correct powed trytes. # We can check the correctness by examining trailing zeros of the # transaction hash. If that fails, we try calculating the pow again. # Use `max_iter` to prevent infinite loop. Calculation error appears # rarely, and usually the second try yields correct result. If we reach # `max_iter`, we raise a ValueError. max_iter = 5 i = 0 # If calculation is successful, we break out from the while loop. while i != max_iter: # Fill timestamps txn.attachment_timestamp = get_current_ms() txn.attachment_timestamp_upper_bound = (math.pow(3, 27) - 1) // 2 # Determine correct trunk and branch transaction if (not previoustx): # this is the head transaction if txn.current_index == txn.last_index: txn.branch_transaction_hash = branch_transaction_hash txn.trunk_transaction_hash = trunk_transaction_hash else: raise ValueError( 'Head transaction is inconsistent in bundle') else: # It is not the head transaction txn.branch_transaction_hash = trunk_transaction_hash txn.trunk_transaction_hash = previoustx # the previous transaction # Let's do the pow locally txn_string = txn.as_tryte_string().__str__() # returns a python unicode string powed_txn_string = get_powed_tx_trytes(txn_string, mwm) # construct trytestring from python string powed_txn_trytes = TryteString(powed_txn_string) # Create powed txn object # This method calculates the hash for the transaction powed_txn = Transaction.from_tryte_string(trytes=powed_txn_trytes) previoustx = powed_txn.hash # put that back in the bundle bundle.transactions[txn.current_index] = powed_txn # Check for inconsistency in hash hash_trits = powed_txn.hash.as_trits() if hash_trits[-mwm:] == trailing_zeros: # We are good to go, exit from while loop break else: i = i + 1 logger.info( 'Ooops, wrong hash detected in try' ' #{rounds}. Recalculating pow... '.format(rounds=i)) # Something really bad happened if i == max_iter: raise with_context( exc=ValueError( 'PoW calculation failed for {max_iter} times.' ' Make sure that the transaction is valid: {tx}'.format( max_iter=max_iter, tx=powed_txn.as_json_compatible())), context={ 'original': txn, }, ) return bundle.as_tryte_strings()
def search_hash(type, hash): result = None if type == "tag" or type == "search": try: result = api.find_transactions(tags=[hash]) if result['hashes'][0]: return "tag", result['hashes'] except BaseException as e: result = e if type == "address" or type =="search": try: result = api.find_transactions(addresses=[hash]) if result['hashes'][0]: balance = get_price(api.get_balances([hash])['balances'][0]) tx = api.get_trytes(result['hashes'])['trytes'] for num in range(len(tx)): tx[num] = Transaction.from_tryte_string(tx[num]) confirm = confirmation([element.hash for element in tx]) for t in tx: t.is_confirmed = confirm[t.hash] t.timestamp = calculate_time(t.attachment_timestamp/1000) t.value = get_convert(t.value) tx = sorted(tx, key=lambda k: k.attachment_timestamp, reverse=True) results = {'balance':balance, 'transactions':tx} return "address", results except BaseException as e: result = e if type == "transaction" or type =="search": try: tx = api.get_trytes(hashes=[hash]) result = Transaction.from_tryte_string(tx['trytes'][0]) if result.hash != TransactionHash(b''): result.timestamp = calculate_time(result.attachment_timestamp/1000) result.is_confirmed = confirmation([result.hash])[result.hash] result.value = get_price(result.value) return "transaction", result except BaseException as e: result = e if type == "bundle" or type =="search": try: result = api.find_transactions(bundles=[hash])['hashes'] if result[0]: results = Bundle.from_tryte_strings(api.get_trytes(result)['trytes']) if True in confirmation(result).values(): results.is_confirmed = True for result in results: result.value = get_convert(result.value) newlis = sorted(results, key=lambda k: k.attachment_timestamp, reverse=True) size = newlis[0].last_index+1 newlist = [newlis[i:i+size] for i in range(0, len(newlis), size)] for x in newlist: x[0].timestamp = calculate_time(x[0].attachment_timestamp/1000) return "bundle", newlist except BaseException as e: result = e return "error", str(result)
def execute(self, api, **arguments): # type: (Iota, ...) -> int channel_key_index = arguments['channel_key_index'] # type: int count = arguments['count'] # type: int depth = arguments['depth'] # type: int dry_run = arguments['dry_run'] # type: bool mam_encrypt_path = arguments['mam_encrypt_path'] # type: Text min_weight_magnitude = arguments['min_weight_magnitude'] # type: int message_encoding = arguments['message_encoding'] # type: Text message_file = arguments['message_file'] # type: Optional[Text] security_level = arguments['security_level'] # type: int start = arguments['start'] # type: int if message_file: with codecs.open(message_file, 'r', message_encoding) as f_: # type: codecs.StreamReaderWriter message = f_.read() else: self.stdout.write( 'Enter message to send. Press Ctrl-D on a blank line when done.\n\n', ) message = self.stdin.read().strip() self.stdout.write('\n') # Generating the encrypted message may take a little while, so we # should provide some feedback to the user so that they know that # their input is being processed (this is especially important if # the user typed in their message, so that they don't press ^D # again, thinking that the program didn't register the first one). self.stdout.write('Encrypting message...\n') proc =\ run( args = [ # mam_encrypt.js mam_encrypt_path, # Required arguments binary_type(api.seed), message, # Options '--channel-key-index', text_type(channel_key_index), '--start', text_type(start), '--count', text_type(count), '--security-level', text_type(security_level), ], check = True, stdout = PIPE, stderr = self.stderr, ) # The output of the JS script is a collection of transaction # trytes, encoded as JSON. filter_ =\ f.FilterRunner( starting_filter = f.Required | f.Unicode | f.JsonDecode | f.Array | f.FilterRepeater( f.ByteString(encoding='ascii') | Trytes(result_type=TransactionTrytes) ), incoming_data = proc.stdout, ) if not filter_.is_valid(): self.stderr.write( 'Invalid output from {mam_encrypt_path}:\n' '\n' 'Output:\n' '{output}\n' '\n' 'Errors:\n' '{errors}\n'.format( errors = pformat(filter_.get_errors(with_context=True)), mam_encrypt_path = mam_encrypt_path, output = proc.stdout, ), ) return 2 transaction_trytes = filter_.cleaned_data # type: List[TransactionTrytes] bundle = Bundle.from_tryte_strings(transaction_trytes) if dry_run: self.stdout.write('Transactions:\n\n') self.stdout.write(json.dumps(bundle, cls=JsonEncoder, indent=2)) else: api.send_trytes( depth = depth, trytes = transaction_trytes, min_weight_magnitude = min_weight_magnitude, ) self.stdout.write('Message broadcast successfully!\n') self.stdout.write( 'Bundle ID: {bundle_hash}\n'.format( bundle_hash = bundle.hash, ), ) return 0
def setUp(self) -> None: # Need two valid bundles super().setUp() self.adapter = MockAdapter() self.single_bundle = Bundle.from_tryte_strings([ TransactionTrytes( '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999POALVTTGQHJFGINKJ9' 'EWRJZBQLLWMMNMNRUT9VFWDDMDWHPJMNDOFZXUQUABGCXZRH9OI9NWEUSHVYXDO' '999999999999999999999999999C99999999999999999999999999RIGEHBD99' '999999999999999999RPCKQTYDOV9IYVYYALBTBLHRFCLFMTCC9ZLOKKGENTDFY' 'COKFUITXUIUJLBNWAEKBJKBYDSRLVHSGELCCCZGNHCYEAKJ9OPRZFIBYEEBTRFT' 'QTWJUKRDKNSEESICPJRTDNZQQYNXOFVXI9CPRNBO9APJMEXATA9999CZGNHCYEA' 'KJ9OPRZFIBYEEBTRFTQTWJUKRDKNSEESICPJRTDNZQQYNXOFVXI9CPRNBO9APJM' 'EXATA9999C99999999999999999999999999FQFFNIHPF999999999MMMMMMMMM' 'BCDJOVFVODAQEPAXIWDRFKCTOFI') ]) self.three_tx_bundle = Bundle.from_tryte_strings(([ TransactionTrytes( 'PBXCFDGDHDEAHDFDPCBDGDPCRCHDXCCDBDEAXCBDEAHDWCTCEAQCIDBDSC9DTCS' 'A99999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999M9OVNPOWKUNQYDHFN9' 'YAL9WIQJDVAFKBU9ZPIHSGTZLGFJODRZINZMDALS9ERTNAJ9VTENWYLBSYALQQL' '999999999999999999999999999EYOTA9TESTS9999999999999999BOPIHBD99' '999999999B99999999JWFDGHYGEQIKSPCWEAHHQACOYHQWINSA9GELCEZNQEUHV' 'DH9UAYJVSTIIKW9URTHHIJYGWXGE9AEWISYWZSLPKSJETGKZEQVPISQSNDHIAXQ' 'RZVFJXFOXZAVMRUGALCQRHUEZPDFNLCIKQGWEKDJURLZLMUZVA99999BSJCSWTG' 'RTJSGZPOXRPICUDATCLCVTF9BEDHSZZRLSH9IRMTFRVAMSSHC9TRYZGHPWRDVTX' 'EXWTZ9999PYOTA9TESTS9999999999999999OSZRBMHPF999999999MMMMMMMMM' 'IVL9PTSTAIRGJLGXFQGIWOJHBKF'), TransactionTrytes( 'BCTCRCCDBDSCEAHDFDPCBDGDPCRCHDXCCDBDEAXCBDEAHDWCTCEAQCIDBDSC9DT' 'CSA999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999LSTTHILAJWQEXWVOJQ' 'GRANRLNHQLKYXVQFBYJ9QDFRISQR9WJYMSSZUBOCVLXF9TACHKGQUEGMJPICXVY' '999999999999999999999999999PYOTA9TESTS9999999999999999BOPIHBD99' 'A99999999B99999999JWFDGHYGEQIKSPCWEAHHQACOYHQWINSA9GELCEZNQEUHV' 'DH9UAYJVSTIIKW9URTHHIJYGWXGE9AEWISYWQQAWNWHDSGZWFTKTYSV99PJIFFM' 'OPFWONAOTRBUEDGLORTHNMXM9EZNILYEIWCQIAVMAGDBHYWWOA99999BSJCSWTG' 'RTJSGZPOXRPICUDATCLCVTF9BEDHSZZRLSH9IRMTFRVAMSSHC9TRYZGHPWRDVTX' 'EXWTZ9999PYOTA9TESTS9999999999999999EMSRBMHPF999999999MMMMMMMMM' 'NXTVOIJXAAJUS9SRVJEVDVOSIUE'), TransactionTrytes( 'CCWCXCFDSCEAHDFDPCBDGDPCRCHDXCCDBDEAXCBDEAHDWCTCEAQCIDBDSC9DTCS' 'A99999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999FSXLFSGAHTGSFPK9FH' 'HURWZJAWQDQCRIFUHMSZWUTNRAIDNGEHGPHLNJOEAIDGLYQRCYSCYDTBZQFDGQK' '999999999999999999999999999PYOTA9TESTS9999999999999999BOPIHBD99' 'B99999999B99999999JWFDGHYGEQIKSPCWEAHHQACOYHQWINSA9GELCEZNQEUHV' 'DH9UAYJVSTIIKW9URTHHIJYGWXGE9AEWISYW9BSJCSWTGRTJSGZPOXRPICUDATC' 'LCVTF9BEDHSZZRLSH9IRMTFRVAMSSHC9TRYZGHPWRDVTXEXWTZ99999BSJCSWTG' 'RTJSGZPOXRPICUDATCLCVTF9BEDHSZZRLSH9IRMTFRVAMSSHC9TRYZGHPWRDVTX' 'EXWTZ9999PYOTA9TESTS9999999999999999LUSRBMHPF999999999MMMMMMMMM' 'BOCWSYQAKMZXDR9ZPHXTXZORELC'), ]))
def _reattach(self, bundle: Bundle) -> Bundle: response = self._iota_api.replay_bundle( bundle.tail_transaction.hash, DEPTH, ) return Bundle.from_tryte_strings(response['trytes'])