3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-13 02:35:52 +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 {
this(params, new ArrayList<BlockChainListener>(), blockStore);
Context.getOrCreate();
Context.getOrCreate(params);
if (wallet != null)
addWallet(wallet);
}

View File

@ -13,14 +13,17 @@ import static com.google.common.base.Preconditions.checkState;
*/
public class Context {
private static final Logger log = LoggerFactory.getLogger(Context.class);
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
* expected to do this yourself in the same manner as fetching a NetworkParameters object (at the start of your app).
*/
public Context() {
confidenceTable = new TxConfidenceTable();
public Context(NetworkParameters params) {
this.confidenceTable = new TxConfidenceTable();
this.params = params;
lastConstructed = this;
// 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);
@ -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.
static Context getOrCreate() {
static Context getOrCreate(NetworkParameters params) {
Context context;
try {
return get();
context = get();
} catch (IllegalStateException e) {
log.warn("Implicitly creating context. This is a migration step and this message will eventually go away.");
new Context();
return slot.get();
context = new Context(params);
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() {
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) {
this.params = checkNotNull(params);
this.context = Context.getOrCreate();
this.context = Context.getOrCreate(params);
this.chain = chain;
fastCatchupTimeSecs = params.getGenesisBlock().getTimeSeconds();
wallets = new CopyOnWriteArrayList<Wallet>();

View File

@ -28,6 +28,8 @@ import java.util.concurrent.*;
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.
* 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));
}
/**
* 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) {
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);
}
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.
/** For internal use only. */
public Wallet(NetworkParameters params, KeyChainGroup keyChainGroup) {
this.context = Context.getOrCreate();
this.params = checkNotNull(params);
public Wallet(Context context, KeyChainGroup keyChainGroup) {
this.context = context;
this.params = context.getParams();
this.keychain = checkNotNull(keyChainGroup);
if (params == UnitTestParams.get())
this.keychain.setLookaheadSize(5); // Cut down excess computation for unit tests.

View File

@ -81,7 +81,7 @@ public class TestWithNetworkConnections {
BriefLogFormatter.init();
unitTestParams = UnitTestParams.get();
new Context();
new Context(unitTestParams);
Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO;
this.blockStore = blockStore;
// 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}
*/
public abstract class AbstractFullPrunedBlockChainTest
{
public abstract class AbstractFullPrunedBlockChainTest {
private static final Logger log = LoggerFactory.getLogger(AbstractFullPrunedBlockChainTest.class);
protected NetworkParameters params;
protected FullPrunedBlockChain chain;
protected FullPrunedBlockStore store;
protected Context context;
@Before
public void setUp() throws Exception {
@ -59,6 +59,7 @@ public abstract class AbstractFullPrunedBlockChainTest
return 10000;
}
};
context = new Context(params);
}
public abstract FullPrunedBlockStore createStore(NetworkParameters params, int blockCount)

View File

@ -67,11 +67,13 @@ public class BlockChainTest {
@Before
public void setUp() throws Exception {
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;
unitTestParams = UnitTestParams.get();
wallet = new Wallet(unitTestParams) {
Context context = new Context(unitTestParams);
wallet = new Wallet(context) {
@Override
public void receiveFromBlock(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType,
int relativityOffset) throws VerificationException {

View File

@ -68,6 +68,7 @@ public class BloomFilterTest {
@Test
public void walletTest() throws Exception {
NetworkParameters params = MainNetParams.get();
Context context = new Context(params);
DumpedPrivateKey privKey = new DumpedPrivateKey(params, "5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C");
@ -77,7 +78,7 @@ public class BloomFilterTest {
KeyChainGroup group = new KeyChainGroup(params);
// Add a random key which happens to have been used in a recent generation
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")));
// 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 someOtherGuy;
private MemoryBlockStore blockStore;
private Context context;
@Before
public void setUp() throws Exception {
@ -58,8 +59,9 @@ public class ChainSplitTest {
Utils.setMockClock(); // Use mock clock
Wallet.SendRequest.DEFAULT_FEE_PER_KB = Coin.ZERO;
unitTestParams = UnitTestParams.get();
context = new Context(unitTestParams);
blockStore = new MemoryBlockStore(unitTestParams);
wallet = new Wallet(unitTestParams);
wallet = new Wallet(context);
ECKey key1 = wallet.freshReceiveKey();
ECKey key2 = wallet.freshReceiveKey();
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.
ECKey miningKey = (new DumpedPrivateKey(params, MINING_PRIVATE_KEY)).getKey();
assertNotNull(miningKey);
Wallet wallet = new Wallet(params);
Context context = new Context(params);
Wallet wallet = new Wallet(context);
wallet.importKey(miningKey);
// Initial balance should be zero by construction.

View File

@ -41,6 +41,8 @@ import static org.junit.Assert.assertTrue;
@RunWith(value = Parameterized.class)
public class FilteredBlockAndPartialMerkleTreeTests extends TestWithPeerGroup {
private Context context;
@Parameterized.Parameters
public static Collection<ClientType[]> parameters() {
return Arrays.asList(new ClientType[] {ClientType.NIO_CLIENT_MANAGER},
@ -112,6 +114,7 @@ public class FilteredBlockAndPartialMerkleTreeTests extends TestWithPeerGroup {
@Test
public void serializeDownloadBlockWithWallet() throws Exception {
unitTestParams = UnitTestParams.get();
context = new Context(unitTestParams);
// 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

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" +
"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");
private Context context;
private Wallet wallet;
private BlockStore blockStore;
private NetworkParameters unitTestParams;
@ -74,7 +75,7 @@ public class LazyParseByteCacheTest {
private byte[] tx2Bytes;
private byte[] tx2BytesWithHeader;
private void resetBlockStore() {
blockStore = new MemoryBlockStore(unitTestParams);
}
@ -82,7 +83,8 @@ public class LazyParseByteCacheTest {
@Before
public void setUp() throws Exception {
unitTestParams = UnitTestParams.get();
wallet = new Wallet(unitTestParams);
context = new Context(unitTestParams);
wallet = new Wallet(context);
wallet.freshReceiveKey();
resetBlockStore();

View File

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

View File

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