mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-11-02 05:27:17 +00:00
Add BIP 34 enforcement
This patch primarily enforces block height being present in the coinbase transaction input, altough it introduces a number of other fixes and changes to support this. * VersionTally now returns the number of blocks at or above a version, rather than just at, to enable forward-compatible support (i.e. v3 blocks include all v2 block tests) * Block version is now explicitely provided in most tests which generate blocks, in order to ensure correct tests are applied * Block height is now used when generating coinbase transactions * Added support for the chain parameters to determine which tests apply to a block, so altcoins can override the defaults if needed. * Added initial checks ahead of full BIP 66 validation checks
This commit is contained in:
@@ -436,14 +436,25 @@ public abstract class AbstractBlockChain {
|
||||
return true;
|
||||
}
|
||||
|
||||
final StoredBlock storedPrev;
|
||||
final int height;
|
||||
final EnumSet<VerificationFlags> flags;
|
||||
|
||||
// Prove the block is internally valid: hash is lower than target, etc. This only checks the block contents
|
||||
// if there is a tx sending or receiving coins using an address in one of our wallets. And those transactions
|
||||
// are only lightly verified: presence in a valid connecting block is taken as proof of validity. See the
|
||||
// article here for more details: http://code.google.com/p/bitcoinj/wiki/SecurityModel
|
||||
try {
|
||||
block.verifyHeader();
|
||||
storedPrev = getStoredBlockInCurrentScope(block.getPrevBlockHash());
|
||||
if (storedPrev != null) {
|
||||
height = storedPrev.getHeight() + 1;
|
||||
} else {
|
||||
height = Block.BLOCK_HEIGHT_UNKNOWN;
|
||||
}
|
||||
flags = params.getValidationFlags(block, versionTally, height);
|
||||
if (shouldVerifyTransactions())
|
||||
block.verifyTransactions();
|
||||
block.verifyTransactions(height, flags);
|
||||
} catch (VerificationException e) {
|
||||
log.error("Failed to verify block: ", e);
|
||||
log.error(block.getHashAsString());
|
||||
@@ -451,7 +462,6 @@ public abstract class AbstractBlockChain {
|
||||
}
|
||||
|
||||
// Try linking it to a place in the currently known blocks.
|
||||
StoredBlock storedPrev = getStoredBlockInCurrentScope(block.getPrevBlockHash());
|
||||
|
||||
if (storedPrev == null) {
|
||||
// We can't find the previous block. Probably we are still in the process of downloading the chain and a
|
||||
@@ -526,7 +536,7 @@ public abstract class AbstractBlockChain {
|
||||
// net, less on test) in order to be applied. It is also limited to
|
||||
// stopping addition of new v2 blocks to the tip of the chain.
|
||||
if (block.getVersion() == Block.BLOCK_VERSION_BIP34) {
|
||||
final Integer count = versionTally.getCount(Block.BLOCK_VERSION_BIP66);
|
||||
final Integer count = versionTally.getCountAtOrAbove(Block.BLOCK_VERSION_BIP66);
|
||||
if (count != null
|
||||
&& count >= params.getMajorityRejectBlockOutdated()) {
|
||||
throw new VerificationException.BlockVersionOutOfDate(block.getVersion());
|
||||
|
||||
@@ -30,13 +30,18 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.bitcoinj.core.Coin.FIFTY_COINS;
|
||||
import static org.bitcoinj.core.Sha256Hash.hashTwice;
|
||||
import org.bitcoinj.script.ScriptChunk;
|
||||
|
||||
/**
|
||||
* <p>A block is a group of transactions, and is one of the fundamental data structures of the Bitcoin system.
|
||||
@@ -72,6 +77,11 @@ public class Block extends Message {
|
||||
/** A value for difficultyTarget (nBits) that allows half of all possible hash solutions. Used in unit testing. */
|
||||
public static final long EASIEST_DIFFICULTY_TARGET = 0x207fFFFFL;
|
||||
|
||||
/** Value to use if the block height is unknown */
|
||||
public static final int BLOCK_HEIGHT_UNKNOWN = -1;
|
||||
/** Height of the first block */
|
||||
public static final int BLOCK_HEIGHT_GENESIS = 0;
|
||||
|
||||
public static final long BLOCK_VERSION_GENESIS = 1;
|
||||
/** Block version introduced in BIP 34: Height in coinbase */
|
||||
public static final long BLOCK_VERSION_BIP34 = 2;
|
||||
@@ -610,10 +620,21 @@ public class Block extends Message {
|
||||
return tree;
|
||||
}
|
||||
|
||||
private void checkTransactions() throws VerificationException {
|
||||
/**
|
||||
* Verify the transactions on a block.
|
||||
*
|
||||
* @param height block height, if known, or -1 otherwise. If provided, used
|
||||
* to validate the coinbase input script of v2 and above blocks.
|
||||
* @throws VerificationException if there was an error verifying the block.
|
||||
*/
|
||||
private void checkTransactions(final int height, final EnumSet<VerificationFlags> flags)
|
||||
throws VerificationException {
|
||||
// The first transaction in a block must always be a coinbase transaction.
|
||||
if (!transactions.get(0).isCoinBase())
|
||||
throw new VerificationException("First tx is not coinbase");
|
||||
if (flags.contains(VerificationFlags.HEIGHT_IN_COINBASE) && height >= BLOCK_HEIGHT_GENESIS) {
|
||||
transactions.get(0).checkCoinBaseHeight(height);
|
||||
}
|
||||
// The rest must not be.
|
||||
for (int i = 1; i < transactions.size(); i++) {
|
||||
if (transactions.get(i).isCoinBase())
|
||||
@@ -642,9 +663,13 @@ public class Block extends Message {
|
||||
/**
|
||||
* Checks the block contents
|
||||
*
|
||||
* @throws VerificationException
|
||||
* @param height block height, if known, or -1 otherwise. If valid, used
|
||||
* to validate the coinbase input script of v2 and above blocks.
|
||||
* @param flags flags to indicate which tests should be applied (i.e.
|
||||
* whether to test for height in the coinbase transaction).
|
||||
* @throws VerificationException if there was an error verifying the block.
|
||||
*/
|
||||
public void verifyTransactions() throws VerificationException {
|
||||
public void verifyTransactions(final int height, final EnumSet<VerificationFlags> flags) throws VerificationException {
|
||||
// Now we need to check that the body of the block actually matches the headers. The network won't generate
|
||||
// an invalid block, but if we didn't validate this then an untrusted man-in-the-middle could obtain the next
|
||||
// valid block from the network and simply replace the transactions in it with their own fictional
|
||||
@@ -653,7 +678,7 @@ public class Block extends Message {
|
||||
throw new VerificationException("Block had no transactions");
|
||||
if (this.getOptimalEncodingMessageSize() > MAX_BLOCK_SIZE)
|
||||
throw new VerificationException("Block larger than MAX_BLOCK_SIZE");
|
||||
checkTransactions();
|
||||
checkTransactions(height, flags);
|
||||
checkMerkleRoot();
|
||||
checkSigOps();
|
||||
for (Transaction transaction : transactions)
|
||||
@@ -662,10 +687,15 @@ public class Block extends Message {
|
||||
|
||||
/**
|
||||
* Verifies both the header and that the transactions hash to the merkle root.
|
||||
*
|
||||
* @param height block height, if known, or -1 otherwise.
|
||||
* @param flags flags to indicate which tests should be applied (i.e.
|
||||
* whether to test for height in the coinbase transaction).
|
||||
* @throws VerificationException if there was an error verifying the block.
|
||||
*/
|
||||
public void verify() throws VerificationException {
|
||||
public void verify(final int height, final EnumSet<VerificationFlags> flags) throws VerificationException {
|
||||
verifyHeader();
|
||||
verifyTransactions();
|
||||
verifyTransactions(height, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -808,19 +838,30 @@ public class Block extends Message {
|
||||
// Used to make transactions unique.
|
||||
private static int txCounter;
|
||||
|
||||
/** Adds a coinbase transaction to the block. This exists for unit tests. */
|
||||
/** Adds a coinbase transaction to the block. This exists for unit tests.
|
||||
*
|
||||
* @param height block height, if known, or -1 otherwise.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void addCoinbaseTransaction(byte[] pubKeyTo, Coin value) {
|
||||
void addCoinbaseTransaction(byte[] pubKeyTo, Coin value, final int height) {
|
||||
unCacheTransactions();
|
||||
transactions = new ArrayList<Transaction>();
|
||||
Transaction coinbase = new Transaction(params);
|
||||
final ScriptBuilder inputBuilder = new ScriptBuilder();
|
||||
|
||||
if (height >= Block.BLOCK_HEIGHT_GENESIS) {
|
||||
final byte[] blockHeightBytes = ScriptBuilder.createHeightScriptData(height);
|
||||
inputBuilder.data(blockHeightBytes);
|
||||
}
|
||||
inputBuilder.data(new byte[]{(byte) txCounter, (byte) (txCounter++ >> 8)});
|
||||
|
||||
// A real coinbase transaction has some stuff in the scriptSig like the extraNonce and difficulty. The
|
||||
// transactions are distinguished by every TX output going to a different key.
|
||||
//
|
||||
// Here we will do things a bit differently so a new address isn't needed every time. We'll put a simple
|
||||
// counter in the scriptSig so every transaction has a different hash.
|
||||
coinbase.addInput(new TransactionInput(params, coinbase,
|
||||
new ScriptBuilder().data(new byte[]{(byte) txCounter, (byte) (txCounter++ >> 8)}).build().getProgram()));
|
||||
inputBuilder.build().getProgram()));
|
||||
coinbase.addOutput(new TransactionOutput(params, coinbase, value,
|
||||
ScriptBuilder.createOutputScript(ECKey.fromPublicOnly(pubKeyTo)).getProgram()));
|
||||
transactions.add(coinbase);
|
||||
@@ -838,19 +879,24 @@ public class Block extends Message {
|
||||
* Returns a solved block that builds on top of this one. This exists for unit tests.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public Block createNextBlock(Address to, long version, long time) {
|
||||
return createNextBlock(to, version, null, time, pubkeyForTesting, FIFTY_COINS);
|
||||
public Block createNextBlock(Address to, long version, long time, Integer blockHeight) {
|
||||
return createNextBlock(to, version, (TransactionOutPoint) null, time,
|
||||
pubkeyForTesting, FIFTY_COINS, blockHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a solved block that builds on top of this one. This exists for unit tests.
|
||||
* In this variant you can specify a public key (pubkey) for use in generating coinbase blocks.
|
||||
*
|
||||
* @param height block height, if known, or -1 otherwise.
|
||||
*/
|
||||
Block createNextBlock(@Nullable Address to, long version, @Nullable TransactionOutPoint prevOut,
|
||||
long time, byte[] pubKey, Coin coinbaseValue) {
|
||||
Block createNextBlock(@Nullable final Address to, final long version,
|
||||
@Nullable TransactionOutPoint prevOut, final long time,
|
||||
final byte[] pubKey, final Coin coinbaseValue,
|
||||
final int height) {
|
||||
Block b = new Block(params, version);
|
||||
b.setDifficultyTarget(difficultyTarget);
|
||||
b.addCoinbaseTransaction(pubKey, coinbaseValue);
|
||||
b.addCoinbaseTransaction(pubKey, coinbaseValue, height);
|
||||
|
||||
if (to != null) {
|
||||
// Add a transaction paying 50 coins to the "to" address.
|
||||
@@ -885,17 +931,20 @@ public class Block extends Message {
|
||||
} catch (VerificationException e) {
|
||||
throw new RuntimeException(e); // Cannot happen.
|
||||
}
|
||||
if (b.getVersion() != version) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Block createNextBlock(@Nullable Address to, TransactionOutPoint prevOut) {
|
||||
return createNextBlock(to, 1, prevOut, getTimeSeconds() + 5, pubkeyForTesting, FIFTY_COINS);
|
||||
return createNextBlock(to, BLOCK_VERSION_GENESIS, prevOut, getTimeSeconds() + 5, pubkeyForTesting, FIFTY_COINS, BLOCK_HEIGHT_UNKNOWN);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Block createNextBlock(@Nullable Address to, Coin value) {
|
||||
return createNextBlock(to, 1, null, getTimeSeconds() + 5, pubkeyForTesting, value);
|
||||
return createNextBlock(to, BLOCK_VERSION_GENESIS, null, getTimeSeconds() + 5, pubkeyForTesting, value, BLOCK_HEIGHT_UNKNOWN);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -904,8 +953,9 @@ public class Block extends Message {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Block createNextBlockWithCoinbase(byte[] pubKey, Coin coinbaseValue) {
|
||||
return createNextBlock(null, 1, null, Utils.currentTimeSeconds(), pubKey, coinbaseValue);
|
||||
public Block createNextBlockWithCoinbase(long version, byte[] pubKey, Coin coinbaseValue, final int height) {
|
||||
return createNextBlock(null, version, (TransactionOutPoint) null,
|
||||
Utils.currentTimeSeconds(), pubKey, coinbaseValue, height);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -913,8 +963,9 @@ public class Block extends Message {
|
||||
* This method is intended for test use only.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
Block createNextBlockWithCoinbase(byte[] pubKey) {
|
||||
return createNextBlock(null, 1, null, Utils.currentTimeSeconds(), pubKey, FIFTY_COINS);
|
||||
Block createNextBlockWithCoinbase(long version, byte[] pubKey, final int height) {
|
||||
return createNextBlock(null, version, (TransactionOutPoint) null,
|
||||
Utils.currentTimeSeconds(), pubKey, FIFTY_COINS, height);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -35,6 +35,7 @@ import java.math.*;
|
||||
import java.util.*;
|
||||
|
||||
import static org.bitcoinj.core.Coin.*;
|
||||
import org.bitcoinj.utils.VersionTally;
|
||||
|
||||
/**
|
||||
* <p>NetworkParameters contains the data needed for working with an instantiation of a Bitcoin chain.</p>
|
||||
@@ -476,4 +477,32 @@ public abstract class NetworkParameters {
|
||||
public int getMajorityWindow() {
|
||||
return majorityWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* The flags indicating which block validation tests should be applied to
|
||||
* the given block. Enables support for alternative blockchains which enable
|
||||
* tests based on different criteria.
|
||||
*
|
||||
* @param block block to determine flags for.
|
||||
* @param height height of the block, if known, null otherwise. Returned
|
||||
* tests should be a safe subset if block height is unknown.
|
||||
*/
|
||||
public EnumSet<VerificationFlags> getValidationFlags(final Block block,
|
||||
final VersionTally tally, final Integer height) {
|
||||
final EnumSet<VerificationFlags> flags = EnumSet.noneOf(VerificationFlags.class);
|
||||
|
||||
if (block.getVersion() >= Block.BLOCK_VERSION_BIP34) {
|
||||
final Integer count = tally.getCountAtOrAbove(Block.BLOCK_VERSION_BIP34);
|
||||
if (null != count && count >= getMajorityEnforceBlockUpgrade()) {
|
||||
flags.add(VerificationFlags.HEIGHT_IN_COINBASE);
|
||||
}
|
||||
}
|
||||
if (block.getVersion() >= Block.BLOCK_VERSION_BIP66) {
|
||||
final Integer count = tally.getCountAtOrAbove(Block.BLOCK_VERSION_BIP66);
|
||||
if (null != count && count >= getMajorityEnforceBlockUpgrade()) {
|
||||
flags.add(VerificationFlags.DER_SIGNATURE_FORMAT);
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ import java.util.*;
|
||||
|
||||
import static org.bitcoinj.core.Utils.*;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import org.bitcoinj.script.ScriptChunk;
|
||||
|
||||
/**
|
||||
* <p>A transaction represents the movement of coins from some addresses to some other addresses. It can also represent
|
||||
@@ -1163,6 +1166,39 @@ public class Transaction extends ChildMessage {
|
||||
return sigOps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check block height is in coinbase input script, for use after BIP 34
|
||||
* enforcement is enabled.
|
||||
*/
|
||||
public void checkCoinBaseHeight(final int height)
|
||||
throws VerificationException {
|
||||
assert height >= Block.BLOCK_HEIGHT_GENESIS;
|
||||
assert isCoinBase();
|
||||
|
||||
// Check block height is in coinbase input script
|
||||
final TransactionInput in = this.getInputs().get(0);
|
||||
final List<ScriptChunk> chunks;
|
||||
|
||||
try {
|
||||
final Script scriptSig = in.getScriptSig();
|
||||
chunks = scriptSig.getChunks();
|
||||
} catch(ScriptException e) {
|
||||
throw new VerificationException("Coinbase input script signature is invalid.", e);
|
||||
}
|
||||
if (chunks.isEmpty()) {
|
||||
throw new VerificationException("Coinbase input script signature is empty.");
|
||||
}
|
||||
final ScriptChunk chunk = chunks.get(0);
|
||||
if (!chunk.isPushData()) {
|
||||
throw new VerificationException("First element of coinbase input script signature is not pushdata.");
|
||||
}
|
||||
final byte[] data = chunk.data;
|
||||
final byte[] expected = ScriptBuilder.createHeightScriptData(height);
|
||||
if (!Arrays.equals(data, expected)) {
|
||||
throw new VerificationException.CoinbaseHeightMismatch("Coinbase height mismatch.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Checks the transaction contents for sanity, in ways that can be done in a standalone manner.
|
||||
* Does <b>not</b> perform all checks on a transaction such as whether the inputs are already spent.
|
||||
|
||||
@@ -80,4 +80,10 @@ public class VerificationException extends RuntimeException {
|
||||
super("Coinbase input as input in non-coinbase transaction");
|
||||
}
|
||||
}
|
||||
|
||||
public static class CoinbaseHeightMismatch extends VerificationException {
|
||||
public CoinbaseHeightMismatch(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
27
core/src/main/java/org/bitcoinj/core/VerificationFlags.java
Normal file
27
core/src/main/java/org/bitcoinj/core/VerificationFlags.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2015 Ross Nicoll
|
||||
*
|
||||
* 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.core;
|
||||
|
||||
/**
|
||||
* Flags used to control which elements of block validation are performed on
|
||||
* received blocks.
|
||||
*/
|
||||
public enum VerificationFlags {
|
||||
/** Check that block height is in coinbase transaction (BIP 34) */
|
||||
HEIGHT_IN_COINBASE,
|
||||
/** Check DER signature format is exact (BIP 66) */
|
||||
DER_SIGNATURE_FORMAT
|
||||
}
|
||||
@@ -18,6 +18,8 @@
|
||||
package org.bitcoinj.params;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bitcoinj.core.Block;
|
||||
import org.bitcoinj.core.Coin;
|
||||
@@ -33,6 +35,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.bitcoinj.core.BitcoinSerializer;
|
||||
import org.bitcoinj.core.VerificationFlags;
|
||||
import org.bitcoinj.utils.VersionTally;
|
||||
|
||||
/**
|
||||
* Parameters for Bitcoin-like networks.
|
||||
|
||||
@@ -30,6 +30,8 @@ import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import static org.bitcoinj.script.ScriptOpCodes.*;
|
||||
|
||||
/**
|
||||
@@ -344,4 +346,17 @@ public class ScriptBuilder {
|
||||
checkArgument(data.length <= 40);
|
||||
return new ScriptBuilder().op(OP_RETURN).data(data).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create script data bytes to represent the given block height.
|
||||
*/
|
||||
public static byte[] createHeightScriptData(final int height) {
|
||||
// TODO: Replace with something generic to any integer value
|
||||
final byte[] int32Buffer = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(height).array();
|
||||
if (int32Buffer[3] == 0) {
|
||||
return Arrays.copyOf(int32Buffer, 3);
|
||||
} else {
|
||||
return int32Buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,12 +167,13 @@ public class FakeTxBuilder {
|
||||
}
|
||||
|
||||
/** Emulates receiving a valid block that builds on top of the chain. */
|
||||
public static BlockPair createFakeBlock(BlockStore blockStore, long version, long timeSeconds,
|
||||
public static BlockPair createFakeBlock(BlockStore blockStore, long version,
|
||||
long timeSeconds, int height,
|
||||
Transaction... transactions) {
|
||||
try {
|
||||
Block chainHead = blockStore.getChainHead().getHeader();
|
||||
Address to = new ECKey().toAddress(chainHead.getParams());
|
||||
Block b = chainHead.createNextBlock(to, version, timeSeconds);
|
||||
Block b = chainHead.createNextBlock(to, version, timeSeconds, height);
|
||||
// Coinbase tx was already added.
|
||||
for (Transaction tx : transactions) {
|
||||
tx.getConfidence().setSource(TransactionConfidence.Source.NETWORK);
|
||||
@@ -193,8 +194,9 @@ public class FakeTxBuilder {
|
||||
}
|
||||
|
||||
/** Emulates receiving a valid block that builds on top of the chain. */
|
||||
public static BlockPair createFakeBlock(BlockStore blockStore, Transaction... transactions) {
|
||||
return createFakeBlock(blockStore, Block.BLOCK_VERSION_GENESIS, Utils.currentTimeSeconds(), transactions);
|
||||
public static BlockPair createFakeBlock(BlockStore blockStore, Integer height,
|
||||
Transaction... transactions) {
|
||||
return createFakeBlock(blockStore, Block.BLOCK_VERSION_GENESIS, Utils.currentTimeSeconds(), height, transactions);
|
||||
}
|
||||
|
||||
public static Block makeSolvedTestBlock(BlockStore blockStore, Address coinsTo) throws BlockStoreException {
|
||||
|
||||
@@ -68,7 +68,7 @@ public class TestWithWallet {
|
||||
if (wallet.isPendingTransactionRelevant(tx))
|
||||
wallet.receivePending(tx, null);
|
||||
} else {
|
||||
FakeTxBuilder.BlockPair bp = createFakeBlock(blockStore, tx);
|
||||
FakeTxBuilder.BlockPair bp = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, tx);
|
||||
wallet.receiveFromBlock(tx, bp.storedBlock, type, 0);
|
||||
if (type == AbstractBlockChain.NewBlockType.BEST_CHAIN)
|
||||
wallet.notifyNewBestBlock(bp.storedBlock);
|
||||
|
||||
@@ -68,19 +68,19 @@ public class VersionTally {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the count for a block version within the window.
|
||||
* Get the count of blocks at or above the given version, within the window.
|
||||
*
|
||||
* @param version the block version to query.
|
||||
* @return the count for the block version, or null if the window is not yet
|
||||
* full.
|
||||
*/
|
||||
public Integer getCount(final long version) {
|
||||
public Integer getCountAtOrAbove(final long version) {
|
||||
if (versionsStored < versionWindow.length) {
|
||||
return null;
|
||||
}
|
||||
int count = 0;
|
||||
for (int versionIdx = 0; versionIdx < versionWindow.length; versionIdx++) {
|
||||
if (versionWindow[versionIdx] == version) {
|
||||
if (versionWindow[versionIdx] >= version) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,13 +37,20 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.bitcoinj.core.Coin.FIFTY_COINS;
|
||||
import org.bitcoinj.store.BlockStore;
|
||||
import org.bitcoinj.store.MemoryBlockStore;
|
||||
import org.bitcoinj.testing.FakeTxBuilder;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
/**
|
||||
* We don't do any wallet tests here, we leave that to {@link ChainSplitTest}
|
||||
*/
|
||||
|
||||
public abstract class AbstractFullPrunedBlockChainTest {
|
||||
@org.junit.Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AbstractFullPrunedBlockChainTest.class);
|
||||
|
||||
protected NetworkParameters params;
|
||||
@@ -125,13 +132,14 @@ public abstract class AbstractFullPrunedBlockChainTest {
|
||||
// to the full StoredUndoableBlock's lying around (ie memory leaks)
|
||||
|
||||
ECKey outKey = new ECKey();
|
||||
int height = 1;
|
||||
|
||||
// Build some blocks on genesis block to create a spendable output
|
||||
Block rollingBlock = params.getGenesisBlock().createNextBlockWithCoinbase(outKey.getPubKey());
|
||||
Block rollingBlock = params.getGenesisBlock().createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++);
|
||||
chain.add(rollingBlock);
|
||||
TransactionOutput spendableOutput = rollingBlock.getTransactions().get(0).getOutput(0);
|
||||
for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) {
|
||||
rollingBlock = rollingBlock.createNextBlockWithCoinbase(outKey.getPubKey());
|
||||
rollingBlock = rollingBlock.createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++);
|
||||
chain.add(rollingBlock);
|
||||
}
|
||||
|
||||
@@ -164,14 +172,15 @@ public abstract class AbstractFullPrunedBlockChainTest {
|
||||
// to the full StoredUndoableBlock's lying around (ie memory leaks)
|
||||
|
||||
ECKey outKey = new ECKey();
|
||||
|
||||
int height = 1;
|
||||
|
||||
// Build some blocks on genesis block to create a spendable output
|
||||
Block rollingBlock = params.getGenesisBlock().createNextBlockWithCoinbase(outKey.getPubKey());
|
||||
Block rollingBlock = params.getGenesisBlock().createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++);
|
||||
chain.add(rollingBlock);
|
||||
TransactionOutPoint spendableOutput = new TransactionOutPoint(params, 0, rollingBlock.getTransactions().get(0).getHash());
|
||||
byte[] spendableOutputScriptPubKey = rollingBlock.getTransactions().get(0).getOutputs().get(0).getScriptBytes();
|
||||
for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) {
|
||||
rollingBlock = rollingBlock.createNextBlockWithCoinbase(outKey.getPubKey());
|
||||
rollingBlock = rollingBlock.createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++);
|
||||
chain.add(rollingBlock);
|
||||
}
|
||||
|
||||
@@ -237,15 +246,16 @@ public abstract class AbstractFullPrunedBlockChainTest {
|
||||
// Check that we aren't accidentally leaving any references
|
||||
// to the full StoredUndoableBlock's lying around (ie memory leaks)
|
||||
ECKey outKey = new ECKey();
|
||||
int height = 1;
|
||||
|
||||
// Build some blocks on genesis block to create a spendable output
|
||||
Block rollingBlock = params.getGenesisBlock().createNextBlockWithCoinbase(outKey.getPubKey());
|
||||
Block rollingBlock = params.getGenesisBlock().createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++);
|
||||
chain.add(rollingBlock);
|
||||
Transaction transaction = rollingBlock.getTransactions().get(0);
|
||||
TransactionOutPoint spendableOutput = new TransactionOutPoint(params, 0, transaction.getHash());
|
||||
byte[] spendableOutputScriptPubKey = transaction.getOutputs().get(0).getScriptBytes();
|
||||
for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) {
|
||||
rollingBlock = rollingBlock.createNextBlockWithCoinbase(outKey.getPubKey());
|
||||
rollingBlock = rollingBlock.createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++);
|
||||
chain.add(rollingBlock);
|
||||
}
|
||||
rollingBlock = rollingBlock.createNextBlock(null);
|
||||
@@ -287,15 +297,16 @@ public abstract class AbstractFullPrunedBlockChainTest {
|
||||
// Check that we aren't accidentally leaving any references
|
||||
// to the full StoredUndoableBlock's lying around (ie memory leaks)
|
||||
ECKey outKey = new ECKey();
|
||||
int height = 1;
|
||||
|
||||
// Build some blocks on genesis block to create a spendable output.
|
||||
Block rollingBlock = params.getGenesisBlock().createNextBlockWithCoinbase(outKey.getPubKey());
|
||||
Block rollingBlock = params.getGenesisBlock().createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++);
|
||||
chain.add(rollingBlock);
|
||||
Transaction transaction = rollingBlock.getTransactions().get(0);
|
||||
TransactionOutPoint spendableOutput = new TransactionOutPoint(params, 0, transaction.getHash());
|
||||
byte[] spendableOutputScriptPubKey = transaction.getOutputs().get(0).getScriptBytes();
|
||||
for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) {
|
||||
rollingBlock = rollingBlock.createNextBlockWithCoinbase(outKey.getPubKey());
|
||||
rollingBlock = rollingBlock.createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++);
|
||||
chain.add(rollingBlock);
|
||||
}
|
||||
rollingBlock = rollingBlock.createNextBlock(null);
|
||||
@@ -340,4 +351,58 @@ public abstract class AbstractFullPrunedBlockChainTest {
|
||||
store.close();
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that if the block height is missing from coinbase of a version 2
|
||||
* block, it's rejected.
|
||||
*/
|
||||
@Test
|
||||
public void missingHeightFromCoinbase() throws Exception {
|
||||
final int UNDOABLE_BLOCKS_STORED = params.getMajorityEnforceBlockUpgrade() + 1;
|
||||
store = createStore(params, UNDOABLE_BLOCKS_STORED);
|
||||
try {
|
||||
chain = new FullPrunedBlockChain(params, store);
|
||||
ECKey outKey = new ECKey();
|
||||
int height = 1;
|
||||
Block chainHead = params.getGenesisBlock();
|
||||
|
||||
// Build some blocks on genesis block to create a spendable output.
|
||||
|
||||
// Put in just enough v1 blocks to stop the v2 blocks from forming a majority
|
||||
for (height = 1; height <= (params.getMajorityWindow() - params.getMajorityEnforceBlockUpgrade()); height++) {
|
||||
chainHead = chainHead.createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS,
|
||||
outKey.getPubKey(), height);
|
||||
chain.add(chainHead);
|
||||
}
|
||||
|
||||
// Fill the rest of the window in with v2 blocks
|
||||
for (; height < params.getMajorityWindow(); height++) {
|
||||
chainHead = chainHead.createNextBlockWithCoinbase(Block.BLOCK_VERSION_BIP34,
|
||||
outKey.getPubKey(), height);
|
||||
chain.add(chainHead);
|
||||
}
|
||||
// Throw a broken v2 block in before we have a supermajority to enable
|
||||
// enforcement, which should validate as-is
|
||||
chainHead = chainHead.createNextBlockWithCoinbase(Block.BLOCK_VERSION_BIP34,
|
||||
outKey.getPubKey(), height * 2);
|
||||
chain.add(chainHead);
|
||||
height++;
|
||||
|
||||
// Trying to add a broken v2 block should now result in rejection as
|
||||
// we have a v2 supermajority
|
||||
thrown.expect(VerificationException.CoinbaseHeightMismatch.class);
|
||||
chainHead = chainHead.createNextBlockWithCoinbase(Block.BLOCK_VERSION_BIP34,
|
||||
outKey.getPubKey(), height * 2);
|
||||
chain.add(chainHead);
|
||||
} catch(final VerificationException ex) {
|
||||
throw (Exception) ex.getCause();
|
||||
} finally {
|
||||
try {
|
||||
store.close();
|
||||
} catch(Exception e) {
|
||||
// Catch and drop any exception so a break mid-test doesn't result
|
||||
// in a new exception being thrown and the original lost
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,11 +131,12 @@ public class BlockChainTest {
|
||||
|
||||
@Test
|
||||
public void receiveCoins() throws Exception {
|
||||
int height = 1;
|
||||
// Quick check that we can actually receive coins.
|
||||
Transaction tx1 = createFakeTx(unitTestParams,
|
||||
COIN,
|
||||
wallet.currentReceiveKey().toAddress(unitTestParams));
|
||||
Block b1 = createFakeBlock(blockStore, tx1).block;
|
||||
Block b1 = createFakeBlock(blockStore, height, tx1).block;
|
||||
chain.add(b1);
|
||||
assertTrue(wallet.getBalance().signum() > 0);
|
||||
}
|
||||
@@ -161,8 +162,8 @@ public class BlockChainTest {
|
||||
// artificially shortened period.
|
||||
Block prev = unitTestParams.getGenesisBlock();
|
||||
Utils.setMockClock(System.currentTimeMillis()/1000);
|
||||
for (int i = 0; i < unitTestParams.getInterval() - 1; i++) {
|
||||
Block newBlock = prev.createNextBlock(coinbaseTo, 1, Utils.currentTimeSeconds());
|
||||
for (int height = 0; height < unitTestParams.getInterval() - 1; height++) {
|
||||
Block newBlock = prev.createNextBlock(coinbaseTo, 1, Utils.currentTimeSeconds(), height);
|
||||
assertTrue(chain.add(newBlock));
|
||||
prev = newBlock;
|
||||
// The fake chain should seem to be "fast" for the purposes of difficulty calculations.
|
||||
@@ -170,13 +171,13 @@ public class BlockChainTest {
|
||||
}
|
||||
// Now add another block that has no difficulty adjustment, it should be rejected.
|
||||
try {
|
||||
chain.add(prev.createNextBlock(coinbaseTo, 1, Utils.currentTimeSeconds()));
|
||||
chain.add(prev.createNextBlock(coinbaseTo, 1, Utils.currentTimeSeconds(), unitTestParams.getInterval()));
|
||||
fail();
|
||||
} catch (VerificationException e) {
|
||||
}
|
||||
// Create a new block with the right difficulty target given our blistering speed relative to the huge amount
|
||||
// of time it's supposed to take (set in the unit test network parameters).
|
||||
Block b = prev.createNextBlock(coinbaseTo, 1, Utils.currentTimeSeconds());
|
||||
Block b = prev.createNextBlock(coinbaseTo, 1, Utils.currentTimeSeconds(), unitTestParams.getInterval() + 1);
|
||||
b.setDifficultyTarget(0x201fFFFFL);
|
||||
b.solve();
|
||||
assertTrue(chain.add(b));
|
||||
@@ -234,23 +235,23 @@ public class BlockChainTest {
|
||||
|
||||
// Build a historical chain of version 3 blocks
|
||||
long timeSeconds = 1231006505;
|
||||
int blockCount = 0;
|
||||
int height = 0;
|
||||
FakeTxBuilder.BlockPair chainHead = null;
|
||||
|
||||
// Put in just enough v2 blocks to be a minority
|
||||
for (blockCount = 0; blockCount < (unitTestParams.getMajorityWindow() - unitTestParams.getMajorityRejectBlockOutdated()); blockCount++) {
|
||||
chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, Block.BLOCK_VERSION_BIP34, timeSeconds);
|
||||
for (height = 0; height < (unitTestParams.getMajorityWindow() - unitTestParams.getMajorityRejectBlockOutdated()); height++) {
|
||||
chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, Block.BLOCK_VERSION_BIP34, timeSeconds, height);
|
||||
versionChain.add(chainHead.block);
|
||||
timeSeconds += 60;
|
||||
}
|
||||
// Fill the rest of the window with v3 blocks
|
||||
for (; blockCount < unitTestParams.getMajorityWindow(); blockCount++) {
|
||||
chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, Block.BLOCK_VERSION_BIP66, timeSeconds);
|
||||
for (; height < unitTestParams.getMajorityWindow(); height++) {
|
||||
chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, Block.BLOCK_VERSION_BIP66, timeSeconds, height);
|
||||
versionChain.add(chainHead.block);
|
||||
timeSeconds += 60;
|
||||
}
|
||||
|
||||
chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, Block.BLOCK_VERSION_BIP34, timeSeconds);
|
||||
chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, Block.BLOCK_VERSION_BIP34, timeSeconds, height);
|
||||
// Trying to add a new v2 block should result in rejection
|
||||
thrown.expect(VerificationException.BlockVersionOutOfDate.class);
|
||||
try {
|
||||
@@ -306,12 +307,13 @@ public class BlockChainTest {
|
||||
// Create a second wallet to receive the coinbase spend.
|
||||
Wallet wallet2 = new Wallet(unitTestParams);
|
||||
ECKey receiveKey = wallet2.freshReceiveKey();
|
||||
int height = 1;
|
||||
chain.addWallet(wallet2);
|
||||
|
||||
Address addressToSendTo = receiveKey.toAddress(unitTestParams);
|
||||
|
||||
// Create a block, sending the coinbase to the coinbaseTo address (which is in the wallet).
|
||||
Block b1 = unitTestParams.getGenesisBlock().createNextBlockWithCoinbase(wallet.currentReceiveKey().getPubKey());
|
||||
Block b1 = unitTestParams.getGenesisBlock().createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, wallet.currentReceiveKey().getPubKey(), height++);
|
||||
chain.add(b1);
|
||||
|
||||
// Check a transaction has been received.
|
||||
@@ -335,7 +337,7 @@ public class BlockChainTest {
|
||||
Transaction tx2 = createFakeTx(unitTestParams, COIN,
|
||||
new ECKey().toAddress(unitTestParams));
|
||||
|
||||
Block b2 = createFakeBlock(blockStore, tx2).block;
|
||||
Block b2 = createFakeBlock(blockStore, height++, tx2).block;
|
||||
chain.add(b2);
|
||||
|
||||
// Wallet still does not have the coinbase transaction available for spend.
|
||||
@@ -355,7 +357,7 @@ public class BlockChainTest {
|
||||
|
||||
// Give it one more block - should now be able to spend coinbase transaction. Non relevant tx.
|
||||
Transaction tx3 = createFakeTx(unitTestParams, COIN, new ECKey().toAddress(unitTestParams));
|
||||
Block b3 = createFakeBlock(blockStore, tx3).block;
|
||||
Block b3 = createFakeBlock(blockStore, height++, tx3).block;
|
||||
chain.add(b3);
|
||||
|
||||
// Wallet now has the coinbase transaction available for spend.
|
||||
@@ -374,7 +376,7 @@ public class BlockChainTest {
|
||||
assertEquals(wallet.getBalance(BalanceType.AVAILABLE), ZERO);
|
||||
|
||||
// Give it one more block - change from coinbaseSpend should now be available in the first wallet.
|
||||
Block b4 = createFakeBlock(blockStore, coinbaseSend2).block;
|
||||
Block b4 = createFakeBlock(blockStore, height++, coinbaseSend2).block;
|
||||
chain.add(b4);
|
||||
assertEquals(wallet.getBalance(BalanceType.AVAILABLE), COIN);
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.junit.Test;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import static org.bitcoinj.core.Utils.HEX;
|
||||
import static org.junit.Assert.*;
|
||||
@@ -57,7 +58,7 @@ public class BlockTest {
|
||||
@Test
|
||||
public void testBlockVerification() throws Exception {
|
||||
Block block = params.getDefaultSerializer().makeBlock(blockBytes);
|
||||
block.verify();
|
||||
block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(VerificationFlags.class));
|
||||
assertEquals("00000000a6e5eb79dcec11897af55e90cd571a4335383a3ccfbc12ec81085935", block.getHashAsString());
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ public class BlockTest {
|
||||
Block block = params.getDefaultSerializer().makeBlock(blockBytes);
|
||||
block.setNonce(12346);
|
||||
try {
|
||||
block.verify();
|
||||
block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(VerificationFlags.class));
|
||||
fail();
|
||||
} catch (VerificationException e) {
|
||||
// Expected.
|
||||
@@ -84,18 +85,18 @@ public class BlockTest {
|
||||
// from containing artificially weak difficulties.
|
||||
block.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET);
|
||||
// Now it should pass.
|
||||
block.verify();
|
||||
block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(VerificationFlags.class));
|
||||
// Break the nonce again at the lower difficulty level so we can try solving for it.
|
||||
block.setNonce(1);
|
||||
try {
|
||||
block.verify();
|
||||
block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(VerificationFlags.class));
|
||||
fail();
|
||||
} catch (VerificationException e) {
|
||||
// Expected to fail as the nonce is no longer correct.
|
||||
}
|
||||
// Should find an acceptable nonce.
|
||||
block.solve();
|
||||
block.verify();
|
||||
block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(VerificationFlags.class));
|
||||
assertEquals(block.getNonce(), 2);
|
||||
}
|
||||
|
||||
@@ -108,7 +109,7 @@ public class BlockTest {
|
||||
block.transactions.set(0, tx2);
|
||||
block.transactions.set(1, tx1);
|
||||
try {
|
||||
block.verify();
|
||||
block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(VerificationFlags.class));
|
||||
fail();
|
||||
} catch (VerificationException e) {
|
||||
// We should get here.
|
||||
@@ -136,7 +137,7 @@ public class BlockTest {
|
||||
@Test
|
||||
public void testUpdateLength() {
|
||||
NetworkParameters params = UnitTestParams.get();
|
||||
Block block = params.getGenesisBlock().createNextBlockWithCoinbase(new ECKey().getPubKey());
|
||||
Block block = params.getGenesisBlock().createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, new ECKey().getPubKey(), Block.BLOCK_HEIGHT_GENESIS);
|
||||
assertEquals(block.bitcoinSerialize().length, block.length);
|
||||
final int origBlockLen = block.length;
|
||||
Transaction tx = new Transaction(params);
|
||||
|
||||
@@ -566,7 +566,7 @@ public class ChainSplitTest {
|
||||
|
||||
Block b1 = unitTestParams.getGenesisBlock().createNextBlock(someOtherGuy);
|
||||
final ECKey coinsTo2 = wallet.freshReceiveKey();
|
||||
Block b2 = b1.createNextBlockWithCoinbase(coinsTo2.getPubKey());
|
||||
Block b2 = b1.createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, coinsTo2.getPubKey(), 2);
|
||||
Block b3 = b2.createNextBlock(someOtherGuy);
|
||||
|
||||
log.debug("Adding block b1");
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -63,7 +64,7 @@ public class CoinbaseBlockTest {
|
||||
|
||||
// Check block.
|
||||
assertNotNull(block);
|
||||
block.verify();
|
||||
block.verify(169482, EnumSet.noneOf(VerificationFlags.class));
|
||||
assertEquals(BLOCK_NONCE, block.getNonce());
|
||||
|
||||
StoredBlock storedBlock = new StoredBlock(block, BigInteger.ONE, BLOCK_OF_INTEREST); // Nonsense work - not used in test.
|
||||
|
||||
@@ -177,13 +177,13 @@ public class FullBlockTestGenerator {
|
||||
Queue<TransactionOutPointWithValue> spendableOutputs = new LinkedList<TransactionOutPointWithValue>();
|
||||
|
||||
int chainHeadHeight = 1;
|
||||
Block chainHead = params.getGenesisBlock().createNextBlockWithCoinbase(coinbaseOutKeyPubKey);
|
||||
Block chainHead = params.getGenesisBlock().createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, coinbaseOutKeyPubKey, chainHeadHeight);
|
||||
blocks.add(new BlockAndValidity(chainHead, true, false, chainHead.getHash(), 1, "Initial Block"));
|
||||
spendableOutputs.offer(new TransactionOutPointWithValue(
|
||||
new TransactionOutPoint(params, 0, chainHead.getTransactions().get(0).getHash()),
|
||||
FIFTY_COINS, chainHead.getTransactions().get(0).getOutputs().get(0).getScriptPubKey()));
|
||||
for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) {
|
||||
chainHead = chainHead.createNextBlockWithCoinbase(coinbaseOutKeyPubKey);
|
||||
chainHead = chainHead.createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, coinbaseOutKeyPubKey, chainHeadHeight);
|
||||
chainHeadHeight++;
|
||||
blocks.add(new BlockAndValidity(chainHead, true, false, chainHead.getHash(), i+1, "Initial Block chain output generation"));
|
||||
spendableOutputs.offer(new TransactionOutPointWithValue(
|
||||
@@ -894,7 +894,7 @@ public class FullBlockTestGenerator {
|
||||
byte[] outScriptBytes = ScriptBuilder.createOutputScript(ECKey.fromPublicOnly(coinbaseOutKeyPubKey)).getProgram();
|
||||
{
|
||||
b44.setDifficultyTarget(b43.block.getDifficultyTarget());
|
||||
b44.addCoinbaseTransaction(coinbaseOutKeyPubKey, ZERO);
|
||||
b44.addCoinbaseTransaction(coinbaseOutKeyPubKey, ZERO, chainHeadHeight + 15);
|
||||
|
||||
Transaction t = new Transaction(params);
|
||||
// Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much
|
||||
@@ -1768,7 +1768,7 @@ public class FullBlockTestGenerator {
|
||||
Coin coinbaseValue = FIFTY_COINS.shiftRight(nextBlockHeight / params.getSubsidyDecreaseBlockCount())
|
||||
.add((prevOut != null ? prevOut.value.subtract(SATOSHI) : ZERO))
|
||||
.add(additionalCoinbaseValue == null ? ZERO : additionalCoinbaseValue);
|
||||
Block block = baseBlock.createNextBlockWithCoinbase(coinbaseOutKeyPubKey, coinbaseValue);
|
||||
Block block = baseBlock.createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, coinbaseOutKeyPubKey, coinbaseValue, nextBlockHeight);
|
||||
Transaction t = new Transaction(params);
|
||||
if (prevOut != null) {
|
||||
// Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much
|
||||
|
||||
@@ -35,6 +35,7 @@ import static org.bitcoinj.testing.FakeTxBuilder.createFakeTx;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ParseByteCacheTest {
|
||||
private static final int BLOCK_HEIGHT_GENESIS = 0;
|
||||
|
||||
private final byte[] txMessage = HEX.withSeparator(" ", 2).decode(
|
||||
"f9 be b4 d9 74 78 00 00 00 00 00 00 00 00 00 00" +
|
||||
@@ -101,7 +102,7 @@ public class ParseByteCacheTest {
|
||||
Transaction tx2 = createFakeTx(unitTestParams, COIN,
|
||||
new ECKey().toAddress(unitTestParams));
|
||||
|
||||
Block b1 = createFakeBlock(blockStore, tx1, tx2).block;
|
||||
Block b1 = createFakeBlock(blockStore, BLOCK_HEIGHT_GENESIS, tx1, tx2).block;
|
||||
|
||||
MessageSerializer bs = unitTestParams.getDefaultSerializer();
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ import static org.junit.Assert.*;
|
||||
|
||||
@RunWith(value = Parameterized.class)
|
||||
public class PeerGroupTest extends TestWithPeerGroup {
|
||||
private static final int BLOCK_HEIGHT_GENESIS = 0;
|
||||
|
||||
private BlockingQueue<Peer> connectedPeers;
|
||||
private BlockingQueue<Peer> disconnectedPeers;
|
||||
private AbstractPeerEventListener listener;
|
||||
@@ -274,7 +276,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
|
||||
// Set up a little block chain. We heard about b1 but not b2 (it is pending download). b3 is solved whilst we
|
||||
// are downloading the chain.
|
||||
Block b1 = FakeTxBuilder.createFakeBlock(blockStore).block;
|
||||
Block b1 = FakeTxBuilder.createFakeBlock(blockStore, BLOCK_HEIGHT_GENESIS).block;
|
||||
blockChain.add(b1);
|
||||
Block b2 = FakeTxBuilder.makeSolvedTestBlock(b1);
|
||||
Block b3 = FakeTxBuilder.makeSolvedTestBlock(b2);
|
||||
@@ -314,7 +316,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
|
||||
// Set up a little block chain.
|
||||
Block b1 = FakeTxBuilder.createFakeBlock(blockStore).block;
|
||||
Block b1 = FakeTxBuilder.createFakeBlock(blockStore, BLOCK_HEIGHT_GENESIS).block;
|
||||
Block b2 = FakeTxBuilder.makeSolvedTestBlock(b1);
|
||||
Block b3 = FakeTxBuilder.makeSolvedTestBlock(b2);
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
@Test
|
||||
public void chainDownloadEnd2End() throws Exception {
|
||||
// A full end-to-end test of the chain download process, with a new block being solved in the middle.
|
||||
Block b1 = createFakeBlock(blockStore).block;
|
||||
Block b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).block;
|
||||
blockChain.add(b1);
|
||||
Block b2 = makeSolvedTestBlock(b1);
|
||||
Block b3 = makeSolvedTestBlock(b2);
|
||||
@@ -199,7 +199,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
public void invTickle() throws Exception {
|
||||
connect();
|
||||
|
||||
Block b1 = createFakeBlock(blockStore).block;
|
||||
Block b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).block;
|
||||
blockChain.add(b1);
|
||||
// Make a missing block.
|
||||
Block b2 = makeSolvedTestBlock(b1);
|
||||
@@ -229,7 +229,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
connect();
|
||||
|
||||
// Make a missing block that we receive.
|
||||
Block b1 = createFakeBlock(blockStore).block;
|
||||
Block b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).block;
|
||||
blockChain.add(b1);
|
||||
Block b2 = makeSolvedTestBlock(b1);
|
||||
|
||||
@@ -305,7 +305,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
// Check that inventory message containing blocks we want is processed correctly.
|
||||
@Test
|
||||
public void newBlock() throws Exception {
|
||||
Block b1 = createFakeBlock(blockStore).block;
|
||||
Block b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).block;
|
||||
blockChain.add(b1);
|
||||
final Block b2 = makeSolvedTestBlock(b1);
|
||||
// Receive notification of a new block.
|
||||
@@ -365,7 +365,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
// Check that it starts downloading the block chain correctly on request.
|
||||
@Test
|
||||
public void startBlockChainDownload() throws Exception {
|
||||
Block b1 = createFakeBlock(blockStore).block;
|
||||
Block b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).block;
|
||||
blockChain.add(b1);
|
||||
Block b2 = makeSolvedTestBlock(b1);
|
||||
blockChain.add(b2);
|
||||
@@ -395,7 +395,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
public void getBlock() throws Exception {
|
||||
connect();
|
||||
|
||||
Block b1 = createFakeBlock(blockStore).block;
|
||||
Block b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).block;
|
||||
blockChain.add(b1);
|
||||
Block b2 = makeSolvedTestBlock(b1);
|
||||
Block b3 = makeSolvedTestBlock(b2);
|
||||
@@ -417,7 +417,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
public void getLargeBlock() throws Exception {
|
||||
connect();
|
||||
|
||||
Block b1 = createFakeBlock(blockStore).block;
|
||||
Block b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).block;
|
||||
blockChain.add(b1);
|
||||
Block b2 = makeSolvedTestBlock(b1);
|
||||
Transaction t = new Transaction(params);
|
||||
@@ -444,7 +444,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
Utils.setMockClock();
|
||||
// Check that blocks before the fast catchup point are retrieved using getheaders, and after using getblocks.
|
||||
// This test is INCOMPLETE because it does not check we handle >2000 blocks correctly.
|
||||
Block b1 = createFakeBlock(blockStore).block;
|
||||
Block b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).block;
|
||||
blockChain.add(b1);
|
||||
Utils.rollMockClock(60 * 10); // 10 minutes later.
|
||||
Block b2 = makeSolvedTestBlock(b1);
|
||||
|
||||
@@ -237,7 +237,7 @@ public class TransactionBroadcastTest extends TestWithPeerGroup {
|
||||
assertEquals(transactions[0], sendResult.tx);
|
||||
assertEquals(1, transactions[0].getConfidence().numBroadcastPeers());
|
||||
// Confirm it.
|
||||
Block b2 = FakeTxBuilder.createFakeBlock(blockStore, t1).block;
|
||||
Block b2 = FakeTxBuilder.createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, t1).block;
|
||||
inbound(p1, b2);
|
||||
pingAndWait(p1);
|
||||
assertNull(outbound(p1));
|
||||
|
||||
@@ -8,6 +8,8 @@ import org.easymock.*;
|
||||
import org.junit.*;
|
||||
|
||||
import java.util.*;
|
||||
import static org.bitcoinj.core.BlockTest.params;
|
||||
import static org.bitcoinj.core.Utils.HEX;
|
||||
|
||||
import static org.easymock.EasyMock.*;
|
||||
import static org.junit.Assert.*;
|
||||
@@ -27,6 +29,7 @@ public class TransactionTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Context context = new Context(PARAMS);
|
||||
dummy = FakeTxBuilder.createFakeTx(PARAMS, Coin.COIN, ADDRESS);
|
||||
tx = newTransaction();
|
||||
}
|
||||
@@ -303,4 +306,17 @@ public class TransactionTest {
|
||||
tx1.getInput(0).setScriptSig(new Script(new byte[111]));
|
||||
assertEquals(79, tx1.getMessageSizeForPriorityCalc());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws VerificationException
|
||||
*/
|
||||
@Test
|
||||
public void testCoinbaseHeightCheck() throws VerificationException {
|
||||
// Coinbase transaction from block 300,000
|
||||
final byte[] transactionBytes = HEX.decode("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4803e09304062f503253482f0403c86d53087ceca141295a00002e522cfabe6d6d7561cf262313da1144026c8f7a43e3899c44f6145f39a36507d36679a8b7006104000000000000000000000001c8704095000000001976a91480ad90d403581fa3bf46086a91b2d9d4125db6c188ac00000000");
|
||||
final int height = 300000;
|
||||
final Transaction transaction = params.getDefaultSerializer().makeTransaction(transactionBytes);
|
||||
transaction.checkCoinBaseHeight(height);
|
||||
}
|
||||
}
|
||||
@@ -451,7 +451,7 @@ public class WalletTest extends TestWithWallet {
|
||||
wallet.commitTx(t3);
|
||||
assertTrue(wallet.isConsistent());
|
||||
// t2 and t3 gets confirmed in the same block.
|
||||
BlockPair bp = createFakeBlock(blockStore, t2, t3);
|
||||
BlockPair bp = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, t2, t3);
|
||||
wallet.receiveFromBlock(t2, bp.storedBlock, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0);
|
||||
wallet.receiveFromBlock(t3, bp.storedBlock, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1);
|
||||
wallet.notifyNewBestBlock(bp.storedBlock);
|
||||
@@ -539,7 +539,7 @@ public class WalletTest extends TestWithWallet {
|
||||
wallet.getBalance(Wallet.BalanceType.ESTIMATED)));
|
||||
|
||||
// Now confirm the transaction by including it into a block.
|
||||
StoredBlock b3 = createFakeBlock(blockStore, spend).storedBlock;
|
||||
StoredBlock b3 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, spend).storedBlock;
|
||||
wallet.receiveFromBlock(spend, b3, BlockChain.NewBlockType.BEST_CHAIN, 0);
|
||||
|
||||
// Change is confirmed. We started with 5.50 so we should have 4.50 left.
|
||||
@@ -615,7 +615,7 @@ public class WalletTest extends TestWithWallet {
|
||||
sendMoneyToWallet(send2, AbstractBlockChain.NewBlockType.BEST_CHAIN);
|
||||
assertEquals(Coin.valueOf(0, 80), wallet.getBalance());
|
||||
Threading.waitForUserCode();
|
||||
BlockPair b4 = createFakeBlock(blockStore);
|
||||
BlockPair b4 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS);
|
||||
confTxns.clear();
|
||||
wallet.notifyNewBestBlock(b4.storedBlock);
|
||||
Threading.waitForUserCode();
|
||||
@@ -916,7 +916,7 @@ public class WalletTest extends TestWithWallet {
|
||||
assertEquals(TransactionConfidence.ConfidenceType.PENDING,
|
||||
notifiedTx[0].getConfidence().getConfidenceType());
|
||||
// Send a block with nothing interesting. Verify we don't get a callback.
|
||||
wallet.notifyNewBestBlock(createFakeBlock(blockStore).storedBlock);
|
||||
wallet.notifyNewBestBlock(createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).storedBlock);
|
||||
Threading.waitForUserCode();
|
||||
assertNull(reasons[0]);
|
||||
final Transaction t1Copy = params.getDefaultSerializer().makeTransaction(t1.bitcoinSerialize());
|
||||
@@ -1151,7 +1151,7 @@ public class WalletTest extends TestWithWallet {
|
||||
// TX should have been seen as relevant.
|
||||
assertEquals(value, wallet.getBalance(Wallet.BalanceType.ESTIMATED));
|
||||
assertEquals(ZERO, wallet.getBalance(Wallet.BalanceType.AVAILABLE));
|
||||
Block b1 = createFakeBlock(blockStore, t1).block;
|
||||
Block b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, t1).block;
|
||||
chain.add(b1);
|
||||
// TX should have been seen as relevant, extracted and processed.
|
||||
assertEquals(value, wallet.getBalance(Wallet.BalanceType.AVAILABLE));
|
||||
@@ -1234,7 +1234,7 @@ public class WalletTest extends TestWithWallet {
|
||||
Address watchedAddress = key.toAddress(params);
|
||||
wallet.addWatchedAddress(watchedAddress);
|
||||
Transaction t1 = createFakeTx(params, CENT, watchedAddress);
|
||||
StoredBlock b3 = createFakeBlock(blockStore, t1).storedBlock;
|
||||
StoredBlock b3 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, t1).storedBlock;
|
||||
wallet.receiveFromBlock(t1, b3, BlockChain.NewBlockType.BEST_CHAIN, 0);
|
||||
assertEquals(CENT, wallet.getBalance());
|
||||
|
||||
@@ -1255,7 +1255,7 @@ public class WalletTest extends TestWithWallet {
|
||||
|
||||
Transaction t1 = createFakeTx(params, CENT, watchedAddress);
|
||||
Transaction t2 = createFakeTx(params, COIN, notMyAddr);
|
||||
StoredBlock b1 = createFakeBlock(blockStore, t1).storedBlock;
|
||||
StoredBlock b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, t1).storedBlock;
|
||||
Transaction st2 = new Transaction(params);
|
||||
st2.addOutput(CENT, notMyAddr);
|
||||
st2.addOutput(COIN, notMyAddr);
|
||||
@@ -1278,7 +1278,7 @@ public class WalletTest extends TestWithWallet {
|
||||
|
||||
assertTrue(wallet.isRequiringUpdateAllBloomFilter());
|
||||
Transaction t1 = createFakeTx(params, CENT, watchedAddress);
|
||||
StoredBlock b1 = createFakeBlock(blockStore, t1).storedBlock;
|
||||
StoredBlock b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, t1).storedBlock;
|
||||
|
||||
TransactionOutPoint outPoint = new TransactionOutPoint(params, 0, t1);
|
||||
|
||||
@@ -1338,7 +1338,7 @@ public class WalletTest extends TestWithWallet {
|
||||
|
||||
for (Address addr : addressesForRemoval) {
|
||||
Transaction t1 = createFakeTx(params, CENT, addr);
|
||||
StoredBlock b1 = createFakeBlock(blockStore, t1).storedBlock;
|
||||
StoredBlock b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, t1).storedBlock;
|
||||
|
||||
TransactionOutPoint outPoint = new TransactionOutPoint(params, 0, t1);
|
||||
|
||||
@@ -1358,7 +1358,7 @@ public class WalletTest extends TestWithWallet {
|
||||
assertTrue(wallet.getBloomFilter(0.001).contains(address.getHash160()));
|
||||
|
||||
Transaction t1 = createFakeTx(params, CENT, address);
|
||||
StoredBlock b1 = createFakeBlock(blockStore, t1).storedBlock;
|
||||
StoredBlock b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, t1).storedBlock;
|
||||
|
||||
TransactionOutPoint outPoint = new TransactionOutPoint(params, 0, t1);
|
||||
|
||||
@@ -1416,7 +1416,7 @@ public class WalletTest extends TestWithWallet {
|
||||
assertEquals(f, results[1]);
|
||||
results[0] = results[1] = null;
|
||||
|
||||
Block b0 = createFakeBlock(blockStore).block;
|
||||
Block b0 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).block;
|
||||
chain.add(b0);
|
||||
Sha256Hash hash3 = Sha256Hash.of(f);
|
||||
assertEquals(hash2, hash3); // File has NOT changed yet. Just new blocks with no txns - delayed.
|
||||
@@ -1424,7 +1424,7 @@ public class WalletTest extends TestWithWallet {
|
||||
assertNull(results[1]);
|
||||
|
||||
Transaction t1 = createFakeTx(params, valueOf(5, 0), key);
|
||||
Block b1 = createFakeBlock(blockStore, t1).block;
|
||||
Block b1 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, t1).block;
|
||||
chain.add(b1);
|
||||
Sha256Hash hash4 = Sha256Hash.of(f);
|
||||
assertFalse(hash3.equals(hash4)); // File HAS changed.
|
||||
@@ -1451,7 +1451,7 @@ public class WalletTest extends TestWithWallet {
|
||||
wallet.importKey(key2);
|
||||
assertEquals(hash5, Sha256Hash.of(f)); // File has NOT changed.
|
||||
Transaction t2 = createFakeTx(params, valueOf(5, 0), key2);
|
||||
Block b3 = createFakeBlock(blockStore, t2).block;
|
||||
Block b3 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, t2).block;
|
||||
chain.add(b3);
|
||||
Thread.sleep(2000); // Wait longer than autosave delay. TODO Fix the racyness.
|
||||
assertEquals(hash5, Sha256Hash.of(f)); // File has still NOT changed.
|
||||
@@ -1511,7 +1511,7 @@ public class WalletTest extends TestWithWallet {
|
||||
// Add a change address to ensure this tx is relevant.
|
||||
tx2.addOutput(CENT, wallet.getChangeAddress());
|
||||
wallet.receivePending(tx2, null);
|
||||
BlockPair bp = createFakeBlock(blockStore, tx1);
|
||||
BlockPair bp = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, tx1);
|
||||
wallet.receiveFromBlock(tx1, bp.storedBlock, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0);
|
||||
wallet.notifyNewBestBlock(bp.storedBlock);
|
||||
assertEquals(ZERO, wallet.getBalance());
|
||||
@@ -2981,7 +2981,7 @@ public class WalletTest extends TestWithWallet {
|
||||
assertEquals(Coin.ZERO, wallet.getBalance(Wallet.BalanceType.ESTIMATED));
|
||||
assertTrue(bool.get());
|
||||
// Confirm it in the same manner as how Bloom filtered blocks do. Verify it shows up.
|
||||
StoredBlock block = createFakeBlock(blockStore, tx).storedBlock;
|
||||
StoredBlock block = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, tx).storedBlock;
|
||||
wallet.notifyTransactionIsInBlock(tx.getHash(), block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1);
|
||||
assertEquals(COIN, wallet.getBalance());
|
||||
}
|
||||
@@ -2989,7 +2989,7 @@ public class WalletTest extends TestWithWallet {
|
||||
@Test
|
||||
public void transactionInBlockNotification() {
|
||||
final Transaction tx = createFakeTx(params, COIN, myAddress);
|
||||
StoredBlock block = createFakeBlock(blockStore, tx).storedBlock;
|
||||
StoredBlock block = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, tx).storedBlock;
|
||||
wallet.receivePending(tx, null);
|
||||
boolean notification = wallet.notifyTransactionIsInBlock(tx.getHash(), block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1);
|
||||
assertTrue(notification);
|
||||
@@ -2997,7 +2997,7 @@ public class WalletTest extends TestWithWallet {
|
||||
Address notMyAddr = new ECKey().toAddress(params);
|
||||
final Transaction tx2 = createFakeTx(params, COIN, notMyAddr);
|
||||
wallet.receivePending(tx2, null);
|
||||
StoredBlock block2 = createFakeBlock(blockStore, tx2).storedBlock;
|
||||
StoredBlock block2 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS + 1, tx2).storedBlock;
|
||||
boolean notification2 = wallet.notifyTransactionIsInBlock(tx2.getHash(), block2, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1);
|
||||
assertFalse(notification2);
|
||||
}
|
||||
@@ -3005,7 +3005,7 @@ public class WalletTest extends TestWithWallet {
|
||||
@Test
|
||||
public void duplicatedBlock() {
|
||||
final Transaction tx = createFakeTx(params, COIN, myAddress);
|
||||
StoredBlock block = createFakeBlock(blockStore, tx).storedBlock;
|
||||
StoredBlock block = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, tx).storedBlock;
|
||||
wallet.notifyNewBestBlock(block);
|
||||
wallet.notifyNewBestBlock(block);
|
||||
}
|
||||
|
||||
@@ -226,9 +226,9 @@ public class ChannelConnectionTest extends TestWithWallet {
|
||||
|
||||
// Now confirm the settle TX and see if the channel deletes itself from the wallet.
|
||||
assertEquals(1, StoredPaymentChannelClientStates.getFromWallet(wallet).mapChannels.size());
|
||||
wallet.notifyNewBestBlock(createFakeBlock(blockStore).storedBlock);
|
||||
wallet.notifyNewBestBlock(createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).storedBlock);
|
||||
assertEquals(1, StoredPaymentChannelClientStates.getFromWallet(wallet).mapChannels.size());
|
||||
wallet.notifyNewBestBlock(createFakeBlock(blockStore).storedBlock);
|
||||
wallet.notifyNewBestBlock(createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS + 1).storedBlock);
|
||||
assertEquals(0, StoredPaymentChannelClientStates.getFromWallet(wallet).mapChannels.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -323,7 +323,7 @@ public class WalletProtobufSerializerTest {
|
||||
@Test
|
||||
public void coinbaseTxns() throws Exception {
|
||||
// Covers issue 420 where the outpoint index of a coinbase tx input was being mis-serialized.
|
||||
Block b = params.getGenesisBlock().createNextBlockWithCoinbase(myKey.getPubKey(), FIFTY_COINS);
|
||||
Block b = params.getGenesisBlock().createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, myKey.getPubKey(), FIFTY_COINS, Block.BLOCK_HEIGHT_GENESIS);
|
||||
Transaction coinbase = b.getTransactions().get(0);
|
||||
assertTrue(coinbase.isCoinBase());
|
||||
BlockChain chain = new BlockChain(params, myWallet, new MemoryBlockStore(params));
|
||||
|
||||
@@ -50,10 +50,10 @@ public class VersionTallyTest {
|
||||
public void testNullWhileEmpty() {
|
||||
VersionTally instance = new VersionTally(unitTestParams);
|
||||
for (int i = 0; i < unitTestParams.getMajorityWindow(); i++) {
|
||||
assertNull(instance.getCount(1));
|
||||
assertNull(instance.getCountAtOrAbove(1));
|
||||
instance.add(1);
|
||||
}
|
||||
assertEquals(unitTestParams.getMajorityWindow(), instance.getCount(1).intValue());
|
||||
assertEquals(unitTestParams.getMajorityWindow(), instance.getCountAtOrAbove(1).intValue());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,16 +74,24 @@ public class VersionTallyTest {
|
||||
|
||||
// Fill the tally with 1s
|
||||
for (int i = 0; i < unitTestParams.getMajorityWindow(); i++) {
|
||||
assertNull(instance.getCount(1));
|
||||
assertNull(instance.getCountAtOrAbove(1));
|
||||
instance.add(1);
|
||||
}
|
||||
assertEquals(unitTestParams.getMajorityWindow(), instance.getCount(1).intValue());
|
||||
assertEquals(unitTestParams.getMajorityWindow(), instance.getCountAtOrAbove(1).intValue());
|
||||
|
||||
// Check the count updates as we replace with 2s
|
||||
for (int i = 0; i < unitTestParams.getMajorityWindow(); i++) {
|
||||
assertEquals(unitTestParams.getMajorityWindow() - i, instance.getCount(1).intValue());
|
||||
assertEquals(i, instance.getCount(2).intValue());
|
||||
assertEquals(i, instance.getCountAtOrAbove(2).intValue());
|
||||
instance.add(2);
|
||||
}
|
||||
|
||||
// Inject a rogue 1
|
||||
instance.add(1);
|
||||
assertEquals(unitTestParams.getMajorityWindow() - 1, instance.getCountAtOrAbove(2).intValue());
|
||||
|
||||
// Check we accept high values as well
|
||||
instance.add(10);
|
||||
assertEquals(unitTestParams.getMajorityWindow() - 1, instance.getCountAtOrAbove(2).intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -94,14 +102,14 @@ public class VersionTallyTest {
|
||||
// Build a historical chain of version 2 blocks
|
||||
long timeSeconds = 1231006505;
|
||||
StoredBlock chainHead = null;
|
||||
for (int blockCount = 0; blockCount < unitTestParams.getMajorityWindow(); blockCount++) {
|
||||
chainHead = FakeTxBuilder.createFakeBlock(blockStore, 2, timeSeconds).storedBlock;
|
||||
for (int height = 0; height < unitTestParams.getMajorityWindow(); height++) {
|
||||
chainHead = FakeTxBuilder.createFakeBlock(blockStore, 2, timeSeconds, height).storedBlock;
|
||||
assertEquals(2, chainHead.getHeader().getVersion());
|
||||
timeSeconds += 60;
|
||||
}
|
||||
|
||||
VersionTally instance = new VersionTally(unitTestParams);
|
||||
instance.initialize(blockStore, chainHead);
|
||||
assertEquals(unitTestParams.getMajorityWindow(), instance.getCount(2).intValue());
|
||||
assertEquals(unitTestParams.getMajorityWindow(), instance.getCountAtOrAbove(2).intValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public class DefaultCoinSelectorTest extends TestWithWallet {
|
||||
// and t3=0.01.
|
||||
Transaction t1 = checkNotNull(sendMoneyToWallet(COIN, AbstractBlockChain.NewBlockType.BEST_CHAIN));
|
||||
// Padding block.
|
||||
wallet.notifyNewBestBlock(FakeTxBuilder.createFakeBlock(blockStore).storedBlock);
|
||||
wallet.notifyNewBestBlock(FakeTxBuilder.createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS).storedBlock);
|
||||
final Coin TWO_COINS = COIN.multiply(2);
|
||||
Transaction t2 = checkNotNull(sendMoneyToWallet(TWO_COINS, AbstractBlockChain.NewBlockType.BEST_CHAIN));
|
||||
Transaction t3 = checkNotNull(sendMoneyToWallet(CENT, AbstractBlockChain.NewBlockType.BEST_CHAIN));
|
||||
|
||||
Reference in New Issue
Block a user