diff --git a/core/src/main/java/org/bitcoinj/core/Wallet.java b/core/src/main/java/org/bitcoinj/core/Wallet.java index ba8b8379..c18ecaee 100644 --- a/core/src/main/java/org/bitcoinj/core/Wallet.java +++ b/core/src/main/java/org/bitcoinj/core/Wallet.java @@ -17,23 +17,6 @@ package org.bitcoinj.core; -import org.bitcoinj.core.TransactionConfidence.ConfidenceType; -import org.bitcoinj.crypto.*; -import org.bitcoinj.params.UnitTestParams; -import org.bitcoinj.script.Script; -import org.bitcoinj.script.ScriptBuilder; -import org.bitcoinj.script.ScriptChunk; -import org.bitcoinj.signers.MissingSigResolutionSigner; -import org.bitcoinj.signers.LocalTransactionSigner; -import org.bitcoinj.signers.TransactionSigner; -import org.bitcoinj.store.UnreadableWalletException; -import org.bitcoinj.store.WalletProtobufSerializer; -import org.bitcoinj.utils.BaseTaggableObject; -import org.bitcoinj.utils.ExchangeRate; -import org.bitcoinj.utils.ListenerRegistration; -import org.bitcoinj.utils.Threading; -import org.bitcoinj.wallet.*; -import org.bitcoinj.wallet.WalletTransaction.Pool; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; import com.google.common.base.Objects.ToStringHelper; @@ -44,21 +27,40 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import com.google.protobuf.ByteString; - +import net.jcip.annotations.GuardedBy; import org.bitcoin.protocols.payments.Protos.PaymentDetails; +import org.bitcoinj.core.TransactionConfidence.ConfidenceType; +import org.bitcoinj.crypto.*; +import org.bitcoinj.params.UnitTestParams; +import org.bitcoinj.script.Script; +import org.bitcoinj.script.ScriptBuilder; +import org.bitcoinj.script.ScriptChunk; +import org.bitcoinj.signers.LocalTransactionSigner; +import org.bitcoinj.signers.MissingSigResolutionSigner; +import org.bitcoinj.signers.TransactionSigner; +import org.bitcoinj.store.UnreadableWalletException; +import org.bitcoinj.store.WalletProtobufSerializer; +import org.bitcoinj.utils.BaseTaggableObject; +import org.bitcoinj.utils.ExchangeRate; +import org.bitcoinj.utils.ListenerRegistration; +import org.bitcoinj.utils.Threading; +import org.bitcoinj.wallet.*; import org.bitcoinj.wallet.Protos.Wallet.EncryptionType; +import org.bitcoinj.wallet.WalletTransaction.Pool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.crypto.params.KeyParameter; import javax.annotation.Nullable; -import javax.annotation.concurrent.GuardedBy; import java.io.*; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import static com.google.common.base.Preconditions.*; @@ -106,7 +108,10 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha private static final long serialVersionUID = 2L; private static final int MINIMUM_BLOOM_DATA_LENGTH = 8; + // Ordering: lock > keychainLock. Keychain 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 ReentrantReadWriteLock keychainLock = Threading.factory.newReentrantReadWriteLock("wallet-keychain"); // The various pools below give quick access to wallet-relevant transactions by the state they're in: // @@ -151,7 +156,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha // 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("lock") protected KeyChainGroup keychain; + @GuardedBy("keychainLock") protected KeyChainGroup keychain; // A list of scripts watched by this wallet. private Set