Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
pokkst committed Feb 11, 2021
2 parents a08b3b6 + 4d73430 commit 8eca494
Show file tree
Hide file tree
Showing 18 changed files with 282 additions and 19 deletions.
7 changes: 5 additions & 2 deletions core/src/main/java/org/bitcoinj/core/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import org.bitcoinj.params.AbstractBitcoinNetParams;
import org.bitcoinj.params.UnitTestParams;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import org.slf4j.Logger;
Expand Down Expand Up @@ -539,8 +540,10 @@ public void solve() {
*/
public BigInteger getDifficultyTargetAsInteger() throws VerificationException {
BigInteger target = Utils.decodeCompactBits(difficultyTarget);
if (target.signum() <= 0 || target.compareTo(params.maxTarget) > 0)
throw new VerificationException("Difficulty target is bad: " + target.toString());
if(getParams().getId() != NetworkParameters.ID_UNITTESTNET) {
if (target.signum() <= 0 || target.compareTo(params.maxTarget) > 0)
throw new VerificationException("Difficulty target is bad: " + target.toString());
}
return target;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import com.google.common.util.concurrent.SettableFuture;
import org.bitcoinj.utils.ListenerRegistration;
import org.bitcoinj.utils.Threading;
import org.bitcoinj.wallet.CoinSelector;
import org.bitcoinj.wallet.selector.CoinSelector;
import org.bitcoinj.wallet.Wallet;

import javax.annotation.Nullable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public byte[] encodeToBitcoin() {
return bos.toByteArray();
}

public static SchnorrSignature decodeFromBitcoin(byte[] bytes) throws SignatureDecodeException, VerificationException {
public static SchnorrSignature decodeFromBitcoin(byte[] bytes) throws VerificationException {
byte[] signature = Arrays.copyOf(bytes, bytes.length-1);
return new SchnorrSignature(signature, bytes[bytes.length-1]);
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/org/bitcoinj/net/SlpDbProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import java.util.Random;

public class SlpDbProcessor {
private String[] slpDbInstances = new String[]{"slpdb.fountainhead.cash", "slpserve.imaginary.cash"};
private String slpDbEndpoint = "/q/";
private final String[] slpDbInstances = new String[]{"slpdb.fountainhead.cash", "slpdb.bitcoin.com"};
private final String slpDbEndpoint = "/q/";

public SlpDbProcessor() {

Expand Down
24 changes: 17 additions & 7 deletions core/src/main/java/org/bitcoinj/script/Script.java
Original file line number Diff line number Diff line change
Expand Up @@ -1521,14 +1521,24 @@ private static void executeCheckDataSig(Transaction txContainingThis, int index,
Sha256Hash hash = Sha256Hash.of(messageByte);

sigValid = ECKey.verify(hash.getBytes(), sig, pubKey);
} catch (Exception e1) {
} catch (VerificationException.NoncanonicalSignature e1) {
try {
SchnorrSignature sig = SchnorrSignature.decodeFromBitcoin(sigBytes);

Sha256Hash hash = Sha256Hash.of(messageByte);

sigValid = ECKey.verifySchnorr(hash.getBytes(), sig, pubKey);
} catch (Exception e) {
e.printStackTrace();
}
} catch(Exception e) {
// There is (at least) one exception that could be hit here (EOFException, if the sig is too short)
// Because I can't verify there aren't more, we use a very generic Exception catch

// This RuntimeException occurs when signing as we run partial/invalid scripts to see if they need more
// signing work to be done inside LocalTransactionSigner.signInputs.
if (!e1.getMessage().contains("Reached past end of ASN.1 stream"))
log.warn("Signature checking failed!", e1);
if (!e.getMessage().contains("Reached past end of ASN.1 stream"))
log.warn("Signature checking failed!", e);
}

if (opcode == OP_CHECKDATASIG)
Expand Down Expand Up @@ -1581,8 +1591,8 @@ private static void executeCheckSig(Transaction txContainingThis, int index, Scr
txContainingThis.hashForSignatureWitness(index, connectedScript, value, sig.sigHashMode(), sig.anyoneCanPay()) :
txContainingThis.hashForSignature(index, connectedScript, (byte) sig.sighashFlags);
sigValid = ECKey.verifySchnorr(hash.getBytes(), sig, pubKey);
} catch (SignatureDecodeException signatureDecodeException) {
signatureDecodeException.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
} catch (SignatureDecodeException e) {
// This exception occurs when signing as we run partial/invalid scripts to see if they need more
Expand Down Expand Up @@ -1679,9 +1689,9 @@ private static int executeMultiSig(Transaction txContainingThis, int index, Scri
usingSchnorr = true;
sigs.pollFirst();
}
} catch (SignatureDecodeException signatureDecodeException) {
} catch (Exception e1) {
usingSchnorr = false;
signatureDecodeException.printStackTrace();
e1.printStackTrace();
}
} catch(Exception e) {
e.printStackTrace();
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/bitcoinj/utils/BIP47Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.bitcoinj.signers.TransactionSigner;
import org.bitcoinj.wallet.*;
import org.bitcoinj.wallet.bip47.NotSecp256k1Exception;
import org.bitcoinj.wallet.selector.CoinSelector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -26,7 +27,6 @@
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.bitcoinj.wallet;

import org.bitcoinj.core.Transaction;
import org.bitcoinj.wallet.selector.DefaultCoinSelector;

/**
* This coin selector will select any transaction at all, regardless of where it came from or whether it was
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/org/bitcoinj/wallet/CoinSelection.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.bitcoinj.core.Coin;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.wallet.selector.CoinSelector;

import java.util.Collection;
import java.util.List;
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/org/bitcoinj/wallet/SendRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.bitcoinj.utils.ExchangeRate;
import org.bitcoinj.wallet.KeyChain.KeyPurpose;
import org.bitcoinj.wallet.Wallet.MissingSigsMode;
import org.bitcoinj.wallet.selector.CoinSelector;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/org/bitcoinj/wallet/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
import org.bitcoinj.wallet.Protos.Wallet.EncryptionType;
import org.bitcoinj.wallet.WalletTransaction.Pool;
import org.bitcoinj.wallet.listeners.*;
import org.bitcoinj.wallet.selector.CoinSelector;
import org.bitcoinj.wallet.selector.DefaultCoinSelector;
import org.bitcoinj.wallet.selector.FilteringCoinSelector;
import org.bitcoinj.wallet.selector.KeyTimeCoinSelector;
import org.bouncycastle.crypto.params.KeyParameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
* limitations under the License.
*/

package org.bitcoinj.wallet;
package org.bitcoinj.wallet.selector;

import org.bitcoinj.core.Coin;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.wallet.CoinSelection;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
* limitations under the License.
*/

package org.bitcoinj.wallet;
package org.bitcoinj.wallet.selector;

import com.google.common.annotations.VisibleForTesting;
import org.bitcoinj.core.*;
import org.bitcoinj.wallet.CoinSelection;

import java.math.BigInteger;
import java.util.ArrayList;
Expand Down Expand Up @@ -62,7 +63,7 @@ public CoinSelection select(Coin target, List<TransactionOutput> candidates) {
}

@VisibleForTesting
static void sortOutputs(ArrayList<TransactionOutput> outputs) {
public static void sortOutputs(ArrayList<TransactionOutput> outputs) {
Collections.sort(outputs, new Comparator<TransactionOutput>() {
@Override
public int compare(TransactionOutput a, TransactionOutput b) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
* limitations under the License.
*/

package org.bitcoinj.wallet;
package org.bitcoinj.wallet.selector;

import org.bitcoinj.core.*;
import org.bitcoinj.wallet.CoinSelection;
import org.bitcoinj.wallet.selector.CoinSelector;

import java.util.HashSet;
import java.util.Iterator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
* limitations under the License.
*/

package org.bitcoinj.wallet;
package org.bitcoinj.wallet.selector;

import org.bitcoinj.core.*;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptException;
import org.bitcoinj.script.ScriptPattern;
import org.bitcoinj.wallet.CoinSelection;
import org.bitcoinj.wallet.Wallet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright by the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.bitcoinj.wallet.selector;

import com.google.common.annotations.VisibleForTesting;
import org.bitcoinj.core.*;
import org.bitcoinj.wallet.CoinSelection;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
* This class implements a {@link CoinSelector} which attempts to get the highest priority
* possible. This means that the transaction is the most likely to get confirmed. Note that this means we may end up
* "spending" more priority than would be required to get the transaction we are creating confirmed.
*/
public class SmallestValueCoinSelector implements CoinSelector {
protected SmallestValueCoinSelector() {
}

@Override
public CoinSelection select(Coin target, List<TransactionOutput> candidates) {
ArrayList<TransactionOutput> selected = new ArrayList<>();
// Sort the inputs by age*value so we get the highest "coindays" spent.
// TODO: Consider changing the wallets internal format to track just outputs and keep them ordered.
ArrayList<TransactionOutput> sortedOutputs = new ArrayList<>(candidates);
// When calculating the wallet balance, we may be asked to select all possible coins, if so, avoid sorting
// them in order to improve performance.
// TODO: Take in network parameters when instanatiated, and then test against the current network. Or just have a boolean parameter for "give me everything"
if (!target.equals(NetworkParameters.MAX_MONEY)) {
sortOutputs(sortedOutputs);
}
// Now iterate over the sorted outputs until we have got as close to the target as possible or a little
// bit over (excessive value will be change).
long total = 0;
for (TransactionOutput output : sortedOutputs) {
if (total >= target.value) break;
// Only pick chain-included transactions, or transactions that are ours and pending.
if (!shouldSelect(output.getParentTransaction())) continue;
selected.add(output);
total += output.getValue().value;
}
// Total may be lower than target here, if the given candidates were insufficient to create to requested
// transaction.
return new CoinSelection(Coin.valueOf(total), selected);
}

@VisibleForTesting
public static void sortOutputs(ArrayList<TransactionOutput> outputs) {
Collections.sort(outputs, new Comparator<TransactionOutput>() {
@Override
public int compare(TransactionOutput a, TransactionOutput b) {
Coin aValue = a.getValue();
Coin bValue = b.getValue();
int c2 = aValue.compareTo(bValue);
if (c2 != 0) return c2;
// They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering.
BigInteger aHash = a.getParentTransactionHash().toBigInteger();
BigInteger bHash = b.getParentTransactionHash().toBigInteger();
return aHash.compareTo(bHash);
}
});
}

/**
* Sub-classes can override this to just customize whether transactions are usable, but keep age sorting.
*/
protected boolean shouldSelect(Transaction tx) {
if (tx != null) {
return isSelectable(tx);
}
return true;
}

public static boolean isSelectable(Transaction tx) {
// Only pick chain-included transactions, or transactions that are ours and pending.
TransactionConfidence confidence = tx.getConfidence();
TransactionConfidence.ConfidenceType type = confidence.getConfidenceType();
return type.equals(TransactionConfidence.ConfidenceType.BUILDING) ||

type.equals(TransactionConfidence.ConfidenceType.PENDING) &&
confidence.getSource().equals(TransactionConfidence.Source.SELF) &&
// In regtest mode we expect to have only one peer, so we won't see transactions propagate.
(confidence.numBroadcastPeers() > 0 || tx.getParams().getId().equals(NetworkParameters.ID_REGTEST));
}

private static SmallestValueCoinSelector instance;

/**
* Returns a global static instance of the selector.
*/
public static SmallestValueCoinSelector get() {
// This doesn't have to be thread safe as the object has no state, so discarded duplicates are
// harmless.
if (instance == null)
instance = new SmallestValueCoinSelector();
return instance;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.bitcoinj.params.UnitTestParams;
import org.bitcoinj.testing.FakeTxBuilder;
import org.bitcoinj.testing.TestWithWallet;
import org.bitcoinj.wallet.selector.DefaultCoinSelector;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
Expand Down
Loading

0 comments on commit 8eca494

Please sign in to comment.