3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-07 14:54:15 +00:00
Add lots more nullity annotations.
Clear lots of nullity static analysis warnings.
Delete some dead code.
Simplify a few expressions.

Resolves issue 317.
This commit is contained in:
Mike Hearn 2013-12-24 00:40:19 +00:00
parent 3d99be48bc
commit d0cd770d62
29 changed files with 130 additions and 224 deletions

View File

@ -88,18 +88,19 @@ public class BlockChain extends AbstractBlockChain {
@Override
protected TransactionOutputChanges connectTransactions(int height, Block block) {
// Don't have to do anything as this is only called if(shouldVerifyTransactions())
return null;
throw new UnsupportedOperationException();
}
@Override
protected TransactionOutputChanges connectTransactions(StoredBlock newBlock) {
// Don't have to do anything as this is only called if(shouldVerifyTransactions())
return null;
throw new UnsupportedOperationException();
}
@Override
protected void disconnectTransactions(StoredBlock block) {
// Don't have to do anything as this is only called if(shouldVerifyTransactions())
// Don't have to do anything as this is only called if(shouldVerifyTransactions())
throw new UnsupportedOperationException();
}
@Override

View File

@ -15,6 +15,8 @@
*/
package com.google.bitcoin.core;
import javax.annotation.Nullable;
/**
* Represents a Message type that can be contained within another Message. ChildMessages that have a cached
* backing byte array need to invalidate their parent's caches as well as their own if they are modified.
@ -24,7 +26,7 @@ package com.google.bitcoin.core;
public abstract class ChildMessage extends Message {
private static final long serialVersionUID = -7657113383624517931L;
private Message parent;
@Nullable private Message parent;
protected ChildMessage() {
}
@ -47,13 +49,13 @@ public abstract class ChildMessage extends Message {
super(params, msg, offset);
}
public ChildMessage(NetworkParameters params, byte[] msg, int offset, Message parent, boolean parseLazy, boolean parseRetain, int length)
public ChildMessage(NetworkParameters params, byte[] msg, int offset, @Nullable Message parent, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, msg, offset, parseLazy, parseRetain, length);
this.parent = parent;
}
public void setParent(Message parent) {
public void setParent(@Nullable Message parent) {
if (this.parent != null && this.parent != parent && parent != null) {
// After old parent is unlinked it won't be able to receive notice if this ChildMessage
// changes internally. To be safe we invalidate the parent cache to ensure it rebuilds

View File

@ -161,7 +161,7 @@ public class ECKey implements Serializable {
* is more convenient if you are importing a key from elsewhere. The public key will be automatically derived
* from the private key.
*/
public ECKey(byte[] privKeyBytes, byte[] pubKey) {
public ECKey(@Nullable byte[] privKeyBytes, @Nullable byte[] pubKey) {
this(privKeyBytes == null ? null : new BigInteger(1, privKeyBytes), pubKey);
}
@ -172,7 +172,7 @@ public class ECKey implements Serializable {
* @param pubKey The keys public key
* @param keyCrypter The KeyCrypter that will be used, with an AES key, to encrypt and decrypt the private key
*/
public ECKey(EncryptedPrivateKey encryptedPrivateKey, byte[] pubKey, KeyCrypter keyCrypter) {
public ECKey(@Nullable EncryptedPrivateKey encryptedPrivateKey, @Nullable byte[] pubKey, KeyCrypter keyCrypter) {
this((byte[])null, pubKey);
this.keyCrypter = Preconditions.checkNotNull(keyCrypter);
@ -186,13 +186,15 @@ public class ECKey implements Serializable {
* be used for signing.
* @param compressed If set to true and pubKey is null, the derived public key will be in compressed form.
*/
public ECKey(BigInteger privKey, byte[] pubKey, boolean compressed) {
public ECKey(@Nullable BigInteger privKey, @Nullable byte[] pubKey, boolean compressed) {
if (privKey == null && pubKey == null)
throw new IllegalArgumentException("ECKey requires at least private or public key");
this.priv = privKey;
this.pub = null;
if (pubKey == null && privKey != null) {
if (pubKey == null) {
// Derive public from private.
this.pub = publicKeyFromPrivate(privKey, compressed);
} else if (pubKey != null) {
} else {
// We expect the pubkey to be in regular encoded form, just as a BigInteger. Therefore the first byte is
// a special marker byte.
// TODO: This is probably not a useful API and may be confusing.
@ -206,7 +208,7 @@ public class ECKey implements Serializable {
* the public key already correctly matches the public key. If only the public key is supplied, this ECKey cannot
* be used for signing.
*/
private ECKey(BigInteger privKey, byte[] pubKey) {
private ECKey(@Nullable BigInteger privKey, @Nullable byte[] pubKey) {
this(privKey, pubKey, false);
}
@ -381,7 +383,7 @@ public class ECKey implements Serializable {
r = (DERInteger) seq.getObjectAt(0);
s = (DERInteger) seq.getObjectAt(1);
} catch (ClassCastException e) {
return null;
throw new IllegalArgumentException(e);
}
decoder.close();
// OpenSSL deviates from the DER spec by interpreting these values as unsigned, though they should not be
@ -431,7 +433,7 @@ public class ECKey implements Serializable {
* @param aesKey The AES key to use for decryption of the private key. If null then no decryption is required.
* @throws KeyCrypterException if this ECKey doesn't have a private part.
*/
public ECDSASignature sign(Sha256Hash input, KeyParameter aesKey) throws KeyCrypterException {
public ECDSASignature sign(Sha256Hash input, @Nullable KeyParameter aesKey) throws KeyCrypterException {
if (FAKE_SIGNATURES)
return TransactionSignature.dummy();
@ -601,7 +603,7 @@ public class ECKey implements Serializable {
* @throws IllegalStateException if this ECKey does not have the private part.
* @throws KeyCrypterException if this ECKey is encrypted and no AESKey is provided or it does not decrypt the ECKey.
*/
public String signMessage(String message, KeyParameter aesKey) throws KeyCrypterException {
public String signMessage(String message, @Nullable KeyParameter aesKey) throws KeyCrypterException {
if (priv == null)
throw new IllegalStateException("This ECKey does not have the private key necessary for signing.");
byte[] data = Utils.formatMessageForSigning(message);
@ -702,6 +704,7 @@ public class ECKey implements Serializable {
* @param compressed Whether or not the original pubkey was compressed.
* @return An ECKey containing only the public part, or null if recovery wasn't possible.
*/
@Nullable
public static ECKey recoverFromSignature(int recId, ECDSASignature sig, Sha256Hash message, boolean compressed) {
Preconditions.checkArgument(recId >= 0, "recId must be positive");
Preconditions.checkArgument(sig.r.compareTo(BigInteger.ZERO) >= 0, "r must be positive");

View File

@ -22,6 +22,7 @@ import com.google.bitcoin.store.FullPrunedBlockStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.LinkedList;
@ -124,6 +125,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
this.tx = tx; this.prevOutScripts = prevOutScripts; this.enforcePayToScriptHash = enforcePayToScriptHash;
}
@Nullable
@Override
public VerificationException call() throws Exception {
try{

View File

@ -380,7 +380,7 @@ public abstract class Message implements Serializable {
* so BitcoinSerializer can avoid 2 instanceof checks + a casting.
*/
public Sha256Hash getHash() {
return null;
throw new UnsupportedOperationException();
}
/**
@ -388,8 +388,6 @@ public abstract class Message implements Serializable {
* implemented in a subclass of ChildMessage lazy parsing may have no effect.
*
* This default implementation is a safe fall back that will ensure it returns a correct value by parsing the message.
*
* @return
*/
public int getMessageSize() {
if (length != UNKNOWN_LENGTH)

View File

@ -22,6 +22,7 @@ import com.google.bitcoin.script.ScriptOpCodes;
import com.google.common.base.Objects;
import org.spongycastle.util.encoders.Hex;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.math.BigInteger;
@ -185,6 +186,7 @@ public abstract class NetworkParameters implements Serializable {
}
/** Returns the network parameters for the given string ID or NULL if not recognized. */
@Nullable
public static NetworkParameters fromID(String id) {
if (id.equals(ID_MAINNET)) {
return MainNetParams.get();

View File

@ -16,6 +16,7 @@
package com.google.bitcoin.core;
import javax.annotation.Nullable;
import java.util.List;
/**
@ -85,5 +86,6 @@ public interface PeerEventListener {
* <p>Note that this will never be called if registered with any executor other than
* {@link com.google.bitcoin.utils.Threading#SAME_THREAD}</p>
*/
@Nullable
public List<Message> getData(Peer peer, GetDataMessage m);
}

View File

@ -149,14 +149,6 @@ public class PeerGroup extends AbstractExecutionThreadService implements Transac
private LinkedBlockingQueue<Object> morePeersMailbox = new LinkedBlockingQueue<Object>();
private void handleBlocksDownloaded() {
double rate = chain.getFalsePositiveRate();
if (rate > bloomFilterFPRate * MAX_FP_RATE_INCREASE) {
log.info("Force update Bloom filter due to high false positive rate");
recalculateFastCatchupAndFilter(true);
}
}
private class PeerStartupListener extends AbstractPeerEventListener {
@Override
public void onPeerConnected(Peer peer, int peerCount) {

View File

@ -21,7 +21,6 @@ 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.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -35,6 +34,7 @@ import java.text.SimpleDateFormat;
import java.util.*;
import static com.google.bitcoin.core.Utils.*;
import static com.google.common.base.Preconditions.*;
/**
* <p>A transaction represents the movement of coins from some addresses to some other addresses. It can also represent
@ -172,7 +172,7 @@ public class Transaction extends ChildMessage implements Serializable {
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
public Transaction(NetworkParameters params, byte[] msg, int offset, Message parent, boolean parseLazy, boolean parseRetain, int length)
public Transaction(NetworkParameters params, byte[] msg, int offset, @Nullable Message parent, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, msg, offset, parent, parseLazy, parseRetain, length);
}
@ -180,7 +180,7 @@ public class Transaction extends ChildMessage implements Serializable {
/**
* Creates a transaction by reading payload starting from offset bytes in. Length of a transaction is fixed.
*/
public Transaction(NetworkParameters params, byte[] msg, Message parent, boolean parseLazy, boolean parseRetain, int length)
public Transaction(NetworkParameters params, byte[] msg, @Nullable Message parent, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, msg, 0, parent, parseLazy, parseRetain, length);
}
@ -363,29 +363,6 @@ public class Transaction extends ChildMessage implements Serializable {
return disconnected;
}
/**
* Connects all inputs using the provided transactions. If any input cannot be connected returns that input or
* null on success.
*/
TransactionInput connectForReorganize(Map<Sha256Hash, Transaction> transactions) {
maybeParse();
for (TransactionInput input : inputs) {
// Coinbase transactions, by definition, do not have connectable inputs.
if (input.isCoinBase()) continue;
TransactionInput.ConnectionResult result =
input.connect(transactions, TransactionInput.ConnectMode.ABORT_ON_CONFLICT);
// Connected to another tx in the wallet?
if (result == TransactionInput.ConnectionResult.SUCCESS)
continue;
// The input doesn't exist in the wallet, eg because it belongs to somebody else (inbound spend).
if (result == TransactionInput.ConnectionResult.NO_SUCH_TX)
continue;
// Could not connect this input, so return it and abort.
return input;
}
return null;
}
/**
* Returns true if every output is marked as spent.
*/
@ -795,11 +772,11 @@ public class Transaction extends ChildMessage implements Serializable {
* @param aesKey The AES key to use to decrypt the key before signing. Null if no decryption is required.
*/
public synchronized void signInputs(SigHash hashType, Wallet wallet, @Nullable KeyParameter aesKey) throws ScriptException {
Preconditions.checkState(inputs.size() > 0);
Preconditions.checkState(outputs.size() > 0);
checkState(inputs.size() > 0);
checkState(outputs.size() > 0);
// I don't currently have an easy way to test other modes work, as the official client does not use them.
Preconditions.checkArgument(hashType == SigHash.ALL, "Only SIGHASH_ALL is currently supported");
checkArgument(hashType == SigHash.ALL, "Only SIGHASH_ALL is currently supported");
// The transaction is signed with the input scripts empty except for the input we are signing. In the case
// where addInput has been used to set up a new transaction, they are already all empty. The input being signed
@ -832,8 +809,7 @@ public class Transaction extends ChildMessage implements Serializable {
// Find the signing key we'll need to use.
ECKey key = input.getOutpoint().getConnectedKey(wallet);
// This assert should never fire. If it does, it means the wallet is inconsistent.
Preconditions.checkNotNull(key, "Transaction exists in wallet that we cannot redeem: %s",
input.getOutpoint().getHash());
checkNotNull(key, "Transaction exists in wallet that we cannot redeem: %s", input.getOutpoint().getHash());
// Keep the key around for the script creation step below.
signingKeys[i] = key;
// The anyoneCanPay feature isn't used at the moment.
@ -858,7 +834,9 @@ public class Transaction extends ChildMessage implements Serializable {
if (signatures[i] == null)
continue;
TransactionInput input = inputs.get(i);
Script scriptPubKey = input.getOutpoint().getConnectedOutput().getScriptPubKey();
final TransactionOutput connectedOutput = input.getOutpoint().getConnectedOutput();
checkNotNull(connectedOutput); // Quiet static analysis: is never null here but cannot be statically proven
Script scriptPubKey = connectedOutput.getScriptPubKey();
if (scriptPubKey.isSentToAddress()) {
input.setScriptSig(ScriptBuilder.createInputScript(signatures[i], signingKeys[i]));
} else if (scriptPubKey.isSentToRawPubKey()) {
@ -887,7 +865,7 @@ public class Transaction extends ChildMessage implements Serializable {
* @param anyoneCanPay Signing mode, see the SigHash enum for documentation.
* @return A newly calculated signature object that wraps the r, s and sighash components.
*/
public synchronized TransactionSignature calculateSignature(int inputIndex, ECKey key, KeyParameter aesKey,
public synchronized TransactionSignature calculateSignature(int inputIndex, ECKey key, @Nullable KeyParameter aesKey,
byte[] connectedPubKeyScript,
SigHash hashType, boolean anyoneCanPay) {
Sha256Hash hash = hashForSignature(inputIndex, connectedPubKeyScript, hashType, anyoneCanPay);

View File

@ -22,6 +22,7 @@ import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.ListIterator;
@ -111,17 +112,6 @@ public class TransactionConfidence implements Serializable {
public int getValue() {
return value;
}
public static ConfidenceType valueOf(int value) {
switch (value) {
case 0: return UNKNOWN;
case 1: return BUILDING;
case 2: return PENDING;
case 4: return DEAD;
default: return null;
}
}
}
private ConfidenceType confidenceType = ConfidenceType.UNKNOWN;
@ -402,7 +392,7 @@ public class TransactionConfidence implements Serializable {
* in such a way that the double-spending transaction takes precedence over this one. It will not become valid now
* unless there is a re-org. Automatically sets the confidence type to DEAD.
*/
public synchronized void setOverridingTransaction(Transaction overridingTransaction) {
public synchronized void setOverridingTransaction(@Nullable Transaction overridingTransaction) {
this.overridingTransaction = overridingTransaction;
setConfidenceType(ConfidenceType.DEAD);
}

View File

@ -19,6 +19,7 @@ package com.google.bitcoin.core;
import com.google.bitcoin.script.Script;
import com.google.common.base.Preconditions;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
@ -67,15 +68,13 @@ public class TransactionInput extends ChildMessage implements Serializable {
length = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length);
}
public TransactionInput(NetworkParameters params, Transaction parentTransaction,
byte[] scriptBytes,
TransactionOutPoint outpoint) {
public TransactionInput(NetworkParameters params, @Nullable Transaction parentTransaction, byte[] scriptBytes,
TransactionOutPoint outpoint) {
super(params);
this.scriptBytes = scriptBytes;
this.outpoint = outpoint;
this.sequence = NO_SEQUENCE;
this.parentTransaction = parentTransaction;
length = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length);
}
@ -278,12 +277,12 @@ public class TransactionInput extends ChildMessage implements Serializable {
*
* @return The TransactionOutput or null if the transactions map doesn't contain the referenced tx.
*/
@Nullable
TransactionOutput getConnectedOutput(Map<Sha256Hash, Transaction> transactions) {
Transaction tx = transactions.get(outpoint.getHash());
if (tx == null)
return null;
TransactionOutput out = tx.getOutputs().get((int) outpoint.getIndex());
return out;
return tx.getOutputs().get((int) outpoint.getIndex());
}
public enum ConnectMode {
@ -414,6 +413,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
* {@link TransactionInput#connect(TransactionOutput)} or variants at some point. If it wasn't connected, then
* this method returns null.
*/
@Nullable
public TransactionOutput getConnectedOutput() {
return getOutpoint().getConnectedOutput();
}

View File

@ -18,6 +18,7 @@ package com.google.bitcoin.core;
import com.google.bitcoin.script.Script;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
@ -43,7 +44,7 @@ public class TransactionOutPoint extends ChildMessage implements Serializable {
// It points to the connected transaction.
Transaction fromTx;
public TransactionOutPoint(NetworkParameters params, long index, Transaction fromTx) {
public TransactionOutPoint(NetworkParameters params, long index, @Nullable Transaction fromTx) {
super(params);
this.index = index;
if (fromTx != null) {
@ -114,6 +115,7 @@ public class TransactionOutPoint extends ChildMessage implements Serializable {
* sides in memory, and they have been linked together, this returns a pointer to the connected output, or null
* if there is no such connection.
*/
@Nullable
public TransactionOutput getConnectedOutput() {
if (fromTx == null) return null;
return fromTx.getOutputs().get((int) index);
@ -121,25 +123,20 @@ public class TransactionOutPoint extends ChildMessage implements Serializable {
/**
* Returns the pubkey script from the connected output.
* @throws java.lang.NullPointerException if there is no connected output.
*/
byte[] getConnectedPubKeyScript() {
byte[] result = checkNotNull(getConnectedOutput().getScriptBytes());
byte[] result = checkNotNull(getConnectedOutput()).getScriptBytes();
checkState(result.length > 0);
return result;
}
/**
* Convenience method to get the connected outputs pubkey hash.
*/
byte[] getConnectedPubKeyHash() throws ScriptException {
return getConnectedOutput().getScriptPubKey().getPubKeyHash();
}
/**
* Returns the ECKey identified in the connected output, for either pay-to-address scripts or pay-to-key scripts.
* If the script forms cannot be understood, throws ScriptException.
* @return an ECKey or null if the connected key cannot be found in the wallet.
*/
@Nullable
public ECKey getConnectedKey(Wallet wallet) throws ScriptException {
TransactionOutput connectedOutput = getConnectedOutput();
checkNotNull(connectedOutput, "Input is not connected so cannot retrieve key");

View File

@ -28,9 +28,7 @@ import java.io.OutputStream;
import java.io.Serializable;
import java.math.BigInteger;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Preconditions.*;
/**
* A TransactionOutput message contains a scriptPubKey that controls who is able to spend its value. It is a sub-part
@ -62,7 +60,7 @@ public class TransactionOutput extends ChildMessage implements Serializable {
/**
* Deserializes a transaction output message. This is usually part of a transaction message.
*/
public TransactionOutput(NetworkParameters params, Transaction parent, byte[] payload,
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, byte[] payload,
int offset) throws ProtocolException {
super(params, payload, offset);
parentTransaction = parent;
@ -311,11 +309,10 @@ public class TransactionOutput extends ChildMessage implements Serializable {
}
/**
* Returns the transaction that owns this output, or null if this is a free standing object.
* Returns the transaction that owns this output, or throws NullPointerException if unowned.
*/
@Nullable
public Transaction getParentTransaction() {
return parentTransaction;
return checkNotNull(parentTransaction, "Free-standing TransactionOutput");
}
/**

View File

@ -218,7 +218,7 @@ public class VersionMessage extends Message {
*/
@Override
byte[] getChecksum() {
return null;
throw new UnsupportedOperationException();
}
/**
@ -226,6 +226,7 @@ public class VersionMessage extends Message {
*/
@Override
void setChecksum(byte[] checksum) {
throw new UnsupportedOperationException();
}
@Override

View File

@ -137,7 +137,7 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi
private final NetworkParameters params;
private Sha256Hash lastBlockSeenHash;
@Nullable private Sha256Hash lastBlockSeenHash;
private int lastBlockSeenHeight;
private long lastBlockSeenTimeSecs;
@ -2584,7 +2584,8 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi
}
}
/** Returns the hash of the last seen best-chain block. */
/** Returns the hash of the last seen best-chain block, or null if the wallet is too old to store this data. */
@Nullable
public Sha256Hash getLastBlockSeenHash() {
lock.lock();
try {
@ -2594,7 +2595,7 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi
}
}
public void setLastBlockSeenHash(Sha256Hash lastBlockSeenHash) {
public void setLastBlockSeenHash(@Nullable Sha256Hash lastBlockSeenHash) {
lock.lock();
try {
this.lastBlockSeenHash = lastBlockSeenHash;

View File

@ -156,9 +156,12 @@ public class TransactionSignature extends ECKey.ECDSASignature {
// Bitcoin encoding is DER signature + sighash byte.
if (requireCanonical && !isEncodingCanonical(bytes))
throw new VerificationException("Signature encoding is not canonical.");
ECKey.ECDSASignature sig = ECKey.ECDSASignature.decodeFromDER(bytes);
if (sig == null)
throw new VerificationException("Could not decode DER component.");
ECKey.ECDSASignature sig;
try {
sig = ECKey.ECDSASignature.decodeFromDER(bytes);
} catch (IllegalArgumentException e) {
throw new VerificationException("Could not decode DER", e);
}
TransactionSignature tsig = new TransactionSignature(sig.r, sig.s);
// In Bitcoin, any value of the final byte is valid, but not necessarily canonical. See javadocs for
// isEncodingCanonical to learn more about this.

View File

@ -18,7 +18,6 @@ package com.google.bitcoin.net;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.InputStream;
@ -42,8 +41,8 @@ public class BlockingClient implements MessageWriteTarget {
private static final int BUFFER_SIZE_LOWER_BOUND = 4096;
private static final int BUFFER_SIZE_UPPER_BOUND = 65536;
@Nonnull private final ByteBuffer dbuf;
@Nonnull private final Socket socket;
private final ByteBuffer dbuf;
private final Socket socket;
private volatile boolean vCloseRequested = false;
/**

View File

@ -21,6 +21,7 @@ import com.google.bitcoin.utils.Threading;
import com.google.common.base.Throwables;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import java.io.IOException;
import java.nio.ByteBuffer;
@ -54,7 +55,7 @@ class ConnectionHandler implements MessageWriteTarget {
@GuardedBy("lock") private final ByteBuffer readBuff;
@GuardedBy("lock") private final SocketChannel channel;
@GuardedBy("lock") private final SelectionKey key;
@GuardedBy("lock") final StreamParser parser;
@GuardedBy("lock") StreamParser parser;
@GuardedBy("lock") private boolean closeCalled = false;
@GuardedBy("lock") private long bytesToWriteRemaining = 0;
@ -68,15 +69,15 @@ class ConnectionHandler implements MessageWriteTarget {
throw new IOException("Parser factory.getNewParser returned null");
}
private ConnectionHandler(StreamParser parser, SelectionKey key) {
private ConnectionHandler(@Nullable StreamParser parser, SelectionKey key) {
this.key = key;
this.channel = checkNotNull(((SocketChannel)key.channel()));
this.parser = parser;
if (parser == null) {
readBuff = null;
closeConnection();
return;
}
this.parser = parser;
readBuff = ByteBuffer.allocateDirect(Math.min(Math.max(parser.getMaxMessageSize(), BUFFER_SIZE_LOWER_BOUND), BUFFER_SIZE_UPPER_BOUND));
parser.setWriteTarget(this); // May callback into us (eg closeConnection() now)
connectedHandlers = null;
@ -212,7 +213,7 @@ class ConnectionHandler implements MessageWriteTarget {
// "flip" the buffer - setting the limit to the current position and setting position to 0
handler.readBuff.flip();
// Use parser.receiveBytes's return value as a check that it stopped reading at the right location
int bytesConsumed = handler.parser.receiveBytes(handler.readBuff);
int bytesConsumed = checkNotNull(handler.parser).receiveBytes(handler.readBuff);
checkState(handler.readBuff.position() == bytesConsumed);
// Now drop the bytes which were read by compacting readBuff (resetting limit and keeping relative
// position)

View File

@ -17,6 +17,7 @@ package com.google.bitcoin.net.discovery;
import com.google.bitcoin.core.NetworkParameters;
import javax.annotation.Nullable;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
@ -42,6 +43,7 @@ public class SeedPeers implements PeerDiscovery {
* @return InetSocketAddress - The address/port of the next node.
* @throws PeerDiscoveryException
*/
@Nullable
public InetSocketAddress getPeer() throws PeerDiscoveryException {
try {
return nextPeer();
@ -50,6 +52,7 @@ public class SeedPeers implements PeerDiscovery {
}
}
@Nullable
private InetSocketAddress nextPeer() throws UnknownHostException {
if (pnseedIndex >= seedAddrs.length) return null;
return new InetSocketAddress(convertAddress(seedAddrs[pnseedIndex++]),

View File

@ -16,14 +16,6 @@
package com.google.bitcoin.protocols.channels;
import java.io.IOException;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.bitcoin.core.Sha256Hash;
import com.google.bitcoin.core.TransactionBroadcaster;
import com.google.bitcoin.core.Wallet;
@ -32,6 +24,13 @@ import com.google.bitcoin.net.ProtobufParser;
import com.google.bitcoin.net.StreamParserFactory;
import org.bitcoin.paymentchannel.Protos;
import javax.annotation.Nullable;
import java.io.IOException;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import static com.google.common.base.Preconditions.checkNotNull;
/**
@ -120,7 +119,7 @@ public class PaymentChannelServerListener {
private PaymentChannelCloseException.CloseReason closeReason;
// The user-provided event handler
@Nonnull private ServerConnectionEventHandler eventHandler;
private ServerConnectionEventHandler eventHandler;
// The payment channel server which does the actual payment channel handling
private final PaymentChannelServer paymentChannelManager;

View File

@ -303,7 +303,7 @@ public class PaymentChannelServerState {
// was not connected to the peergroup when the contract was broadcast (which may cause issues down the road, and
// disables our double-spend check next)
Transaction walletContract = wallet.getTransaction(multisigContract.getHash());
checkState(walletContract != null, "Wallet did not contain multisig contract {} after state was marked READY", multisigContract.getHash());
checkNotNull(walletContract, "Wallet did not contain multisig contract {} after state was marked READY", multisigContract.getHash());
// Note that we check for DEAD state here, but this test is essentially useless in production because we will
// miss most double-spends due to bloom filtering right now anyway. This will eventually fixed by network-wide

View File

@ -22,6 +22,8 @@ import com.google.bitcoin.core.Sha256Hash;
import com.google.bitcoin.net.ProtobufParser;
import org.bitcoin.paymentchannel.Protos;
import javax.annotation.Nullable;
/**
* A connection-specific event handler that handles events generated by client connections on a
* {@link PaymentChannelServerListener}
@ -30,7 +32,7 @@ public abstract class ServerConnectionEventHandler {
private ProtobufParser connectionChannel;
// Called by ServerListener before channelOpen to set connectionChannel when it is ready to received application messages
// Also called with null to clear connectionChannel after channelClosed()
synchronized void setConnectionChannel(ProtobufParser connectionChannel) { this.connectionChannel = connectionChannel; }
synchronized void setConnectionChannel(@Nullable ProtobufParser connectionChannel) { this.connectionChannel = connectionChannel; }
/**
* <p>Closes the channel with the client (will generate a

View File

@ -141,6 +141,7 @@ public class StoredPaymentChannelClientStates implements WalletExtension {
/**
* Finds a channel with the given id and contract hash and returns it, or returns null.
*/
@Nullable
StoredClientChannel getChannel(Sha256Hash id, Sha256Hash contractHash) {
lock.lock();
try {

View File

@ -18,6 +18,7 @@ package com.google.bitcoin.protocols.channels;
import com.google.bitcoin.core.*;
import javax.annotation.Nullable;
import java.math.BigInteger;
import java.util.Date;
@ -41,8 +42,8 @@ public class StoredServerChannel {
private PaymentChannelServer connectedHandler = null;
PaymentChannelServerState state = null;
StoredServerChannel(PaymentChannelServerState state, Transaction contract, TransactionOutput clientOutput,
long refundTransactionUnlockTimeSecs, ECKey myKey, BigInteger bestValueToMe, byte[] bestValueSignature) {
StoredServerChannel(@Nullable PaymentChannelServerState state, Transaction contract, TransactionOutput clientOutput,
long refundTransactionUnlockTimeSecs, ECKey myKey, BigInteger bestValueToMe, @Nullable byte[] bestValueSignature) {
this.contract = contract;
this.clientOutput = clientOutput;
this.refundTransactionUnlockTimeSecs = refundTransactionUnlockTimeSecs;

View File

@ -21,6 +21,7 @@ import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -458,6 +459,7 @@ public class H2FullPrunedBlockStore implements FullPrunedBlockStore {
}
}
@Nullable
public StoredBlock get(Sha256Hash hash, boolean wasUndoableOnly) throws BlockStoreException {
// Optimize for chain head
if (chainHeadHash != null && chainHeadHash.equals(hash))
@ -467,8 +469,7 @@ public class H2FullPrunedBlockStore implements FullPrunedBlockStore {
maybeConnect();
PreparedStatement s = null;
try {
s = conn.get()
.prepareStatement("SELECT chainWork, height, header, wasUndoable FROM headers WHERE hash = ?");
s = conn.get().prepareStatement("SELECT chainWork, height, header, wasUndoable FROM headers WHERE hash = ?");
// We skip the first 4 bytes because (on prodnet) the minimum target has 4 0-bytes
byte[] hashBytes = new byte[28];
System.arraycopy(hash.getBytes(), 3, hashBytes, 0, 28);
@ -478,16 +479,13 @@ public class H2FullPrunedBlockStore implements FullPrunedBlockStore {
return null;
}
// Parse it.
if (wasUndoableOnly && !results.getBoolean(4))
return null;
BigInteger chainWork = new BigInteger(results.getBytes(1));
int height = results.getInt(2);
Block b = new Block(params, results.getBytes(3));
b.verifyHeader();
StoredBlock stored = new StoredBlock(b, chainWork, height);
return stored;
return new StoredBlock(b, chainWork, height);
} catch (SQLException ex) {
throw new BlockStoreException(ex);
} catch (ProtocolException e) {
@ -498,21 +496,27 @@ public class H2FullPrunedBlockStore implements FullPrunedBlockStore {
// blocks.
throw new BlockStoreException(e);
} finally {
if (s != null)
if (s != null) {
try {
s.close();
} catch (SQLException e) { throw new BlockStoreException("Failed to close PreparedStatement"); }
} catch (SQLException e) {
throw new BlockStoreException("Failed to close PreparedStatement");
}
}
}
}
@Nullable
public StoredBlock get(Sha256Hash hash) throws BlockStoreException {
return get(hash, false);
}
@Nullable
public StoredBlock getOnceUndoableStoredBlock(Sha256Hash hash) throws BlockStoreException {
return get(hash, true);
}
@Nullable
public StoredUndoableBlock getUndoBlock(Sha256Hash hash) throws BlockStoreException {
maybeConnect();
PreparedStatement s = null;
@ -629,6 +633,7 @@ public class H2FullPrunedBlockStore implements FullPrunedBlockStore {
}
}
@Nullable
public StoredTransactionOutput getTransactionOutput(Sha256Hash hash, long index) throws BlockStoreException {
maybeConnect();
PreparedStatement s = null;
@ -647,8 +652,7 @@ public class H2FullPrunedBlockStore implements FullPrunedBlockStore {
int height = results.getInt(1);
BigInteger value = new BigInteger(results.getBytes(2));
// Tell the StoredTransactionOutput that we are a coinbase, as that is encoded in height
StoredTransactionOutput txout = new StoredTransactionOutput(hash, index, value, height, true, results.getBytes(3));
return txout;
return new StoredTransactionOutput(hash, index, value, height, true, results.getBytes(3));
} catch (SQLException ex) {
throw new BlockStoreException(ex);
} finally {

View File

@ -21,99 +21,10 @@ import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.*;
/**
* A StoredTransaction message contains the information necessary to check a transaction later (ie after a reorg).
* It is used to avoid having to store the entire transaction when we only need its inputs+outputs.
*/
class StoredTransaction implements Serializable {
private static final long serialVersionUID = 6243881368122528323L;
/**
* A transaction has some value and a script used for authenticating that the redeemer is allowed to spend
* this output.
*/
private List<StoredTransactionOutput> outputs;
private List<TransactionInput> inputs;
private long version;
private long lockTime;
private Sha256Hash hash;
public StoredTransaction(NetworkParameters params, Transaction tx, int height) {
inputs = new LinkedList<TransactionInput>();
outputs = new LinkedList<StoredTransactionOutput>();
for (TransactionInput in : tx.getInputs())
inputs.add(new TransactionInput(params, null, in.getScriptBytes(), in.getOutpoint()));
for (TransactionOutput out : tx.getOutputs())
outputs.add(new StoredTransactionOutput(null, out, height, tx.isCoinBase()));
this.version = tx.getVersion();
this.lockTime = tx.getLockTime();
this.hash = tx.getHash();
}
/**
* The lits of inputs in this transaction
*/
public List<TransactionInput> getInputs() {
return inputs;
}
/**
* The lits of outputs in this transaction
* Note that the hashes of all of these are null
*/
public List<StoredTransactionOutput> getOutputs() {
return outputs;
}
/**
* The hash of this stored transaction
*/
public Sha256Hash getHash() {
return hash;
}
/**
* The lockTime of the stored transaction
*/
public long getLockTime() {
return lockTime;
}
/**
* The version of the stored transaction
*/
public long getVersion() {
return version;
}
/**
* A coinbase transaction is one that creates a new coin. They are the first transaction in each block and their
* value is determined by a formula that all implementations of BitCoin share. In 2011 the value of a coinbase
* transaction is 50 coins, but in future it will be less. A coinbase transaction is defined not only by its
* position in a block but by the data in the inputs.
*/
public boolean isCoinBase() {
return inputs.get(0).isCoinBase();
}
public String toString() {
return "Stored Transaction: " + hash.toString();
}
public int hashCode() {
return getHash().hashCode();
}
public boolean equals(Object o) {
if (!(o instanceof StoredTransaction)) return false;
return ((StoredTransaction) o).getHash().equals(this.getHash());
}
}
/**
* Used as a key for memory map (to avoid having to think about NetworkParameters,
* which is required for {@link TransactionOutPoint}
@ -203,6 +114,7 @@ class TransactionalHashMap<KeyType, ValueType> {
tempMap.remove();
}
@Nullable
public ValueType get(KeyType key) {
if (Boolean.TRUE.equals(inTransaction.get())) {
if (tempMap.get() != null) {
@ -228,6 +140,7 @@ class TransactionalHashMap<KeyType, ValueType> {
}
}
@Nullable
public ValueType remove(KeyType key) {
if (Boolean.TRUE.equals(inTransaction.get())) {
ValueType retVal = map.get(key);
@ -275,6 +188,7 @@ class TransactionalMultiKeyHashMap<UniqueKeyType, MultiKeyType, ValueType> {
mapValues.abortDatabaseBatchWrite();
}
@Nullable
public ValueType get(UniqueKeyType key) {
return mapValues.get(key);
}
@ -291,6 +205,7 @@ class TransactionalMultiKeyHashMap<UniqueKeyType, MultiKeyType, ValueType> {
}
}
@Nullable
public ValueType removeByUniqueKey(UniqueKeyType key) {
return mapValues.remove(key);
}
@ -360,18 +275,21 @@ public class MemoryFullPrunedBlockStore implements FullPrunedBlockStore {
blockMap.put(hash, new StoredBlockAndWasUndoableFlag(storedBlock, true));
}
@Nullable
public synchronized StoredBlock get(Sha256Hash hash) throws BlockStoreException {
Preconditions.checkNotNull(blockMap, "MemoryFullPrunedBlockStore is closed");
StoredBlockAndWasUndoableFlag storedBlock = blockMap.get(hash);
return storedBlock == null ? null : storedBlock.block;
}
@Nullable
public synchronized StoredBlock getOnceUndoableStoredBlock(Sha256Hash hash) throws BlockStoreException {
Preconditions.checkNotNull(blockMap, "MemoryFullPrunedBlockStore is closed");
StoredBlockAndWasUndoableFlag storedBlock = blockMap.get(hash);
return (storedBlock != null && storedBlock.wasUndoable) ? storedBlock.block : null;
}
@Nullable
public synchronized StoredUndoableBlock getUndoBlock(Sha256Hash hash) throws BlockStoreException {
Preconditions.checkNotNull(fullBlockMap, "MemoryFullPrunedBlockStore is closed");
return fullBlockMap.get(hash);
@ -408,6 +326,7 @@ public class MemoryFullPrunedBlockStore implements FullPrunedBlockStore {
transactionOutputMap = null;
}
@Nullable
public synchronized StoredTransactionOutput getTransactionOutput(Sha256Hash hash, long index) throws BlockStoreException {
Preconditions.checkNotNull(transactionOutputMap, "MemoryFullPrunedBlockStore is closed");
return transactionOutputMap.get(new StoredTransactionOutPoint(hash, index));

View File

@ -21,6 +21,7 @@ import com.google.bitcoin.utils.Threading;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
@ -74,10 +75,10 @@ public class SPVBlockStore implements BlockStore {
//
// We don't care about the value in this cache. It is always notFoundMarker. Unfortunately LinkedHashSet does not
// provide the removeEldestEntry control.
protected static final StoredBlock notFoundMarker = new StoredBlock(null, null, -1);
protected LinkedHashMap<Sha256Hash, StoredBlock> notFoundCache = new LinkedHashMap<Sha256Hash, StoredBlock>() {
protected static final Object notFoundMarker = new Object();
protected LinkedHashMap<Sha256Hash, Object> notFoundCache = new LinkedHashMap<Sha256Hash, Object>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Sha256Hash, StoredBlock> entry) {
protected boolean removeEldestEntry(Map.Entry<Sha256Hash, Object> entry) {
return size() > 100; // This was chosen arbitrarily.
}
};
@ -181,6 +182,7 @@ public class SPVBlockStore implements BlockStore {
} finally { lock.unlock(); }
}
@Nullable
public StoredBlock get(Sha256Hash hash) throws BlockStoreException {
final MappedByteBuffer buffer = this.buffer;
if (buffer == null) throw new BlockStoreException("Store closed");

View File

@ -364,7 +364,10 @@ public class WalletProtobufSerializer {
public Wallet readWallet(InputStream input) throws UnreadableWalletException {
try {
Protos.Wallet walletProto = parseToProto(input);
NetworkParameters params = NetworkParameters.fromID(walletProto.getNetworkIdentifier());
final String paramsID = walletProto.getNetworkIdentifier();
NetworkParameters params = NetworkParameters.fromID(paramsID);
if (params == null)
throw new UnreadableWalletException("Unknown network parameters ID " + paramsID);
Wallet wallet = new Wallet(params);
readWallet(walletProto, wallet);
return wallet;

View File

@ -25,6 +25,8 @@ import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.util.LinkedList;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A coin selector that takes all coins assigned to keys created before the given timestamp.
* Used as part of the implementation of {@link Wallet#setKeyRotationTime(java.util.Date)}.
@ -65,6 +67,7 @@ public class KeyTimeCoinSelector implements CoinSelector {
log.info("Skipping tx output {} because it's not of simple form.", output);
continue;
}
checkNotNull(controllingKey, "Coin selector given output as candidate for which we lack the key");
if (controllingKey.getCreationTimeSeconds() >= unixTimeSeconds) continue;
// It's older than the cutoff time so select.
valueGathered = valueGathered.add(output.getValue());