diff --git a/src/com/google/bitcoin/core/Block.java b/src/com/google/bitcoin/core/Block.java
index 3d81a56f..0245edef 100644
--- a/src/com/google/bitcoin/core/Block.java
+++ b/src/com/google/bitcoin/core/Block.java
@@ -348,13 +348,13 @@ public class Block extends Message {
/**
* Checks the block data to ensure it follows the rules laid out in the network parameters. Specifically, throws
- * an exception if the proof of work is invalid, if the timestamp is too far from what it should be, or if the
- * transactions don't hash to the value in the merkle root field. This is not everything that is required
- * for a block to be valid, only what is checkable independent of the chain.
+ * an exception if the proof of work is invalid, or if the timestamp is too far from what it should be. This is
+ * not everything that is required for a block to be valid, only what is checkable independent of the
+ * chain and without a transaction index.
*
* @throws VerificationException
*/
- public void verify() throws VerificationException {
+ public void verifyHeader() throws VerificationException {
// Prove that this block is OK. It might seem that we can just ignore most of these checks given that the
// network is also verifying the blocks, but we cannot as it'd open us to a variety of obscure attacks.
//
@@ -362,15 +362,28 @@ public class Block extends Message {
// enough, it's probably been done by the network.
checkProofOfWork(true);
checkTimestamp();
+ }
+
+ /**
+ * Checks the block contents
+ * @throws VerificationException
+ */
+ public void verifyTransactions() 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
// transactions that reference spent or non-existant inputs.
- if (transactions != null) {
- assert transactions.size() > 0;
- checkTransactions();
- checkMerkleRoot();
- }
+ assert transactions.size() > 0;
+ checkTransactions();
+ checkMerkleRoot();
+ }
+
+ /**
+ * Verifies both the header and that the transactions hash to the merkle root.
+ */
+ public void verify() throws VerificationException {
+ verifyHeader();
+ verifyTransactions();
}
@Override
@@ -490,7 +503,7 @@ public class Block extends Message {
b.setTime(time);
b.solve();
try {
- b.verify();
+ b.verifyHeader();
} catch (VerificationException e) {
throw new RuntimeException(e); // Cannot happen.
}
diff --git a/src/com/google/bitcoin/core/BlockChain.java b/src/com/google/bitcoin/core/BlockChain.java
index 375efacd..27e91342 100644
--- a/src/com/google/bitcoin/core/BlockChain.java
+++ b/src/com/google/bitcoin/core/BlockChain.java
@@ -149,12 +149,27 @@ public class BlockChain {
return true;
}
- // Prove the block is internally valid: hash is lower than target, merkle root is correct and so on.
+ // Does this block contain any transactions we might care about? Check this up front before verifying the
+ // blocks validity so we can skip the merkle root verification if the contents aren't interesting. This saves
+ // a lot of time for big blocks.
+ boolean contentsImportant = false;
+ HashMap> walletToTxMap = new HashMap>();;
+ if (block.transactions != null) {
+ scanTransactions(block, walletToTxMap);
+ contentsImportant = walletToTxMap.size() > 0;
+ }
+
+ // 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.verify();
+ block.verifyHeader();
+ if (contentsImportant)
+ block.verifyTransactions();
} catch (VerificationException e) {
- log.error("Failed to verify block:", e);
- log.error(block.toString());
+ log.error("Failed to verify block: ", e);
+ log.error(block.getHashAsString());
throw e;
}
@@ -176,9 +191,7 @@ public class BlockChain {
StoredBlock newStoredBlock = storedPrev.build(block);
checkDifficultyTransitions(storedPrev, newStoredBlock);
blockStore.put(newStoredBlock);
- // block.transactions may be null here if we received only a header and not a full block. This does not
- // happen currently but might in future if getheaders is implemented.
- connectBlock(newStoredBlock, storedPrev, block.transactions);
+ connectBlock(newStoredBlock, storedPrev, walletToTxMap);
}
if (tryConnecting)
@@ -188,7 +201,8 @@ public class BlockChain {
return true;
}
- private void connectBlock(StoredBlock newStoredBlock, StoredBlock storedPrev, List newTransactions)
+ private void connectBlock(StoredBlock newStoredBlock, StoredBlock storedPrev,
+ HashMap> newTransactions)
throws BlockStoreException, VerificationException {
if (storedPrev.equals(chainHead)) {
// This block connects to the best known block, it is a normal continuation of the system.
@@ -296,14 +310,16 @@ public class BlockChain {
}
private void sendTransactionsToWallet(StoredBlock block, NewBlockType blockType,
- List newTransactions) throws VerificationException {
- // Scan the transactions to find out if any mention addresses we own.
- for (Transaction tx : newTransactions) {
+ HashMap> newTransactions) throws VerificationException {
+ for (Wallet wallet : newTransactions.keySet()) {
try {
- scanTransaction(block, tx, blockType);
+ List txns = newTransactions.get(wallet);
+ for (Transaction tx : txns) {
+ wallet.receive(tx, block, blockType);
+ }
} catch (ScriptException e) {
- // We don't want scripts we don't understand to break the block chain,
- // so just note that this tx was not scanned here and continue.
+ // We don't want scripts we don't understand to break the block chain so just note that this tx was
+ // not scanned here and continue.
log.warn("Failed to parse a script: " + e.toString());
}
}
@@ -409,33 +425,50 @@ public class BlockChain {
receivedDifficulty.toString(16) + " vs " + newDifficulty.toString(16));
}
- private void scanTransaction(StoredBlock block, Transaction tx, NewBlockType blockType)
- throws ScriptException, VerificationException {
- for (Wallet wallet : wallets) {
- boolean shouldReceive = false;
- for (TransactionOutput output : tx.outputs) {
- // TODO: Handle more types of outputs, not just regular to address outputs.
- if (output.getScriptPubKey().isSentToIP()) return;
- // This is not thread safe as a key could be removed between the call to isMine and receive.
- if (output.isMine(wallet)) {
- shouldReceive = true;
- }
- }
-
- // Coinbase transactions don't have anything useful in their inputs (as they create coins out of thin air).
- if (!tx.isCoinBase()) {
- for (TransactionInput i : tx.inputs) {
- byte[] pubkey = i.getScriptSig().getPubKey();
- // This is not thread safe as a key could be removed between the call to isPubKeyMine and receive.
- if (wallet.isPubKeyMine(pubkey)) {
- shouldReceive = true;
+ /**
+ * For the transactions in the given block, update the txToWalletMap such that each wallet maps to a list of
+ * transactions for which it is relevant.
+ */
+ private void scanTransactions(Block block, HashMap> walletToTxMap)
+ throws VerificationException {
+ for (Transaction tx : block.transactions) {
+ try {
+ for (Wallet wallet : wallets) {
+ boolean shouldReceive = false;
+ for (TransactionOutput output : tx.outputs) {
+ // TODO: Handle more types of outputs, not just regular to address outputs.
+ if (output.getScriptPubKey().isSentToIP()) return;
+ // This is not thread safe as a key could be removed between the call to isMine and receive.
+ if (output.isMine(wallet)) {
+ shouldReceive = true;
+ }
}
+
+ // Coinbase transactions don't have anything useful in their inputs (as they create coins out of thin air).
+ if (!shouldReceive && !tx.isCoinBase()) {
+ for (TransactionInput i : tx.inputs) {
+ byte[] pubkey = i.getScriptSig().getPubKey();
+ // This is not thread safe as a key could be removed between the call to isPubKeyMine and receive.
+ if (wallet.isPubKeyMine(pubkey)) {
+ shouldReceive = true;
+ }
+ }
+ }
+
+ if (!shouldReceive) continue;
+ List txList = walletToTxMap.get(wallet);
+ if (txList == null) {
+ txList = new LinkedList();
+ walletToTxMap.put(wallet, txList);
+ }
+ txList.add(tx);
}
+ } catch (ScriptException e) {
+ // We don't want scripts we don't understand to break the block chain so just note that this tx was
+ // not scanned here and continue.
+ log.warn("Failed to parse a script: " + e.toString());
}
-
- if (shouldReceive)
- wallet.receive(tx, block, blockType);
- }
+ }
}
/**
diff --git a/src/com/google/bitcoin/store/DiskBlockStore.java b/src/com/google/bitcoin/store/DiskBlockStore.java
index c3fd9db1..9401dd51 100644
--- a/src/com/google/bitcoin/store/DiskBlockStore.java
+++ b/src/com/google/bitcoin/store/DiskBlockStore.java
@@ -115,7 +115,7 @@ public class DiskBlockStore implements BlockStore {
}
} else {
// Don't try to verify the genesis block to avoid upsetting the unit tests.
- b.verify();
+ b.verifyHeader();
// Calculate its height and total chain work.
s = prev.build(b);
}
diff --git a/tests/com/google/bitcoin/core/BlockChainTest.java b/tests/com/google/bitcoin/core/BlockChainTest.java
index 1f0bc5c8..4aad9880 100644
--- a/tests/com/google/bitcoin/core/BlockChainTest.java
+++ b/tests/com/google/bitcoin/core/BlockChainTest.java
@@ -16,16 +16,18 @@
package com.google.bitcoin.core;
-import com.google.bitcoin.bouncycastle.util.encoders.Hex;
+import com.google.bitcoin.store.BlockStore;
import com.google.bitcoin.store.MemoryBlockStore;
import org.junit.Before;
import org.junit.Test;
import java.math.BigInteger;
+import static com.google.bitcoin.core.TestUtils.createFakeBlock;
+import static com.google.bitcoin.core.TestUtils.createFakeTx;
import static org.junit.Assert.*;
-// NOTE: Handling of chain splits/reorgs are in ChainSplitTests.
+// Handling of chain splits/reorgs are in ChainSplitTests.
public class BlockChainTest {
private static final NetworkParameters testNet = NetworkParameters.testNet();
@@ -33,21 +35,27 @@ public class BlockChainTest {
private Wallet wallet;
private BlockChain chain;
+ private BlockStore blockStore;
private Address coinbaseTo;
private NetworkParameters unitTestParams;
- private Address someOtherGuy;
+
+ private void resetBlockStore() {
+ blockStore = new MemoryBlockStore(unitTestParams);
+ }
@Before
public void setUp() {
+
testNetChain = new BlockChain(testNet, new Wallet(testNet), new MemoryBlockStore(testNet));
unitTestParams = NetworkParameters.unitTests();
wallet = new Wallet(unitTestParams);
wallet.addKey(new ECKey());
- chain = new BlockChain(unitTestParams, wallet, new MemoryBlockStore(unitTestParams));
+
+ resetBlockStore();
+ chain = new BlockChain(unitTestParams, wallet, blockStore);
coinbaseTo = wallet.keychain.get(0).toAddress(unitTestParams);
- someOtherGuy = new ECKey().toAddress(unitTestParams);
}
@Test
@@ -68,10 +76,39 @@ public class BlockChainTest {
} catch (VerificationException e) {
b2.setNonce(n);
}
+
// Now it works because we reset the nonce.
assertTrue(testNetChain.add(b2));
}
+ @Test
+ public void merkleRoots() throws Exception {
+ // Test that merkle root verification takes place when a relevant transaction is present and doesn't when
+ // there isn't any such tx present (as an optimization).
+ Transaction tx1 = createFakeTx(unitTestParams,
+ Utils.toNanoCoins(1, 0),
+ wallet.keychain.get(0).toAddress(unitTestParams));
+ Block b1 = createFakeBlock(unitTestParams, blockStore, tx1).block;
+ chain.add(b1);
+ resetBlockStore();
+ Sha256Hash hash = b1.getMerkleRoot();
+ b1.setMerkleRoot(Sha256Hash.ZERO_HASH);
+ try {
+ chain.add(b1);
+ fail();
+ } catch (VerificationException e) {
+ // Expected.
+ b1.setMerkleRoot(hash);
+ }
+ // Now add a second block with no relevant transactions and then break it.
+ Transaction tx2 = createFakeTx(unitTestParams, Utils.toNanoCoins(1, 0),
+ new ECKey().toAddress(unitTestParams));
+ Block b2 = createFakeBlock(unitTestParams, blockStore, tx2).block;
+ hash = b2.getMerkleRoot();
+ b2.setMerkleRoot(Sha256Hash.ZERO_HASH);
+ chain.add(b2); // Broken block is accepted because its contents don't matter to us.
+ }
+
@Test
public void testUnconnectedBlocks() throws Exception {
Block b1 = unitTestParams.genesisBlock.createNextBlock(coinbaseTo);
@@ -163,7 +200,7 @@ public class BlockChainTest {
b2.setTime(1296734343L);
b2.setPrevBlockHash(new Sha256Hash("000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604"));
assertEquals("000000037b21cac5d30fc6fda2581cf7b2612908aed2abbcc429c45b0557a15f", b2.getHashAsString());
- b2.verify();
+ b2.verifyHeader();
return b2;
}
@@ -174,7 +211,7 @@ public class BlockChainTest {
b1.setTime(1296734340);
b1.setPrevBlockHash(new Sha256Hash("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"));
assertEquals("000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604", b1.getHashAsString());
- b1.verify();
+ b1.verifyHeader();
return b1;
}
}
diff --git a/tests/com/google/bitcoin/core/TestUtils.java b/tests/com/google/bitcoin/core/TestUtils.java
new file mode 100644
index 00000000..4a631000
--- /dev/null
+++ b/tests/com/google/bitcoin/core/TestUtils.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright 2011 Google Inc.
+ *
+ * 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 com.google.bitcoin.core;
+
+import com.google.bitcoin.store.BlockStore;
+import com.google.bitcoin.store.BlockStoreException;
+
+import java.math.BigInteger;
+
+public class TestUtils {
+ public static Transaction createFakeTx(NetworkParameters params, BigInteger nanocoins, Address to) {
+ Transaction t = new Transaction(params);
+ TransactionOutput o1 = new TransactionOutput(params, t, nanocoins, to);
+ t.addOutput(o1);
+ // Make a previous tx simply to send us sufficient coins. This prev tx is not really valid but it doesn't
+ // matter for our purposes.
+ Transaction prevTx = new Transaction(params);
+ TransactionOutput prevOut = new TransactionOutput(params, prevTx, nanocoins, to);
+ prevTx.addOutput(prevOut);
+ // Connect it.
+ t.addInput(prevOut);
+ return t;
+ }
+
+ public static class BlockPair {
+ StoredBlock storedBlock;
+ Block block;
+ }
+
+ // Emulates receiving a valid block that builds on top of the chain.
+ public static BlockPair createFakeBlock(NetworkParameters params, BlockStore blockStore,
+ Transaction... transactions) {
+ try {
+ Block b = blockStore.getChainHead().getHeader().createNextBlock(new ECKey().toAddress(params));
+ for (Transaction tx : transactions)
+ b.addTransaction(tx);
+ b.solve();
+ BlockPair pair = new BlockPair();
+ pair.block = b;
+ pair.storedBlock = blockStore.getChainHead().build(b);
+ blockStore.put(pair.storedBlock);
+ blockStore.setChainHead(pair.storedBlock);
+ return pair;
+ } catch (VerificationException e) {
+ throw new RuntimeException(e); // Cannot happen.
+ } catch (BlockStoreException e) {
+ throw new RuntimeException(e); // Cannot happen.
+ }
+ }
+}
diff --git a/tests/com/google/bitcoin/core/WalletTest.java b/tests/com/google/bitcoin/core/WalletTest.java
index 911fd3cc..761a7435 100644
--- a/tests/com/google/bitcoin/core/WalletTest.java
+++ b/tests/com/google/bitcoin/core/WalletTest.java
@@ -24,6 +24,8 @@ import org.junit.Test;
import java.math.BigInteger;
+import static com.google.bitcoin.core.TestUtils.createFakeBlock;
+import static com.google.bitcoin.core.TestUtils.createFakeTx;
import static com.google.bitcoin.core.Utils.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -46,50 +48,11 @@ public class WalletTest {
blockStore = new MemoryBlockStore(params);
}
- private Transaction createFakeTx(BigInteger nanocoins, Address to) {
- Transaction t = new Transaction(params);
- TransactionOutput o1 = new TransactionOutput(params, t, nanocoins, to);
- t.addOutput(o1);
- // Make a previous tx simply to send us sufficient coins. This prev tx is not really valid but it doesn't
- // matter for our purposes.
- Transaction prevTx = new Transaction(params);
- TransactionOutput prevOut = new TransactionOutput(params, prevTx, nanocoins, to);
- prevTx.addOutput(prevOut);
- // Connect it.
- t.addInput(prevOut);
- return t;
- }
-
- class BlockPair {
- StoredBlock storedBlock;
- Block block;
- }
-
- // Emulates receiving a valid block that builds on top of the chain.
- private BlockPair createFakeBlock(Transaction... transactions) {
- try {
- Block b = blockStore.getChainHead().getHeader().createNextBlock(new ECKey().toAddress(params));
- for (Transaction tx : transactions)
- b.addTransaction(tx);
- b.solve();
- BlockPair pair = new BlockPair();
- pair.block = b;
- pair.storedBlock = blockStore.getChainHead().build(b);
- blockStore.put(pair.storedBlock);
- blockStore.setChainHead(pair.storedBlock);
- return pair;
- } catch (VerificationException e) {
- throw new RuntimeException(e); // Cannot happen.
- } catch (BlockStoreException e) {
- throw new RuntimeException(e); // Cannot happen.
- }
- }
-
@Test
public void basicSpending() throws Exception {
// We'll set up a wallet that receives a coin, then sends a coin of lesser value and keeps the change.
BigInteger v1 = Utils.toNanoCoins(1, 0);
- Transaction t1 = createFakeTx(v1, myAddress);
+ Transaction t1 = createFakeTx(params, v1, myAddress);
wallet.receive(t1, null, BlockChain.NewBlockType.BEST_CHAIN);
assertEquals(v1, wallet.getBalance());
@@ -109,13 +72,13 @@ public class WalletTest {
public void sideChain() throws Exception {
// The wallet receives a coin on the main chain, then on a side chain. Only main chain counts towards balance.
BigInteger v1 = Utils.toNanoCoins(1, 0);
- Transaction t1 = createFakeTx(v1, myAddress);
+ Transaction t1 = createFakeTx(params, v1, myAddress);
wallet.receive(t1, null, BlockChain.NewBlockType.BEST_CHAIN);
assertEquals(v1, wallet.getBalance());
BigInteger v2 = toNanoCoins(0, 50);
- Transaction t2 = createFakeTx(v2, myAddress);
+ Transaction t2 = createFakeTx(params, v2, myAddress);
wallet.receive(t2, null, BlockChain.NewBlockType.SIDE_CHAIN);
assertEquals(v1, wallet.getBalance());
@@ -123,7 +86,7 @@ public class WalletTest {
@Test
public void listeners() throws Exception {
- final Transaction fakeTx = createFakeTx(Utils.toNanoCoins(1, 0), myAddress);
+ final Transaction fakeTx = createFakeTx(params, Utils.toNanoCoins(1, 0), myAddress);
final boolean[] didRun = new boolean[1];
WalletEventListener listener = new WalletEventListener() {
public void onCoinsReceived(Wallet w, Transaction tx, BigInteger prevBalance, BigInteger newBalance) {
@@ -144,10 +107,10 @@ public class WalletTest {
// Receive 5 coins then half a coin.
BigInteger v1 = toNanoCoins(5, 0);
BigInteger v2 = toNanoCoins(0, 50);
- Transaction t1 = createFakeTx(v1, myAddress);
- Transaction t2 = createFakeTx(v2, myAddress);
- StoredBlock b1 = createFakeBlock(t1).storedBlock;
- StoredBlock b2 = createFakeBlock(t2).storedBlock;
+ Transaction t1 = createFakeTx(params, v1, myAddress);
+ Transaction t2 = createFakeTx(params, v2, myAddress);
+ StoredBlock b1 = createFakeBlock(params, blockStore, t1).storedBlock;
+ StoredBlock b2 = createFakeBlock(params, blockStore, t2).storedBlock;
BigInteger expected = toNanoCoins(5, 50);
wallet.receive(t1, b1, BlockChain.NewBlockType.BEST_CHAIN);
wallet.receive(t2, b2, BlockChain.NewBlockType.BEST_CHAIN);
@@ -165,7 +128,7 @@ public class WalletTest {
wallet.getBalance(Wallet.BalanceType.ESTIMATED)));
// Now confirm the transaction by including it into a block.
- StoredBlock b3 = createFakeBlock(spend).storedBlock;
+ StoredBlock b3 = createFakeBlock(params, blockStore, spend).storedBlock;
wallet.receive(spend, b3, BlockChain.NewBlockType.BEST_CHAIN);
// Change is confirmed. We started with 5.50 so we should have 4.50 left.
@@ -180,22 +143,22 @@ public class WalletTest {
@Test
public void blockChainCatchup() throws Exception {
- Transaction tx1 = createFakeTx(Utils.toNanoCoins(1, 0), myAddress);
- StoredBlock b1 = createFakeBlock(tx1).storedBlock;
+ Transaction tx1 = createFakeTx(params, Utils.toNanoCoins(1, 0), myAddress);
+ StoredBlock b1 = createFakeBlock(params, blockStore, tx1).storedBlock;
wallet.receive(tx1, b1, BlockChain.NewBlockType.BEST_CHAIN);
// Send 0.10 to somebody else.
Transaction send1 = wallet.createSend(new ECKey().toAddress(params), toNanoCoins(0, 10), myAddress);
// Pretend it makes it into the block chain, our wallet state is cleared but we still have the keys, and we
// want to get back to our previous state. We can do this by just not confirming the transaction as
// createSend is stateless.
- StoredBlock b2 = createFakeBlock(send1).storedBlock;
+ StoredBlock b2 = createFakeBlock(params, blockStore, send1).storedBlock;
wallet.receive(send1, b2, BlockChain.NewBlockType.BEST_CHAIN);
assertEquals(bitcoinValueToFriendlyString(wallet.getBalance()), "0.90");
// And we do it again after the catchup.
Transaction send2 = wallet.createSend(new ECKey().toAddress(params), toNanoCoins(0, 10), myAddress);
// What we'd really like to do is prove the official client would accept it .... no such luck unfortunately.
wallet.confirmSend(send2);
- StoredBlock b3 = createFakeBlock(send2).storedBlock;
+ StoredBlock b3 = createFakeBlock(params, blockStore, send2).storedBlock;
wallet.receive(send2, b3, BlockChain.NewBlockType.BEST_CHAIN);
assertEquals(bitcoinValueToFriendlyString(wallet.getBalance()), "0.80");
}
@@ -203,7 +166,7 @@ public class WalletTest {
@Test
public void balances() throws Exception {
BigInteger nanos = Utils.toNanoCoins(1, 0);
- Transaction tx1 = createFakeTx(nanos, myAddress);
+ Transaction tx1 = createFakeTx(params, nanos, myAddress);
wallet.receive(tx1, null, BlockChain.NewBlockType.BEST_CHAIN);
assertEquals(nanos, tx1.getValueSentToMe(wallet, true));
// Send 0.10 to somebody else.
@@ -216,7 +179,7 @@ public class WalletTest {
@Test
public void transactions() throws Exception {
// This test covers a bug in which Transaction.getValueSentFromMe was calculating incorrectly.
- Transaction tx = createFakeTx(Utils.toNanoCoins(1, 0), myAddress);
+ Transaction tx = createFakeTx(params, Utils.toNanoCoins(1, 0), myAddress);
// Now add another output (ie, change) that goes to some other address.
Address someOtherGuy = new ECKey().toAddress(params);
TransactionOutput output = new TransactionOutput(params, tx, Utils.toNanoCoins(0, 5), someOtherGuy);
@@ -255,7 +218,7 @@ public class WalletTest {
// Receive 1 BTC.
BigInteger nanos = Utils.toNanoCoins(1, 0);
- Transaction t1 = createFakeTx(nanos, myAddress);
+ Transaction t1 = createFakeTx(params, nanos, myAddress);
wallet.receive(t1, null, BlockChain.NewBlockType.BEST_CHAIN);
// Create a send to a merchant.
Transaction send1 = wallet.createSend(new ECKey().toAddress(params), toNanoCoins(0, 50));