Example #1
0
 def generate_optimization_tx(self, sender, output_list):
     """ Due to limits on the number of inputs allowed for a transaction, a wallet can contain
     more value than is spendable in a single transaction. This generates a self-payment
     that combines small value tx outputs together.
     """
     request = api.GenerateOptimizationTxRequest(sender, output_list)
     return self.stub.GenerateOptimizationTx(request).tx_proposal
Example #2
0
def run_test(stub, amount, monitor_id, dest, max_seconds, token_id):
    tx_stats = {}
    sync_start = time.time()
    wait_for_accounts_sync(stub, [monitor_id], 3)
    logging.info("Time to sync: %s", time.time() - sync_start)

    resp = stub.GetBalance(
        mobilecoind_api_pb2.GetBalanceRequest(monitor_id=monitor_id, token_id=token_id))
    starting_balance = resp.balance
    logging.info("Starting balance prior to transfer: %s", starting_balance)

    # Try building a payment that sends all of our balance
    # We may get a defragmentation error -- if we do, then submit optimization Tx outs
    # until we don't get that error anymore
    while True:
        try:
            tx_resp = stub.SendPayment(
                mobilecoind_api_pb2.SendPaymentRequest(
                    sender_monitor_id=monitor_id,
                    sender_subaddress=0,
                    outlay_list=[
                        mobilecoind_api_pb2.Outlay(
                            value=amount,
                            receiver=dest,
                        )
                    ],
                    fee=0,
                    tombstone=0,
                    token_id=token_id,
                ))
            break
        except grpc.RpcError as e:
            if "insufficient funds due to utxo fragmentation" in e.details.lower():
                logging.info("Got defragmentation error, building an optimization transaction")
                opt_tx = stub.GenerateOptimizationTx(
                    mobilecoind_api_pb2.GenerateOptimizationTxRequest(
                        monitor_id=monitor_id,
                        subaddress=0,
                        fee=0,
                        token_id=token_id,
                    ))
                tx_resp = stub.SubmitTx(
                    mobilecoind_api_pb2.SubmitTxRequest(
                        tx_proposal=opt_tx.tx_proposal
                    ))
                tx_stats[0] = {
                    'start': time.time(),
                    'time_delta': None,
                    'tombstone': tx_resp.sender_tx_receipt.tombstone,
                    'block_delta': None,
                    'status': TransferStatus.pending,
                    'receipt': tx_resp,
                }
                stats = poll(monitor_id, tx_stats, stub)
                # Subtract fee from amount, so that we don't get an insufficient funds error
                # in the next cycle (since it costs us a fee to defragment)
                amount = amount - opt_tx.tx_proposal.fee
            else:
                logging.error("RPC Error encountered")
                raise

    tx_stats[0] = {
        'start': time.time(),
        'time_delta': None,
        'tombstone': tx_resp.sender_tx_receipt.tombstone,
        'block_delta': None,
        'status': TransferStatus.pending,
        'receipt': tx_resp,
    }
    stats = poll(monitor_id, tx_stats, stub)
    # FIXME: Move max seconds check inside polling
    assert tx_stats[0]['time_delta'] < max_seconds, "Did not clear in time"
    assert tx_stats[0]['status'] == TransferStatus.success, "Transfer did not succeed"
    return stats