def tx_push(ctx, txblob): """ Sends a signed transaction blob to a node """ tx = None try: txbin = parse_hexblob(txblob) pbdata = xrd_pb2.Transaction() pbdata.ParseFromString(txbin) tx = Transaction.from_pbdata(pbdata) except Exception as e: click.echo("tx blob is not valid") quit(1) tmp_json = tx.to_json() # FIXME: binary fields are represented in base64. Improve output print(tmp_json) if len(tx.signature) == 0: click.echo('Signature missing') quit(1) stub = ctx.obj.get_stub_public_api() pushTransactionReq = xrd_pb2.PushTransactionReq(transaction_signed=tx.pbdata) pushTransactionResp = stub.PushTransaction(pushTransactionReq, timeout=CONNECTION_TIMEOUT) print(pushTransactionResp.error_code)
def sign_and_push_transaction(self, tx, xmss, index, group_index=None, slave_index=None, enable_save=True): logger.info("Signing %s transaction by %s | OTS index %s", tx.type, xmss.qaddress, xmss.ots_index) tx.sign(xmss) if not tx.validate(True): raise Exception("Invalid Transaction") if enable_save: if slave_index is None: # noqa self._wallet.set_ots_index( index, xmss.ots_index ) # Move to next OTS index before broadcasting txn else: self._wallet.set_slave_ots_index(index, group_index, slave_index, xmss.ots_index) push_transaction_req = xrd_pb2.PushTransactionReq( transaction_signed=tx.pbdata) push_transaction_resp = self._public_stub.PushTransaction( push_transaction_req, timeout=CONNECTION_TIMEOUT) if push_transaction_resp.error_code != xrd_pb2.PushTransactionResp.SUBMITTED: raise Exception(push_transaction_resp.error_description)
def tx_multi_sig_create(ctx, src, master, threshold, fee, ots_key_index): """ Creates Multi Sig Create Transaction, that results into the formation of new multi_sig_address if accepted. """ signatories = [] weights = [] while True: address = click.prompt('Address of Signatory ', default='') if address == '': break weight = int(click.prompt('Weight ')) signatories.append(parse_qaddress(address)) weights.append(weight) try: _, src_xmss = _select_wallet(ctx, src) if not src_xmss: click.echo("A local wallet is required to sign the transaction") quit(1) address_src_pk = src_xmss.pk ots_key_index = validate_ots_index(ots_key_index, src_xmss) src_xmss.set_ots_index(ots_key_index) master_addr = None if master: master_addr = parse_qaddress(master) # FIXME: This could be problematic. Check fee_shor = _quanta_to_shor(fee) except KeyboardInterrupt: click.echo("Terminated by user") quit(1) except Exception as e: click.echo("Error validating arguments: {}".format(e)) quit(1) try: stub = ctx.obj.get_stub_public_api() tx = MultiSigCreate.create(signatories=signatories, weights=weights, threshold=threshold, fee=fee_shor, xmss_pk=address_src_pk, master_addr=master_addr) tx.sign(src_xmss) push_transaction_req = xrd_pb2.PushTransactionReq(transaction_signed=tx.pbdata) push_transaction_resp = stub.PushTransaction(push_transaction_req, timeout=CONNECTION_TIMEOUT) print(push_transaction_resp.error_code) print('Multi sig Address Q{}'.format(bin2hstr(MultiSigAddressState.generate_multi_sig_address(tx.txhash)))) except Exception as e: print("Error {}".format(str(e)))
def test_transferCoins_push_unsigned(self): with set_xrd_dir('wallet_ver1'): with State() as db_state: p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager = ChainManager(db_state) xrdnode = xrdNode(mining_address=b'') xrdnode.set_chain_manager(chain_manager) xrdnode._p2pfactory = p2p_factory xrdnode._pow = p2p_factory.pow xrdnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(xrdnode) context = Mock(spec=ServicerContext) alice = get_alice_xmss() bob = get_bob_xmss() request = xrd_pb2.TransferCoinsReq( addresses_to=[bob.address], amounts=[101], fee=12, xmss_pk=alice.pk ) response = service.TransferCoins(request=request, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() self.assertIsNotNone(response) self.assertIsNotNone(response.extended_transaction_unsigned) self.assertEqual('transfer', response.extended_transaction_unsigned.tx.WhichOneof('transactionType')) self.assertEqual(12, response.extended_transaction_unsigned.tx.fee) self.assertEqual(alice.pk, response.extended_transaction_unsigned.tx.public_key) self.assertEqual(0, response.extended_transaction_unsigned.tx.nonce) self.assertEqual(b'', response.extended_transaction_unsigned.tx.signature) self.assertEqual(b'', response.extended_transaction_unsigned.tx.transaction_hash) self.assertEqual(bob.address, response.extended_transaction_unsigned.tx.transfer.addrs_to[0]) self.assertEqual(101, response.extended_transaction_unsigned.tx.transfer.amounts[0]) req_push = xrd_pb2.PushTransactionReq(transaction_signed=response.extended_transaction_unsigned.tx) resp_push = service.PushTransaction(req_push, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() self.assertIsNotNone(resp_push) self.assertEqual(xrd_pb2.PushTransactionResp.VALIDATION_FAILED, resp_push.error_code)
def tx_transfertoken(ctx, src, master, token_txhash, dsts, amounts, decimals, fee, ots_key_index): """ Create Transfer Token Transaction, which moves tokens from src to dst. """ if decimals > 19: click.echo("The number of decimal cannot exceed 19 under any configuration") quit(1) try: addresses_dst, shor_amounts = _parse_dsts_amounts(dsts, amounts, token_decimals=decimals) bin_token_txhash = parse_hexblob(token_txhash) master_addr = None if master: master_addr = parse_qaddress(master) # FIXME: This could be problematic. Check fee_shor = _quanta_to_shor(fee) _, src_xmss = _select_wallet(ctx, src) if not src_xmss: click.echo("A local wallet is required to sign the transaction") quit(1) address_src_pk = src_xmss.pk ots_key_index = validate_ots_index(ots_key_index, src_xmss) src_xmss.set_ots_index(ots_key_index) except KeyboardInterrupt: click.echo("Terminated by user") quit(1) except Exception as e: click.echo("Error validating arguments: {}".format(e)) quit(1) try: stub = ctx.obj.get_stub_public_api() tx = TransferTokenTransaction.create(token_txhash=bin_token_txhash, addrs_to=addresses_dst, amounts=shor_amounts, fee=fee_shor, xmss_pk=address_src_pk, master_addr=master_addr) tx.sign(src_xmss) push_transaction_req = xrd_pb2.PushTransactionReq(transaction_signed=tx.pbdata) push_transaction_resp = stub.PushTransaction(push_transaction_req, timeout=CONNECTION_TIMEOUT) print(push_transaction_resp.error_code) except Exception as e: print("Error {}".format(str(e)))
def valid_payment_permission(public_stub, master_address_state, payment_xmss, json_slave_txn): access_type = master_address_state.get_slave_permission(payment_xmss.pk) if access_type == -1: tx = Transaction.from_json(json_slave_txn) public_stub.PushTransaction(request=xrd_pb2.PushTransactionReq( transaction_signed=tx.pbdata)) return None if access_type == 0: return True return False
def tx_message(ctx, src, master, addr_to, message, fee, ots_key_index): """ Message Transaction """ try: _, src_xmss = _select_wallet(ctx, src) if not src_xmss: click.echo("A local wallet is required to sign the transaction") quit(1) address_src_pk = src_xmss.pk ots_key_index = validate_ots_index(ots_key_index, src_xmss) src_xmss.set_ots_index(ots_key_index) message = message.encode() addr_to = parse_qaddress(addr_to, False) master_addr = None if master: master_addr = parse_qaddress(master) fee_shor = _quanta_to_shor(fee) except Exception as e: click.echo("Error validating arguments: {}".format(e)) quit(1) try: stub = ctx.obj.get_stub_public_api() tx = MessageTransaction.create(message_hash=message, addr_to=addr_to, fee=fee_shor, xmss_pk=address_src_pk, master_addr=master_addr) tx.sign(src_xmss) push_transaction_req = xrd_pb2.PushTransactionReq(transaction_signed=tx.pbdata) push_transaction_resp = stub.PushTransaction(push_transaction_req, timeout=CONNECTION_TIMEOUT) print(push_transaction_resp) except Exception as e: print("Error {}".format(str(e)))
def transfer(destinations, fee, mixin, unlock_time): if len(destinations) > config.dev.transaction_multi_output_limit: raise Exception('Payment Failed: Amount exceeds the allowed limit') addrs_to = [] amounts = [] for tx in destinations: addrs_to.append(bytes(hstr2bin(tx['address'][1:]))) # Skipping 'Q' amounts.append(tx['amount']) stub = get_public_stub() xmss = get_unused_payment_xmss(stub) if not xmss: raise Exception('Payment Failed: No Unused Payment XMSS found') tx = TransferTransaction.create(addrs_to=addrs_to, amounts=amounts, message_data=None, fee=fee, xmss_pk=xmss.pk, master_addr=payment_slaves[0]) tx.sign(xmss) response = stub.PushTransaction(request=xrd_pb2.PushTransactionReq( transaction_signed=tx.pbdata)) if response.error_code != 3: raise Exception('Transaction Submission Failed, Response Code: %s', response.error_code) response = {'tx_hash': bin2hstr(tx.txhash)} return response
def test_messageTxn_sign(self): with set_xrd_dir('wallet_ver1'): with State() as db_state: p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager = ChainManager(db_state) xrdnode = xrdNode(mining_address=b'') xrdnode.set_chain_manager(chain_manager) xrdnode._p2pfactory = p2p_factory xrdnode._pow = p2p_factory.pow xrdnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(xrdnode) context = Mock(spec=ServicerContext) alice = get_alice_xmss() my_message = b'Hello xrd!' request = xrd_pb2.MessageTxnReq( message=my_message, fee=12, xmss_pk=alice.pk ) response = service.GetMessageTxn(request=request, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() self.assertIsNotNone(response) self.assertIsNotNone(response.extended_transaction_unsigned.tx) self.assertEqual('message', response.extended_transaction_unsigned.tx.WhichOneof('transactionType')) self.assertEqual(12, response.extended_transaction_unsigned.tx.fee) self.assertEqual(alice.pk, response.extended_transaction_unsigned.tx.public_key) self.assertEqual(0, response.extended_transaction_unsigned.tx.nonce) self.assertEqual(b'', response.extended_transaction_unsigned.tx.signature) self.assertEqual(b'', response.extended_transaction_unsigned.tx.transaction_hash) self.assertEqual(my_message, response.extended_transaction_unsigned.tx.message.message_hash) tmp_hash_pre = response.extended_transaction_unsigned.tx.master_addr tmp_hash_pre += response.extended_transaction_unsigned.tx.fee.to_bytes(8, byteorder='big', signed=False) tmp_hash_pre += response.extended_transaction_unsigned.tx.message.message_hash tmp_hash = sha256(tmp_hash_pre) hash_found = bin2hstr(Transaction.from_pbdata(response.extended_transaction_unsigned.tx). get_data_hash()) self.assertEqual(hash_found, bin2hstr(tmp_hash)) signed_transaction = response.extended_transaction_unsigned.tx signed_transaction.signature = alice.sign(tmp_hash) req_push = xrd_pb2.PushTransactionReq(transaction_signed=signed_transaction) resp_push = service.PushTransaction(req_push, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() self.assertIsNotNone(resp_push) self.assertEqual(xrd_pb2.PushTransactionResp.SUBMITTED, resp_push.error_code) self.assertEqual('b7ee814a548a6bbb8d97b2d3a0eb9e1f8b6ceee49b764e3c7b23d104aca6abeb', bin2hstr(resp_push.tx_hash))
def test_transferCoins_sign(self): with set_xrd_dir('wallet_ver1'): with State() as db_state: p2p_factory = Mock(spec=P2PFactory) p2p_factory.pow = Mock(spec=POW) chain_manager = ChainManager(db_state) xrdnode = xrdNode(mining_address=b'') xrdnode.set_chain_manager(chain_manager) xrdnode._p2pfactory = p2p_factory xrdnode._pow = p2p_factory.pow xrdnode._peer_addresses = ['127.0.0.1', '192.168.1.1'] service = PublicAPIService(xrdnode) context = Mock(spec=ServicerContext) alice = get_alice_xmss() bob = get_bob_xmss() request = xrd_pb2.TransferCoinsReq( addresses_to=[bob.address], amounts=[101], fee=12, xmss_pk=alice.pk ) response = service.TransferCoins(request=request, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() self.assertIsNotNone(response) self.assertIsNotNone(response.extended_transaction_unsigned.tx) self.assertEqual('transfer', response.extended_transaction_unsigned.tx.WhichOneof('transactionType')) self.assertEqual(12, response.extended_transaction_unsigned.tx.fee) self.assertEqual(alice.pk, response.extended_transaction_unsigned.tx.public_key) self.assertEqual(0, response.extended_transaction_unsigned.tx.nonce) self.assertEqual(b'', response.extended_transaction_unsigned.tx.signature) self.assertEqual(b'', response.extended_transaction_unsigned.tx.transaction_hash) self.assertEqual(bob.address, response.extended_transaction_unsigned.tx.transfer.addrs_to[0]) self.assertEqual(101, response.extended_transaction_unsigned.tx.transfer.amounts[0]) tmp_hash_pre = bytes(xrdHelper.getAddress(response.extended_transaction_unsigned.tx.public_key)) tmp_hash_pre += str(response.extended_transaction_unsigned.tx.fee).encode() tmp_hash_pre += response.extended_transaction_unsigned.tx.transfer.addrs_to[0] tmp_hash_pre += str(response.extended_transaction_unsigned.tx.transfer.amounts[0]).encode() self.assertEqual('010300a1da274e68c88b0ccf448e0b1916fa789b01eb2ed4e9ad565ce264c939078' '2a9c61ac02f31320103001d65d7e59aed5efbeae64246e0f3184d7c42411421eb38' '5ba30f2c1c005a85ebc4419cfd313031', bin2hstr(tmp_hash_pre)) tmp_hash = sha256(tmp_hash_pre) self.assertEqual('3645f2819aba65479f9a7fad3f5d7a41a9357410a595fa02fb947bfe3ed96e0f', bin2hstr(tmp_hash)) signed_transaction = response.extended_transaction_unsigned.tx signed_transaction.signature = alice.sign(tmp_hash) req_push = xrd_pb2.PushTransactionReq(transaction_signed=signed_transaction) resp_push = service.PushTransaction(req_push, context=context) context.set_code.assert_not_called() context.set_details.assert_not_called() self.assertIsNotNone(resp_push) self.assertEqual(xrd_pb2.PushTransactionResp.SUBMITTED, resp_push.error_code) self.assertEqual('30955fdc5e2d9dbe5fb9bf812f2e1b6c4b409a8a7c7a75f1c3e9ba1ffdd8e60e', bin2hstr(resp_push.tx_hash))
def tx_token(ctx, src, master, symbol, name, owner, decimals, fee, ots_key_index): """ Create Token Transaction, that results into the formation of new token if accepted. """ initial_balances = [] if decimals > 19: click.echo("The number of decimal cannot exceed 19 under any possible configuration") quit(1) while True: address = click.prompt('Address ', default='') if address == '': break amount = int(click.prompt('Amount ')) * (10 ** int(decimals)) initial_balances.append(xrd_pb2.AddressAmount(address=parse_qaddress(address), amount=amount)) try: _, src_xmss = _select_wallet(ctx, src) if not src_xmss: click.echo("A local wallet is required to sign the transaction") quit(1) address_src_pk = src_xmss.pk ots_key_index = validate_ots_index(ots_key_index, src_xmss) src_xmss.set_ots_index(ots_key_index) address_owner = parse_qaddress(owner) master_addr = None if master: master_addr = parse_qaddress(master) # FIXME: This could be problematic. Check fee_shor = _quanta_to_shor(fee) if len(name) > config.dev.max_token_name_length: raise Exception("Token name must be shorter than {} chars".format(config.dev.max_token_name_length)) if len(symbol) > config.dev.max_token_symbol_length: raise Exception("Token symbol must be shorter than {} chars".format(config.dev.max_token_symbol_length)) except KeyboardInterrupt: click.echo("Terminated by user") quit(1) except Exception as e: click.echo("Error validating arguments: {}".format(e)) quit(1) try: stub = ctx.obj.get_stub_public_api() tx = TokenTransaction.create(symbol=symbol.encode(), name=name.encode(), owner=address_owner, decimals=decimals, initial_balances=initial_balances, fee=fee_shor, xmss_pk=address_src_pk, master_addr=master_addr) tx.sign(src_xmss) push_transaction_req = xrd_pb2.PushTransactionReq(transaction_signed=tx.pbdata) push_transaction_resp = stub.PushTransaction(push_transaction_req, timeout=CONNECTION_TIMEOUT) print(push_transaction_resp.error_code) except Exception as e: print("Error {}".format(str(e)))
def tx_transfer(ctx, src, master, dsts, amounts, message_data, fee, ots_key_index): """ Transfer coins from src to dsts """ address_src_pk = None master_addr = None addresses_dst = [] shor_amounts = [] fee_shor = [] signing_object = None message_data = message_data.encode() try: # Retrieve signing object selected_wallet = _select_wallet(ctx, src) if selected_wallet is None or len(selected_wallet) != 2: click.echo("A wallet was not found") quit(1) _, src_xmss = selected_wallet if not src_xmss: click.echo("A local wallet is required to sign the transaction") quit(1) address_src_pk = src_xmss.pk ots_key_index = validate_ots_index(ots_key_index, src_xmss) src_xmss.set_ots_index(ots_key_index) signing_object = src_xmss # Get and validate other inputs if master: master_addr = parse_qaddress(master) addresses_dst, shor_amounts = _parse_dsts_amounts(dsts, amounts, check_multi_sig_address=True) fee_shor = _quanta_to_shor(fee) except Exception as e: click.echo("Error validating arguments: {}".format(e)) quit(1) try: # Create transaction tx = TransferTransaction.create(addrs_to=addresses_dst, amounts=shor_amounts, message_data=message_data, fee=fee_shor, xmss_pk=address_src_pk, master_addr=master_addr) # Sign transaction tx.sign(signing_object) # Print result txjson = tx_unbase64(tx.to_json()) print(txjson) if not tx.validate(): print("It was not possible to validate the signature") quit(1) print("\nTransaction Blob (signed): \n") txblob = tx.pbdata.SerializeToString() txblobhex = hexlify(txblob).decode() print(txblobhex) # Push transaction print("Sending to a xrd Node...") stub = ctx.obj.get_stub_public_api() push_transaction_req = xrd_pb2.PushTransactionReq(transaction_signed=tx.pbdata) push_transaction_resp = stub.PushTransaction(push_transaction_req, timeout=CONNECTION_TIMEOUT) # Print result print(push_transaction_resp) except Exception as e: print("Error {}".format(str(e)))