mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-12 10:15:52 +00:00
Wallet: add output shuffling (a second time - where did it go?!). It's optional for unit testing.
This commit is contained in:
parent
c8ffc1eaee
commit
4df728a7d9
@ -21,6 +21,7 @@ import com.google.bitcoin.crypto.TransactionSignature;
|
||||
import com.google.bitcoin.script.Script;
|
||||
import com.google.bitcoin.script.ScriptBuilder;
|
||||
import com.google.bitcoin.script.ScriptOpCodes;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
@ -1129,6 +1130,12 @@ public class Transaction extends ChildMessage implements Serializable {
|
||||
return Collections.unmodifiableList(outputs);
|
||||
}
|
||||
|
||||
/** Randomly re-orders the transaction outputs: good for privacy */
|
||||
public void shuffleOutputs() {
|
||||
maybeParse();
|
||||
Collections.shuffle(outputs);
|
||||
}
|
||||
|
||||
/** @return the given transaction: same as getInputs().get(index). */
|
||||
public TransactionInput getInput(int index) {
|
||||
maybeParse();
|
||||
|
@ -21,6 +21,7 @@ import com.google.bitcoin.core.TransactionConfidence.ConfidenceType;
|
||||
import com.google.bitcoin.crypto.KeyCrypter;
|
||||
import com.google.bitcoin.crypto.KeyCrypterException;
|
||||
import com.google.bitcoin.crypto.KeyCrypterScrypt;
|
||||
import com.google.bitcoin.params.UnitTestParams;
|
||||
import com.google.bitcoin.script.Script;
|
||||
import com.google.bitcoin.script.ScriptBuilder;
|
||||
import com.google.bitcoin.script.ScriptChunk;
|
||||
@ -1655,6 +1656,13 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi
|
||||
*/
|
||||
public CoinSelector coinSelector = null;
|
||||
|
||||
/**
|
||||
* If true (the default), the outputs will be shuffled during completion to randomize the location of the change
|
||||
* output, if any. This is normally what you want for privacy reasons but in unit tests it can be annoying
|
||||
* so it can be disabled here.
|
||||
*/
|
||||
public boolean shuffleOutputs = true;
|
||||
|
||||
// Tracks if this has been passed to wallet.completeTx already: just a safety check.
|
||||
private boolean completed;
|
||||
|
||||
@ -1738,6 +1746,8 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi
|
||||
*/
|
||||
public Transaction createSend(Address address, BigInteger nanocoins) throws InsufficientMoneyException {
|
||||
SendRequest req = SendRequest.to(address, nanocoins);
|
||||
if (params == UnitTestParams.get())
|
||||
req.shuffleOutputs = false;
|
||||
completeTx(req);
|
||||
return req.tx;
|
||||
}
|
||||
@ -1952,6 +1962,10 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi
|
||||
log.info(" with a fee of {}", bitcoinValueToFriendlyString(calculatedFee));
|
||||
}
|
||||
|
||||
// Now shuffle the outputs to obfuscate which is the change.
|
||||
if (req.shuffleOutputs)
|
||||
req.tx.shuffleOutputs();
|
||||
|
||||
// Now sign the inputs, thus proving that we are entitled to redeem the connected outputs.
|
||||
req.tx.signInputs(Transaction.SigHash.ALL, this, req.aesKey);
|
||||
|
||||
|
@ -253,6 +253,7 @@ public class PaymentChannelClientState {
|
||||
Wallet.SendRequest req = Wallet.SendRequest.forTx(template);
|
||||
req.coinSelector = AllowUnconfirmedCoinSelector.get();
|
||||
editContractSendRequest(req);
|
||||
req.shuffleOutputs = false; // TODO: Fix things so shuffling is usable.
|
||||
wallet.completeTx(req);
|
||||
BigInteger multisigFee = req.fee;
|
||||
multisigContract = req.tx;
|
||||
|
@ -394,7 +394,8 @@ public class PaymentChannelServerState {
|
||||
// die. We could probably add features to the SendRequest API to make this a bit more efficient.
|
||||
signMultisigInput(tx, Transaction.SigHash.NONE, true);
|
||||
// Let wallet handle adding additional inputs/fee as necessary.
|
||||
wallet.completeTx(req);
|
||||
req.shuffleOutputs = false;
|
||||
wallet.completeTx(req); // TODO: Fix things so shuffling is usable.
|
||||
feePaidForPayment = req.fee;
|
||||
log.info("Calculated fee is {}", feePaidForPayment);
|
||||
if (feePaidForPayment.compareTo(bestValueToMe) >= 0) {
|
||||
|
@ -283,6 +283,7 @@ public class WalletTest extends TestWithWallet {
|
||||
}
|
||||
|
||||
// Complete the transaction successfully.
|
||||
req.shuffleOutputs = false;
|
||||
wallet.completeTx(req);
|
||||
|
||||
Transaction t2 = req.tx;
|
||||
@ -371,6 +372,7 @@ public class WalletTest extends TestWithWallet {
|
||||
req.aesKey = aesKey;
|
||||
Address a = req.changeAddress = new ECKey().toAddress(params);
|
||||
req.ensureMinRequiredFee = false;
|
||||
req.shuffleOutputs = false;
|
||||
wallet.completeTx(req);
|
||||
Transaction t3 = req.tx;
|
||||
assertEquals(a, t3.getOutput(1).getScriptPubKey().getToAddress(params));
|
||||
@ -1760,6 +1762,7 @@ public class WalletTest extends TestWithWallet {
|
||||
request19.tx.clearInputs();
|
||||
request19 = SendRequest.forTx(request19.tx);
|
||||
request19.feePerKb = BigInteger.ONE;
|
||||
request19.shuffleOutputs = false;
|
||||
wallet.completeTx(request19);
|
||||
assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request19.fee);
|
||||
assertEquals(2, request19.tx.getInputs().size());
|
||||
@ -1767,7 +1770,6 @@ public class WalletTest extends TestWithWallet {
|
||||
for (TransactionOutput out : request19.tx.getOutputs())
|
||||
outValue19 = outValue19.add(out.getValue());
|
||||
// But now our change output is CENT-minfee, so we have to pay min fee
|
||||
// Change this assert when we eventually randomize output order
|
||||
assertEquals(request19.tx.getOutput(request19.tx.getOutputs().size() - 1).getValue(), CENT.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE));
|
||||
assertEquals(outValue19, Utils.COIN.add(CENT).subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE));
|
||||
|
||||
@ -1827,6 +1829,7 @@ public class WalletTest extends TestWithWallet {
|
||||
request25 = SendRequest.forTx(request25.tx);
|
||||
request25.feePerKb = CENT.divide(BigInteger.valueOf(3));
|
||||
request25.ensureMinRequiredFee = false;
|
||||
request25.shuffleOutputs = false;
|
||||
wallet.completeTx(request25);
|
||||
assertEquals(CENT.subtract(BigInteger.ONE), request25.fee);
|
||||
assertEquals(2, request25.tx.getInputs().size());
|
||||
@ -1834,7 +1837,6 @@ public class WalletTest extends TestWithWallet {
|
||||
for (TransactionOutput out : request25.tx.getOutputs())
|
||||
outValue25 = outValue25.add(out.getValue());
|
||||
// Our change output should be one satoshi
|
||||
// Change this assert when we eventually randomize output order
|
||||
assertEquals(BigInteger.ONE, request25.tx.getOutput(request25.tx.getOutputs().size() - 1).getValue());
|
||||
// and our fee should be CENT-1 satoshi
|
||||
assertEquals(outValue25, Utils.COIN.add(BigInteger.ONE));
|
||||
@ -2044,6 +2046,7 @@ public class WalletTest extends TestWithWallet {
|
||||
SendRequest request1 = SendRequest.to(notMyAddr, 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());
|
||||
@ -2066,6 +2069,7 @@ public class WalletTest extends TestWithWallet {
|
||||
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());
|
||||
|
Loading…
x
Reference in New Issue
Block a user