org.bitcoinj.wallet.Wallet Maven / Gradle / Ivy
/*
* Copyright 2013 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* 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;
import com.google.common.annotations.*;
import com.google.common.base.*;
import com.google.common.collect.*;
import com.google.common.primitives.*;
import com.google.common.util.concurrent.*;
import com.google.protobuf.*;
import net.jcip.annotations.*;
import org.bitcoinj.core.listeners.*;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Base58;
import org.bitcoinj.core.AbstractBlockChain;
import org.bitcoinj.core.BlockChain;
import org.bitcoinj.core.BloomFilter;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Context;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.FilteredBlock;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Message;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Peer;
import org.bitcoinj.core.PeerFilterProvider;
import org.bitcoinj.core.PeerGroup;
import org.bitcoinj.script.ScriptException;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.StoredBlock;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionBag;
import org.bitcoinj.core.TransactionBroadcast;
import org.bitcoinj.core.TransactionBroadcaster;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutPoint;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.UTXO;
import org.bitcoinj.core.UTXOProvider;
import org.bitcoinj.core.UTXOProviderException;
import org.bitcoinj.core.Utils;
import org.bitcoinj.core.VerificationException;
import org.bitcoinj.core.TransactionConfidence.*;
import org.bitcoinj.crypto.*;
import org.bitcoinj.script.*;
import org.bitcoinj.script.Script.ScriptType;
import org.bitcoinj.signers.*;
import org.bitcoinj.utils.*;
import org.bitcoinj.wallet.Protos.Wallet.*;
import org.bitcoinj.wallet.WalletTransaction.*;
import org.bitcoinj.wallet.listeners.KeyChainEventListener;
import org.bitcoinj.wallet.listeners.ScriptsChangeEventListener;
import org.bitcoinj.wallet.listeners.WalletChangeEventListener;
import org.bitcoinj.wallet.listeners.WalletCoinsReceivedEventListener;
import org.bitcoinj.wallet.listeners.WalletCoinsSentEventListener;
import org.bitcoinj.wallet.listeners.WalletReorganizeEventListener;
import org.slf4j.*;
import org.bouncycastle.crypto.params.*;
import javax.annotation.*;
import java.io.*;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import static com.google.common.base.Preconditions.*;
// To do list:
//
// - Take all wallet-relevant data out of Transaction and put it into WalletTransaction. Make Transaction immutable.
// - Only store relevant transaction outputs, don't bother storing the rest of the data. Big RAM saving.
// - Split block chain and tx output tracking into a superclass that doesn't have any key or spending related code.
// - Simplify how transactions are tracked and stored: in particular, have the wallet maintain positioning information
// for transactions independent of the transactions themselves, so the timeline can be walked without having to
// process and sort every single transaction.
// - Split data persistence out into a backend class and make the wallet transactional, so we can store a wallet
// in a database not just in RAM.
// - Make clearing of transactions able to only rewind the wallet a certain distance instead of all blocks.
// - Make it scale:
// - eliminate all the algorithms with quadratic complexity (or worse)
// - don't require everything to be held in RAM at once
// - consider allowing eviction of no longer re-orgable transactions or keys that were used up
//
// Finally, find more ways to break the class up and decompose it. Currently every time we move code out, other code
// fills up the lines saved!
/**
* A Wallet stores keys and a record of transactions that send and receive value from those keys. Using these,
* it is able to create new transactions that spend the recorded transactions, and this is the fundamental operation
* of the Bitcoin protocol.
*
* To learn more about this class, read
* working with the wallet.
*
* To fill up a Wallet with transactions, you need to use it in combination with a {@link BlockChain} and various
* other objects, see the Getting started tutorial
* on the website to learn more about how to set everything up.
*
* Wallets can be serialized using protocol buffers. You need to save the wallet whenever it changes, there is an
* auto-save feature that simplifies this for you although you're still responsible for manually triggering a save when
* your app is about to quit because the auto-save feature waits a moment before actually committing to disk to avoid IO
* thrashing when the wallet is changing very fast (eg due to a block chain sync). See
* {@link Wallet#autosaveToFile(File, long, TimeUnit, WalletFiles.Listener)}
* for more information about this.
*/
public class Wallet extends BaseTaggableObject
implements NewBestBlockListener, TransactionReceivedInBlockListener, PeerFilterProvider, KeyBag, TransactionBag, ReorganizeListener {
private static final Logger log = LoggerFactory.getLogger(Wallet.class);
private static final int MINIMUM_BLOOM_DATA_LENGTH = 8;
// Ordering: lock > keyChainGroupLock. KeyChainGroup is protected separately to allow fast querying of current receive address
// even if the wallet itself is busy e.g. saving or processing a big reorg. Useful for reducing UI latency.
protected final ReentrantLock lock = Threading.lock("wallet");
protected final ReentrantLock keyChainGroupLock = Threading.lock("wallet-keychaingroup");
// The various pools below give quick access to wallet-relevant transactions by the state they're in:
//
// Pending: Transactions that didn't make it into the best chain yet. Pending transactions can be killed if a
// double spend against them appears in the best chain, in which case they move to the dead pool.
// If a double spend appears in the pending state as well, we update the confidence type
// of all txns in conflict to IN_CONFLICT and wait for the miners to resolve the race.
// Unspent: Transactions that appeared in the best chain and have outputs we can spend. Note that we store the
// entire transaction in memory even though for spending purposes we only really need the outputs, the
// reason being that this simplifies handling of re-orgs. It would be worth fixing this in future.
// Spent: Transactions that appeared in the best chain but don't have any spendable outputs. They're stored here
// for history browsing/auditing reasons only and in future will probably be flushed out to some other
// kind of cold storage or just removed.
// Dead: Transactions that we believe will never confirm get moved here, out of pending. Note that Bitcoin
// Core has no notion of dead-ness: the assumption is that double spends won't happen so there's no
// need to notify the user about them. We take a more pessimistic approach and try to track the fact that
// transactions have been double spent so applications can do something intelligent (cancel orders, show
// to the user in the UI, etc). A transaction can leave dead and move into spent/unspent if there is a
// re-org to a chain that doesn't include the double spend.
private final Map pending;
private final Map unspent;
private final Map spent;
private final Map dead;
// All transactions together.
protected final Map transactions;
// All the TransactionOutput objects that we could spend (ignoring whether we have the private key or not).
// Used to speed up various calculations.
protected final HashSet myUnspents = Sets.newHashSet();
// Transactions that were dropped by the risk analysis system. These are not in any pools and not serialized
// to disk. We have to keep them around because if we ignore a tx because we think it will never confirm, but
// then it actually does confirm and does so within the same network session, remote peers will not resend us
// the tx data along with the Bloom filtered block, as they know we already received it once before
// (so it would be wasteful to repeat). Thus we keep them around here for a while. If we drop our network
// connections then the remote peers will forget that we were sent the tx data previously and send it again
// when relaying a filtered merkleblock.
private final LinkedHashMap riskDropped = new LinkedHashMap() {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > 1000;
}
};
// The key chain group is not thread safe, and generally the whole hierarchy of objects should not be mutated
// outside the wallet lock. So don't expose this object directly via any accessors!
@GuardedBy("keyChainGroupLock") private KeyChainGroup keyChainGroup;
// A list of scripts watched by this wallet.
@GuardedBy("keyChainGroupLock") private Set