/** * <p>Gets a bloom filter that contains all of the public keys from this wallet, and which will provide the given * false-positive rate if it has size elements. Keep in mind that you will get 2 elements in the bloom filter for * each key in the wallet, for the public key and the hash of the public key (address form).</p> * * <p>This is used to generate a BloomFilter which can be {@link BloomFilter#merge(BloomFilter)}d with another. * It could also be used if you have a specific target for the filter's size.</p> * * <p>See the docs for {@link BloomFilter#BloomFilter(int, double, long, org.bitcoinj.core.BloomFilter.BloomUpdate)} for a brief explanation of anonymity when using bloom * filters.</p> */ @Override @GuardedBy("keyChainGroupLock") public BloomFilter getBloomFilter(int size, double falsePositiveRate, long nTweak) { beginBloomFilterCalculation(); try { BloomFilter filter = keyChainGroup.getBloomFilter(size, falsePositiveRate, nTweak); for (Script script : watchedScripts) { for (ScriptChunk chunk : script.getChunks()) { // Only add long (at least 64 bit) data to the bloom filter. // If any long constants become popular in scripts, we will need logic // here to exclude them. if (!chunk.isOpCode() && chunk.data.length >= MINIMUM_BLOOM_DATA_LENGTH) { filter.insert(chunk.data); } } } for (TransactionOutPoint point : bloomOutPoints) filter.insert(point.unsafeBitcoinSerialize()); return filter; } finally { endBloomFilterCalculation(); } }
/** * <p>Gets a bloom filter that contains all of the public keys from this wallet, and which will provide the given * false-positive rate if it has size elements. Keep in mind that you will get 2 elements in the bloom filter for * each key in the wallet, for the public key and the hash of the public key (address form).</p> * * <p>This is used to generate a BloomFilter which can be {@link BloomFilter#merge(BloomFilter)}d with another. * It could also be used if you have a specific target for the filter's size.</p> * * <p>See the docs for {@link BloomFilter(int, double)} for a brief explanation of anonymity when using bloom * filters.</p> */ @Override @GuardedBy("keyChainGroupLock") public BloomFilter getBloomFilter(int size, double falsePositiveRate, long nTweak) { beginBloomFilterCalculation(); try { BloomFilter filter = keyChainGroup.getBloomFilter(size, falsePositiveRate, nTweak); for (Script script : watchedScripts) { for (ScriptChunk chunk : script.getChunks()) { // Only add long (at least 64 bit) data to the bloom filter. // If any long constants become popular in scripts, we will need logic // here to exclude them. if (!chunk.isOpCode() && chunk.data.length >= MINIMUM_BLOOM_DATA_LENGTH) { filter.insert(chunk.data); } } } for (TransactionOutPoint point : bloomOutPoints) filter.insert(point.unsafeBitcoinSerialize()); return filter; } finally { endBloomFilterCalculation(); } }
@Test public void watchingScriptsBloomFilter() throws Exception { assertFalse(wallet.isRequiringUpdateAllBloomFilter()); Address watchedAddress = new ECKey().toAddress(PARAMS); Transaction t1 = createFakeTx(PARAMS, CENT, watchedAddress); TransactionOutPoint outPoint = new TransactionOutPoint(PARAMS, 0, t1); wallet.addWatchedAddress(watchedAddress); assertTrue(wallet.isRequiringUpdateAllBloomFilter()); // Note that this has a 1e-12 chance of failing this unit test due to a false positive assertFalse(wallet.getBloomFilter(1e-12).contains(outPoint.unsafeBitcoinSerialize())); sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, t1); assertTrue(wallet.getBloomFilter(1e-12).contains(outPoint.unsafeBitcoinSerialize())); }
@Test public void removeScriptsBloomFilter() throws Exception { List<Address> addressesForRemoval = new ArrayList<Address>(); for (int i = 0; i < 10; i++) { Address watchedAddress = new ECKey().toAddress(PARAMS); addressesForRemoval.add(watchedAddress); wallet.addWatchedAddress(watchedAddress); } wallet.removeWatchedAddresses(addressesForRemoval); for (Address addr : addressesForRemoval) { Transaction t1 = createFakeTx(PARAMS, CENT, addr); TransactionOutPoint outPoint = new TransactionOutPoint(PARAMS, 0, t1); // Note that this has a 1e-12 chance of failing this unit test due to a false positive assertFalse(wallet.getBloomFilter(1e-12).contains(outPoint.unsafeBitcoinSerialize())); sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, t1); assertFalse(wallet.getBloomFilter(1e-12).contains(outPoint.unsafeBitcoinSerialize())); } }
@Nullable public Value getRawTxFee(TransactionWatcherWallet wallet) { Preconditions.checkState(!isTrimmed, "Cannot get raw tx fee from a trimmed transaction"); Value fee = type.value(0); for (TransactionInput input : tx.getInputs()) { TransactionOutPoint outPoint = input.getOutpoint(); BitTransaction inTx = wallet.getTransaction(outPoint.getHash()); if (inTx == null || !inTx.isOutputAvailable((int) outPoint.getIndex())) { return null; } TransactionOutput txo = inTx.getOutput((int) outPoint.getIndex()); fee = fee.add(txo.getValue()); } for (TransactionOutput output : getOutputs()) { fee = fee.subtract(output.getValue()); } return fee; }
@Override public synchronized Collection<TransactionOutPoint> getUnspentForScriptHash(ByteString prefix) { Collection<ByteString> txinfo = db_map.getSet(prefix, 10000); LinkedList<TransactionOutPoint> outs = new LinkedList<TransactionOutPoint>(); for(ByteString key : txinfo) { ByteString tx_data = key.substring(0,32); ByteBuffer bb = ByteBuffer.wrap(key.substring(32).toByteArray()); bb.order(java.nio.ByteOrder.LITTLE_ENDIAN); int idx=bb.getInt(); Sha256Hash tx_id = new Sha256Hash(tx_data.toByteArray()); TransactionOutPoint o = new TransactionOutPoint(jelly.getNetworkParameters(), idx, tx_id); outs.add(o); } return outs; }
public void putTxOutSpents(Transaction tx) { LinkedList<String> tx_outs = new LinkedList<String>(); for(TransactionInput in : tx.getInputs()) { if (!in.isCoinBase()) { TransactionOutPoint out = in.getOutpoint(); String key = out.getHash().toString() + ":" + out.getIndex(); //file_db.addTxOutSpentByMap(key, tx.getHash()); tx_outs.add(key); } } }
public boolean areSomeInputsPending(Transaction tx) { MemPoolInfo info = latest_info; if (info == null) return false; //Hard to say for(TransactionInput tx_in : tx.getInputs()) { if (!tx_in.isCoinBase()) { TransactionOutPoint tx_out = tx_in.getOutpoint(); Sha256Hash parent_hash = tx_out.getHash(); if (info.tx_set.contains(parent_hash)) return true; } } return false; }
@Test public void removeScriptsBloomFilter() throws Exception { List<Address> addressesForRemoval = new ArrayList<>(); for (int i = 0; i < 10; i++) { Address watchedAddress = new ECKey().toAddress(PARAMS); addressesForRemoval.add(watchedAddress); wallet.addWatchedAddress(watchedAddress); } wallet.removeWatchedAddresses(addressesForRemoval); for (Address addr : addressesForRemoval) { Transaction t1 = createFakeTx(PARAMS, CENT, addr); TransactionOutPoint outPoint = new TransactionOutPoint(PARAMS, 0, t1); // Note that this has a 1e-12 chance of failing this unit test due to a false positive assertFalse(wallet.getBloomFilter(1e-12).contains(outPoint.unsafeBitcoinSerialize())); sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, t1); assertFalse(wallet.getBloomFilter(1e-12).contains(outPoint.unsafeBitcoinSerialize())); } }
@Test public void marriedKeychainBloomFilter() throws Exception { createMarriedWallet(2, 2); Address address = wallet.currentReceiveAddress(); assertTrue(wallet.getBloomFilter(0.001).contains(address.getHash160())); Transaction t1 = createFakeTx(PARAMS, CENT, address); TransactionOutPoint outPoint = new TransactionOutPoint(PARAMS, 0, t1); assertFalse(wallet.getBloomFilter(0.001).contains(outPoint.unsafeBitcoinSerialize())); sendMoneyToWallet(BlockChain.NewBlockType.BEST_CHAIN, t1); assertTrue(wallet.getBloomFilter(0.001).contains(outPoint.unsafeBitcoinSerialize())); }
public Value getValueSent(TransactionWatcherWallet wallet) { if (isTrimmed) { return getValueSent(); } else { tx.ensureParsed(); // Find the value of the inputs that draw value from the wallet Value sent = type.value(0); Map<Sha256Hash, BitTransaction> transactions = wallet.getTransactions(); for (TransactionInput input : tx.getInputs()) { TransactionOutPoint outPoint = input.getOutpoint(); // This input is taking value from a transaction in our wallet. To discover the value, // we must find the connected transaction. OutPointOutput connected = wallet.getUnspentTxOutput(outPoint); if (connected == null) { BitTransaction spendingTx = transactions.get(outPoint.getHash()); int index = (int) outPoint.getIndex(); if (spendingTx != null && spendingTx.isOutputAvailable(index)) { connected = new OutPointOutput(spendingTx, index); } } if (connected == null) continue; // The connected output may be the change to the sender of a previous input sent to this wallet. In this // case we ignore it. if (!connected.getOutput().isMineOrWatched(wallet)) continue; sent = sent.add(connected.getValue()); } return sent; } }
public OutPointOutput getUnspentTxOutput(TransactionOutPoint outPoint) { lock.lock(); try { return unspentOutputs.get(TrimmedOutPoint.get(outPoint)); } finally { lock.unlock(); } }
public List<TransactionOutPoint> listUnspentOutPoints(Address fromAddress) throws JsonRPCStatusException, IOException { List<Address> addresses = Collections.singletonList(fromAddress); List<UnspentOutput> unspentOutputsRPC = listUnspent(0, defaultMaxConf, addresses); // RPC UnspentOutput objects List<TransactionOutPoint> unspentOutPoints = new ArrayList<TransactionOutPoint>(); for (UnspentOutput it : unspentOutputsRPC) { unspentOutPoints.add(new TransactionOutPoint(getNetParams(), it.getVout(), it.getTxid())); } return unspentOutPoints; }
public synchronized Collection<TransactionOutPoint> getUnspentForAddress(Address a) { String prefix = getPrefixForAddress(a); Collection<String> keys = getByKey("").getKeysByPrefix(prefix, this); LinkedList<TransactionOutPoint> outs = new LinkedList<TransactionOutPoint>(); try { for(String key : keys) { byte[] key_data=Hex.decodeHex(key.toCharArray()); ByteBuffer bb = ByteBuffer.wrap(key_data); bb.order(java.nio.ByteOrder.LITTLE_ENDIAN); bb.position(20); byte[] tx_data = new byte[32]; bb.get(tx_data); int idx=bb.getInt(); Sha256Hash tx_id = new Sha256Hash(tx_data); TransactionOutPoint o = new TransactionOutPoint(jelly.getNetworkParameters(), idx, tx_id); outs.add(o); } } catch(org.apache.commons.codec.DecoderException e) { throw new RuntimeException(e); } return outs; }
public String getKeyForInput(TransactionInput in) { if (in.isCoinBase()) return null; try { byte[] public_key=null; Address a = in.getFromAddress(); public_key = a.getHash160(); return getKey(public_key, in.getOutpoint().getHash(), (int)in.getOutpoint().getIndex()); } catch(ScriptException e) { //Lets try this the other way try { TransactionOutPoint out_p = in.getOutpoint(); Transaction src_tx = tx_util.getTransaction(out_p.getHash()); TransactionOutput out = src_tx.getOutput((int)out_p.getIndex()); return getKeyForOutput(out, (int)out_p.getIndex()); } catch(ScriptException e2) { return null; } } }
@Test public void testCompleteTxWithExistingInputs() throws Exception { // Tests calling completeTx with a SendRequest that already has a few inputs in it // Generate a few outputs to us StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, OTHER_ADDRESS), BigInteger.ONE, 1); Transaction tx1 = createFakeTx(PARAMS, COIN, myAddress); wallet.receiveFromBlock(tx1, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); Transaction tx2 = createFakeTx(PARAMS, COIN, myAddress); assertNotEquals(tx1.getHash(), tx2.getHash()); wallet.receiveFromBlock(tx2, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); Transaction tx3 = createFakeTx(PARAMS, CENT, myAddress); wallet.receiveFromBlock(tx3, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 2); SendRequest request1 = SendRequest.to(OTHER_ADDRESS, CENT); // If we just complete as-is, we will use one of the COIN outputs to get higher priority, // resulting in a change output request1.shuffleOutputs = false; wallet.completeTx(request1); assertEquals(1, request1.tx.getInputs().size()); assertEquals(2, request1.tx.getOutputs().size()); assertEquals(CENT, request1.tx.getOutput(0).getValue()); assertEquals(COIN.subtract(CENT), request1.tx.getOutput(1).getValue()); // Now create an identical request2 and add an unsigned spend of the CENT output SendRequest request2 = SendRequest.to(OTHER_ADDRESS, CENT); request2.tx.addInput(tx3.getOutput(0)); // Now completeTx will result in one input, one output wallet.completeTx(request2); assertEquals(1, request2.tx.getInputs().size()); assertEquals(1, request2.tx.getOutputs().size()); assertEquals(CENT, request2.tx.getOutput(0).getValue()); // Make sure it was properly signed request2.tx.getInput(0).getScriptSig().correctlySpends(request2.tx, 0, tx3.getOutput(0).getScriptPubKey()); // However, if there is no connected output, we will grab a COIN output anyway and add the CENT to fee SendRequest request3 = SendRequest.to(OTHER_ADDRESS, CENT); request3.tx.addInput(new TransactionInput(PARAMS, request3.tx, new byte[]{}, new TransactionOutPoint(PARAMS, 0, tx3.getHash()))); // Now completeTx will result in two inputs, two outputs and a fee of a CENT // Note that it is simply assumed that the inputs are correctly signed, though in fact the first is not request3.shuffleOutputs = false; wallet.completeTx(request3); assertEquals(2, request3.tx.getInputs().size()); assertEquals(2, request3.tx.getOutputs().size()); assertEquals(CENT, request3.tx.getOutput(0).getValue()); assertEquals(COIN.subtract(CENT), request3.tx.getOutput(1).getValue()); SendRequest request4 = SendRequest.to(OTHER_ADDRESS, CENT); request4.tx.addInput(tx3.getOutput(0)); // Now if we manually sign it, completeTx will not replace our signature wallet.signTransaction(request4); byte[] scriptSig = request4.tx.getInput(0).getScriptBytes(); wallet.completeTx(request4); assertEquals(1, request4.tx.getInputs().size()); assertEquals(1, request4.tx.getOutputs().size()); assertEquals(CENT, request4.tx.getOutput(0).getValue()); assertArrayEquals(scriptSig, request4.tx.getInput(0).getScriptBytes()); }
@Override public Transaction getChannelTransaction (TransactionOutPoint anchor, ChannelStatus channelStatus, ECKey client, ECKey server) { return null; }
public HistoryTx(TransactionOutPoint txop, int height) { this.txHash = txop.getHash(); this.height = height; }
public UnspentTx(TransactionOutPoint txop, long value, int height) { super(txop, height); this.txPos = (int) txop.getIndex(); this.value = value; }
private TransactionOutPoint getTransactionOutPoint(CoinType type, int index, ByteString hash) { return new TransactionOutPoint(type, index & 0xFFFFFFFFL, byteStringToHash(hash)); }
public static TrimmedOutPoint get(TransactionOutPoint outPoint) { return new TrimmedOutPoint(outPoint.getParams(), outPoint.getIndex(), outPoint.getHash()); }
public OutPointOutput(TransactionOutPoint outPoint, TransactionOutput output, boolean isGenerated) { this(new TrimmedOutput(output, outPoint.getIndex(), outPoint.getHash()), isGenerated); }
@SuppressWarnings({ "static-access", "deprecation", "unused" }) static public void complete(WalletOperation wallet, @Nullable BAPassword WALLET_PW, Transaction tx, ArrayList<byte[]> AuthSigs, PairedAuthenticator po) throws UnableToCompleteTxSigningException { try{ //Prep the keys needed for signing byte[] key = Hex.decode(po.getMasterPublicKey()); byte[] chain = Hex.decode(po.getChainCode()); //Loop to create a signature for each input int i = 0; for(TransactionInput in: tx.getInputs()) { // We search the TransactionOutput because we build the Tx from raw hex data, not parent Tx is set. TransactionOutPoint txOp = in.getOutpoint(); TransactionOutput out = wallet.findTransactionOutpointByHash(txOp.getHash().toString(), txOp.getIndex()); if(out == null) throw new UnableToCompleteTxSigningException("Cannot find corresponding transaction outout for input:\n " + in.toString()); String inAddress = out.getScriptPubKey().getToAddress(wallet.getNetworkParams()).toString(); ATAddress atAdd = wallet.findAddressInAccounts(inAddress); //Authenticator Key ECKey authKey = wallet.getPairedAuthenticatorKey(po, atAdd.getKeyIndex()); ECKey walletKey = wallet.getPrivECKeyFromAccount(atAdd.getAccountIndex(), atAdd.getType(), atAdd.getKeyIndex(), WALLET_PW, true); // Create Program for the script List<ECKey> keys = ImmutableList.of(authKey, walletKey); Script scriptpubkey = ScriptBuilder.createMultiSigOutputScript(2,keys); //Create P2SH // IMPORTANT - AuthSigs and the signiture we create here should refer to the same input !! TransactionSignature sig1 = TransactionSignature.decodeFromBitcoin(AuthSigs.get(i), true); TransactionSignature sig2 = tx.calculateSignature(i, walletKey, scriptpubkey, Transaction.SigHash.ALL, false); List<TransactionSignature> sigs = ImmutableList.of(sig1, sig2); Script inputScript = ScriptBuilder.createP2SHMultiSigInputScript(sigs, scriptpubkey); in.setScriptSig(inputScript); i++; } } catch (Exception e){ //wallet.disconnectInputs(tx.getInputs()); e.printStackTrace(); throw new UnableToCompleteTxSigningException("Unable to finish transaction signing"); } }
public void sendUnspent(StratumConnection conn, Object request_id, ByteString target) throws AddressFormatException { try { Subscriber sub = new Subscriber(conn, request_id); JSONObject reply = sub.startReply(); Collection<TransactionOutPoint> outs = jelly.getUtxoSource().getUnspentForScriptHash(target); JSONArray arr =new JSONArray(); for(TransactionOutPoint out : outs) { JSONObject o = new JSONObject(); o.put("tx_hash", out.getHash().toString()); o.put("tx_pos", out.getIndex()); SortedTransaction s_tx = new SortedTransaction(out.getHash(), false); Transaction tx = s_tx.tx; long value = tx.getOutput((int)out.getIndex()).getValue().longValue(); o.put("value",value); o.put("height", s_tx.getEffectiveHeight()); arr.put(o); } reply.put("result", arr); sub.sendReply(reply); } catch(org.json.JSONException e) { throw new RuntimeException(e); } }
Transaction getChannelTransaction (TransactionOutPoint anchor, ChannelStatus channelStatus, ECKey client, ECKey server);
public Collection<TransactionOutPoint> getUnspentForScriptHash(ByteString bs);