Coverage Summary for Class: RskAllowUnconfirmedCoinSelector (co.rsk.peg.bitcoin)
Class |
Method, %
|
Line, %
|
RskAllowUnconfirmedCoinSelector |
0%
(0/3)
|
0%
(0/14)
|
RskAllowUnconfirmedCoinSelector$1 |
0%
(0/2)
|
0%
(0/8)
|
Total |
0%
(0/5)
|
0%
(0/22)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 package co.rsk.peg.bitcoin;
20
21 import com.google.common.annotations.VisibleForTesting;
22 import co.rsk.bitcoinj.core.Coin;
23 import co.rsk.bitcoinj.core.NetworkParameters;
24 import co.rsk.bitcoinj.core.TransactionOutput;
25 import co.rsk.bitcoinj.wallet.CoinSelector;
26 import co.rsk.bitcoinj.wallet.CoinSelection;
27
28 import java.math.BigInteger;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.Comparator;
32 import java.util.List;
33
34 /**
35 * Custom Coin selector :
36 * All outputs are selectable (like AllowUnconfirmedCoinSelector). We don't know how many confirmations an output has, but we just add them to the wallet once they have a lot of confirmations
37 * Sorts outputs just by hash number (ignores output value and number of confirmation) which produces a pseudo random order.
38 * Created by mario on 05/10/2016.
39 */
40 public class RskAllowUnconfirmedCoinSelector implements CoinSelector{
41
42 @Override
43 public CoinSelection select(Coin target, List<TransactionOutput> candidates) {
44 ArrayList<TransactionOutput> selected = new ArrayList<TransactionOutput>();
45 // Sort the inputs by age*value so we get the highest "coindays" spent.
46 // TODO: Consider changing the wallets internal format to track just outputs and keep them ordered.
47 ArrayList<TransactionOutput> sortedOutputs = new ArrayList<TransactionOutput>(candidates);
48 // When calculating the wallet balance, we may be asked to select all possible coins, if so, avoid sorting
49 // them in order to improve performance.
50 // TODO: Take in network parameters when instanatiated, and then test against the current network. Or just have a boolean parameter for "give me everything"
51 if (!target.equals(NetworkParameters.MAX_MONEY)) {
52 sortOutputs(sortedOutputs);
53 }
54 // Now iterate over the sorted outputs until we have got as close to the target as possible or a little
55 // bit over (excessive value will be change).
56 long total = 0;
57 for (TransactionOutput output : sortedOutputs) {
58 if (total >= target.value) {
59 break;
60 }
61
62 selected.add(output);
63 total += output.getValue().value;
64 }
65 // Total may be lower than target here, if the given candidates were insufficient to create to requested
66 // transaction.
67 return new CoinSelection(Coin.valueOf(total), selected);
68 }
69
70 @VisibleForTesting
71 public void sortOutputs(List<TransactionOutput> outputs) {
72 Collections.sort(outputs, new Comparator<TransactionOutput>() {
73 @Override
74 public int compare(TransactionOutput a, TransactionOutput b) {
75 a.getIndex();
76 BigInteger aHash = a.getParentTransactionHash().toBigInteger();
77 BigInteger bHash = b.getParentTransactionHash().toBigInteger();
78 int ret = aHash.compareTo(bHash);
79 if(ret == 0) {
80 ret = Integer.compare(a.getIndex(), b.getIndex());
81 }
82 return ret;
83 }
84 });
85 }
86 }