def Send(self, ReceiverAddress, Message, Test_Node=False): def Bundle_Generation(Recepient, ToSend): text_transfer = TryteString.from_string(str(ToSend)) txn_2 = ProposedTransaction(address=Address(Recepient), message=text_transfer, value=0) bundle.add_transaction(txn_2) bundle = ProposedBundle() if type(ReceiverAddress) == list and type(Message) == list and ( len(ReceiverAddress) == len(Message)): for i in range(len(ReceiverAddress)): Bundle_Generation(ReceiverAddress[i], Message[i]) elif type(ReceiverAddress) == str and type(Message) == str: Bundle_Generation(ReceiverAddress, Message) bundle.finalize() coded = bundle.as_tryte_strings() hashed = bundle.hash #Return the fastest sender node from the DB if localhost is not present. if str(self.Node) != "http://localhost:14265": if Test_Node == False: self.Node = Return_Fastest_Node()["Send"] self.IOTA_Api = Iota(self.Node, seed=self.Seed_Copy) send = self.IOTA_Api.send_trytes(trytes=coded, depth=4) return hashed
def issue_milestone(address, api, index, *reference_transaction): txn1 = ProposedTransaction(address=Address(address), value=0) txn2 = ProposedTransaction(address=Address(address), value=0) bundle = ProposedBundle() bundle.add_transaction(txn1) bundle.add_transaction(txn2) bundle[0]._legacy_tag = Tag(converter.int_to_trytestring(index, 9)) bundle_logic.finalize(bundle) tips = api.get_transactions_to_approve(depth=3) trunk = tips['trunkTransaction'] if reference_transaction: branch = reference_transaction[0] else: branch = tips['branchTransaction'] bundle_trytes = bundle.as_tryte_strings() milestone = api.attach_to_tangle(trunk, branch, bundle_trytes, 9) api.broadcast_and_store(milestone['trytes']) return milestone
def test_finalize_insecure_bundle(self): """ When finalizing, the bundle detects an insecure bundle hash. References: - https://github.com/iotaledger/iota.lib.py/issues/84 """ # noinspection SpellCheckingInspection bundle =\ ProposedBundle([ ProposedTransaction( address =\ Address( '9XV9RJGFJJZWITDPKSQXRTHCKJAIZZY9BYLBEQUX' 'UNCLITRQDR9CCD99AANMXYEKD9GLJGVB9HIAGRIBQ', ), tag = Tag('PPDIDNQDJZGUQKOWJ9JZRCKOVGP'), timestamp = 1509136296, value = 0, ), ]) bundle.finalize() # The resulting bundle hash is insecure (contains a [1, 1, 1]), so # the legacy tag is manipulated until a secure hash is generated. # noinspection SpellCheckingInspection self.assertEqual(bundle[0].legacy_tag, Tag('ZTDIDNQDJZGUQKOWJ9JZRCKOVGP')) # The proper tag is left alone, however. # noinspection SpellCheckingInspection self.assertEqual(bundle[0].tag, Tag('PPDIDNQDJZGUQKOWJ9JZRCKOVGP')) # The bundle hash takes the modified legacy tag into account. # noinspection SpellCheckingInspection self.assertEqual( bundle.hash, BundleHash( 'NYSJSEGCWESDAFLIFCNJFWGZ9PCYDOT9VCSALKBD' '9UUNKBJAJCB9KVMTHZDPRDDXC9UFJQBJBQFUPJKFC', ) )
def pay(amount, reciever, message): proposedTrx = ProposedTransaction(address=Address(reciever), value=0, tag=Tag("AACHELORTEST"), message=TryteString.from_string(message)) proposedBundle = ProposedBundle([proposedTrx]) preparedBundle = api.prepare_transfer(proposedBundle) publishedBundle = api.send_transfer(depth=3, transfers=proposedBundle) return publishedBundle
def Send(self, ReceiverAddress, Message): def Bundle_Generation(Recepient, ToSend): text_transfer = TryteString.from_string(str(ToSend)) txn_2 = ProposedTransaction(address=Address(Recepient), message=text_transfer, value=0) bundle.add_transaction(txn_2) bundle = ProposedBundle() if type(ReceiverAddress) == list and type(Message) == list and ( len(ReceiverAddress) == len(Message)): for i in range(len(ReceiverAddress)): Bundle_Generation(ReceiverAddress[i], Message[i]) elif type(ReceiverAddress) == str and type(Message) == str: Bundle_Generation(ReceiverAddress, Message) bundle.finalize() coded = bundle.as_tryte_strings() hashed = bundle.hash send = self.IOTA_Api.send_trytes(trytes=coded, depth=4) return hashed
def mock_get_trytes(self, txnHashesAll): ret = {'trytes': []} for txnHash in txnHashesAll: for txn in self.transfers: if txn[0].hash == txnHash: bundle = ProposedBundle() bundle.add_transaction(txn[0]) bundle.finalize() ret['trytes'].append(bundle.as_tryte_strings()[0]) return ret
def generate_transaction_and_attach(step, node): arg_list = step.hashes world.config['nodeId'] = node world.config['apiCall'] = 'attachToTangle' options = {} api = api_utils.prepare_api_call(node) api_utils.prepare_options(arg_list, options) addresses = options.get('address') value = options.get('value') transaction = ProposedTransaction(address=Address(addresses[0]), value=value) bundle = ProposedBundle() bundle.add_transaction(transaction) bundle.finalize() trytes = str(bundle[0].as_tryte_string()) gtta = api.get_transactions_to_approve(depth=3) branch = str(gtta['branchTransaction']) trunk = str(gtta['trunkTransaction']) sent = api.attach_to_tangle(trunk, branch, [trytes], 9) world.responses['attachToTangle'] = {} world.responses['attachToTangle'][node] = sent logger.info('Transaction Sent') setattr(static_vals, "TEST_STORE_TRANSACTION", sent.get('trytes'))
def Send(self, ReceiverAddress, Message): text_transfer = TryteString.from_string(str(Message)) #This now proposes a transaction to a person. The "message = ..." command is a message that the receiver should be able to decode once arrived. txn_2 = ProposedTransaction(address=Address(ReceiverAddress), message=text_transfer, value=0) #Now create a new bundle (i.e. propose a bundle) bundle = ProposedBundle() #Add the transaction "txn_2" to the bundle. We can also add several addresses for receiving but we get to that later. bundle.add_transaction(txn_2) bundle.finalize() coded = bundle.as_tryte_strings() send = self.api.send_trytes(trytes=coded, depth=4)
def send_transaction(node_url, address, tag, messages, values): propose_bundle = ProposedBundle() # Setting output transaction ... txn_output = ProposedTransaction( address = Address(address), value = values, tag = Tag(tag), message = TryteString.from_string(messages) ) propose_bundle.add_transaction(txn_output) propose_bundle.finalize() trytes = propose_bundle.as_tryte_strings() api = Iota(node_url) # Tips trunk_hash, branch_hash = gtta(node_url) for tx_tryte in trytes: # Attachment timestamp insert timestamp = TryteString.from_trits( trits_from_int(int(time.time() * 1000), pad=27)) tx_tryte = insert_to_trytes(2619, 2628, str(timestamp), tx_tryte) # timestamp_lower_bound = MIN_VALUE # timestamp_upper_bound = MAX_VALUE tx_tryte = insert_to_trytes(2637, 2646, str("MMMMMMMMM"), tx_tryte) # Tips insert - trunk tx_tryte = insert_to_trytes(2430, 2511, str(trunk_hash), tx_tryte) # Tips insert - branch tx_tryte = insert_to_trytes(2511, 2592, str(branch_hash), tx_tryte) # Do PoW for this transaction tx_tryte = attach_to_tangle(node_url, trunk_hash, branch_hash, tx_tryte) # Prepare to store and broadcast ... try: api.broadcast_and_store(tx_tryte) except Exception as e: return str("Error: %s" % (str(e))) return str(propose_bundle.hash)
def create_transaction_bundle(address, tag, value): """ Create a generic transaction bundle. :param address: The address that will be associated with the transaction :param tag: The tag that will be associated with the transaction :param value: The value of the transaction """ txn = ProposedTransaction(address=Address(address), tag=Tag(tag), value=value) bundle = ProposedBundle() bundle.add_transaction(txn) bundle.finalize() return bundle
def Send(self, Receiver_Address, Message): if isinstance(Message, bytes): Message = Message.decode() Trytes_Convertion = TryteString.from_string(Message) TX = ProposedTransaction(address = Address(Receiver_Address), message = Trytes_Convertion, value = 0) bundle = ProposedBundle() bundle.add_transaction(TX) bundle.finalize() TX_Hash = str(bundle.hash) bundle_as_trytes = bundle.as_tryte_strings() TX_Success = False try: TX_Confirmation = self.IOTA_Api.send_trytes(trytes = bundle_as_trytes, depth = 4) TX_Success = TX_Hash except: if "iota.adapter.BadApiResponse" in str(sys.exc_info()[1]): print("Node not in Sync, finding another node....") #< ---------------------------------------------------- elif "The subtangle has not been updated yet." in str(sys.exc_info()[1]): print("Node not synced yet, finding another node...") #< ---------------------------------------------------- elif "429 response from node"in str(sys.exc_info()[1]): print("Too many requests to node, finding an alternative node...") #< ---------------------------------------------------- elif "[Errno 111] Connection refused" in str(sys.exc_info()[1]): print("Connection error, finding an alternative node...") #< ---------------------------------------------------- elif "403 Forbidden" in str(sys.exc_info()[1]): print("No access granted to node, finding an alternative node...") #< ---------------------------------------------------- # special case; a node accepts with POW set to "True" elif "certificate verify failed" in str(sys.exc_info()[1]): print("Node does not have a valid SSL certificate, finding an alternative node...") else: print("Unexpected exception caught in send") #< ---------------------------------------------------- print(sys.exc_info()[1]) #< ---------------------------------------------------- return TX_Success
def create_and_attach_transaction(api, arg_list): """ Create a transaction and attach it to the tangle. :param api: The api target you would like to make the call to :param arg_list: The argument list (dictionary) for the transaction :return sent: The return value for the attachToTangle call (contains the attached transaction trytes) """ transaction = ProposedTransaction(**arg_list) bundle = ProposedBundle() bundle.add_transaction(transaction) bundle.finalize() trytes = str(bundle[0].as_tryte_string()) gtta = api.get_transactions_to_approve(depth=3) branch = str(gtta['branchTransaction']) trunk = str(gtta['trunkTransaction']) sent = api.attach_to_tangle(trunk, branch, [trytes], 9) return sent
def _execute(self, request): # Required parameters. seed = request['seed'] # type: Seed bundle = ProposedBundle(request['transfers']) # Optional parameters. change_address = request.get( 'changeAddress') # type: Optional[Address] proposed_inputs = request.get( 'inputs') # type: Optional[List[Address]] want_to_spend = bundle.balance if want_to_spend > 0: # We are spending inputs, so we need to gather and sign them. if proposed_inputs is None: # No inputs provided. Scan addresses for unspent inputs. gi_response = GetInputsCommand(self.adapter)( seed=seed, threshold=want_to_spend, ) confirmed_inputs = gi_response['inputs'] else: # Inputs provided. Check to make sure we have sufficient # balance. available_to_spend = 0 confirmed_inputs = [] # type: List[Address] gb_response = GetBalancesCommand(self.adapter)( addresses=[i.address for i in proposed_inputs], ) for i, balance in enumerate(gb_response.get('balances') or []): input_ = proposed_inputs[i] if balance > 0: available_to_spend += balance # Update the address balance from the API response, just in # case somebody tried to cheat. input_.balance = balance confirmed_inputs.append(input_) if available_to_spend < want_to_spend: raise with_context( exc=BadApiResponse( 'Insufficient balance; found {found}, need {need} ' '(``exc.context`` has more info).'.format( found=available_to_spend, need=want_to_spend, ), ), context={ 'available_to_spend': available_to_spend, 'confirmed_inputs': confirmed_inputs, 'request': request, 'want_to_spend': want_to_spend, }, ) bundle.add_inputs(confirmed_inputs) if bundle.balance < 0: if not change_address: change_address =\ GetNewAddressesCommand(self.adapter)(seed=seed)['addresses'][0] bundle.send_unspent_inputs_to(change_address) bundle.finalize() if confirmed_inputs: bundle.sign_inputs(KeyGenerator(seed)) else: bundle.finalize() return { 'trytes': bundle.as_tryte_strings(), }
def setUp(self): super(ProposedBundleTestCase, self).setUp() # We will use a seed to generate addresses and private keys, to # ensure a realistic scenario (and because the alternative is to # inject mocks all over the place!). # noinspection SpellCheckingInspection self.seed =\ Seed( b'TESTVALUE9DONTUSEINPRODUCTION99999RLC9CS' b'ZUILGDTLJMRCJSDVEEJO9A9LHAEHMNAMVXRMOXTBN' ) # To speed things up a little bit, though, we can pre-generate a # few addresses to use as inputs. # noinspection SpellCheckingInspection self.input_0_bal_eq_42 =\ Address( balance = 42, key_index = 0, security_level = 1, trytes = b'JBLDCCSI9VKU9ZHNZCUTC9NLQIIJX9SIKUJNKNKE' b'9KKMHXFMIXHLKQQAVTTNPRCZENGLIPALHKLNKTXCU', ) # noinspection SpellCheckingInspection self.input_1_bal_eq_40 =\ Address( balance = 40, key_index = 1, security_level = 1, trytes = b'KHWHSTISMVVSDCOMHVFIFCTINWZT9EHJUATYSMCX' b'DSMZXPL9KXREBBYHJGRBCYVGPJQEHEDPXLBDJNQNX', ) # noinspection SpellCheckingInspection self.input_2_bal_eq_2 =\ Address( balance = 2, key_index = 2, security_level = 1, trytes = b'GOAAMRU9EALPO9GKBOWUVZVQEJMB9CSGIZJATHRB' b'TRRJPNTSQRZTASRBTQCRFAIDOGTWSHIDGOUUULQIG', ) # noinspection SpellCheckingInspection self.input_3_bal_eq_100 =\ Address( balance = 100, key_index = 3, security_level = 1, trytes = b'9LPQCSJGYUJMLWKMLJ9KYUYJ9RMDBZZWPHXMGKRG' b'YLOAZNKJR9VDYSONVAJRIPVWCOZKFMEKUSWHPSDDZ', ) # noinspection SpellCheckingInspection self.input_4_bal_eq_42_sl_2 =\ Address( balance = 42, key_index = 4, security_level = 2, trytes = b'NVGLHFZWLEQAWBDJXCWJBMVBVNXEG9DALNBTAYMK' b'EMMJ9BCDVVHJJLSTQW9JEJXUUX9JNFGALBNASRDUD', ) # noinspection SpellCheckingInspection self.input_5_bal_eq_42_sl_3 =\ Address( balance = 42, key_index = 5, security_level = 3, trytes = b'XXYRPQ9BDZGKZZQLYNSBDD9HZLI9OFRK9TZCTU9P' b'FAJYXZIZGO9BWLOCNGVMTLFQFMGJWYRMLXSCW9UTQ', ) self.bundle = ProposedBundle()
class ProposedBundleTestCase(TestCase): def setUp(self): super(ProposedBundleTestCase, self).setUp() # We will use a seed to generate addresses and private keys, to # ensure a realistic scenario (and because the alternative is to # inject mocks all over the place!). # noinspection SpellCheckingInspection self.seed =\ Seed( b'TESTVALUE9DONTUSEINPRODUCTION99999RLC9CS' b'ZUILGDTLJMRCJSDVEEJO9A9LHAEHMNAMVXRMOXTBN' ) # To speed things up a little bit, though, we can pre-generate a # few addresses to use as inputs. # noinspection SpellCheckingInspection self.input_0_bal_eq_42 =\ Address( balance = 42, key_index = 0, security_level = 1, trytes = b'JBLDCCSI9VKU9ZHNZCUTC9NLQIIJX9SIKUJNKNKE' b'9KKMHXFMIXHLKQQAVTTNPRCZENGLIPALHKLNKTXCU', ) # noinspection SpellCheckingInspection self.input_1_bal_eq_40 =\ Address( balance = 40, key_index = 1, security_level = 1, trytes = b'KHWHSTISMVVSDCOMHVFIFCTINWZT9EHJUATYSMCX' b'DSMZXPL9KXREBBYHJGRBCYVGPJQEHEDPXLBDJNQNX', ) # noinspection SpellCheckingInspection self.input_2_bal_eq_2 =\ Address( balance = 2, key_index = 2, security_level = 1, trytes = b'GOAAMRU9EALPO9GKBOWUVZVQEJMB9CSGIZJATHRB' b'TRRJPNTSQRZTASRBTQCRFAIDOGTWSHIDGOUUULQIG', ) # noinspection SpellCheckingInspection self.input_3_bal_eq_100 =\ Address( balance = 100, key_index = 3, security_level = 1, trytes = b'9LPQCSJGYUJMLWKMLJ9KYUYJ9RMDBZZWPHXMGKRG' b'YLOAZNKJR9VDYSONVAJRIPVWCOZKFMEKUSWHPSDDZ', ) # noinspection SpellCheckingInspection self.input_4_bal_eq_42_sl_2 =\ Address( balance = 42, key_index = 4, security_level = 2, trytes = b'NVGLHFZWLEQAWBDJXCWJBMVBVNXEG9DALNBTAYMK' b'EMMJ9BCDVVHJJLSTQW9JEJXUUX9JNFGALBNASRDUD', ) # noinspection SpellCheckingInspection self.input_5_bal_eq_42_sl_3 =\ Address( balance = 42, key_index = 5, security_level = 3, trytes = b'XXYRPQ9BDZGKZZQLYNSBDD9HZLI9OFRK9TZCTU9P' b'FAJYXZIZGO9BWLOCNGVMTLFQFMGJWYRMLXSCW9UTQ', ) self.bundle = ProposedBundle() def test_add_transaction_short_message(self): """ Adding a transaction to a bundle, with a message short enough to fit inside a single transaction. """ # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999AETEXB' b'D9YBTH9EMFKF9CAHJIAIKDBEPAMH99DEN9DAJETGN'), message=TryteString.from_string('Hello, IOTA!'), value=42, )) # We can fit the message inside a single fragment, so only one # transaction is necessary. self.assertEqual(len(self.bundle), 1) def test_add_transaction_long_message(self): """ Adding a transaction to a bundle, with a message so long that it has to be split into multiple transactions. """ # noinspection SpellCheckingInspection address = Address(b'TESTVALUE9DONTUSEINPRODUCTION99999N9GIUF' b'HCFIUGLBSCKELC9IYENFPHCEWHIDCHCGGEH9OFZBN') tag = Tag.from_string('H2G2') self.bundle.add_transaction( ProposedTransaction( address=address, tag=tag, message=TryteString.from_string(''' "Good morning," said Deep Thought at last. "Er... Good morning, O Deep Thought," said Loonquawl nervously. "Do you have... er, that is..." "... an answer for you?" interrupted Deep Thought majestically. "Yes. I have." The two men shivered with expectancy. Their waiting had not been in vain. "There really is one?" breathed Phouchg. "There really is one," confirmed Deep Thought. "To Everything? To the great Question of Life, the Universe and Everything?" "Yes." Both of the men had been trained for this moment; their lives had been a preparation for it; they had been selected at birth as those who would witness the answer; but even so they found themselves gasping and squirming like excited children. "And you're ready to give it to us?" urged Loonquawl. "I am." "Now?" "Now," said Deep Thought. They both licked their dry lips. "Though I don't think," added Deep Thought, "that you're going to like it." "Doesn't matter," said Phouchg. "We must know it! Now!" "Now?" enquired Deep Thought. "Yes! Now!" "All right," said the computer and settled into silence again. The two men fidgeted. The tension was unbearable. "You're really not going to like it," observed Deep Thought. "Tell us!" "All right," said Deep Thought. "The Answer to the Great Question..." "Yes?" "Of Life, the Universe and Everything..." said Deep Thought. "Yes??" "Is..." "Yes?!" "Forty-two," said Deep Thought, with infinite majesty and calm. '''), # Now you know.... # Eh, who am I kidding? You probably knew before I did (: value=42, )) # Because the message is too long to fit into a single fragment, # the transaction is split into two parts. self.assertEqual(len(self.bundle), 2) txn1 = self.bundle[0] self.assertEqual(txn1.address, address) self.assertEqual(txn1.tag, tag) self.assertEqual(txn1.value, 42) txn2 = self.bundle[1] self.assertEqual(txn2.address, address) self.assertEqual(txn2.tag, tag) # Supplementary transactions are assigned zero IOTA value. self.assertEqual(txn2.value, 0) def test_add_transaction_error_already_finalized(self): """ Attempting to add a transaction to a bundle that is already finalized. """ # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION999999DCBIE' b'U9AIE9H9BCKGMCVCUGYDKDLCAEOHOHZGW9KGS9VGH'), value=0, )) self.bundle.finalize() with self.assertRaises(RuntimeError): self.bundle.add_transaction( ProposedTransaction( address=Address(b''), value=0, )) def test_add_transaction_error_negative_value(self): """ Attempting to add a transaction with a negative value to a bundle. Use :py:meth:`ProposedBundle.add_inputs` to add inputs to a bundle. """ with self.assertRaises(ValueError): self.bundle.add_transaction( ProposedTransaction( address=Address(b''), value=-1, )) def test_add_inputs_no_change(self): """ Adding inputs to cover the exact amount of the bundle spend. """ # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999VELDTF' b'QHDFTHIHFE9II9WFFDFHEATEI99GEDC9BAUH9EBGZ'), value=29, )) # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999OGVEEF' b'BCYAM9ZEAADBGBHH9BPBOHFEGCFAM9DESCCHODZ9Y'), value=13, )) self.bundle.add_inputs([ self.input_1_bal_eq_40, self.input_2_bal_eq_2, ]) # Just to be tricky, add an unnecessary change address, just to # make sure the bundle ignores it. # noinspection SpellCheckingInspection self.bundle.send_unspent_inputs_to( Address(b'TESTVALUE9DONTUSEINPRODUCTION99999FDCDFD' b'VAF9NFLCSCSFFCLCW9KFL9TCAAO9IIHATCREAHGEA'), ) self.bundle.finalize() # All of the addresses that we generate for this test case have # security level set to 1, so we only need 1 transaction per # input (4 total, including the spends). # # Also note: because the transaction is already balanced, no change # transaction is necessary. self.assertEqual(len(self.bundle), 4) def test_add_inputs_with_change(self): """ Adding inputs to a bundle results in unspent inputs. """ tag = Tag(b'CHANGE9TXN') # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999VELDTF' b'QHDFTHIHFE9II9WFFDFHEATEI99GEDC9BAUH9EBGZ'), value=29, )) # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999OGVEEF' b'BCYAM9ZEAADBGBHH9BPBOHFEGCFAM9DESCCHODZ9Y'), tag=tag, value=13, )) self.bundle.add_inputs([self.input_3_bal_eq_100]) # noinspection SpellCheckingInspection change_address =\ Address( b'TESTVALUE9DONTUSEINPRODUCTION99999KAFGVC' b'IBLHS9JBZCEFDELEGFDCZGIEGCPFEIQEYGA9UFPAE' ) self.bundle.send_unspent_inputs_to(change_address) self.bundle.finalize() # 2 spends + 1 input (with security level 1) + 1 change self.assertEqual(len(self.bundle), 4) change_txn = self.bundle[-1] self.assertEqual(change_txn.address, change_address) self.assertEqual(change_txn.value, 58) self.assertEqual(change_txn.tag, tag) def test_add_inputs_security_level(self): """ Each input's security level determines the number of transactions we will need in order to store the entire signature. """ # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address( b'TESTVALUE9DONTUSEINPRODUCTION99999XE9IVG' b'EFNDOCQCMERGUATCIEGGOHPHGFIAQEZGNHQ9W99CH', ), value=84, ), ) self.bundle.add_inputs([ self.input_4_bal_eq_42_sl_2, self.input_5_bal_eq_42_sl_3, ]) self.bundle.finalize() # Each input's security level determines how many transactions will # be needed to hold all of its signature fragments: # 1 spend + 2 fragments for input 0 + 3 fragments for input 1 self.assertEqual(len(self.bundle), 6) def test_add_inputs_error_already_finalized(self): """ Attempting to add inputs to a bundle that is already finalized. """ # Add 1 transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address( b'TESTVALUE9DONTUSEINPRODUCTION99999XE9IVG' b'EFNDOCQCMERGUATCIEGGOHPHGFIAQEZGNHQ9W99CH', ), value=0, ), ) self.bundle.finalize() with self.assertRaises(RuntimeError): # Even though no inputs are provided, it's still an error; you # shouldn't even be calling ``add_inputs`` once the bundle is # finalized! self.bundle.add_inputs([]) def test_send_unspent_inputs_to_error_already_finalized(self): """ Invoking ``send_unspent_inputs_to`` on a bundle that is already finalized. """ # Add 1 transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999XE9IVG' b'EFNDOCQCMERGUATCIEGGOHPHGFIAQEZGNHQ9W99CH'), value=0, )) self.bundle.finalize() with self.assertRaises(RuntimeError): self.bundle.send_unspent_inputs_to(Address(b'')) def test_finalize_error_already_finalized(self): """ Attempting to finalize a bundle that is already finalized. """ # Add 1 transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999XE9IVG' b'EFNDOCQCMERGUATCIEGGOHPHGFIAQEZGNHQ9W99CH'), value=0, )) self.bundle.finalize() with self.assertRaises(RuntimeError): self.bundle.finalize() def test_finalize_error_no_transactions(self): """ Attempting to finalize a bundle with no transactions. """ with self.assertRaises(ValueError): self.bundle.finalize() def test_finalize_error_negative_balance(self): """ Attempting to finalize a bundle with unspent inputs. """ # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999IGEFUG' b'LIHIJGJGZ9CGRENCRHF9XFEAWD9ILFWEJFKDLITCC'), value=42, )) self.bundle.add_inputs([self.input_0_bal_eq_42, self.input_2_bal_eq_2]) # Bundle spends 42 IOTAs, but inputs total 44 IOTAs. self.assertEqual(self.bundle.balance, -2) # In order to finalize this bundle, we need to specify a change # address. with self.assertRaises(ValueError): self.bundle.finalize() def test_finalize_error_positive_balance(self): """ Attempting to finalize a bundle with insufficient inputs. """ # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999IGEFUG' b'LIHIJGJGZ9CGRENCRHF9XFEAWD9ILFWEJFKDLITCC'), value=42, )) self.bundle.add_inputs([self.input_1_bal_eq_40]) # Bundle spends 42 IOTAs, but inputs total only 40 IOTAs. self.assertEqual(self.bundle.balance, 2) # In order to finalize this bundle, we need to provide additional # inputs. with self.assertRaises(ValueError): self.bundle.finalize() def test_finalize_insecure_bundle(self): """ When finalizing, the bundle detects an insecure bundle hash. References: - https://github.com/iotaledger/iota.lib.py/issues/84 """ # noinspection SpellCheckingInspection bundle =\ ProposedBundle([ ProposedTransaction( address =\ Address( '9XV9RJGFJJZWITDPKSQXRTHCKJAIZZY9BYLBEQUX' 'UNCLITRQDR9CCD99AANMXYEKD9GLJGVB9HIAGRIBQ', ), tag = Tag('PPDIDNQDJZGUQKOWJ9JZRCKOVGP'), timestamp = 1509136296, value = 0, ), ]) bundle.finalize() # The resulting bundle hash is insecure (contains a [1, 1, 1]), so # the legacy tag is manipulated until a secure hash is generated. # noinspection SpellCheckingInspection self.assertEqual(bundle[0].legacy_tag, Tag('ZTDIDNQDJZGUQKOWJ9JZRCKOVGP')) # The proper tag is left alone, however. # noinspection SpellCheckingInspection self.assertEqual(bundle[0].tag, Tag('PPDIDNQDJZGUQKOWJ9JZRCKOVGP')) # The bundle hash takes the modified legacy tag into account. # noinspection SpellCheckingInspection self.assertEqual( bundle.hash, BundleHash( 'NYSJSEGCWESDAFLIFCNJFWGZ9PCYDOT9VCSALKBD' '9UUNKBJAJCB9KVMTHZDPRDDXC9UFJQBJBQFUPJKFC', )) def test_sign_inputs(self): """ Signing inputs in a finalized bundle, using a key generator. """ # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX'), value=42, )) self.bundle.add_inputs([self.input_1_bal_eq_40, self.input_2_bal_eq_2]) self.bundle.finalize() self.bundle.sign_inputs(KeyGenerator(self.seed)) # Quick sanity check: # 1 spend + 2 inputs (security level 1) = 3 transactions. # Applying signatures should not introduce any new transactions # into the bundle. # # Note: we will see what happens when we use inputs with different # security levels in the next test. self.assertEqual(len(self.bundle), 3) # The spending transaction does not have a signature. self.assertEqual( self.bundle[0].signature_message_fragment, Fragment(b''), ) # The signature fragments are really long, and we already have unit # tests for the signature fragment generator, so to keep this test # focused, we are only interested in whether a signature fragment # gets applied. # # References: # - :py:class:`test.crypto.signing_test.SignatureFragmentGeneratorTestCase` for i in range(1, len(self.bundle)): if self.bundle[i].signature_message_fragment == Fragment(b''): self.fail( "Transaction {i}'s signature fragment is unexpectedly empty!" .format(i=i, ), ) def test_sign_inputs_security_level(self): """ You may include inputs with different security levels in the same bundle. """ # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address( b'TESTVALUE9DONTUSEINPRODUCTION99999XE9IVG' b'EFNDOCQCMERGUATCIEGGOHPHGFIAQEZGNHQ9W99CH', ), value=84, ), ) self.bundle.add_inputs([ self.input_4_bal_eq_42_sl_2, self.input_5_bal_eq_42_sl_3, ]) self.bundle.finalize() self.bundle.sign_inputs(KeyGenerator(self.seed)) # Quick sanity check. self.assertEqual(len(self.bundle), 6) # The spending transaction does not have a signature. self.assertEqual( self.bundle[0].signature_message_fragment, Fragment(b''), ) # The signature fragments are really long, and we already have unit # tests for the signature fragment generator, so to keep this test # focused, we are only interested in whether a signature fragment # gets applied. # # References: # - :py:class:`test.crypto.signing_test.SignatureFragmentGeneratorTestCase` for i in range(1, len(self.bundle)): if self.bundle[i].signature_message_fragment == Fragment(b''): self.fail( "Transaction {i}'s signature fragment is unexpectedly empty!" .format(i=i, ), ) def test_sign_inputs_error_not_finalized(self): """ Attempting to sign inputs in a bundle that hasn't been finalized yet. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX'), value=42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) # Oops; did we forget something? # self.bundle.finalize() with self.assertRaises(RuntimeError): self.bundle.sign_inputs(KeyGenerator(b'')) def test_sign_input_at_single_fragment(self): """ Signing an input at the specified index, only 1 fragment needed. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX'), value=42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) self.bundle.finalize() private_key =\ KeyGenerator(self.seed).get_key_for(self.input_0_bal_eq_42) self.bundle.sign_input_at(1, private_key) # Only 2 transactions are needed for this bundle: # 1 spend + 1 input (security level = 1). self.assertEqual(len(self.bundle), 2) # The spending transaction does not have a signature. self.assertEqual( self.bundle[0].signature_message_fragment, Fragment(b''), ) # The signature fragments are really long, and we already have unit # tests for the signature fragment generator, so to keep this test # focused, we are only interested in whether a signature fragment # gets applied. # # References: # - :py:class:`test.crypto.signing_test.SignatureFragmentGeneratorTestCase` for i in range(1, len(self.bundle)): if self.bundle[i].signature_message_fragment == Fragment(b''): self.fail( "Transaction {i}'s signature fragment is unexpectedly empty!" .format(i=i, ), ) def test_sign_input_at_multiple_fragments(self): """ Signing an input at the specified index, multiple fragments needed. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX'), value=42, )) self.bundle.add_inputs([self.input_5_bal_eq_42_sl_3]) self.bundle.finalize() private_key =\ KeyGenerator(self.seed).get_key_for(self.input_5_bal_eq_42_sl_3) self.bundle.sign_input_at(1, private_key) # 1 spend + 3 inputs (security level = 3). self.assertEqual(len(self.bundle), 4) # The spending transaction does not have a signature. self.assertEqual( self.bundle[0].signature_message_fragment, Fragment(b''), ) # The signature fragments are really long, and we already have unit # tests for the signature fragment generator, so to keep this test # focused, we are only interested in whether a signature fragment # gets applied. # # References: # - :py:class:`test.crypto.signing_test.SignatureFragmentGeneratorTestCase` for i in range(1, len(self.bundle)): if self.bundle[i].signature_message_fragment == Fragment(b''): self.fail( "Transaction {i}'s signature fragment is unexpectedly empty!" .format(i=i, ), ) def test_sign_input_at_error_not_finalized(self): """ Cannot sign inputs because the bundle isn't finalized yet. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX'), value=42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) # Oops; did we forget something? # self.bundle.finalize() private_key =\ KeyGenerator(self.seed).get_key_for(self.input_0_bal_eq_42) with self.assertRaises(RuntimeError): self.bundle.sign_input_at(1, private_key) def test_sign_input_at_error_index_invalid(self): """ The specified index doesn't exist in the bundle. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX'), value=42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) self.bundle.finalize() private_key =\ KeyGenerator(self.seed).get_key_for(self.input_0_bal_eq_42) with self.assertRaises(IndexError): self.bundle.sign_input_at(2, private_key) def test_sign_input_at_error_index_not_input(self): """ The specified index references a transaction that is not an input. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX'), value=42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) self.bundle.finalize() private_key =\ KeyGenerator(self.seed).get_key_for(self.input_0_bal_eq_42) with self.assertRaises(ValueError): # You can't sign the spend transaction, silly! self.bundle.sign_input_at(0, private_key) def test_sign_input_at_error_already_signed(self): """ Attempting to sign an input that is already signed. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address=Address(b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX'), value=42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) self.bundle.finalize() # The existing signature fragment doesn't have to be valid; it just # has to be not empty. self.bundle[1].signature_message_fragment = Fragment(b'A') private_key =\ KeyGenerator(self.seed).get_key_for(self.input_0_bal_eq_42) with self.assertRaises(ValueError): self.bundle.sign_input_at(1, private_key)
def _execute(self, request): # Required parameters. seed = request['seed'] # type: Seed bundle = ProposedBundle(request['transfers']) # Optional parameters. change_address = request.get('changeAddress') # type: Optional[Address] proposed_inputs = request.get('inputs') # type: Optional[List[Address]] want_to_spend = bundle.balance if want_to_spend > 0: # We are spending inputs, so we need to gather and sign them. if proposed_inputs is None: # No inputs provided. Scan addresses for unspent inputs. gi_response = GetInputsCommand(self.adapter)( seed = seed, threshold = want_to_spend, ) confirmed_inputs = gi_response['inputs'] else: # Inputs provided. Check to make sure we have sufficient # balance. available_to_spend = 0 confirmed_inputs = [] # type: List[Address] gb_response = GetBalancesCommand(self.adapter)( addresses = [i.address for i in proposed_inputs], ) for i, balance in enumerate(gb_response.get('balances') or []): input_ = proposed_inputs[i] if balance > 0: available_to_spend += balance # Update the address balance from the API response, just in # case somebody tried to cheat. input_.balance = balance confirmed_inputs.append(input_) if available_to_spend < want_to_spend: raise with_context( exc = BadApiResponse( 'Insufficient balance; found {found}, need {need} ' '(``exc.context`` has more info).'.format( found = available_to_spend, need = want_to_spend, ), ), context = { 'available_to_spend': available_to_spend, 'confirmed_inputs': confirmed_inputs, 'request': request, 'want_to_spend': want_to_spend, }, ) bundle.add_inputs(confirmed_inputs) if bundle.balance < 0: if not change_address: change_address =\ GetNewAddressesCommand(self.adapter)(seed=seed)['addresses'][0] bundle.send_unspent_inputs_to(change_address) bundle.finalize() if confirmed_inputs: bundle.sign_inputs(KeyGenerator(seed)) else: bundle.finalize() return { 'trytes': bundle.as_tryte_strings(), }
keys = yaml_file.keys() for key in keys: if key != 'seeds' and key != 'defaults': nodes[key] = yaml_file[key] host = yaml_file['nodes']['nodeA']['host'] port = yaml_file['nodes']['nodeA']['ports']['api'] api = Iota('http://{}:{}'.format(host, port)) txn = ProposedTransaction( address = Address('KSAFREMKHHYHSXNLGZPFVHANVHVMKWSGEAHGTXZCSQMXTCZXOGBLVPCWFKVAEQYDJMQALKZRKOTWLGBSC'), value = 0 ) bundle = ProposedBundle() bundle.add_transaction(txn) bundle.add_transaction(txn) index_trytes = str(int_to_trytes(index, 9)) bundle[0]._legacy_tag = Tag(index_trytes) finalize.finalize(bundle) bundle_trytes = bundle.as_tryte_strings() tips = api.get_transactions_to_approve(depth=3) branch = tips['branchTransaction'] trunk = tips['trunkTransaction']
class ProposedBundleTestCase(TestCase): def setUp(self): super(ProposedBundleTestCase, self).setUp() # We will use a seed to generate addresses and private keys, to # ensure a realistic scenario (and because the alternative is to # inject mocks all over the place!). # noinspection SpellCheckingInspection self.seed =\ Seed( b'TESTVALUE9DONTUSEINPRODUCTION99999RLC9CS' b'ZUILGDTLJMRCJSDVEEJO9A9LHAEHMNAMVXRMOXTBN' ) # To speed things up a little bit, though, we can pre-generate a # few addresses to use as inputs. # noinspection SpellCheckingInspection self.input_0_bal_eq_42 =\ Address( balance = 42, key_index = 0, security_level = 1, trytes = b'JBLDCCSI9VKU9ZHNZCUTC9NLQIIJX9SIKUJNKNKE' b'9KKMHXFMIXHLKQQAVTTNPRCZENGLIPALHKLNKTXCU', ) # noinspection SpellCheckingInspection self.input_1_bal_eq_40 =\ Address( balance = 40, key_index = 1, security_level = 1, trytes = b'KHWHSTISMVVSDCOMHVFIFCTINWZT9EHJUATYSMCX' b'DSMZXPL9KXREBBYHJGRBCYVGPJQEHEDPXLBDJNQNX', ) # noinspection SpellCheckingInspection self.input_2_bal_eq_2 =\ Address( balance = 2, key_index = 2, security_level = 1, trytes = b'GOAAMRU9EALPO9GKBOWUVZVQEJMB9CSGIZJATHRB' b'TRRJPNTSQRZTASRBTQCRFAIDOGTWSHIDGOUUULQIG', ) # noinspection SpellCheckingInspection self.input_3_bal_eq_100 =\ Address( balance = 100, key_index = 3, security_level = 1, trytes = b'9LPQCSJGYUJMLWKMLJ9KYUYJ9RMDBZZWPHXMGKRG' b'YLOAZNKJR9VDYSONVAJRIPVWCOZKFMEKUSWHPSDDZ', ) # noinspection SpellCheckingInspection self.input_4_bal_eq_42_sl_2 =\ Address( balance = 42, key_index = 4, security_level = 2, trytes = b'NVGLHFZWLEQAWBDJXCWJBMVBVNXEG9DALNBTAYMK' b'EMMJ9BCDVVHJJLSTQW9JEJXUUX9JNFGALBNASRDUD', ) # noinspection SpellCheckingInspection self.input_5_bal_eq_42_sl_3 =\ Address( balance = 42, key_index = 5, security_level = 3, trytes = b'XXYRPQ9BDZGKZZQLYNSBDD9HZLI9OFRK9TZCTU9P' b'FAJYXZIZGO9BWLOCNGVMTLFQFMGJWYRMLXSCW9UTQ', ) self.bundle = ProposedBundle() def test_add_transaction_short_message(self): """ Adding a transaction to a bundle, with a message short enough to fit inside a single transaction. """ # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999AETEXB' b'D9YBTH9EMFKF9CAHJIAIKDBEPAMH99DEN9DAJETGN' ), message = TryteString.from_string('Hello, IOTA!'), value = 42, )) # We can fit the message inside a single fragment, so only one # transaction is necessary. self.assertEqual(len(self.bundle), 1) def test_add_transaction_long_message(self): """ Adding a transaction to a bundle, with a message so long that it has to be split into multiple transactions. """ # noinspection SpellCheckingInspection address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999N9GIUF' b'HCFIUGLBSCKELC9IYENFPHCEWHIDCHCGGEH9OFZBN' ) tag = Tag.from_string('H2G2') self.bundle.add_transaction(ProposedTransaction( address = address, tag = tag, message = TryteString.from_string( ''' "Good morning," said Deep Thought at last. "Er... Good morning, O Deep Thought," said Loonquawl nervously. "Do you have... er, that is..." "... an answer for you?" interrupted Deep Thought majestically. "Yes. I have." The two men shivered with expectancy. Their waiting had not been in vain. "There really is one?" breathed Phouchg. "There really is one," confirmed Deep Thought. "To Everything? To the great Question of Life, the Universe and Everything?" "Yes." Both of the men had been trained for this moment; their lives had been a preparation for it; they had been selected at birth as those who would witness the answer; but even so they found themselves gasping and squirming like excited children. "And you're ready to give it to us?" urged Loonquawl. "I am." "Now?" "Now," said Deep Thought. They both licked their dry lips. "Though I don't think," added Deep Thought, "that you're going to like it." "Doesn't matter," said Phouchg. "We must know it! Now!" "Now?" enquired Deep Thought. "Yes! Now!" "All right," said the computer and settled into silence again. The two men fidgeted. The tension was unbearable. "You're really not going to like it," observed Deep Thought. "Tell us!" "All right," said Deep Thought. "The Answer to the Great Question..." "Yes?" "Of Life, the Universe and Everything..." said Deep Thought. "Yes??" "Is..." "Yes?!" "Forty-two," said Deep Thought, with infinite majesty and calm. ''' ), # Now you know.... # Eh, who am I kidding? You probably knew before I did (: value = 42, )) # Because the message is too long to fit into a single fragment, # the transaction is split into two parts. self.assertEqual(len(self.bundle), 2) txn1 = self.bundle[0] self.assertEqual(txn1.address, address) self.assertEqual(txn1.tag, tag) self.assertEqual(txn1.value, 42) txn2 = self.bundle[1] self.assertEqual(txn2.address, address) self.assertEqual(txn2.tag, tag) # Supplementary transactions are assigned zero IOTA value. self.assertEqual(txn2.value, 0) def test_add_transaction_error_already_finalized(self): """ Attempting to add a transaction to a bundle that is already finalized. """ # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION999999DCBIE' b'U9AIE9H9BCKGMCVCUGYDKDLCAEOHOHZGW9KGS9VGH' ), value = 0, )) self.bundle.finalize() with self.assertRaises(RuntimeError): self.bundle.add_transaction(ProposedTransaction( address = Address(b''), value = 0, )) def test_add_transaction_error_negative_value(self): """ Attempting to add a transaction with a negative value to a bundle. Use :py:meth:`ProposedBundle.add_inputs` to add inputs to a bundle. """ with self.assertRaises(ValueError): self.bundle.add_transaction(ProposedTransaction( address = Address(b''), value = -1, )) def test_add_inputs_no_change(self): """ Adding inputs to cover the exact amount of the bundle spend. """ # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999VELDTF' b'QHDFTHIHFE9II9WFFDFHEATEI99GEDC9BAUH9EBGZ' ), value = 29, )) # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999OGVEEF' b'BCYAM9ZEAADBGBHH9BPBOHFEGCFAM9DESCCHODZ9Y' ), value = 13, )) self.bundle.add_inputs([ self.input_1_bal_eq_40, self.input_2_bal_eq_2, ]) # Just to be tricky, add an unnecessary change address, just to # make sure the bundle ignores it. # noinspection SpellCheckingInspection self.bundle.send_unspent_inputs_to( Address( b'TESTVALUE9DONTUSEINPRODUCTION99999FDCDFD' b'VAF9NFLCSCSFFCLCW9KFL9TCAAO9IIHATCREAHGEA' ), ) self.bundle.finalize() # All of the addresses that we generate for this test case have # security level set to 1, so we only need 1 transaction per # input (4 total, including the spends). # # Also note: because the transaction is already balanced, no change # transaction is necessary. self.assertEqual(len(self.bundle), 4) def test_add_inputs_with_change(self): """ Adding inputs to a bundle results in unspent inputs. """ tag = Tag(b'CHANGE9TXN') # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999VELDTF' b'QHDFTHIHFE9II9WFFDFHEATEI99GEDC9BAUH9EBGZ' ), value = 29, )) # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999OGVEEF' b'BCYAM9ZEAADBGBHH9BPBOHFEGCFAM9DESCCHODZ9Y' ), tag = tag, value = 13, )) self.bundle.add_inputs([self.input_3_bal_eq_100]) # noinspection SpellCheckingInspection change_address =\ Address( b'TESTVALUE9DONTUSEINPRODUCTION99999KAFGVC' b'IBLHS9JBZCEFDELEGFDCZGIEGCPFEIQEYGA9UFPAE' ) self.bundle.send_unspent_inputs_to(change_address) self.bundle.finalize() # 2 spends + 1 input (with security level 1) + 1 change self.assertEqual(len(self.bundle), 4) change_txn = self.bundle[-1] self.assertEqual(change_txn.address, change_address) self.assertEqual(change_txn.value, 58) self.assertEqual(change_txn.tag, tag) def test_add_inputs_security_level(self): """ Each input's security level determines the number of transactions we will need in order to store the entire signature. """ # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999XE9IVG' b'EFNDOCQCMERGUATCIEGGOHPHGFIAQEZGNHQ9W99CH', ), value = 84, ), ) self.bundle.add_inputs([ self.input_4_bal_eq_42_sl_2, self.input_5_bal_eq_42_sl_3, ]) self.bundle.finalize() # Each input's security level determines how many transactions will # be needed to hold all of its signature fragments: # 1 spend + 2 fragments for input 0 + 3 fragments for input 1 self.assertEqual(len(self.bundle), 6) def test_add_inputs_error_already_finalized(self): """ Attempting to add inputs to a bundle that is already finalized. """ # Add 1 transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999XE9IVG' b'EFNDOCQCMERGUATCIEGGOHPHGFIAQEZGNHQ9W99CH', ), value = 0, ), ) self.bundle.finalize() with self.assertRaises(RuntimeError): # Even though no inputs are provided, it's still an error; you # shouldn't even be calling ``add_inputs`` once the bundle is # finalized! self.bundle.add_inputs([]) def test_send_unspent_inputs_to_error_already_finalized(self): """ Invoking ``send_unspent_inputs_to`` on a bundle that is already finalized. """ # Add 1 transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999XE9IVG' b'EFNDOCQCMERGUATCIEGGOHPHGFIAQEZGNHQ9W99CH' ), value = 0, )) self.bundle.finalize() with self.assertRaises(RuntimeError): self.bundle.send_unspent_inputs_to(Address(b'')) def test_finalize_error_already_finalized(self): """ Attempting to finalize a bundle that is already finalized. """ # Add 1 transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999XE9IVG' b'EFNDOCQCMERGUATCIEGGOHPHGFIAQEZGNHQ9W99CH' ), value = 0, )) self.bundle.finalize() with self.assertRaises(RuntimeError): self.bundle.finalize() def test_finalize_error_no_transactions(self): """ Attempting to finalize a bundle with no transactions. """ with self.assertRaises(ValueError): self.bundle.finalize() def test_finalize_error_negative_balance(self): """ Attempting to finalize a bundle with unspent inputs. """ # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999IGEFUG' b'LIHIJGJGZ9CGRENCRHF9XFEAWD9ILFWEJFKDLITCC' ), value = 42, )) self.bundle.add_inputs([self.input_0_bal_eq_42, self.input_2_bal_eq_2]) # Bundle spends 42 IOTAs, but inputs total 44 IOTAs. self.assertEqual(self.bundle.balance, -2) # In order to finalize this bundle, we need to specify a change # address. with self.assertRaises(ValueError): self.bundle.finalize() def test_finalize_error_positive_balance(self): """ Attempting to finalize a bundle with insufficient inputs. """ # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999IGEFUG' b'LIHIJGJGZ9CGRENCRHF9XFEAWD9ILFWEJFKDLITCC' ), value = 42, )) self.bundle.add_inputs([self.input_1_bal_eq_40]) # Bundle spends 42 IOTAs, but inputs total only 40 IOTAs. self.assertEqual(self.bundle.balance, 2) # In order to finalize this bundle, we need to provide additional # inputs. with self.assertRaises(ValueError): self.bundle.finalize() def test_finalize_insecure_bundle(self): """ When finalizing, the bundle detects an insecure bundle hash. References: - https://github.com/iotaledger/iota.lib.py/issues/84 """ # noinspection SpellCheckingInspection bundle =\ ProposedBundle([ ProposedTransaction( address =\ Address( '9XV9RJGFJJZWITDPKSQXRTHCKJAIZZY9BYLBEQUX' 'UNCLITRQDR9CCD99AANMXYEKD9GLJGVB9HIAGRIBQ', ), tag = Tag('PPDIDNQDJZGUQKOWJ9JZRCKOVGP'), timestamp = 1509136296, value = 0, ), ]) bundle.finalize() # The resulting bundle hash is insecure (contains a [1, 1, 1]), so # the legacy tag is manipulated until a secure hash is generated. # noinspection SpellCheckingInspection self.assertEqual(bundle[0].legacy_tag, Tag('ZTDIDNQDJZGUQKOWJ9JZRCKOVGP')) # The proper tag is left alone, however. # noinspection SpellCheckingInspection self.assertEqual(bundle[0].tag, Tag('PPDIDNQDJZGUQKOWJ9JZRCKOVGP')) # The bundle hash takes the modified legacy tag into account. # noinspection SpellCheckingInspection self.assertEqual( bundle.hash, BundleHash( 'NYSJSEGCWESDAFLIFCNJFWGZ9PCYDOT9VCSALKBD' '9UUNKBJAJCB9KVMTHZDPRDDXC9UFJQBJBQFUPJKFC', ) ) def test_sign_inputs(self): """ Signing inputs in a finalized bundle, using a key generator. """ # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX' ), value = 42, )) self.bundle.add_inputs([self.input_1_bal_eq_40, self.input_2_bal_eq_2]) self.bundle.finalize() self.bundle.sign_inputs(KeyGenerator(self.seed)) # Quick sanity check: # 1 spend + 2 inputs (security level 1) = 3 transactions. # Applying signatures should not introduce any new transactions # into the bundle. # # Note: we will see what happens when we use inputs with different # security levels in the next test. self.assertEqual(len(self.bundle), 3) # The spending transaction does not have a signature. self.assertEqual( self.bundle[0].signature_message_fragment, Fragment(b''), ) # The signature fragments are really long, and we already have unit # tests for the signature fragment generator, so to keep this test # focused, we are only interested in whether a signature fragment # gets applied. # # References: # - :py:class:`test.crypto.signing_test.SignatureFragmentGeneratorTestCase` for i in range(1, len(self.bundle)): if self.bundle[i].signature_message_fragment == Fragment(b''): self.fail( "Transaction {i}'s signature fragment is unexpectedly empty!".format( i = i, ), ) def test_sign_inputs_security_level(self): """ You may include inputs with different security levels in the same bundle. """ # noinspection SpellCheckingInspection self.bundle.add_transaction( ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999XE9IVG' b'EFNDOCQCMERGUATCIEGGOHPHGFIAQEZGNHQ9W99CH', ), value = 84, ), ) self.bundle.add_inputs([ self.input_4_bal_eq_42_sl_2, self.input_5_bal_eq_42_sl_3, ]) self.bundle.finalize() self.bundle.sign_inputs(KeyGenerator(self.seed)) # Quick sanity check. self.assertEqual(len(self.bundle), 6) # The spending transaction does not have a signature. self.assertEqual( self.bundle[0].signature_message_fragment, Fragment(b''), ) # The signature fragments are really long, and we already have unit # tests for the signature fragment generator, so to keep this test # focused, we are only interested in whether a signature fragment # gets applied. # # References: # - :py:class:`test.crypto.signing_test.SignatureFragmentGeneratorTestCase` for i in range(1, len(self.bundle)): if self.bundle[i].signature_message_fragment == Fragment(b''): self.fail( "Transaction {i}'s signature fragment is unexpectedly empty!".format( i = i, ), ) def test_sign_inputs_error_not_finalized(self): """ Attempting to sign inputs in a bundle that hasn't been finalized yet. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX' ), value = 42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) # Oops; did we forget something? # self.bundle.finalize() with self.assertRaises(RuntimeError): self.bundle.sign_inputs(KeyGenerator(b'')) def test_sign_input_at_single_fragment(self): """ Signing an input at the specified index, only 1 fragment needed. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX' ), value = 42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) self.bundle.finalize() private_key =\ KeyGenerator(self.seed).get_key_for(self.input_0_bal_eq_42) self.bundle.sign_input_at(1, private_key) # Only 2 transactions are needed for this bundle: # 1 spend + 1 input (security level = 1). self.assertEqual(len(self.bundle), 2) # The spending transaction does not have a signature. self.assertEqual( self.bundle[0].signature_message_fragment, Fragment(b''), ) # The signature fragments are really long, and we already have unit # tests for the signature fragment generator, so to keep this test # focused, we are only interested in whether a signature fragment # gets applied. # # References: # - :py:class:`test.crypto.signing_test.SignatureFragmentGeneratorTestCase` for i in range(1, len(self.bundle)): if self.bundle[i].signature_message_fragment == Fragment(b''): self.fail( "Transaction {i}'s signature fragment is unexpectedly empty!".format( i = i, ), ) def test_sign_input_at_multiple_fragments(self): """ Signing an input at the specified index, multiple fragments needed. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX' ), value = 42, )) self.bundle.add_inputs([self.input_5_bal_eq_42_sl_3]) self.bundle.finalize() private_key =\ KeyGenerator(self.seed).get_key_for(self.input_5_bal_eq_42_sl_3) self.bundle.sign_input_at(1, private_key) # 1 spend + 3 inputs (security level = 3). self.assertEqual(len(self.bundle), 4) # The spending transaction does not have a signature. self.assertEqual( self.bundle[0].signature_message_fragment, Fragment(b''), ) # The signature fragments are really long, and we already have unit # tests for the signature fragment generator, so to keep this test # focused, we are only interested in whether a signature fragment # gets applied. # # References: # - :py:class:`test.crypto.signing_test.SignatureFragmentGeneratorTestCase` for i in range(1, len(self.bundle)): if self.bundle[i].signature_message_fragment == Fragment(b''): self.fail( "Transaction {i}'s signature fragment is unexpectedly empty!".format( i = i, ), ) def test_sign_input_at_error_not_finalized(self): """ Cannot sign inputs because the bundle isn't finalized yet. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX' ), value = 42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) # Oops; did we forget something? # self.bundle.finalize() private_key =\ KeyGenerator(self.seed).get_key_for(self.input_0_bal_eq_42) with self.assertRaises(RuntimeError): self.bundle.sign_input_at(1, private_key) def test_sign_input_at_error_index_invalid(self): """ The specified index doesn't exist in the bundle. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX' ), value = 42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) self.bundle.finalize() private_key =\ KeyGenerator(self.seed).get_key_for(self.input_0_bal_eq_42) with self.assertRaises(IndexError): self.bundle.sign_input_at(2, private_key) def test_sign_input_at_error_index_not_input(self): """ The specified index references a transaction that is not an input. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX' ), value = 42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) self.bundle.finalize() private_key =\ KeyGenerator(self.seed).get_key_for(self.input_0_bal_eq_42) with self.assertRaises(ValueError): # You can't sign the spend transaction, silly! self.bundle.sign_input_at(0, private_key) def test_sign_input_at_error_already_signed(self): """ Attempting to sign an input that is already signed. """ # Add a transaction so that we can finalize the bundle. # noinspection SpellCheckingInspection self.bundle.add_transaction(ProposedTransaction( address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999QARFLF' b'TDVATBVFTFCGEHLFJBMHPBOBOHFBSGAGWCM9PG9GX' ), value = 42, )) self.bundle.add_inputs([self.input_0_bal_eq_42]) self.bundle.finalize() # The existing signature fragment doesn't have to be valid; it just # has to be not empty. self.bundle[1].signature_message_fragment = Fragment(b'A') private_key =\ KeyGenerator(self.seed).get_key_for(self.input_0_bal_eq_42) with self.assertRaises(ValueError): self.bundle.sign_input_at(1, private_key)
import time import logging import sys sys.path.append( "/home/pi/.local/lib/python2.7/site-packages" ) #path muss hinzugefügt werden damit PyOta librarys gefunden werden können from iota import Iota, ProposedTransaction, ProposedBundle, Address, Tag, TryteString #importe Iota-Bibliothek um die API anzusprechen from iota.crypto.addresses import AddressGenerator # Reciever Seed: GCUKFZRLCTBGBDKQCQY9SMJPDPLFBDJJFTXZANHDJUTCZKIQQEUHSAVOYWKPTDDNEWRGBFWDMWYYRLRUR # returned Address at index 0 for Security Level 2 reciever_address = "LOZMZOKJWWVASYYWT999JPLDBMUSFZKMLZW9IXHTOAUOQKZMRLRAZCWECAFONWKT9HSHKHLMKAWSQFFXX" seed = "DSPOAXMVSC99IUIVJXTIBZFATVFKTCLLJYOLAGSMFJGFXAWEB9GNTQWEDVRYHKIOQF9T9IZY9IVPKTSZK" url = "https://potato.iotasalad.org:14265" #fullnode url api = Iota(url, seed) #erstelle Iota API logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG) logger = logging.getLogger(__name__) api.adapter.set_logger(logger) proposedTrx = ProposedTransaction( address=Address(reciever_address), value=0, tag=Tag("BACHELORTEST"), message=TryteString.from_string("This is a test transaction")) proposedBundle = ProposedBundle([proposedTrx]) preparedBundle = api.prepare_transfer(proposedBundle) publishedBundle = api.send_transfer(depth=3, transfers=proposedBundle)
import json import requests from iota import Iota from iota import TryteString headers = {'X-IOTA-API-Version': '1'} getTips = {"command": "getTips"} def call_iota_api(f): r = requests.post("http://140.116.247.117:14265", data=json.dumps(f), headers=headers) return r.text SEED = 'BXOM9LUNLPSEXBRJV9UUNLHSUHABEOGHQOGNBNBUEYSGOFZOEPYKEYRSFTXBOEJLUODUQXXGQ9NWQBSGH' api = Iota('http://140.116.247.117:14265', b'BXOM9LUNLPSEXBRJV9UUNLHSUHABEOGHQOGNBNBUEYSGOFZOEPYKEYRSFTXBOEJLUODUQXXGQ9NWQBSGH') gna_result = api.get_new_addresses(count=2) bundle = ProposedBundle() tag = iota.Tag('TESTINGPYTHON') pt = iota.ProposedTransaction( address=iota.Address('9TPHVCFLAZTZSDUWFBLCJOZICJKKPVDMAASWJZNFFBKRDDTEOUJHR9JVGTJNI9IYNVISZVXARWJFKUZWC'), value=0, tag=tag, message=iota.TryteString('HELLO') ) bundle.add_transaction(pt) addy = gna_result["addresses"][0] addy.balance = 0 addy.key_index = 0 bundle.add_inputs([
API = Iota(RoutingWrapper(PUBLIC_NODE).add_route( 'attachToTangle', LOCAL_NODE).add_route('interruptAttachingToTangle', LOCAL_NODE), seed=SEED) """ Every function of API using attachToTangle or interruptAttachingToTangle (e.g. API.send_transfer, API.attach_to_tangle, ...) sends its attachToTangle- and interruptAttachingToTangle-commands to the local full node and all other commands (like findTransactionsToApprove and broadcastTransactions) to the public full node. """ from iota import ProposedBundle, ProposedTransaction, Address, Tag, TryteString bundle = ProposedBundle() output = ProposedTransaction( # receiving address of the transfer address=Address( b'ADDRESS9GOES9HERE99999999999999999999999999999999999TESTVALUE9DONTUSEINPRODUCTION' ), # Amount of Iota you want to send value=1, # Optional Tag (27-trytes) tag=Tag(b'ROUTING9WRAPPER9WORKS'), # Message (2187-trytes) message=TryteString.from_string(