Example #1
0
  public void putInternal(Transaction tx, Sha256Hash block_hash, StatusContext ctx) {

    if (block_hash == null) {
      ctx.setStatus("TX_SERIALIZE");
      SerializedTransaction s_tx = new SerializedTransaction(tx);
      ctx.setStatus("TX_PUT");
      // System.out.println("Transaction " + tx.getHash() + " " + Util.measureSerialization(s_tx));
      file_db.getTransactionMap().put(tx.getHash(), s_tx);
    }

    // putTxOutSpents(tx);
    boolean confirmed = (block_hash != null);

    ctx.setStatus("TX_GET_ADDR");
    Collection<String> addrs = getAllAddresses(tx, confirmed);

    Random rnd = new Random();

    ctx.setStatus("TX_SAVE_ADDRESS");
    file_db.addAddressesToTxMap(addrs, tx.getHash());

    imported_transactions.incrementAndGet();
    int h = -1;
    if (block_hash != null) {
      ctx.setStatus("TX_GET_HEIGHT");
      h = block_store.getHeight(block_hash);
    }

    ctx.setStatus("TX_NOTIFY");
    jelly.getElectrumNotifier().notifyNewTransaction(tx, addrs, h);
    ctx.setStatus("TX_DONE");
  }
  private void readTransaction(Protos.Transaction txProto, NetworkParameters params) {
    Transaction tx = new Transaction(params);
    if (txProto.hasUpdatedAt()) {
      tx.setUpdateTime(new Date(txProto.getUpdatedAt()));
    }

    for (Protos.TransactionOutput outputProto : txProto.getTransactionOutputList()) {
      BigInteger value = BigInteger.valueOf(outputProto.getValue());
      byte[] scriptBytes = outputProto.getScriptBytes().toByteArray();
      TransactionOutput output = new TransactionOutput(params, tx, value, scriptBytes);
      tx.addOutput(output);
    }

    for (Protos.TransactionInput transactionInput : txProto.getTransactionInputList()) {
      byte[] scriptBytes = transactionInput.getScriptBytes().toByteArray();
      TransactionOutPoint outpoint =
          new TransactionOutPoint(
              params,
              transactionInput.getTransactionOutPointIndex(),
              byteStringToHash(transactionInput.getTransactionOutPointHash()));
      TransactionInput input = new TransactionInput(params, tx, scriptBytes, outpoint);
      if (transactionInput.hasSequence()) {
        input.setSequenceNumber(transactionInput.getSequence());
      }
      tx.addInput(input);
    }

    for (ByteString blockHash : txProto.getBlockHashList()) {
      tx.addBlockAppearance(byteStringToHash(blockHash));
    }

    if (txProto.hasLockTime()) {
      tx.setLockTime(0xffffffffL & txProto.getLockTime());
    }

    // Transaction should now be complete.
    Sha256Hash protoHash = byteStringToHash(txProto.getHash());
    Preconditions.checkState(
        tx.getHash().equals(protoHash),
        "Transaction did not deserialize completely: %s vs %s",
        tx.getHash(),
        protoHash);
    Preconditions.checkState(
        !txMap.containsKey(txProto.getHash()),
        "Wallet contained duplicate transaction %s",
        byteStringToHash(txProto.getHash()));
    txMap.put(txProto.getHash(), tx);
  }
Example #3
0
 public void broadcastTransaction(@Nonnull final Transaction tx) {
   final Intent intent =
       new Intent(
           BlockchainService.ACTION_BROADCAST_TRANSACTION,
           null,
           this,
           BlockchainServiceImpl.class);
   intent.putExtra(BlockchainService.ACTION_BROADCAST_TRANSACTION_HASH, tx.getHash().getBytes());
   startService(intent);
 }
 @VisibleForTesting
 synchronized void doStoreChannelInWallet(Sha256Hash id) {
   StoredPaymentChannelClientStates channels =
       (StoredPaymentChannelClientStates)
           wallet.getExtensions().get(StoredPaymentChannelClientStates.EXTENSION_ID);
   checkNotNull(
       channels,
       "You have not added the StoredPaymentChannelClientStates extension to the wallet.");
   checkState(channels.getChannel(id, multisigContract.getHash()) == null);
   storedChannel =
       new StoredClientChannel(id, multisigContract, refundTx, myKey, valueToMe, refundFees, true);
   channels.putChannel(storedChannel);
   wallet.addOrUpdateExtension(channels);
 }
Example #5
0
  private void putInternal(Block block, StatusContext ctx) {
    long t1 = System.currentTimeMillis();
    Sha256Hash hash = block.getHash();

    ctx.setStatus("BLOCK_CHECK_EXIST");
    if (file_db.getBlockMap().containsKey(hash)) {
      imported_blocks.incrementAndGet();
      return;
    }
    // Mark block as in progress

    Semaphore block_wait_sem;
    synchronized (in_progress) {
      block_wait_sem = in_progress.get(hash);
      if (block_wait_sem == null) {
        block_wait_sem = new Semaphore(0);
        in_progress.put(hash, block_wait_sem);
      }
    }

    // Kick off threaded storage of transactions
    int size = 0;

    ctx.setStatus("BLOCK_TX_CACHE_INSERT");
    synchronized (transaction_cache) {
      for (Transaction tx : block.getTransactions()) {
        transaction_cache.put(tx.getHash(), SerializedTransaction.scrubTransaction(params, tx));
      }
    }

    ctx.setStatus("BLOCK_TX_ENQUE");
    LinkedList<Sha256Hash> tx_list = new LinkedList<Sha256Hash>();

    Collection<Map.Entry<String, Sha256Hash>> addrTxLst =
        new LinkedList<Map.Entry<String, Sha256Hash>>();
    Map<Sha256Hash, SerializedTransaction> txs_map =
        new HashMap<Sha256Hash, SerializedTransaction>();

    for (Transaction tx : block.getTransactions()) {
      imported_transactions.incrementAndGet();
      Collection<String> addrs = getAllAddresses(tx, true);

      for (String addr : addrs) {
        addrTxLst.add(
            new java.util.AbstractMap.SimpleEntry<String, Sha256Hash>(addr, tx.getHash()));
      }

      txs_map.put(tx.getHash(), new SerializedTransaction(tx));

      tx_list.add(tx.getHash());
      size++;
    }

    ctx.setStatus("TX_SAVEALL");
    file_db.getTransactionMap().putAll(txs_map);

    ctx.setStatus("BLOCK_TX_MAP_ADD");
    file_db.addTxsToBlockMap(tx_list, hash);

    ctx.setStatus("ADDR_SAVEALL");
    file_db.addAddressesToTxMap(addrTxLst);

    int h = block_store.getHeight(hash);

    for (Transaction tx : block.getTransactions()) {
      Collection<String> addrs = getAllAddresses(tx, true);
      ctx.setStatus("TX_NOTIFY");
      jelly.getElectrumNotifier().notifyNewTransaction(tx, addrs, h);
      ctx.setStatus("TX_DONE");
    }

    // Once all transactions are in, check for prev block in this store

    ctx.setStatus("BLOCK_WAIT_PREV");
    Sha256Hash prev_hash = block.getPrevBlockHash();

    waitForBlockStored(prev_hash);

    // System.out.println("Block " + hash + " " + Util.measureSerialization(new
    // SerializedBlock(block)));

    ctx.setStatus("BLOCK_SAVE");
    file_db.getBlockMap().put(hash, new SerializedBlock(block));

    block_wait_sem.release(1024);
    boolean wait_for_utxo = false;
    if (jelly.isUpToDate() && jelly.getUtxoTrieMgr().isUpToDate()) {
      wait_for_utxo = true;
    }

    jelly.getUtxoTrieMgr().notifyBlock(wait_for_utxo);
    if (wait_for_utxo) {
      jelly.getEventLog().alarm("UTXO root hash: " + jelly.getUtxoTrieMgr().getRootHash());
    }
    jelly.getElectrumNotifier().notifyNewBlock(block);

    long t2 = System.currentTimeMillis();
    DecimalFormat df = new DecimalFormat("0.000");
    double sec = (t2 - t1) / 1000.0;

    if (h % block_print_every == 0) {
      jelly
          .getEventLog()
          .alarm(
              "Saved block: "
                  + hash
                  + " - "
                  + h
                  + " - "
                  + size
                  + " ("
                  + df.format(sec)
                  + " seconds)");
    }
    jelly
        .getEventLog()
        .log(
            "Saved block: "
                + hash
                + " - "
                + h
                + " - "
                + size
                + " ("
                + df.format(sec)
                + " seconds)");

    imported_blocks.incrementAndGet();
  }
  private static Protos.Transaction makeTxProto(WalletTransaction wtx) {
    Transaction tx = wtx.getTransaction();
    Protos.Transaction.Builder txBuilder = Protos.Transaction.newBuilder();

    txBuilder
        .setPool(Protos.Transaction.Pool.valueOf(wtx.getPool().getValue()))
        .setHash(hashToByteString(tx.getHash()))
        .setVersion((int) tx.getVersion());

    if (tx.getUpdateTime() != null) {
      txBuilder.setUpdatedAt(tx.getUpdateTime().getTime());
    }

    if (tx.getLockTime() > 0) {
      txBuilder.setLockTime((int) tx.getLockTime());
    }

    // Handle inputs.
    for (TransactionInput input : tx.getInputs()) {
      Protos.TransactionInput.Builder inputBuilder =
          Protos.TransactionInput.newBuilder()
              .setScriptBytes(ByteString.copyFrom(input.getScriptBytes()))
              .setTransactionOutPointHash(hashToByteString(input.getOutpoint().getHash()))
              .setTransactionOutPointIndex((int) input.getOutpoint().getIndex());
      if (input.hasSequence()) {
        inputBuilder.setSequence((int) input.getSequenceNumber());
      }
      txBuilder.addTransactionInput(inputBuilder);
    }

    // Handle outputs.
    for (TransactionOutput output : tx.getOutputs()) {
      Protos.TransactionOutput.Builder outputBuilder =
          Protos.TransactionOutput.newBuilder()
              .setScriptBytes(ByteString.copyFrom(output.getScriptBytes()))
              .setValue(output.getValue().longValue());
      final TransactionInput spentBy = output.getSpentBy();
      if (spentBy != null) {
        Sha256Hash spendingHash = spentBy.getParentTransaction().getHash();
        int spentByTransactionIndex = spentBy.getParentTransaction().getInputs().indexOf(spentBy);
        outputBuilder
            .setSpentByTransactionHash(hashToByteString(spendingHash))
            .setSpentByTransactionIndex(spentByTransactionIndex);
      }
      txBuilder.addTransactionOutput(outputBuilder);
    }

    // Handle which blocks tx was seen in.
    if (tx.getAppearsInHashes() != null) {
      for (Sha256Hash hash : tx.getAppearsInHashes()) {
        txBuilder.addBlockHash(hashToByteString(hash));
      }
    }

    if (tx.hasConfidence()) {
      TransactionConfidence confidence = tx.getConfidence();
      Protos.TransactionConfidence.Builder confidenceBuilder =
          Protos.TransactionConfidence.newBuilder();
      writeConfidence(txBuilder, confidence, confidenceBuilder);
    }

    return txBuilder.build();
  }
Example #7
0
  private void processInMessage(JSONObject msg) throws Exception {
    long idx = msg.optLong("id", -1);
    Object id = msg.opt("id");
    try {

      if (!msg.has("method")) {
        System.out.println("Unknown message: " + msg.toString());
        return;
      }
      String method = msg.getString("method");
      if (method.equals("server.version")) {
        JSONObject reply = new JSONObject();
        reply.put("id", id);
        reply.put("result", "0.9");
        reply.put("jelectrum", JELECTRUM_VERSION);
        version_info = msg.get("params").toString();
        sendMessage(reply);
      } else if (method.equals("server.banner")) {
        JSONObject reply = new JSONObject();
        reply.put("id", id);
        reply.put("result", "Jelectrum");
        sendMessage(reply);
      } else if (method.equals("blockchain.headers.subscribe")) {
        // Should send this on each new block:
        // {"id": 1, "result": {"nonce": 3114737334, "prev_block_hash":
        // "000000000000000089e1f388af7cda336b6241b3f0b0ca36def7a8f22e44d39b", "timestamp":
        // 1387995813, "merkle_root":
        // "0debf5bd535624a955d229337a9bf3da5f370cc5a1f5fbee7261b0bdd0bd0f10", "block_height":
        // 276921, "version": 2, "bits": 419668748}}

        jelectrum.getElectrumNotifier().registerBlockchainHeaders(this, id, true);

      } else if (method.equals("blockchain.numblocks.subscribe")) {
        // Should send this on each new block:
        // {"id": 1, "result": {"nonce": 3114737334, "prev_block_hash":
        // "000000000000000089e1f388af7cda336b6241b3f0b0ca36def7a8f22e44d39b", "timestamp":
        // 1387995813, "merkle_root":
        // "0debf5bd535624a955d229337a9bf3da5f370cc5a1f5fbee7261b0bdd0bd0f10", "block_height":
        // 276921, "version": 2, "bits": 419668748}}

        jelectrum.getElectrumNotifier().registerBlockCount(this, id, true);

      } else if (method.equals("blockchain.address.get_history")) {
        // {"id": 29, "result": [{"tx_hash":
        // "fc054ede2383904323d9b54991693b9150bb1a0a7cd3c344afb883d3ffc093f4", "height": 274759},
        // {"tx_hash": "9dc9363fe032e08630057edb61488fc8fa9910d8b21f02eb1b12ef2928c88550", "height":
        // 274709}]}

        JSONArray params = msg.getJSONArray("params");
        String address = params.getString(0);
        jelectrum.getElectrumNotifier().sendAddressHistory(this, id, address);

      } else if (method.equals("blockchain.address.subscribe")) {
        // the result is
        // sha256(fc054ede2383904323d9b54991693b9150bb1a0a7cd3c344afb883d3ffc093f4:274759:7bb11e62ceb5c9e918d9de541ec8d5d215353c6bbf2fcb32b300ec641f3a0b3f:274708:)
        // tx:height:tx:height:
        // or null if no transactions

        JSONArray params = msg.getJSONArray("params");
        String address = params.getString(0);

        subscription_count.getAndIncrement();
        if (first_address == null) {
          first_address = address;
        }

        jelectrum.getElectrumNotifier().registerBlockchainAddress(this, id, true, address);

      } else if (method.equals("server.peers.subscribe")) {
        JSONObject reply = new JSONObject();
        JSONArray lst = new JSONArray();
        reply.put("id", id);
        reply.put("result", lst);
        sendMessage(reply);
      } else if (method.equals("blockchain.transaction.get")) {
        JSONObject reply = new JSONObject();
        reply.put("id", id);

        JSONArray params = msg.getJSONArray("params");

        Sha256Hash hash = new Sha256Hash(params.getString(0));

        Transaction tx = jelectrum.getImporter().getTransaction(hash);
        if (tx == null) {
          reply.put("error", "unknown transaction");
        } else {
          byte buff[] = tx.bitcoinSerialize();
          reply.put("result", Util.getHexString(buff));
        }

        sendMessage(reply);
      } else if (method.equals("blockchain.block.get_header")) {
        JSONObject reply = new JSONObject();
        reply.put("id", id);

        JSONArray arr = msg.getJSONArray("params");
        int height = arr.getInt(0);

        Sha256Hash block_hash = jelectrum.getBlockChainCache().getBlockHashAtHeight(height);
        StoredBlock blk = jelectrum.getDB().getBlockStoreMap().get(block_hash);

        JSONObject result = new JSONObject();
        jelectrum.getElectrumNotifier().populateBlockData(blk, result);

        reply.put("result", result);

        sendMessage(reply);

      } else if (method.equals("blockchain.transaction.broadcast")) {
        JSONArray arr = msg.getJSONArray("params");
        String hex = arr.getString(0);

        byte[] tx_data = new Hex().decode(hex.getBytes());
        Transaction tx = new Transaction(jelectrum.getNetworkParameters(), tx_data);

        // jelectrum.getPeerGroup().broadcastTransaction(tx);
        JSONObject res = jelectrum.getBitcoinRPC().submitTransaction(hex);

        JSONObject reply = new JSONObject();

        reply.put("id", id);
        reply.put("result", tx.getHash().toString());
        sendMessage(reply);

        jelectrum.getImporter().saveTransaction(tx);

      } else if (method.equals("blockchain.transaction.get_merkle")) {
        JSONObject reply = new JSONObject();
        reply.put("id", id);

        JSONArray arr = msg.getJSONArray("params");
        Sha256Hash tx_hash = new Sha256Hash(arr.getString(0));
        int height = arr.getInt(1);

        Sha256Hash block_hash = jelectrum.getBlockChainCache().getBlockHashAtHeight(height);
        Block blk =
            jelectrum
                .getDB()
                .getBlockMap()
                .get(block_hash)
                .getBlock(jelectrum.getNetworkParameters());

        JSONObject result = Util.getMerkleTreeForTransaction(blk.getTransactions(), tx_hash);
        result.put("block_height", height);

        reply.put("result", result);

        sendMessage(reply);
      } else if (method.equals("blockchain.block.get_chunk")) {
        JSONObject reply = new JSONObject();
        reply.put("id", id);
        JSONArray arr = msg.getJSONArray("params");
        int index = arr.getInt(0);

        reply.put("result", jelectrum.getHeaderChunkAgent().getChunk(index));

        sendMessage(reply);
      } else {
        jelectrum.getEventLog().log(connection_id + " - Unknown electrum method: " + method);
        System.out.println("Unknown method - " + method);
        JSONObject reply = new JSONObject();
        reply.put("id", id);
        reply.put("error", "unknown method - " + method);
        sendMessage(reply);
      }
    } catch (Throwable t) {
      JSONObject reply = new JSONObject();
      reply.put("id", id);
      reply.put("error", "Exception: " + t);
      sendMessage(reply);
      jelectrum.getEventLog().log(connection_id + " - error: " + t);
      jelectrum.getEventLog().log(t);
      // t.printStackTrace();
    }
  }