/**
* Copyright 2013 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 org.bitcoinj.wallet;
import org.bitcoinj.core.*;
import org.bitcoinj.params.RegTestParams;
import org.bitcoinj.params.UnitTestParams;
import org.bitcoinj.testing.FakeTxBuilder;
import org.bitcoinj.testing.TestWithWallet;
import org.bitcoinj.wallet.CoinSelection;
import org.bitcoinj.wallet.DefaultCoinSelector;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.net.InetAddress;
import java.util.ArrayList;
import static org.bitcoinj.core.Coin.*;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.junit.Assert.*;
public class DefaultCoinSelectorTest extends TestWithWallet {
private static final NetworkParameters params = UnitTestParams.get();
@Before
@Override
public void setUp() throws Exception {
super.setUp();
Utils.setMockClock(); // Use mock clock
}
@After
@Override
public void tearDown() throws Exception {
super.tearDown();
}
@Test
public void selectable() throws Exception {
Transaction t;
t = new Transaction(params);
t.getConfidence().setConfidenceType(TransactionConfidence.ConfidenceType.PENDING);
assertFalse(DefaultCoinSelector.isSelectable(t));
t.getConfidence().setSource(TransactionConfidence.Source.SELF);
assertFalse(DefaultCoinSelector.isSelectable(t));
t.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("1.2.3.4")));
assertFalse(DefaultCoinSelector.isSelectable(t));
t.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("5.6.7.8")));
assertTrue(DefaultCoinSelector.isSelectable(t));
t = new Transaction(params);
t.getConfidence().setConfidenceType(TransactionConfidence.ConfidenceType.BUILDING);
assertTrue(DefaultCoinSelector.isSelectable(t));
t = new Transaction(RegTestParams.get());
t.getConfidence().setConfidenceType(TransactionConfidence.ConfidenceType.PENDING);
t.getConfidence().setSource(TransactionConfidence.Source.SELF);
assertTrue(DefaultCoinSelector.isSelectable(t));
}
@Test
public void depthOrdering() throws Exception {
// Send two transactions in two blocks on top of each other.
Transaction t1 = checkNotNull(sendMoneyToWallet(COIN, AbstractBlockChain.NewBlockType.BEST_CHAIN));
Transaction t2 = checkNotNull(sendMoneyToWallet(COIN, AbstractBlockChain.NewBlockType.BEST_CHAIN));
// Check we selected just the oldest one.
DefaultCoinSelector selector = new DefaultCoinSelector();
CoinSelection selection = selector.select(COIN, wallet.calculateAllSpendCandidates(true));
assertTrue(selection.gathered.contains(t1.getOutputs().get(0)));
assertEquals(COIN, selection.valueGathered);
// Check we ordered them correctly (by depth).
ArrayList<TransactionOutput> candidates = new ArrayList<TransactionOutput>();
candidates.add(t2.getOutput(0));
candidates.add(t1.getOutput(0));
DefaultCoinSelector.sortOutputs(candidates);
assertEquals(t1.getOutput(0), candidates.get(0));
assertEquals(t2.getOutput(0), candidates.get(1));
}
@Test
public void coinAgeOrdering() throws Exception {
// Send three transactions in four blocks on top of each other. Coin age of t1 is 1*4=4, coin age of t2 = 2*2=4
// and t3=0.01.
Transaction t1 = checkNotNull(sendMoneyToWallet(COIN, AbstractBlockChain.NewBlockType.BEST_CHAIN));
// Padding block.
wallet.notifyNewBestBlock(FakeTxBuilder.createFakeBlock(blockStore).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));
// Should be ordered t2, t1, t3.
ArrayList<TransactionOutput> candidates = new ArrayList<TransactionOutput>();
candidates.add(t3.getOutput(0));
candidates.add(t2.getOutput(0));
candidates.add(t1.getOutput(0));
DefaultCoinSelector.sortOutputs(candidates);
assertEquals(t2.getOutput(0), candidates.get(0));
assertEquals(t1.getOutput(0), candidates.get(1));
assertEquals(t3.getOutput(0), candidates.get(2));
}
}