diff --git a/core/build.gradle b/core/build.gradle index 790bda488de..866bcf973eb 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -3,23 +3,22 @@ apply plugin: 'com.google.protobuf' apply plugin: 'maven' apply plugin: 'eclipse' -version = '0.15.2' +version = '0.15.5' archivesBaseName = 'groestlcoinj-core' eclipse.project.name = 'groestlcoinj-core' dependencies { - compile 'org.bouncycastle:bcprov-jdk15on:1.60' - implementation 'com.lambdaworks:scrypt:1.4.0' - implementation 'com.google.guava:guava:27.0.1-android' + compile 'org.bouncycastle:bcprov-jdk15to18:1.63' + implementation 'com.google.guava:guava:27.1-android' compile 'com.google.protobuf:protobuf-java:3.6.1' - implementation 'com.squareup.okhttp3:okhttp:3.12.1' - implementation 'org.slf4j:slf4j-api:1.7.25' + implementation 'com.squareup.okhttp3:okhttp:3.12.3' + implementation 'org.slf4j:slf4j-api:1.7.28' implementation 'net.jcip:jcip-annotations:1.0' compileOnly 'org.fusesource.leveldbjni:leveldbjni-all:1.8' testImplementation 'junit:junit:4.12' testImplementation 'org.easymock:easymock:3.2' testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.5.2' - testImplementation 'org.slf4j:slf4j-jdk14:1.7.25' + testImplementation 'org.slf4j:slf4j-jdk14:1.7.28' testImplementation 'com.h2database:h2:1.3.167' testImplementation 'org.fusesource.leveldbjni:leveldbjni-all:1.8' } @@ -27,6 +26,7 @@ dependencies { sourceCompatibility = 1.7 compileJava.options.encoding = 'UTF-8' compileTestJava.options.encoding = 'UTF-8' +javadoc.options.encoding = 'UTF-8' protobuf { protoc { diff --git a/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java b/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java index 19422223361..6fc6de00d8f 100644 --- a/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java +++ b/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java @@ -69,8 +69,8 @@ * we say it is an orphan chain. Orphan chains can occur when blocks are solved and received during the initial block * chain download, or if we connect to a peer that doesn't send us blocks in order.

* - *

A reorganize occurs when the blocks that make up the best known chain changes. Note that simply adding a - * new block to the top of the best chain isn't as reorganize, but that a reorganize is always triggered by adding + *

A reorganize occurs when the blocks that make up the best known chain change. Note that simply adding a + * new block to the top of the best chain isn't a reorganize, but that a reorganize is always triggered by adding * a new block that connects to some other (non best head) block. By "best" we mean the chain representing the largest * amount of work done.

* @@ -543,7 +543,8 @@ private void connectBlock(final Block block, StoredBlock storedPrev, boolean exp block.transactions == null ? block : block.cloneAsHeader(), txOutChanges); versionTally.add(block.getVersion()); setChainHead(newStoredBlock); - log.debug("Chain is now {} blocks high, running listeners", newStoredBlock.getHeight()); + if (log.isDebugEnabled()) + log.debug("Chain is now {} blocks high, running listeners", newStoredBlock.getHeight()); informListenersForNewBlock(block, NewBlockType.BEST_CHAIN, filteredTxHashList, filteredTxn, newStoredBlock); } else { // This block connects to somewhere other than the top of the best known chain. We treat these differently. @@ -898,7 +899,8 @@ private void tryConnectingOrphans() throws VerificationException, BlockStoreExce StoredBlock prev = getStoredBlockInCurrentScope(orphanBlock.block.getPrevBlockHash()); if (prev == null) { // This is still an unconnected/orphan block. - log.debug("Orphan block {} is not connectable right now", orphanBlock.block.getHash()); + if (log.isDebugEnabled()) + log.debug("Orphan block {} is not connectable right now", orphanBlock.block.getHash()); continue; } // Otherwise we can connect it now. @@ -1042,7 +1044,7 @@ void trackFalsePositives(int count) { // Track false positives in batch by adding alpha to the false positive estimate once per count. // Each false positive counts as 1.0 towards the estimate. falsePositiveRate += FP_ESTIMATOR_ALPHA * count; - if (count > 0) + if (count > 0 && log.isDebugEnabled()) log.debug("{} false positives, current rate = {} trend = {}", count, falsePositiveRate, falsePositiveTrend); } diff --git a/core/src/main/java/org/bitcoinj/core/ECKey.java b/core/src/main/java/org/bitcoinj/core/ECKey.java index 0144ebf7f81..6572b061570 100644 --- a/core/src/main/java/org/bitcoinj/core/ECKey.java +++ b/core/src/main/java/org/bitcoinj/core/ECKey.java @@ -148,7 +148,7 @@ public int compare(ECKey k1, ECKey k2) { // The two parts of the key. If "priv" is set, "pub" can always be calculated. If "pub" is set but not "priv", we // can only verify signatures not make them. - protected final BigInteger priv; // A field element. + @Nullable protected final BigInteger priv; // A field element. protected final LazyECPoint pub; // Creation time of the key in seconds since the epoch, or zero if the key was deserialized from a version that did @@ -992,7 +992,7 @@ public static ECKey recoverFromSignature(int recId, ECDSASignature sig, Sha256Ha // 1.2. Convert the integer x to an octet string X of length mlen using the conversion routine // specified in Section 2.3.7, where mlen = ⌈(log2 p)/8⌉ or mlen = ⌈m/8⌉. // 1.3. Convert the octet string (16 set binary digits)||X to an elliptic curve point R using the - // conversion routine specified in Section 2.3.4. If this conversion routine outputs “invalid”, then + // conversion routine specified in Section 2.3.4. If this conversion routine outputs "invalid", then // do another iteration of Step 1. // // More concisely, what these points mean is to use X as a compressed public key. diff --git a/core/src/main/java/org/bitcoinj/core/Peer.java b/core/src/main/java/org/bitcoinj/core/Peer.java index a8cbcb2847e..87531b7a175 100644 --- a/core/src/main/java/org/bitcoinj/core/Peer.java +++ b/core/src/main/java/org/bitcoinj/core/Peer.java @@ -575,7 +575,8 @@ private void processVersionMessage(VersionMessage m) throws ProtocolException { // Now it's our turn ... // Send an ACK message stating we accept the peers protocol version. sendMessage(new VersionAck()); - log.debug("{}: Incoming version handshake complete.", this); + if (log.isDebugEnabled()) + log.debug("{}: Incoming version handshake complete.", this); incomingVersionHandshakeFuture.set(this); } @@ -586,12 +587,14 @@ private void processVersionAck(VersionAck m) throws ProtocolException { if (outgoingVersionHandshakeFuture.isDone()) { throw new ProtocolException("got more than one version ack"); } - log.debug("{}: Outgoing version handshake complete.", this); + if (log.isDebugEnabled()) + log.debug("{}: Outgoing version handshake complete.", this); outgoingVersionHandshakeFuture.set(this); } private void versionHandshakeComplete() { - log.debug("{}: Handshake complete.", this); + if (log.isDebugEnabled()) + log.debug("{}: Handshake complete.", this); setTimeoutEnabled(false); for (final ListenerRegistration registration : connectedEventListeners) { registration.executor.execute(new Runnable() { @@ -640,10 +643,11 @@ protected void processNotFoundMessage(NotFoundMessage m) { protected void processAlert(AlertMessage m) { try { - if (m.isSignatureValid()) { - log.debug("Received alert from peer {}: {}", this, m.getStatusBar()); - } else { - log.debug("Received alert with invalid signature from peer {}: {}", this, m.getStatusBar()); + if (log.isDebugEnabled()) { + if (m.isSignatureValid()) + log.debug("Received alert from peer {}: {}", this, m.getStatusBar()); + else + log.debug("Received alert with invalid signature from peer {}: {}", this, m.getStatusBar()); } } catch (Throwable t) { // Signature checking can FAIL on Android platforms before Gingerbread apparently due to bugs in their @@ -758,7 +762,8 @@ protected void processTransaction(final Transaction tx) throws VerificationExcep tx.verify(); lock.lock(); try { - log.debug("{}: Received tx {}", getAddress(), tx.getTxId()); + if (log.isDebugEnabled()) + log.debug("{}: Received tx {}", getAddress(), tx.getTxId()); // Label the transaction as coming in from the P2P network (as opposed to being created by us, direct import, // etc). This helps the wallet decide how to risk analyze it later. // @@ -967,18 +972,19 @@ public void onFailure(Throwable throwable) { } protected void processBlock(Block m) { - if (log.isDebugEnabled()) { + if (log.isDebugEnabled()) log.debug("{}: Received broadcast block {}", getAddress(), m.getHashAsString()); - } // Was this block requested by getBlock()? if (maybeHandleRequestedData(m)) return; if (blockChain == null) { - log.debug("Received block but was not configured with an AbstractBlockChain"); + if (log.isDebugEnabled()) + log.debug("Received block but was not configured with an AbstractBlockChain"); return; } // Did we lose download peer status after requesting block data? if (!vDownloadData) { - log.debug("{}: Received block we did not ask for: {}", getAddress(), m.getHashAsString()); + if (log.isDebugEnabled()) + log.debug("{}: Received block we did not ask for: {}", getAddress(), m.getHashAsString()); return; } pendingBlockDownloads.remove(m.getHash()); @@ -1032,11 +1038,13 @@ protected void endFilteredBlock(FilteredBlock m) { if (log.isDebugEnabled()) log.debug("{}: Received broadcast filtered block {}", getAddress(), m.getHash().toString()); if (!vDownloadData) { - log.debug("{}: Received block we did not ask for: {}", getAddress(), m.getHash().toString()); + if (log.isDebugEnabled()) + log.debug("{}: Received block we did not ask for: {}", getAddress(), m.getHash().toString()); return; } if (blockChain == null) { - log.debug("Received filtered block but was not configured with an AbstractBlockChain"); + if (log.isDebugEnabled()) + log.debug("Received filtered block but was not configured with an AbstractBlockChain"); return; } // Note that we currently do nothing about peers which maliciously do not include transactions which @@ -1220,7 +1228,8 @@ protected void processInv(InventoryMessage inv) { // We created this transaction ourselves, so don't download. it.remove(); } else { - log.debug("{}: getdata on tx {}", getAddress(), item.hash); + if (log.isDebugEnabled()) + log.debug("{}: getdata on tx {}", getAddress(), item.hash); getdata.addTransaction(item.hash, vPeerVersionMessage.isWitnessSupported()); // Register with the garbage collector that we care about the confidence data for a while. pendingTxDownloads.add(conf); @@ -1521,7 +1530,8 @@ public void complete() { if (!future.isDone()) { long elapsed = Utils.currentTimeMillis() - startTimeMsec; Peer.this.addPingTimeData(elapsed); - log.debug("{}: ping time is {} ms", Peer.this.toString(), elapsed); + if (log.isDebugEnabled()) + log.debug("{}: ping time is {} ms", Peer.this.toString(), elapsed); future.set(elapsed); } } @@ -1725,7 +1735,7 @@ public void setBloomFilter(BloomFilter filter, boolean andQueryMemPool) { if (ver == null || !ver.isBloomFilteringSupported()) return; vBloomFilter = filter; - log.debug("{}: Sending Bloom filter{}", this, andQueryMemPool ? " and querying mempool" : ""); + log.info("{}: Sending Bloom filter{}", this, andQueryMemPool ? " and querying mempool" : ""); sendMessage(filter); if (andQueryMemPool) sendMessage(new MemoryPoolMessage()); diff --git a/core/src/main/java/org/bitcoinj/core/PeerGroup.java b/core/src/main/java/org/bitcoinj/core/PeerGroup.java index dad12a8d3de..fd800024ff1 100644 --- a/core/src/main/java/org/bitcoinj/core/PeerGroup.java +++ b/core/src/main/java/org/bitcoinj/core/PeerGroup.java @@ -178,34 +178,37 @@ public class PeerGroup implements TransactionBroadcaster { @Override public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { // We received a relevant transaction. We MAY need to recalculate and resend the Bloom filter, but only - // if we have received a transaction that includes a relevant P2PK output. + // if we have received a transaction that includes a relevant P2PK or P2WPKH output. // - // The reason is that P2PK outputs, when spent, will not repeat any data we can predict in their + // The reason is that P2PK and P2WPKH outputs, when spent, will not repeat any data we can predict in their // inputs. So a remote peer will update the Bloom filter for us when such an output is seen matching the - // existing filter, so that it includes the tx hash in which the P2PK output was observed. Thus + // existing filter, so that it includes the tx hash in which the P2PK/P2WPKH output was observed. Thus // the spending transaction will always match (due to the outpoint structure). // // Unfortunately, whilst this is required for correct sync of the chain in blocks, there are two edge cases. // - // (1) If a wallet receives a relevant, confirmed p2pubkey output that was not broadcast across the network, + // (1) If a wallet receives a relevant, confirmed P2PK/P2WPKH output that was not broadcast across the network, // for example in a coinbase transaction, then the node that's serving us the chain will update its filter // but the rest will not. If another transaction then spends it, the other nodes won't match/relay it. // - // (2) If we receive a p2pubkey output broadcast across the network, all currently connected nodes will see + // (2) If we receive a P2PK/P2WPKH output broadcast across the network, all currently connected nodes will see // it and update their filter themselves, but any newly connected nodes will receive the last filter we // calculated, which would not include this transaction. // - // For this reason we check if the transaction contained any relevant pay to pubkeys and force a recalc + // For this reason we check if the transaction contained any relevant P2PKs or P2WPKHs and force a recalc // and possibly retransmit if so. The recalculation process will end up including the tx hash into the // filter. In case (1), we need to retransmit the filter to the connected peers. In case (2), we don't // and shouldn't, we should just recalculate and cache the new filter for next time. for (TransactionOutput output : tx.getOutputs()) { - if (ScriptPattern.isP2PK(output.getScriptPubKey()) && output.isMine(wallet)) { - if (tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) - recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED); - else - recalculateFastCatchupAndFilter(FilterRecalculateMode.DONT_SEND); - return; + Script scriptPubKey = output.getScriptPubKey(); + if (ScriptPattern.isP2PK(scriptPubKey) || ScriptPattern.isP2WPKH(scriptPubKey)) { + if (output.isMine(wallet)) { + if (tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) + recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED); + else + recalculateFastCatchupAndFilter(FilterRecalculateMode.DONT_SEND); + return; + } } } } diff --git a/core/src/main/java/org/bitcoinj/core/SegwitAddress.java b/core/src/main/java/org/bitcoinj/core/SegwitAddress.java index 96de6c567e1..0601e7ded38 100644 --- a/core/src/main/java/org/bitcoinj/core/SegwitAddress.java +++ b/core/src/main/java/org/bitcoinj/core/SegwitAddress.java @@ -71,7 +71,7 @@ private SegwitAddress(NetworkParameters params, int witnessVersion, byte[] witne private static byte[] encode(int witnessVersion, byte[] witnessProgram) throws AddressFormatException { byte[] convertedProgram = convertBits(witnessProgram, 0, witnessProgram.length, 8, 5, true); byte[] bytes = new byte[1 + convertedProgram.length]; - bytes[0] = (byte) (Script.encodeToOpN(witnessVersion) & 0xff); + bytes[0] = (byte) (witnessVersion & 0xff); System.arraycopy(convertedProgram, 0, bytes, 1, convertedProgram.length); return bytes; } diff --git a/core/src/main/java/org/bitcoinj/core/Transaction.java b/core/src/main/java/org/bitcoinj/core/Transaction.java index 50b8abbe395..99d2baa7946 100644 --- a/core/src/main/java/org/bitcoinj/core/Transaction.java +++ b/core/src/main/java/org/bitcoinj/core/Transaction.java @@ -927,7 +927,7 @@ public TransactionInput addInput(Sha256Hash spendTxHash, long outputIndex, Scrip * to understand the values of sigHash and anyoneCanPay: otherwise you can use the other form of this method * that sets them to typical defaults. * - * @throws ScriptException if the scriptPubKey is not a pay to address or pay to pubkey script. + * @throws ScriptException if the scriptPubKey is not a pay to address or P2PK script. */ public TransactionInput addSignedInput(TransactionOutPoint prevOut, Script scriptPubKey, ECKey sigKey, SigHash sigHash, boolean anyoneCanPay) throws ScriptException { @@ -1040,7 +1040,7 @@ public TransactionOutput addOutput(Coin value, Script script) { * * @param inputIndex Which input to calculate the signature for, as an index. * @param key The private key used to calculate the signature. - * @param redeemScript Byte-exact contents of the scriptPubKey that is being satisified, or the P2SH redeem script. + * @param redeemScript Byte-exact contents of the scriptPubKey that is being satisfied, or the P2SH redeem script. * @param hashType Signing mode, see the enum for documentation. * @param anyoneCanPay Signing mode, see the SigHash enum for documentation. * @return A newly calculated signature object that wraps the r, s and sighash components. @@ -1059,7 +1059,7 @@ public TransactionSignature calculateSignature(int inputIndex, ECKey key, * * @param inputIndex Which input to calculate the signature for, as an index. * @param key The private key used to calculate the signature. - * @param redeemScript The scriptPubKey that is being satisified, or the P2SH redeem script. + * @param redeemScript The scriptPubKey that is being satisfied, or the P2SH redeem script. * @param hashType Signing mode, see the enum for documentation. * @param anyoneCanPay Signing mode, see the SigHash enum for documentation. * @return A newly calculated signature object that wraps the r, s and sighash components. @@ -1080,7 +1080,7 @@ public TransactionSignature calculateSignature(int inputIndex, ECKey key, * @param inputIndex Which input to calculate the signature for, as an index. * @param key The private key used to calculate the signature. * @param aesKey The AES key to use for decryption of the private key. If null then no decryption is required. - * @param redeemScript Byte-exact contents of the scriptPubKey that is being satisified, or the P2SH redeem script. + * @param redeemScript Byte-exact contents of the scriptPubKey that is being satisfied, or the P2SH redeem script. * @param hashType Signing mode, see the enum for documentation. * @param anyoneCanPay Signing mode, see the SigHash enum for documentation. * @return A newly calculated signature object that wraps the r, s and sighash components. @@ -1101,7 +1101,7 @@ public TransactionSignature calculateSignature(int inputIndex, ECKey key, * @param inputIndex Which input to calculate the signature for, as an index. * @param key The private key used to calculate the signature. * @param aesKey The AES key to use for decryption of the private key. If null then no decryption is required. - * @param redeemScript The scriptPubKey that is being satisified, or the P2SH redeem script. + * @param redeemScript The scriptPubKey that is being satisfied, or the P2SH redeem script. * @param hashType Signing mode, see the enum for documentation. * @param anyoneCanPay Signing mode, see the SigHash enum for documentation. * @return A newly calculated signature object that wraps the r, s and sighash components. diff --git a/core/src/main/java/org/bitcoinj/core/Utils.java b/core/src/main/java/org/bitcoinj/core/Utils.java index c8bfd8f703d..4f387404f18 100644 --- a/core/src/main/java/org/bitcoinj/core/Utils.java +++ b/core/src/main/java/org/bitcoinj/core/Utils.java @@ -569,8 +569,8 @@ private enum OS { private static Runtime runtime = null; private static OS os = null; static { - String runtimeProp = System.getProperty("java.runtime.name").toLowerCase(Locale.US); - if (runtimeProp == null) + String runtimeProp = System.getProperty("java.runtime.name", "").toLowerCase(Locale.US); + if (runtimeProp.equals("")) runtime = null; else if (runtimeProp.contains("android")) runtime = Runtime.ANDROID; @@ -581,8 +581,8 @@ else if (runtimeProp.contains("java(tm) se")) else log.info("Unknown java.runtime.name '{}'", runtimeProp); - String osProp = System.getProperty("os.name").toLowerCase(Locale.US); - if (osProp == null) + String osProp = System.getProperty("os.name", "").toLowerCase(Locale.US); + if (osProp.equals("")) os = null; else if (osProp.contains("linux")) os = OS.LINUX; diff --git a/core/src/main/java/org/bitcoinj/core/VersionMessage.java b/core/src/main/java/org/bitcoinj/core/VersionMessage.java index 1d9924c1e99..249489c8d56 100644 --- a/core/src/main/java/org/bitcoinj/core/VersionMessage.java +++ b/core/src/main/java/org/bitcoinj/core/VersionMessage.java @@ -41,7 +41,7 @@ public class VersionMessage extends Message { /** The version of this library release, as a string. */ - public static final String BITCOINJ_VERSION = "0.15.2"; + public static final String BITCOINJ_VERSION = "0.15.5"; /** The value that is prepended to the subVer field of this application. */ public static final String LIBRARY_SUBVER = "/groestlcoinj:" + BITCOINJ_VERSION + "/"; diff --git a/core/src/main/java/org/bitcoinj/crypto/BIP38PrivateKey.java b/core/src/main/java/org/bitcoinj/crypto/BIP38PrivateKey.java index 8642759f26d..75b7c2d52ea 100644 --- a/core/src/main/java/org/bitcoinj/crypto/BIP38PrivateKey.java +++ b/core/src/main/java/org/bitcoinj/crypto/BIP38PrivateKey.java @@ -17,8 +17,9 @@ package org.bitcoinj.crypto; import org.bitcoinj.core.*; +import org.bouncycastle.crypto.generators.SCrypt; + import com.google.common.primitives.Bytes; -import com.lambdaworks.crypto.SCrypt; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; @@ -133,7 +134,7 @@ public ECKey decrypt(String passphrase) throws BadPassphraseException { private ECKey decryptNoEC(String normalizedPassphrase) { try { - byte[] derived = SCrypt.scrypt(normalizedPassphrase.getBytes(StandardCharsets.UTF_8), addressHash, 16384, 8, 8, 64); + byte[] derived = SCrypt.generate(normalizedPassphrase.getBytes(StandardCharsets.UTF_8), addressHash, 16384, 8, 8, 64); byte[] key = Arrays.copyOfRange(derived, 32, 64); SecretKeySpec keyspec = new SecretKeySpec(key, "AES"); @@ -155,7 +156,7 @@ private ECKey decryptEC(String normalizedPassphrase) { byte[] ownerEntropy = Arrays.copyOfRange(content, 0, 8); byte[] ownerSalt = hasLotAndSequence ? Arrays.copyOfRange(ownerEntropy, 0, 4) : ownerEntropy; - byte[] passFactorBytes = SCrypt.scrypt(normalizedPassphrase.getBytes(StandardCharsets.UTF_8), ownerSalt, 16384, 8, 8, 32); + byte[] passFactorBytes = SCrypt.generate(normalizedPassphrase.getBytes(StandardCharsets.UTF_8), ownerSalt, 16384, 8, 8, 32); if (hasLotAndSequence) { byte[] hashBytes = Bytes.concat(passFactorBytes, ownerEntropy); checkState(hashBytes.length == 40); @@ -166,7 +167,7 @@ private ECKey decryptEC(String normalizedPassphrase) { byte[] salt = Bytes.concat(addressHash, ownerEntropy); checkState(salt.length == 12); - byte[] derived = SCrypt.scrypt(k.getPubKey(), salt, 1024, 1, 1, 64); + byte[] derived = SCrypt.generate(k.getPubKey(), salt, 1024, 1, 1, 64); byte[] aeskey = Arrays.copyOfRange(derived, 32, 64); SecretKeySpec keyspec = new SecretKeySpec(aeskey, "AES"); diff --git a/core/src/main/java/org/bitcoinj/crypto/KeyCrypterScrypt.java b/core/src/main/java/org/bitcoinj/crypto/KeyCrypterScrypt.java index cff7e038520..ed236750b7d 100644 --- a/core/src/main/java/org/bitcoinj/crypto/KeyCrypterScrypt.java +++ b/core/src/main/java/org/bitcoinj/crypto/KeyCrypterScrypt.java @@ -20,12 +20,12 @@ import com.google.common.base.Objects; import com.google.common.base.Stopwatch; import com.google.protobuf.ByteString; -import com.lambdaworks.crypto.SCrypt; import org.bitcoinj.core.Utils; import org.bitcoinj.wallet.Protos; import org.bitcoinj.wallet.Protos.ScryptParameters; import org.bitcoinj.wallet.Protos.Wallet.EncryptionType; import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.generators.SCrypt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.bouncycastle.crypto.BufferedBlockCipher; @@ -157,9 +157,9 @@ public KeyParameter deriveKey(CharSequence password) throws KeyCrypterException } final Stopwatch watch = Stopwatch.createStarted(); - byte[] keyBytes = SCrypt.scrypt(passwordBytes, salt, (int) scryptParameters.getN(), scryptParameters.getR(), scryptParameters.getP(), KEY_LENGTH); + byte[] keyBytes = SCrypt.generate(passwordBytes, salt, (int) scryptParameters.getN(), scryptParameters.getR(), scryptParameters.getP(), KEY_LENGTH); watch.stop(); - log.info("Deriving key took {} for {} scrypt iterations.", watch, scryptParameters.getN()); + log.info("Deriving key took {} for {}.", watch, scryptParametersString()); return new KeyParameter(keyBytes); } catch (Exception e) { throw new KeyCrypterException("Could not generate key from password and salt.", e); @@ -264,7 +264,11 @@ public EncryptionType getUnderstoodEncryptionType() { @Override public String toString() { - return "AES-" + KEY_LENGTH * 8 + "-CBC, Scrypt (N: " + scryptParameters.getN() + ")"; + return "AES-" + KEY_LENGTH * 8 + "-CBC, Scrypt (" + scryptParametersString() + ")"; + } + + private String scryptParametersString() { + return "N=" + scryptParameters.getN() + ", r=" + scryptParameters.getR() + ", p=" + scryptParameters.getP(); } @Override diff --git a/core/src/main/java/org/bitcoinj/script/Script.java b/core/src/main/java/org/bitcoinj/script/Script.java index fab1d66a5da..843fffa35ea 100644 --- a/core/src/main/java/org/bitcoinj/script/Script.java +++ b/core/src/main/java/org/bitcoinj/script/Script.java @@ -189,7 +189,7 @@ public List getChunks() { * *

The reason for this split, instead of just interpreting directly, is to make it easier * to reach into a programs structure and pull out bits of data without having to run it. - * This is necessary to render the to/from addresses of transactions in a user interface. + * This is necessary to render the to addresses of transactions in a user interface. * Bitcoin Core does something similar.

*/ private void parse(byte[] program) throws ScriptException { diff --git a/core/src/main/java/org/bitcoinj/script/ScriptChunk.java b/core/src/main/java/org/bitcoinj/script/ScriptChunk.java index a8b2d29830d..fc54d4d5c64 100644 --- a/core/src/main/java/org/bitcoinj/script/ScriptChunk.java +++ b/core/src/main/java/org/bitcoinj/script/ScriptChunk.java @@ -44,11 +44,11 @@ public class ScriptChunk { public final byte[] data; private int startLocationInProgram; - public ScriptChunk(int opcode, byte[] data) { + public ScriptChunk(int opcode, @Nullable byte[] data) { this(opcode, data, -1); } - public ScriptChunk(int opcode, byte[] data, int startLocationInProgram) { + public ScriptChunk(int opcode, @Nullable byte[] data, int startLocationInProgram) { this.opcode = opcode; this.data = data; this.startLocationInProgram = startLocationInProgram; diff --git a/core/src/main/java/org/bitcoinj/script/ScriptPattern.java b/core/src/main/java/org/bitcoinj/script/ScriptPattern.java index ff282e427fa..3f6321e51a6 100644 --- a/core/src/main/java/org/bitcoinj/script/ScriptPattern.java +++ b/core/src/main/java/org/bitcoinj/script/ScriptPattern.java @@ -197,8 +197,8 @@ public static byte[] extractHashFromP2WH(Script script) { } /** - * Returns whether this script matches the format used for multisig outputs: - * {@code [n] [keys...] [m] CHECKMULTISIG} + * Returns whether this script matches the format used for m-of-n multisig outputs: + * {@code [m] [keys...] [n] CHECKMULTISIG} */ public static boolean isSentToMultisig(Script script) { List chunks = script.chunks; diff --git a/core/src/main/java/org/bitcoinj/wallet/Wallet.java b/core/src/main/java/org/bitcoinj/wallet/Wallet.java index b31f6e3be07..6088ff50ea9 100644 --- a/core/src/main/java/org/bitcoinj/wallet/Wallet.java +++ b/core/src/main/java/org/bitcoinj/wallet/Wallet.java @@ -2609,9 +2609,17 @@ private void maybeMovePool(Transaction tx, String context) { } /** - * Calls {@link Wallet#commitTx} if tx is not already in the pending pool + * Updates the wallet with the given transaction: puts it into the pending pool, sets the spent flags and runs + * the onCoinsSent/onCoinsReceived event listener. + *

+ * Triggers an auto save (if enabled.) + *

+ * Unlike {@link Wallet#commitTx} this method does not throw an exception if the transaction + * was already added to the wallet, instead it will return {@code false} * + * @param tx transaction to commit * @return true if the tx was added to the wallet, or false if it was already in the pending pool + * @throws VerificationException If transaction fails to verify */ public boolean maybeCommitTx(Transaction tx) throws VerificationException { tx.verify(); @@ -2699,15 +2707,21 @@ public boolean maybeCommitTx(Transaction tx) throws VerificationException { } /** - *

Updates the wallet with the given transaction: puts it into the pending pool, sets the spent flags and runs - * the onCoinsSent/onCoinsReceived event listener. Used in two situations:

- * + * Updates the wallet with the given transaction: puts it into the pending pool, sets the spent flags and runs + * the onCoinsSent/onCoinsReceived event listener. Used in two situations: + *

*

    *
  1. When we have just successfully transmitted the tx we created to the network.
  2. *
  3. When we receive a pending transaction that didn't appear in the chain yet, and we did not create it.
  4. *
+ *

+ * Triggers an auto save (if enabled.) + *

+ * Unlike {@link Wallet#maybeCommitTx} {@code commitTx} throws an exception if the transaction + * was already added to the wallet. * - *

Triggers an auto save.

+ * @param tx transaction to commit + * @throws VerificationException if transaction was already in the pending pool */ public void commitTx(Transaction tx) throws VerificationException { checkArgument(maybeCommitTx(tx), "commitTx called on the same transaction twice"); diff --git a/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java b/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java index 2b8539c632f..b69dcd52d9f 100644 --- a/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java +++ b/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java @@ -607,8 +607,8 @@ public void shutdown() { } @Test - public void testBloomOnP2Pubkey() throws Exception { - // Cover bug 513. When a relevant transaction with a p2pubkey output is found, the Bloom filter should be + public void testBloomOnP2PK() throws Exception { + // Cover bug 513. When a relevant transaction with a P2PK output is found, the Bloom filter should be // recalculated to include that transaction hash but not re-broadcast as the remote nodes should have followed // the same procedure. However a new node that's connected should get the fresh filter. peerGroup.start(); @@ -616,12 +616,13 @@ public void testBloomOnP2Pubkey() throws Exception { // Create a couple of peers. InboundMessageQueuer p1 = connectPeer(1); InboundMessageQueuer p2 = connectPeer(2); - // Create a pay to pubkey tx. + // Create a P2PK tx. Transaction tx = FakeTxBuilder.createFakeTx(UNITTEST, COIN, key); Transaction tx2 = new Transaction(UNITTEST); tx2.addInput(tx.getOutput(0)); TransactionOutPoint outpoint = tx2.getInput(0).getOutpoint(); assertTrue(p1.lastReceivedFilter.contains(key.getPubKey())); + assertTrue(p1.lastReceivedFilter.contains(key.getPubKeyHash())); assertFalse(p1.lastReceivedFilter.contains(tx.getTxId().getBytes())); inbound(p1, tx); // p1 requests dep resolution, p2 is quiet. @@ -635,6 +636,7 @@ public void testBloomOnP2Pubkey() throws Exception { // Now we connect p3 and there is a new bloom filter sent, that DOES match the relevant outpoint. InboundMessageQueuer p3 = connectPeer(3); assertTrue(p3.lastReceivedFilter.contains(key.getPubKey())); + assertTrue(p3.lastReceivedFilter.contains(key.getPubKeyHash())); assertTrue(p3.lastReceivedFilter.contains(outpoint.unsafeBitcoinSerialize())); } diff --git a/core/src/test/java/org/bitcoinj/script/ScriptTest.java b/core/src/test/java/org/bitcoinj/script/ScriptTest.java index 8777f0b37c7..587557203e5 100644 --- a/core/src/test/java/org/bitcoinj/script/ScriptTest.java +++ b/core/src/test/java/org/bitcoinj/script/ScriptTest.java @@ -437,7 +437,7 @@ public void testCLTVPaymentChannelOutput() { @Test public void getToAddress() throws Exception { - // pay to pubkey + // P2PK ECKey toKey = new ECKey(); Address toAddress = LegacyAddress.fromKey(TESTNET, toKey); assertEquals(toAddress, ScriptBuilder.createP2PKOutputScript(toKey).getToAddress(TESTNET, true)); diff --git a/core/src/test/java/org/bitcoinj/wallet/DefaultRiskAnalysisTest.java b/core/src/test/java/org/bitcoinj/wallet/DefaultRiskAnalysisTest.java index d731352fd1a..5a146d4e251 100644 --- a/core/src/test/java/org/bitcoinj/wallet/DefaultRiskAnalysisTest.java +++ b/core/src/test/java/org/bitcoinj/wallet/DefaultRiskAnalysisTest.java @@ -209,7 +209,7 @@ public void standardOutputs() throws Exception { tx.addInput(MAINNET.getGenesisBlock().getTransactions().get(0).getOutput(0)); // A pay to address output tx.addOutput(Coin.CENT, ScriptBuilder.createP2PKHOutputScript(key1)); - // A pay to pubkey output + // A P2PK output tx.addOutput(Coin.CENT, ScriptBuilder.createP2PKOutputScript(key1)); tx.addOutput(Coin.CENT, ScriptBuilder.createP2PKOutputScript(key1)); // 1-of-2 multisig output. diff --git a/examples/build.gradle b/examples/build.gradle index 5c1b1a0df96..2134d7be043 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -5,12 +5,13 @@ eclipse.project.name = 'bitcoinj-examples' dependencies { implementation project(':core') - implementation 'com.google.guava:guava:27.0.1-android' + implementation 'com.google.guava:guava:27.1-android' implementation 'net.sf.jopt-simple:jopt-simple:5.0.4' - implementation 'org.slf4j:slf4j-jdk14:1.7.25' + implementation 'org.slf4j:slf4j-jdk14:1.7.28' implementation 'org.fusesource.leveldbjni:leveldbjni-all:1.8' } sourceCompatibility = 1.8 compileJava.options.encoding = 'UTF-8' compileTestJava.options.encoding = 'UTF-8' +javadoc.options.encoding = 'UTF-8' diff --git a/tools/build.gradle b/tools/build.gradle index 9a78bfde62c..476b4ecb013 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -5,14 +5,15 @@ eclipse.project.name = 'bitcoinj-tools' dependencies { implementation project(':core') - implementation 'com.google.guava:guava:27.0.1-android' + implementation 'com.google.guava:guava:27.1-android' implementation 'net.sf.jopt-simple:jopt-simple:5.0.4' - implementation 'org.slf4j:slf4j-jdk14:1.7.25' + implementation 'org.slf4j:slf4j-jdk14:1.7.28' } sourceCompatibility = 1.8 compileJava.options.encoding = 'UTF-8' compileTestJava.options.encoding = 'UTF-8' +javadoc.options.encoding = 'UTF-8' task wallet_tool(type: JavaExec) { description = 'Print and manipulate wallets.' diff --git a/wallettemplate/build.gradle b/wallettemplate/build.gradle index 9e0fe15d27a..918bc208300 100644 --- a/wallettemplate/build.gradle +++ b/wallettemplate/build.gradle @@ -11,11 +11,11 @@ eclipse.project.name = 'bitcoinj-wallettemplate' dependencies { implementation project(':core') - implementation 'com.google.guava:guava:27.0.1-android' + implementation 'com.google.guava:guava:27.1-android' implementation 'org.fxmisc.easybind:easybind:1.0.2' implementation 'de.jensd:fontawesomefx:8.0.0' implementation 'net.glxn:qrgen:1.3' - implementation 'org.slf4j:slf4j-jdk14:1.7.25' + implementation 'org.slf4j:slf4j-jdk14:1.7.28' } javafx { @@ -25,6 +25,7 @@ javafx { sourceCompatibility = 1.11 compileJava.options.encoding = 'UTF-8' compileTestJava.options.encoding = 'UTF-8' +javadoc.options.encoding = 'UTF-8' mainClassName = 'wallettemplate.Main'