Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/dashevo/dashj into featur…
Browse files Browse the repository at this point in the history
…e-coinjoin
  • Loading branch information
HashEngineering committed Aug 28, 2023
2 parents 24ac28c + 1a02ccf commit 5b13677
Show file tree
Hide file tree
Showing 17 changed files with 453 additions and 284 deletions.
54 changes: 0 additions & 54 deletions core/src/main/java/org/bitcoinj/core/PeerGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -2510,13 +2510,6 @@ public TransactionBroadcast broadcastTransaction(final Transaction tx, final int
}
tx.getConfidence().setPeerInfo(getConnectedPeers().size(), minConnections);

// keep track of how many times a transaction is sent
int sendCount = 0;
if(pendingTxSendCounts.containsKey(tx.getHash())) {
sendCount = pendingTxSendCounts.get(tx.getHash());
}
pendingTxSendCounts.put(tx.getHash(), ++sendCount);

final TransactionBroadcast broadcast = new TransactionBroadcast(this, tx);
broadcast.setMinConnections(minConnections);
broadcast.setDropPeersAfterBroadcast(dropPeersAfterBroadcast && tx.getConfidence().numBroadcastPeers() == 0);
Expand Down Expand Up @@ -2549,53 +2542,6 @@ public void onFailure(Throwable throwable) {
}
}, MoreExecutors.directExecutor());

// Handle the case of 0.14.0.x nodes disconnecting dashj when sending transactions
// This will resend the transaction one if it was only sent to 1 peer
// This will resend the transaction up to 9 times if any one peer was disconnected while sending
Futures.addCallback(broadcast.future(), new FutureCallback<Transaction>() {
final int MAX_ATTEMPTS = 9;
Context context = Context.get();
@Override
public void onSuccess(Transaction transaction) {
log.info("Successfully sent tx {}", transaction.getTxId());
Context.propagate(context);

if(transaction.getConfidence().numBroadcastPeers() == 0) {
// TODO: this tx was sent to a single peer, should we send it again to make sure or see if there are more connections?
Integer sentCount = pendingTxSendCounts.get(transaction.getTxId());

if (sentCount != null) {
if (sentCount <= 2) {
log.info("resending tx {} since it was only sent to 1 peer", tx.getHash());
broadcastTransaction(tx);
} else {
pendingTxSendCounts.put(tx.getHash(), sentCount + MAX_ATTEMPTS);
}
}
}
pendingTxSendCounts.remove(tx.getHash());
}

@Override
public void onFailure(Throwable throwable) {
Context.propagate(context);
int sentCount = pendingTxSendCounts.get(tx.getHash());
if(throwable instanceof PeerException) {
log.info("Failed to send tx {} due to disconnects", tx.getHash());

if(sentCount <= MAX_ATTEMPTS) {
log.info("resending tx {} due to disconnects", tx.getHash());
broadcastTransaction(tx);
} else {
pendingTxSendCounts.remove(tx.getHash());
}
} else {
log.info("Failed to send tx {} due to rejections from peers", tx.getHash());
pendingTxSendCounts.remove(tx.getHash());
}
}
}, MoreExecutors.directExecutor());

// Keep a reference to the TransactionBroadcast object. This is important because otherwise, the entire tree
// of objects we just created would become garbage if the user doesn't hold on to the returned future, and
// eventually be collected. This in turn could result in the transaction not being committed to the wallet
Expand Down
28 changes: 28 additions & 0 deletions core/src/main/java/org/bitcoinj/core/Transaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -1785,6 +1785,34 @@ public boolean isTrusted(TransactionBag bag) {
return false;
}

/**
* This method simulates the BIP61 Reject messages from Dash Core prior to v19.
* It is not likely that a transaction created by DashJ would have any of these issues.
*
*
* @return RejectMessage corresponding to a reason that the network may reject this transaction
*/
public RejectMessage determineRejectMessage() {
try {
verify();
} catch (VerificationException e) {
return new RejectMessage(params, RejectMessage.RejectCode.MALFORMED, getTxId(), e.getMessage(), "");
}
// do any outputs contain dust?
if (getOutputs().stream().anyMatch(TransactionOutput::isDust)) {
return new RejectMessage(params, RejectMessage.RejectCode.DUST, getTxId(), "", "");
}
// is the fee high enough
Coin fee = getFee();
if (fee != null) {
int size = bitcoinSerialize().length;
Coin minFee = Coin.valueOf(size).multiply(REFERENCE_DEFAULT_MIN_TX_FEE.value).div(1000);
if (minFee.isGreaterThan(fee)) {
return new RejectMessage(params, RejectMessage.RejectCode.INSUFFICIENTFEE, getTxId(), "", "");
}
}
return null;
}
return true;
}

Expand Down
39 changes: 9 additions & 30 deletions core/src/main/java/org/bitcoinj/core/TransactionBroadcast.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,32 +97,7 @@ public void setDropPeersAfterBroadcast(boolean dropPeersAfterBroadcast) {
this.dropPeersAfterBroadcast = dropPeersAfterBroadcast;
}

private PreMessageReceivedEventListener rejectionListener = new PreMessageReceivedEventListener() {
@Override
public Message onPreMessageReceived(Peer peer, Message m) {
if (m instanceof RejectMessage) {
RejectMessage rejectMessage = (RejectMessage)m;
if (tx.getTxId().equals(rejectMessage.getRejectedObjectHash())) {
rejects.put(peer, rejectMessage);
tx.getConfidence().markRejectedBy(peer.getAddress(), rejectMessage);
tx.getConfidence().queueListeners(TransactionConfidence.Listener.ChangeReason.REJECT);

int size = rejects.size();
long threshold = Math.round(numWaitingFor / 2.0);
if (size > threshold) {
log.warn("Threshold for considering broadcast rejected has been reached ({}/{})", size, threshold);
future.setException(new RejectedTransactionException(tx, rejectMessage));
peerGroup.removePreMessageReceivedEventListener(this);
peerGroup.removeDisconnectedEventListener(disconnectedListener);
}
}
}
return m;
}
};

public ListenableFuture<Transaction> broadcast() {
peerGroup.addPreMessageReceivedEventListener(Threading.SAME_THREAD, rejectionListener);
peerGroup.addDisconnectedEventListener(Threading.SAME_THREAD, disconnectedListener);
log.info("Waiting for {} peers required for broadcast, we have {} ...", minConnections, peerGroup.getConnectedPeers().size());
peerGroup.waitForPeers(minConnections).addListener(new EnoughAvailablePeers(), Threading.SAME_THREAD);
Expand Down Expand Up @@ -226,7 +201,6 @@ public void onConfidenceChanged(TransactionConfidence conf, ChangeReason reason)
// We're done! It's important that the PeerGroup lock is not held (by this thread) at this
// point to avoid triggering inversions when the Future completes.
log.info("broadcastTransaction: {} complete", tx.getTxId());
peerGroup.removePreMessageReceivedEventListener(rejectionListener);
peerGroup.removeDisconnectedEventListener(disconnectedListener);
conf.removeEventListener(this);
future.set(tx); // RE-ENTRANCY POINT
Expand Down Expand Up @@ -322,18 +296,23 @@ private int getDisconnectedPeers() {
return count;
}

private PeerDisconnectedEventListener disconnectedListener = new PeerDisconnectedEventListener() {
private final PeerDisconnectedEventListener disconnectedListener = new PeerDisconnectedEventListener() {
@Override
public void onPeerDisconnected(Peer peer, int peerCount) {
//log.info(peer + " was disconnected while sending a tx {}", tx.getHash());
if(sentToPeers.containsKey(peer.getAddress())) {
sentToPeers.put(peer.getAddress(), true);
log.info(peer + " was disconnected while sending a transaction to it. tx: {}", tx.getHash());
log.info(peer + " was disconnected while sending a transaction to it. tx: {}", tx.getTxId());
int numDisconnectedPeers = getDisconnectedPeers();

RejectMessage rm = tx.determineRejectMessage();
if (rm == null)
rm = new RejectMessage(peer.getVersionMessage().params, RejectMessage.RejectCode.OTHER, tx.getTxId(),"Peer disconnected after receiving this tx", "The transaction is invalid");
tx.getConfidence().markRejectedBy(peer.getAddress(), rm);
tx.getConfidence().queueListeners(TransactionConfidence.Listener.ChangeReason.REJECT);

if(numDisconnectedPeers >= Math.round(numToBroadcastTo / 2.0)) {
log.info(peer + " was disconnected, setting exception on this transaction broadcast");
future.setException(new PeerException(peer + " was disconnected"));
peerGroup.removePreMessageReceivedEventListener(rejectionListener);
peerGroup.removeDisconnectedEventListener(this);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ public synchronized String toString() {
for (Map.Entry<PeerAddress, RejectMessage> entry : rejects.entrySet()) {
builder.append(String.format(" Rejected by %s: %s - %s - %s", entry.getKey(),
entry.getValue().getReasonCode().toString(), entry.getValue().getRejectedMessage(), entry.getValue().getReasonString()));
builder.append("\n");
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/bitcoinj/core/VersionMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
public class VersionMessage extends Message {

/** The version of this library release, as a string. */
public static final String BITCOINJ_VERSION = "19.0.3-SNAPSHOT";
public static final String BITCOINJ_VERSION = "19.0.5";
/** The value that is prepended to the subVer field of this application. */
public static final String LIBRARY_SUBVER = "/DashJ:" + BITCOINJ_VERSION + "/";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,9 @@ public static BLSDeterministicKey deriveThisOrNextChildKey(BLSDeterministicKey p
public static BLSDeterministicKey deriveChildKey(BLSDeterministicKey parent, ChildNumber childNumber) throws HDDerivationException {
if (!parent.hasPrivKey()) {
ExtendedPublicKey extendedPublicKey = parent.extendedPublicKey.publicChild(childNumber.getI(), parent.pub.isLegacy());
System.out.println("deriving (public): " + childNumber + ": " + Utils.HEX.encode(extendedPublicKey.getPublicKey().serialize()) + " from:" + parent);
return new BLSDeterministicKey(extendedPublicKey, parent);
} else {
ExtendedPrivateKey extendedPrivateKey = parent.extendedPrivateKey.privateChild(childNumber.getI(), parent.pub.isLegacy());
System.out.println("deriving (private):" + childNumber + ": " + Utils.HEX.encode(extendedPrivateKey.getPublicKey().serialize()) + " from:" + parent);
return new BLSDeterministicKey(extendedPrivateKey, parent);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.io.BaseEncoding;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Base58;
import org.bitcoinj.core.ECKey;
Expand Down Expand Up @@ -777,4 +778,16 @@ public void formatKeyWithAddress(boolean includePrivateKeys, @Nullable KeyParame
builder.append(" ").append(toStringWithPrivate(aesKey, params)).append("\n");
}
}

public byte[] getPrivatePublic() {
checkNotNull(priv);
byte[] result = new byte[64];
System.arraycopy(priv.getEncoded(), 0, result, 0, 32);
System.arraycopy(pub.getEncoded(), 0, result, 32, 32);
return result;
}

public String getPrivatePublicBase64() {
return BaseEncoding.base64().encode(getPrivatePublic());
}
}
Loading

0 comments on commit 5b13677

Please sign in to comment.