3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-13 10:45:51 +00:00

Add NetworkParameters to the Context, and verify consistency when a context is fetched.

Make Wallet accept Context as a c'tor parameter and then update unit tests (which switch params very often) to create contexts when necessary.
This commit is contained in:
Mike Hearn 2015-03-01 21:12:00 +01:00
parent 0ba5f61c88
commit aae60d8391
15 changed files with 78 additions and 42 deletions

View File

@ -46,7 +46,7 @@ public class BlockChain extends AbstractBlockChain {
*/ */
public BlockChain(NetworkParameters params, Wallet wallet, BlockStore blockStore) throws BlockStoreException { public BlockChain(NetworkParameters params, Wallet wallet, BlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList<BlockChainListener>(), blockStore); this(params, new ArrayList<BlockChainListener>(), blockStore);
Context.getOrCreate(); Context.getOrCreate(params);
if (wallet != null) if (wallet != null)
addWallet(wallet); addWallet(wallet);
} }

View File

@ -13,14 +13,17 @@ import static com.google.common.base.Preconditions.checkState;
*/ */
public class Context { public class Context {
private static final Logger log = LoggerFactory.getLogger(Context.class); private static final Logger log = LoggerFactory.getLogger(Context.class);
private TxConfidenceTable confidenceTable; private TxConfidenceTable confidenceTable;
private NetworkParameters params;
/** /**
* Creates a new context object. For now, this will be done for you by the framework. Eventually you will be * Creates a new context object. For now, this will be done for you by the framework. Eventually you will be
* expected to do this yourself in the same manner as fetching a NetworkParameters object (at the start of your app). * expected to do this yourself in the same manner as fetching a NetworkParameters object (at the start of your app).
*/ */
public Context() { public Context(NetworkParameters params) {
confidenceTable = new TxConfidenceTable(); this.confidenceTable = new TxConfidenceTable();
this.params = params;
lastConstructed = this; lastConstructed = this;
// We may already have a context in our TLS slot. This can happen a lot during unit tests, so just ignore it. // We may already have a context in our TLS slot. This can happen a lot during unit tests, so just ignore it.
slot.set(this); slot.set(this);
@ -58,14 +61,18 @@ public class Context {
} }
// A temporary internal shim designed to help us migrate internally in a way that doesn't wreck source compatibility. // A temporary internal shim designed to help us migrate internally in a way that doesn't wreck source compatibility.
static Context getOrCreate() { static Context getOrCreate(NetworkParameters params) {
Context context;
try { try {
return get(); context = get();
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
log.warn("Implicitly creating context. This is a migration step and this message will eventually go away."); log.warn("Implicitly creating context. This is a migration step and this message will eventually go away.");
new Context(); context = new Context(params);
return slot.get(); return context;
} }
if (context.getParams() != params)
throw new IllegalStateException("Context does not match implicit network params: " + context.getParams() + " vs " + params);
return context;
} }
/** /**
@ -90,4 +97,13 @@ public class Context {
public TxConfidenceTable getConfidenceTable() { public TxConfidenceTable getConfidenceTable() {
return confidenceTable; return confidenceTable;
} }
/**
* Returns the {@link org.bitcoinj.core.NetworkParameters} specified when this context was (auto) created. The
* network parameters defines various hard coded constants for a specific instance of a Bitcoin network, such as
* main net, testnet, etc.
*/
public NetworkParameters getParams() {
return params;
}
} }

View File

@ -309,7 +309,7 @@ public class PeerGroup implements TransactionBroadcaster {
*/ */
private PeerGroup(NetworkParameters params, @Nullable AbstractBlockChain chain, ClientConnectionManager connectionManager, @Nullable TorClient torClient) { private PeerGroup(NetworkParameters params, @Nullable AbstractBlockChain chain, ClientConnectionManager connectionManager, @Nullable TorClient torClient) {
this.params = checkNotNull(params); this.params = checkNotNull(params);
this.context = Context.getOrCreate(); this.context = Context.getOrCreate(params);
this.chain = chain; this.chain = chain;
fastCatchupTimeSecs = params.getGenesisBlock().getTimeSeconds(); fastCatchupTimeSecs = params.getGenesisBlock().getTimeSeconds();
wallets = new CopyOnWriteArrayList<Wallet>(); wallets = new CopyOnWriteArrayList<Wallet>();

View File

@ -28,6 +28,8 @@ import java.util.concurrent.*;
import static com.google.common.base.Preconditions.*; import static com.google.common.base.Preconditions.*;
// TODO: Modify the getDepthInBlocks method to require the chain height to be specified, in preparation for ceasing to touch every tx on every block.
/** /**
* <p>A TransactionConfidence object tracks data you can use to make a confidence decision about a transaction. * <p>A TransactionConfidence object tracks data you can use to make a confidence decision about a transaction.
* It also contains some pre-canned rules for common scenarios: if you aren't really sure what level of confidence * It also contains some pre-canned rules for common scenarios: if you aren't really sure what level of confidence

View File

@ -212,6 +212,15 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
this(params, new KeyChainGroup(params)); this(params, new KeyChainGroup(params));
} }
/**
* Creates a new, empty wallet with a randomly chosen seed and no transactions. Make sure to provide for sufficient
* backup! Any keys will be derived from the seed. If you want to restore a wallet from disk instead, see
* {@link #loadFromFile}.
*/
public Wallet(Context context) {
this(context, new KeyChainGroup(context.getParams()));
}
public static Wallet fromSeed(NetworkParameters params, DeterministicSeed seed) { public static Wallet fromSeed(NetworkParameters params, DeterministicSeed seed) {
return new Wallet(params, new KeyChainGroup(params, seed)); return new Wallet(params, new KeyChainGroup(params, seed));
} }
@ -244,11 +253,15 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
return new Wallet(params, group); return new Wallet(params, group);
} }
public Wallet(NetworkParameters params, KeyChainGroup keyChainGroup) {
this(Context.getOrCreate(params), keyChainGroup);
}
// TODO: When this class moves to the Wallet package, along with the protobuf serializer, then hide this. // TODO: When this class moves to the Wallet package, along with the protobuf serializer, then hide this.
/** For internal use only. */ /** For internal use only. */
public Wallet(NetworkParameters params, KeyChainGroup keyChainGroup) { public Wallet(Context context, KeyChainGroup keyChainGroup) {
this.context = Context.getOrCreate(); this.context = context;
this.params = checkNotNull(params); this.params = context.getParams();
this.keychain = checkNotNull(keyChainGroup); this.keychain = checkNotNull(keyChainGroup);
if (params == UnitTestParams.get()) if (params == UnitTestParams.get())
this.keychain.setLookaheadSize(5); // Cut down excess computation for unit tests. this.keychain.setLookaheadSize(5); // Cut down excess computation for unit tests.

View File

@ -81,7 +81,7 @@ public class TestWithNetworkConnections {
BriefLogFormatter.init(); BriefLogFormatter.init();
unitTestParams = UnitTestParams.get(); unitTestParams = UnitTestParams.get();
new Context(); new Context(unitTestParams);
Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO; Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO;
this.blockStore = blockStore; this.blockStore = blockStore;
// Allow subclasses to override the wallet object with their own. // Allow subclasses to override the wallet object with their own.

View File

@ -43,13 +43,13 @@ import static org.junit.Assert.*;
* We don't do any wallet tests here, we leave that to {@link ChainSplitTest} * We don't do any wallet tests here, we leave that to {@link ChainSplitTest}
*/ */
public abstract class AbstractFullPrunedBlockChainTest public abstract class AbstractFullPrunedBlockChainTest {
{
private static final Logger log = LoggerFactory.getLogger(AbstractFullPrunedBlockChainTest.class); private static final Logger log = LoggerFactory.getLogger(AbstractFullPrunedBlockChainTest.class);
protected NetworkParameters params; protected NetworkParameters params;
protected FullPrunedBlockChain chain; protected FullPrunedBlockChain chain;
protected FullPrunedBlockStore store; protected FullPrunedBlockStore store;
protected Context context;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@ -59,6 +59,7 @@ public abstract class AbstractFullPrunedBlockChainTest
return 10000; return 10000;
} }
}; };
context = new Context(params);
} }
public abstract FullPrunedBlockStore createStore(NetworkParameters params, int blockCount) public abstract FullPrunedBlockStore createStore(NetworkParameters params, int blockCount)

View File

@ -67,11 +67,13 @@ public class BlockChainTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
BriefLogFormatter.initVerbose(); BriefLogFormatter.initVerbose();
testNetChain = new BlockChain(testNet, new Wallet(testNet), new MemoryBlockStore(testNet)); Context testNetContext = new Context(testNet);
testNetChain = new BlockChain(testNet, new Wallet(testNetContext), new MemoryBlockStore(testNet));
Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO; Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO;
unitTestParams = UnitTestParams.get(); unitTestParams = UnitTestParams.get();
wallet = new Wallet(unitTestParams) { Context context = new Context(unitTestParams);
wallet = new Wallet(context) {
@Override @Override
public void receiveFromBlock(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType, public void receiveFromBlock(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType,
int relativityOffset) throws VerificationException { int relativityOffset) throws VerificationException {

View File

@ -68,6 +68,7 @@ public class BloomFilterTest {
@Test @Test
public void walletTest() throws Exception { public void walletTest() throws Exception {
NetworkParameters params = MainNetParams.get(); NetworkParameters params = MainNetParams.get();
Context context = new Context(params);
DumpedPrivateKey privKey = new DumpedPrivateKey(params, "5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"); DumpedPrivateKey privKey = new DumpedPrivateKey(params, "5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C");
@ -77,7 +78,7 @@ public class BloomFilterTest {
KeyChainGroup group = new KeyChainGroup(params); KeyChainGroup group = new KeyChainGroup(params);
// Add a random key which happens to have been used in a recent generation // Add a random key which happens to have been used in a recent generation
group.importKeys(privKey.getKey(), ECKey.fromPublicOnly(HEX.decode("03cb219f69f1b49468bd563239a86667e74a06fcba69ac50a08a5cbc42a5808e99"))); group.importKeys(privKey.getKey(), ECKey.fromPublicOnly(HEX.decode("03cb219f69f1b49468bd563239a86667e74a06fcba69ac50a08a5cbc42a5808e99")));
Wallet wallet = new Wallet(params, group); Wallet wallet = new Wallet(context, group);
wallet.commitTx(new Transaction(params, HEX.decode("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0d038754030114062f503253482fffffffff01c05e559500000000232103cb219f69f1b49468bd563239a86667e74a06fcba69ac50a08a5cbc42a5808e99ac00000000"))); wallet.commitTx(new Transaction(params, HEX.decode("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0d038754030114062f503253482fffffffff01c05e559500000000232103cb219f69f1b49468bd563239a86667e74a06fcba69ac50a08a5cbc42a5808e99ac00000000")));
// We should have 2 per pubkey, and one for the pay-2-pubkey output we have // We should have 2 per pubkey, and one for the pay-2-pubkey output we have

View File

@ -51,6 +51,7 @@ public class ChainSplitTest {
private Address coinsTo2; private Address coinsTo2;
private Address someOtherGuy; private Address someOtherGuy;
private MemoryBlockStore blockStore; private MemoryBlockStore blockStore;
private Context context;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@ -58,8 +59,9 @@ public class ChainSplitTest {
Utils.setMockClock(); // Use mock clock Utils.setMockClock(); // Use mock clock
Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO; Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO;
unitTestParams = UnitTestParams.get(); unitTestParams = UnitTestParams.get();
context = new Context(unitTestParams);
blockStore = new MemoryBlockStore(unitTestParams); blockStore = new MemoryBlockStore(unitTestParams);
wallet = new Wallet(unitTestParams); wallet = new Wallet(context);
ECKey key1 = wallet.freshReceiveKey(); ECKey key1 = wallet.freshReceiveKey();
ECKey key2 = wallet.freshReceiveKey(); ECKey key2 = wallet.freshReceiveKey();
chain = new BlockChain(unitTestParams, wallet, blockStore); chain = new BlockChain(unitTestParams, wallet, blockStore);

View File

@ -65,8 +65,8 @@ public class CoinbaseBlockTest {
// Create a wallet contain the miner's key that receives a spend from a coinbase. // Create a wallet contain the miner's key that receives a spend from a coinbase.
ECKey miningKey = (new DumpedPrivateKey(params, MINING_PRIVATE_KEY)).getKey(); ECKey miningKey = (new DumpedPrivateKey(params, MINING_PRIVATE_KEY)).getKey();
assertNotNull(miningKey); assertNotNull(miningKey);
Context context = new Context(params);
Wallet wallet = new Wallet(params); Wallet wallet = new Wallet(context);
wallet.importKey(miningKey); wallet.importKey(miningKey);
// Initial balance should be zero by construction. // Initial balance should be zero by construction.

View File

@ -41,6 +41,8 @@ import static org.junit.Assert.assertTrue;
@RunWith(value = Parameterized.class) @RunWith(value = Parameterized.class)
public class FilteredBlockAndPartialMerkleTreeTests extends TestWithPeerGroup { public class FilteredBlockAndPartialMerkleTreeTests extends TestWithPeerGroup {
private Context context;
@Parameterized.Parameters @Parameterized.Parameters
public static Collection<ClientType[]> parameters() { public static Collection<ClientType[]> parameters() {
return Arrays.asList(new ClientType[] {ClientType.NIO_CLIENT_MANAGER}, return Arrays.asList(new ClientType[] {ClientType.NIO_CLIENT_MANAGER},
@ -112,6 +114,7 @@ public class FilteredBlockAndPartialMerkleTreeTests extends TestWithPeerGroup {
@Test @Test
public void serializeDownloadBlockWithWallet() throws Exception { public void serializeDownloadBlockWithWallet() throws Exception {
unitTestParams = UnitTestParams.get(); unitTestParams = UnitTestParams.get();
context = new Context(unitTestParams);
// First we create all the neccessary objects, including lots of serialization and double-checks // First we create all the neccessary objects, including lots of serialization and double-checks
// Note that all serialized forms here are generated by the reference client/pulled from block explorer // Note that all serialized forms here are generated by the reference client/pulled from block explorer

View File

@ -61,7 +61,8 @@ public class LazyParseByteCacheTest {
"b6 3b 50 88 19 90 e4 b4 0d 6a ee 36 29 00 00 00" + "b6 3b 50 88 19 90 e4 b4 0d 6a ee 36 29 00 00 00" +
"00 8b 48 30 45 02 21 00 f3 58 1e 19 72 ae 8a c7" + "00 8b 48 30 45 02 21 00 f3 58 1e 19 72 ae 8a c7" +
"c7 36 7a 7a 25 3b c1 13 52 23 ad b9 a4 68 bb 3a"); "c7 36 7a 7a 25 3b c1 13 52 23 ad b9 a4 68 bb 3a");
private Context context;
private Wallet wallet; private Wallet wallet;
private BlockStore blockStore; private BlockStore blockStore;
private NetworkParameters unitTestParams; private NetworkParameters unitTestParams;
@ -74,7 +75,7 @@ public class LazyParseByteCacheTest {
private byte[] tx2Bytes; private byte[] tx2Bytes;
private byte[] tx2BytesWithHeader; private byte[] tx2BytesWithHeader;
private void resetBlockStore() { private void resetBlockStore() {
blockStore = new MemoryBlockStore(unitTestParams); blockStore = new MemoryBlockStore(unitTestParams);
} }
@ -82,7 +83,8 @@ public class LazyParseByteCacheTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
unitTestParams = UnitTestParams.get(); unitTestParams = UnitTestParams.get();
wallet = new Wallet(unitTestParams); context = new Context(unitTestParams);
wallet = new Wallet(context);
wallet.freshReceiveKey(); wallet.freshReceiveKey();
resetBlockStore(); resetBlockStore();

View File

@ -35,7 +35,7 @@ public class TxConfidenceTableTest {
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
BriefLogFormatter.init(); BriefLogFormatter.init();
Context context = new Context(); Context context = new Context(params);
table = context.getConfidenceTable(); table = context.getConfidenceTable();
Address to = new ECKey().toAddress(params); Address to = new ECKey().toAddress(params);

View File

@ -17,25 +17,19 @@
package org.bitcoinj.wallet; package org.bitcoinj.wallet;
import java.util.Arrays; import com.google.common.collect.*;
import org.bitcoinj.core.*; import org.bitcoinj.core.*;
import org.bitcoinj.crypto.TransactionSignature; import org.bitcoinj.crypto.*;
import org.bitcoinj.params.MainNetParams; import org.bitcoinj.params.*;
import org.bitcoinj.script.Script; import org.bitcoinj.script.*;
import org.bitcoinj.script.ScriptBuilder; import org.bitcoinj.wallet.DefaultRiskAnalysis.*;
import org.bitcoinj.script.ScriptChunk; import org.junit.*;
import com.google.common.collect.ImmutableList;
import org.bitcoinj.wallet.DefaultRiskAnalysis;
import org.bitcoinj.wallet.RiskAnalysis;
import org.bitcoinj.wallet.DefaultRiskAnalysis.RuleViolation;
import org.junit.Before;
import org.junit.Test;
import static org.bitcoinj.core.Coin.COIN; import java.util.*;
import static org.bitcoinj.script.ScriptOpCodes.OP_PUSHDATA1;
import static org.junit.Assert.assertEquals; import static org.bitcoinj.core.Coin.*;
import static org.junit.Assert.assertNull; import static org.bitcoinj.script.ScriptOpCodes.*;
import static org.junit.Assert.fail; import static org.junit.Assert.*;
public class DefaultRiskAnalysisTest { public class DefaultRiskAnalysisTest {
// Uses mainnet because isStandard checks are disabled on testnet. // Uses mainnet because isStandard checks are disabled on testnet.
@ -47,7 +41,7 @@ public class DefaultRiskAnalysisTest {
@Before @Before
public void setup() { public void setup() {
wallet = new Wallet(params) { wallet = new Wallet(new Context(params)) {
@Override @Override
public int getLastBlockSeenHeight() { public int getLastBlockSeenHeight() {
return 1000; return 1000;