Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mixing fixes #1

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
948a431
Fixed bunch of bugs, seems to work now.
sfriebe Aug 3, 2017
38bea60
Made eclipse classpath relative, removed temporary files from reposit…
sfriebe Sep 6, 2017
8193f28
Fixed some bugs and added a few methods to make library
sfriebe Sep 6, 2017
1f17e7d
Removed unneeded files.
sfriebe Sep 6, 2017
fcc99ba
Update BitNymWrapper, MixingTabController and BitNymWallet to allow m…
Oct 11, 2017
69008fc
Improve mixing
Oct 24, 2017
a08678f
Put doMix() functionality inside BitNymWallet
Oct 30, 2017
458e801
Improve mixing
Nov 9, 2017
8dff6da
Recognize when both mix partner try to mix active simultaneously
Nov 9, 2017
6fdc45e
Use context as parameter and Context.propagate on certain methods to …
Nov 14, 2017
edaa924
Update mixing
PhilbertM May 25, 2018
fb1cd59
Add error codes and gui output when mixing fails
PhilbertM Jun 15, 2018
e4e08f1
Fix mixing problems due to inconsistency in transaction chain
PhilbertM Jul 23, 2018
3535ab1
Avoid some null pointers and remove listeners properly on mixing abor…
PhilbertM Sep 4, 2018
6895da7
Test requesting blocks on multiple peers, clean up
PhilbertM Nov 9, 2018
f0d36f5
Change WaitForDataListener
PhilbertM Nov 21, 2018
d486d2c
Removing calls to javax.xml.bind.DatatypeConverter.printHexBinary().
sfriebe Dec 19, 2018
157b1f6
Improve code style, add enum for abort messages.
PhilbertM Jan 8, 2019
55db1ab
Remove TestMessage and debug outputs
PhilbertM Jan 11, 2019
437d822
Merge remote-tracking branch 'origin/remove-javax' into mixing-fixes
PhilbertM Jan 11, 2019
aeab376
Fix merge
PhilbertM Jan 11, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions src/bitnymWallet/BitNymWallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ public void messageReceived(TestMessage message, Identifier source) {
System.exit(52);
}
// 2 peers are enough
pg.setMaxConnections(2);
pg.setMaxConnections(5);

/*
// TODO(SF): Remove failing peers
Expand Down Expand Up @@ -482,10 +482,9 @@ private void startTimeout() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("DEBUG: Timeout started");
stopTimeout = false;
int timeout = 4 * 60;
while (timeout > 0 && stopTimeout == false) {
while (timeout > 0 && !stopTimeout) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Expand Down Expand Up @@ -517,8 +516,10 @@ private void mixAborted(int errorCode) {
removeBroadcastAnnouncementChangeEventListener(broadcastListener);
broadcastListener = null;
removeTransactionGeneratorListener(tgListener);
// avoid using old bc on timeout (maybe TODO this only on timeout
getBroadcastAnnouncements().clear();
// avoid using old bc on timeout
if(errorCode == 0) {
getBroadcastAnnouncements().clear();
}
reinitMixer();
listenerAdded = false;
stopTimeout = true;
Expand Down Expand Up @@ -597,7 +598,6 @@ public void onMixAborted(int errorCode) {
System.out.println("After removing old ones having " + getBroadcastAnnouncements().size() + " broadcasts.");

if (getBroadcastAnnouncements().isEmpty()) {
// Send a broadcast ourself
// check what time broadcast would have
long bcTime = (CLTVScriptPair.currentBitcoinBIP113Time(bc)-1);
System.out.println("Broadcast is " + bcTime + " old");
Expand All @@ -607,13 +607,11 @@ public void onMixAborted(int errorCode) {
tgListener = new TransactionGeneratorListener() {
@Override
public void onTransactionWroteToFile() {
System.out.println("DEBUG: onTransactionWroteToFile called");
// check if mixing is possible every time a new broadcast is received
listenToBroadcasts(lockTime);
//check if broadcast
System.out.println("DEBUG: check for BCs");
if (!getBroadcastAnnouncements().isEmpty()) {
System.out.println("BroadCast found, try mixing");
System.out.println("Broadcast found, try mixing");
try {
mixWithNewestBroadcast(lockTime);
// Remove all stored broadcasts since one of them has been used
Expand All @@ -627,6 +625,7 @@ public void onTransactionWroteToFile() {
};
addTransactionGeneratorListener(tgListener);

// Send a broadcast ourself
sendBroadcastAnnouncement(0);
if (bcTime < (System.currentTimeMillis() / 1000) - (BROADCAST_TIME * 60)) {
System.out.println("Broadcast would be too old. Send new one");
Expand Down
22 changes: 16 additions & 6 deletions src/bitnymWallet/MixPartnerDiscovery.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package bitnymWallet;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutionException;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -34,6 +32,7 @@ public class MixPartnerDiscovery implements NewBestBlockListener, BlocksDownload
private List<Transaction> broadcasts;
private Wallet wallet;
private List<BroadcastAnnouncementChangeEventListener> listeners;
public Transaction lastReceived;

public MixPartnerDiscovery(NetworkParameters params, PeerGroup pg, BlockChain bc, Wallet wallet) {
this.pg = pg;
Expand Down Expand Up @@ -117,11 +116,20 @@ public void notifyNewBestBlock(StoredBlock sblock)
@Override
public void onBlocksDownloaded(Peer arg0, Block arg1,
@Nullable FilteredBlock arg2, int arg3) {
System.out.println("received block");
System.out.println("received block: " + arg2.getBlockHeader().getHashAsString());
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));

arg2.getTransactionCount();
String hashes = "DEBUG: Hashes";
PhilbertM marked this conversation as resolved.
Show resolved Hide resolved
for (Sha256Hash hash : arg2.getTransactionHashes()) {
hashes = hashes + ", " + hash.toString();
}
System.out.println(hashes);
boolean receivedBcastAnnouncmnt = false;
Map<Sha256Hash, Transaction> assocTxs = arg2.getAssociatedTransactions();
for(Transaction tx : assocTxs.values()) {
System.out.println("from within mixpartner discovery " + tx);
System.out.println("from within mixpartner discovery " + tx);
lastReceived = tx;
if(tx.getOutputs().size() > 1 &&
BroadcastAnnouncement.isBroadcastAnnouncementScript(tx.getOutput(1).getScriptBytes()))
//&& !wallet.isTransactionRelevant(tx)) {
Expand Down Expand Up @@ -168,7 +176,9 @@ public void addBroadcastAnnouncementChangeEventListener(BroadcastAnnouncementCha
}

public void removeBroadcastAnnouncementChangeEventListener(BroadcastAnnouncementChangeEventListener l) {
System.out.println("DEBUG: Remove BCListners. Current size:" + listeners.size());
this.listeners.remove(l);
System.out.println("DEBUG: Size now: " + listeners.size());
}

public BroadcastAnnouncement getNewestBroadcast() throws NoBroadcastAnnouncementsException {
Expand Down
29 changes: 8 additions & 21 deletions src/bitnymWallet/Mixer.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ public void waitForData(boolean status) {

@Override
public void messageReceived(SendProofMessage msg, Identifier arg1) {
System.out.println("DEBUG: Passive Mix, first part of mix received");
//deserialize received tx, and add own input and output and
//sign then and send back
System.out.println("try to deserialize tx received from mixpartner");
Expand Down Expand Up @@ -233,7 +232,6 @@ public void messageReceived(SendProofMessage msg, Identifier arg1) {

@Override
public void messageReceived(SendProofMessage msg, Identifier arg1) {
PhilbertM marked this conversation as resolved.
Show resolved Hide resolved
System.out.println("Passive, last message received. Check and restart ptp");
// TODO Auto-generated method stub
if(!checkTx(rcvdTx, deserializeTransaction(msg.data))) {
System.out.println("checktx failed");
Expand All @@ -259,7 +257,6 @@ public void messageReceived(SendProofMessage msg, Identifier arg1) {
System.out.println("New Tx:");
System.out.println(ownProof.getLastTransaction());
this.wallet.sendMessage(new SendProofMessage(serialize(ownProof)), mixPartnerAdress);
//this.wallet.sendMessage(serialize(ownProof), mixPartnerAdress);
System.out.println("done");
}

Expand All @@ -271,7 +268,7 @@ private boolean checkTxInputIsFromProof(Transaction rcvdTx, int i) {
// TODO sometimes index i is too high (1, but array size of rcvdTx only 1)
PhilbertM marked this conversation as resolved.
Show resolved Hide resolved
try {
System.out.println("DEBUG: transaction for comparison " + rcvdTx.getInput(i).getOutpoint().toString() + "(" + rcvdTx.getInput(i).getOutpoint().getHash() + ")");
System.out.println("DEBUG: last transaction of parnter " + partnerProof.getLastTransaction().toString() + "(" + partnerProof.getLastTransaction().getHash() + ")");
System.out.println("DEBUG: last transaction of partner " + partnerProof.getLastTransaction().toString() + "(" + partnerProof.getLastTransaction().getHash() + ")");
System.out.println("DEBUG: Index 1(Partner): " + partnerProof.getLastTransactionOutput().getIndex() + ", Index 2(TX): " + rcvdTx.getInput(i).getOutpoint().getIndex());
return rcvdTx.getInput(i).getOutpoint().getHash().equals(partnerProof.getLastTransaction().getHash()) &&
partnerProof.getLastTransactionOutput().getIndex() == rcvdTx.getInput(i).getOutpoint().getIndex();
Expand All @@ -285,7 +282,7 @@ private boolean checkTxInputIsFromProof(Transaction rcvdTx, int i) {

public void initiateMix() {
if (mixing) {
// already mixing , do not initiatemix
// already mixing , do not initiate mix
System.out.println("already mixing! Can't mix active");
return;
}
Expand Down Expand Up @@ -329,15 +326,14 @@ public void messageSent(long id, Identifier destination, State state) {
System.out.println("New Tx");
System.out.println(ownProof.getLastTransaction());

System.out.println("mixpartneradress " + mixPartnerAdress.getTorAddress());
System.out.println("mixpartner address " + mixPartnerAdress.getTorAddress());
//ping();
System.out.println("listen for proof (first message of mix(?))");
this.wallet.ptp.setReceiveListener(SendProofMessage.class, new MessageReceivedListener<SendProofMessage>() {

//deserialize proof
@Override
public void messageReceived(SendProofMessage msg, Identifier arg1) {
System.out.println("Mix active, first message received, try starting challenge response");
partnerProof = (ProofMessage) deserialize(msg.data);
partnerProof.addWaitForDataListener(new WaitForDataListener() {
@Override
Expand Down Expand Up @@ -471,15 +467,8 @@ public void messageReceived(MixRequestMessage mixRequestMessage, Identifier sour
System.out.println("Mix request received, mixing passive");
if (mixing) {
// mixing active, do not mix passive
System.out.println("Already mixing, can't mix passive");
System.out.println("Check if simultaneously mixing active");
System.out.println("Already mixing, can't mix passive. Check if simultaneously mixing active");
if (mixPartnerAdress.equals(source)) {
// necessary to check if mixing active?
System.out.println("Assertion: simultaneously mixing active");
System.out.println("Check who would have been first:");
System.out.println(mixRequestMessage.timeStamp);
System.out.println(mixRequestTimestamp);
System.out.println(mixRequestMessage.timeStamp - mixRequestTimestamp);
if (mixRequestTimestamp != 0) {
if(mixRequestTimestamp == mixRequestMessage.timeStamp) {
// abort
Expand All @@ -489,14 +478,12 @@ public void messageReceived(MixRequestMessage mixRequestMessage, Identifier sour
}
if (mixRequestMessage.timeStamp > mixRequestTimestamp) {
//own Request was faster mix active, other should have same result and mix passive
System.out.println("Would stay active");
//mixAbort(11);
System.out.println("stay active");
return;
}
}
System.out.println("Would be passive");
System.out.println("mix passive");
passiveMix(mixRequestMessage.data);
//mixAbort(11);
}
PhilbertM marked this conversation as resolved.
Show resolved Hide resolved
return;
}
Expand Down Expand Up @@ -724,8 +711,8 @@ private Transaction deserializeTransaction(byte[] arg0) {
Transaction rcvdTx = null;
BitcoinSerializer bs = new BitcoinSerializer(params, false);
try {
rcvdTx = bs.makeTransaction(arg0);
} catch (ProtocolException e) {
rcvdTx = bs.makeTransaction(arg0);
PhilbertM marked this conversation as resolved.
Show resolved Hide resolved
} catch (ProtocolException | NegativeArraySizeException e) {
e.printStackTrace();
}
return rcvdTx;
Expand Down
115 changes: 60 additions & 55 deletions src/bitnymWallet/ProofMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,7 @@
import java.util.List;
import javax.annotation.Nullable;

import org.bitcoinj.core.BitcoinSerializer;
import org.bitcoinj.core.Block;
import org.bitcoinj.core.BlockChain;
import org.bitcoinj.core.BloomFilter;
import org.bitcoinj.core.FilteredBlock;
import org.bitcoinj.core.GetDataMessage;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.PartialMerkleTree;
import org.bitcoinj.core.Peer;
import org.bitcoinj.core.PeerGroup;
import org.bitcoinj.core.ProtocolException;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.StoredBlock;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.Utils;
import org.bitcoinj.core.*;
import org.bitcoinj.core.TransactionConfidence.ConfidenceType;
import org.bitcoinj.core.TransactionConfidence.Listener;
import org.bitcoinj.core.TransactionOutput;
Expand Down Expand Up @@ -143,8 +128,14 @@ public ProofMessage(List<Transaction> vP, List<Integer> oIdices) {
public boolean isValidPath() {
//check that the transaction build a path and are not just random txs,
//by checking the tx hashes with those of the outpoints
System.out.println("DEBUG PATH:");
for (Transaction tx : validationPath) {
System.out.println("TX: " + tx.getHash().toString());
}
for(int i=validationPath.size()-1; i > 1; i--) {
Transaction tx = validationPath.get(i);
System.out.println("DEBUG: output is " + tx.getInput(outputIndices.get(i)).getOutpoint().getHash());
System.out.println("DEBUG: Validationpath is " + validationPath.get(i-1).getHash());
if(!tx.getInput(outputIndices.get(i)).getOutpoint().getHash().equals(validationPath.get(i-1).getHash())) {
System.out.println("not a valid path!");
return false;
Expand Down Expand Up @@ -223,63 +214,77 @@ public boolean isNymTxInBlockChain(NetworkParameters params, BlockChain bc, Peer
//get filtered block with transaction and check merkel tree
final BlockStore blockstore = bc.getBlockStore();
System.out.println("check that transaction is in blockchain");
System.out.println("DEBUG: Last TX: " + getLastTransaction());
final Peer dpeer = pg.getDownloadPeer();
BloomFilter filter = dpeer.getBloomFilter();
System.out.println("Download peer: " + dpeer.toString());
System.out.println("Peers connected : " + pg.getConnectedPeers().size());

filter.insert(getLastTransaction().getInput(0).getOutpoint().unsafeBitcoinSerialize());

dpeer.setBloomFilter(filter);
GetDataMessage msg = new GetDataMessage(params);
assert(appearedInChainheight > 0);
msg.addFilteredBlock(getBlockHashByHeight(bc, appearedInChainheight));
final Object monitor = new Object();
//listener forces monitorstate to be final, so we use a wrapper class, to still be able to modify it
class BooleanWrapper {
boolean monitorState = false;

void setMonitorState(boolean b) {
this.monitorState = b;
}

boolean getMonitorState() {
return this.monitorState;
}
}
final BooleanWrapper monState = new BooleanWrapper();
final BooleanWrapper isTxInBlockchain = new BooleanWrapper();
dpeer.addBlocksDownloadedEventListener(new BlocksDownloadedEventListener() {

@Override
public void onBlocksDownloaded(Peer arg0, Block arg1,
@Nullable FilteredBlock arg2, int arg3) {
System.out.println("execute onblocksdownloaded listener on block + " + arg2.getBlockHeader().getHashAsString());
List<Sha256Hash> matchedHashesOut = new ArrayList<>();
PartialMerkleTree tree = arg2.getPartialMerkleTree();
Sha256Hash merkleroot = tree.getTxnHashAndMerkleRoot(matchedHashesOut);
System.out.println("DEBUG: merkleroot:" + merkleroot.toString());
try {
System.out.println("DEBUG: Hashes: " + matchedHashesOut.contains(getLastTransaction().getHash()));
System.out.println("DEBUG: merkleroot blockHeader " + merkleroot.equals(arg2.getBlockHeader().getMerkleRoot()));
System.out.println("DEBUG: merkleroot blockstore" + merkleroot.equals(blockstore.get(arg2.getBlockHeader().getHash()).getHeader().getMerkleRoot()));
if(matchedHashesOut.contains(getLastTransaction().getHash()) &&
merkleroot.equals(arg2.getBlockHeader().getMerkleRoot()) &&
merkleroot.equals(blockstore.get(arg2.getBlockHeader().getHash()).getHeader().getMerkleRoot())) {
System.out.println("DEBUG: isTxInBlockchain TRUE");
isTxInBlockchain.setMonitorState(true);
GetDataMessage msg = new GetDataMessage(params);
assert(appearedInChainheight > 0);
msg.addFilteredBlock(getBlockHashByHeight(bc, appearedInChainheight));
System.out.println("Block requested: " + getBlockHashByHeight(bc, appearedInChainheight));
for(Peer peer : pg.getConnectedPeers()) {
BloomFilter filter = peer.getBloomFilter();

filter.insert(getLastTransaction().getInput(0).getOutpoint().unsafeBitcoinSerialize());

peer.setBloomFilter(filter);

peer.addBlocksDownloadedEventListener(new BlocksDownloadedEventListener() {

@Override
public void onBlocksDownloaded(Peer arg0, Block arg1,
PhilbertM marked this conversation as resolved.
Show resolved Hide resolved
@Nullable FilteredBlock arg2, int arg3) {
System.out.println("Peer: " + arg0.toString());
System.out.println("execute onblocksdownloaded listener on block + " + arg2.getBlockHeader().getHashAsString());
List<Sha256Hash> matchedHashesOut = new ArrayList<>();
PartialMerkleTree tree = arg2.getPartialMerkleTree();
Sha256Hash merkleroot = tree.getTxnHashAndMerkleRoot(matchedHashesOut);
System.out.println("DEBUG: merkleroot:" + merkleroot.toString());
if (!matchedHashesOut.isEmpty()) {
System.out.println(matchedHashesOut.get(0));
}
} catch (BlockStoreException e) {
e.printStackTrace();
}

synchronized (monitor) {
monState.setMonitorState(false);
System.out.println("DEBUG: isTxInBlockchain Finished!");
monitor.notifyAll(); // unlock again
try {
System.out.println("DEBUG: Hashes: " + matchedHashesOut.contains(getLastTransaction().getHash()));
System.out.println("Hashes should contain " + getLastTransaction().getHash());
System.out.println("DEBUG: merkleroot blockHeader " + merkleroot.equals(arg2.getBlockHeader().getMerkleRoot()));
System.out.println("DEBUG: merkleroot blockstore" + merkleroot.equals(blockstore.get(arg2.getBlockHeader().getHash()).getHeader().getMerkleRoot()));
if(matchedHashesOut.contains(getLastTransaction().getHash()) &&
merkleroot.equals(arg2.getBlockHeader().getMerkleRoot()) &&
merkleroot.equals(blockstore.get(arg2.getBlockHeader().getHash()).getHeader().getMerkleRoot())) {
System.out.println("DEBUG: isTxInBlockchain TRUE");
isTxInBlockchain.setMonitorState(true);
}
} catch (BlockStoreException e) {
e.printStackTrace();
}

synchronized (monitor) {
monState.setMonitorState(false);
System.out.println("DEBUG: isTxInBlockchain Finished!");
monitor.notifyAll(); // unlock again
}
peer.removeBlocksDownloadedEventListener(this);
}
dpeer.removeBlocksDownloadedEventListener(this);
}
});
dpeer.sendMessage(msg);
});
peer.sendMessage(msg);
}
System.out.println("send getdatamessage to verify tx is in blockchain");
waitForData(true);
//return when finished
Expand Down