示例#1
0
 @Override
 public synchronized boolean deleteTransaction(Sha256Hash transactionId) {
   TransactionEx tex = _backing.getTransaction(transactionId);
   if (tex == null) return false;
   Transaction tx = TransactionEx.toTransaction(tex);
   _backing.beginTransaction();
   try {
     // See if any of the outputs are stored locally and remove them
     for (int i = 0; i < tx.outputs.length; i++) {
       TransactionOutput output = tx.outputs[i];
       OutPoint outPoint = new OutPoint(tx.getHash(), i);
       TransactionOutputEx utxo = _backing.getUnspentOutput(outPoint);
       if (utxo != null) {
         _backing.deleteUnspentOutput(outPoint);
       }
     }
     // remove it from the backing
     _backing.deleteTransaction(transactionId);
     _backing.setTransactionSuccessful();
   } finally {
     _backing.endTransaction();
   }
   updateLocalBalance(); // will still need a new sync besides re-calculating
   return true;
 }
示例#2
0
  @Override
  public synchronized boolean cancelQueuedTransaction(Sha256Hash transaction) {
    Map<Sha256Hash, byte[]> outgoingTransactions = _backing.getOutgoingTransactions();

    if (!outgoingTransactions.containsKey(transaction)) {
      return false;
    }

    Transaction tx;
    try {
      tx = Transaction.fromBytes(outgoingTransactions.get(transaction));
    } catch (TransactionParsingException e) {
      return false;
    }

    _backing.beginTransaction();
    try {

      // See if any of the outputs are stored locally and remove them
      for (int i = 0; i < tx.outputs.length; i++) {
        TransactionOutput output = tx.outputs[i];
        OutPoint outPoint = new OutPoint(tx.getHash(), i);
        TransactionOutputEx utxo = _backing.getUnspentOutput(outPoint);
        if (utxo != null) {
          _backing.deleteUnspentOutput(outPoint);
        }
      }

      // Remove a queued transaction from our outgoing buffer
      _backing.removeOutgoingTransaction(transaction);

      // remove it from the backing
      _backing.deleteTransaction(transaction);
      _backing.setTransactionSuccessful();
    } finally {
      _backing.endTransaction();
    }

    // calc the new balance to remove the outgoing amount
    // the total balance will still be wrong, as we already deleted some UTXOs to build the queued
    // transaction
    // these will get restored after the next sync
    updateLocalBalance();

    // markTransactionAsSpent(transaction);
    return true;
  }
示例#3
0
  private void markTransactionAsSpent(Transaction transaction) {
    _backing.beginTransaction();
    try {
      // Remove inputs from unspent, marking them as spent
      for (TransactionInput input : transaction.inputs) {
        TransactionOutputEx parentOutput = _backing.getUnspentOutput(input.outPoint);
        if (parentOutput != null) {
          _backing.deleteUnspentOutput(input.outPoint);
          _backing.putParentTransactionOutput(parentOutput);
        }
      }

      // See if any of the outputs are for ourselves and store them as
      // unspent
      for (int i = 0; i < transaction.outputs.length; i++) {
        TransactionOutput output = transaction.outputs[i];
        if (isMine(output.script)) {
          _backing.putUnspentOutput(
              new TransactionOutputEx(
                  new OutPoint(transaction.getHash(), i),
                  -1,
                  output.value,
                  output.script.getScriptBytes(),
                  false));
        }
      }

      // Store transaction locally, so we have it in our history and don't
      // need to fetch it in a minute
      _backing.putTransaction(TransactionEx.fromUnconfirmedTransaction(transaction));
      _backing.setTransactionSuccessful();
    } finally {
      _backing.endTransaction();
    }

    // Tell account that we have a new transaction
    onNewTransaction(TransactionEx.fromUnconfirmedTransaction(transaction), transaction);

    // Calculate local balance cache. It has changed because we have done
    // some spending
    updateLocalBalance();
    persistContextIfNecessary();
  }
示例#4
0
  protected boolean synchronizeUnspentOutputs(Collection<Address> addresses) {
    // Get the current unspent outputs as dictated by the block chain
    QueryUnspentOutputsResponse UnspentOutputResponse;
    try {
      UnspentOutputResponse =
          _wapi
              .queryUnspentOutputs(new QueryUnspentOutputsRequest(Wapi.VERSION, addresses))
              .getResult();
    } catch (WapiException e) {
      _logger.logError("Server connection failed with error code: " + e.errorCode, e);
      postEvent(Event.SERVER_CONNECTION_ERROR);
      return false;
    }
    Collection<TransactionOutputEx> remoteUnspent = UnspentOutputResponse.unspent;
    // Store the current block height
    setBlockChainHeight(UnspentOutputResponse.height);
    // Make a map for fast lookup
    Map<OutPoint, TransactionOutputEx> remoteMap = toMap(remoteUnspent);

    // Get the current unspent outputs as it is believed to be locally
    Collection<TransactionOutputEx> localUnspent = _backing.getAllUnspentOutputs();
    // Make a map for fast lookup
    Map<OutPoint, TransactionOutputEx> localMap = toMap(localUnspent);

    // Find remotely removed unspent outputs
    for (TransactionOutputEx l : localUnspent) {
      TransactionOutputEx r = remoteMap.get(l.outPoint);
      if (r == null) {
        // An output has gone. Maybe it was spent in another wallet, or
        // never confirmed due to missing fees, double spend, or mutated.
        // Either way, we delete it locally
        _backing.deleteUnspentOutput(l.outPoint);
      }
    }

    // Find remotely added unspent outputs
    Set<Sha256Hash> transactionsToAddOrUpdate = new HashSet<Sha256Hash>();
    List<TransactionOutputEx> unspentOutputsToAddOrUpdate = new LinkedList<TransactionOutputEx>();
    for (TransactionOutputEx r : remoteUnspent) {
      TransactionOutputEx l = localMap.get(r.outPoint);
      if (l == null || l.height != r.height) {
        // New remote output or new height (Maybe it confirmed or we
        // might even have had a reorg). Either way we just update it
        unspentOutputsToAddOrUpdate.add(r);
        transactionsToAddOrUpdate.add(r.outPoint.hash);
        // Note: We are not adding the unspent output to the DB just yet. We
        // first want to verify the full set of funding transactions of the
        // transaction that this unspent output belongs to
      }
    }

    // Fetch updated or added transactions
    if (transactionsToAddOrUpdate.size() > 0) {
      GetTransactionsResponse response;
      try {
        response =
            _wapi
                .getTransactions(
                    new GetTransactionsRequest(Wapi.VERSION, transactionsToAddOrUpdate))
                .getResult();
      } catch (WapiException e) {
        _logger.logError("Server connection failed with error code: " + e.errorCode, e);
        postEvent(Event.SERVER_CONNECTION_ERROR);
        return false;
      }
      try {
        handleNewExternalTransactions(response.transactions);
      } catch (WapiException e) {
        _logger.logError("Server connection failed with error code: " + e.errorCode, e);
        postEvent(Event.SERVER_CONNECTION_ERROR);
        return false;
      }
      // Finally update out list of unspent outputs with added or updated
      // outputs
      for (TransactionOutputEx output : unspentOutputsToAddOrUpdate) {
        _backing.putUnspentOutput(output);
      }
    }

    return true;
  }