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); }
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); }
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(); }
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(); } }