UTXOProvider: getOpenTransactionOutputs() to take a list of ECKeys rather than addresses.

This commit is contained in:
Andreas Schildbach 2018-03-01 17:16:31 +01:00
parent d92dfdfd14
commit 2c768bfe07
7 changed files with 19 additions and 22 deletions

View File

@ -25,15 +25,13 @@ import java.util.List;
* <p>A {@link org.bitcoinj.store.FullPrunedBlockStore} is an internal implementation within bitcoinj.</p> * <p>A {@link org.bitcoinj.store.FullPrunedBlockStore} is an internal implementation within bitcoinj.</p>
*/ */
public interface UTXOProvider { public interface UTXOProvider {
// TODO currently the access to outputs is by address. Change to ECKey
/** /**
* Get the list of {@link UTXO}'s for a given address. * Get the list of {@link UTXO}'s for given keys.
* @param addresses List of address. * @param keys List of keys.
* @return The list of transaction outputs. * @return The list of transaction outputs.
* @throws UTXOProviderException If there is an error. * @throws UTXOProviderException If there is an error.
*/ */
List<UTXO> getOpenTransactionOutputs(List<LegacyAddress> addresses) throws UTXOProviderException; List<UTXO> getOpenTransactionOutputs(List<ECKey> keys) throws UTXOProviderException;
/** /**
* Get the height of the chain head. * Get the height of the chain head.

View File

@ -1150,14 +1150,15 @@ public abstract class DatabaseFullPrunedBlockStore implements FullPrunedBlockSto
} }
@Override @Override
public List<UTXO> getOpenTransactionOutputs(List<LegacyAddress> addresses) throws UTXOProviderException { public List<UTXO> getOpenTransactionOutputs(List<ECKey> keys) throws UTXOProviderException {
PreparedStatement s = null; PreparedStatement s = null;
List<UTXO> outputs = new ArrayList<>(); List<UTXO> outputs = new ArrayList<>();
try { try {
maybeConnect(); maybeConnect();
s = conn.get().prepareStatement(getTransactionOutputSelectSQL()); s = conn.get().prepareStatement(getTransactionOutputSelectSQL());
for (LegacyAddress address : addresses) { for (ECKey key : keys) {
s.setString(1, address.toString()); // TODO switch to pubKeyHash in order to support native segwit addresses
s.setString(1, LegacyAddress.fromKey(params, key).toString());
ResultSet rs = s.executeQuery(); ResultSet rs = s.executeQuery();
while (rs.next()) { while (rs.next()) {
Sha256Hash hash = Sha256Hash.wrap(rs.getBytes(1)); Sha256Hash hash = Sha256Hash.wrap(rs.getBytes(1));

View File

@ -30,6 +30,7 @@ import java.nio.ByteBuffer;
import org.bitcoinj.core.LegacyAddress; import org.bitcoinj.core.LegacyAddress;
import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.StoredBlock; import org.bitcoinj.core.StoredBlock;
@ -420,16 +421,16 @@ public class LevelDBFullPrunedBlockStore implements FullPrunedBlockStore {
} }
@Override @Override
public List<UTXO> getOpenTransactionOutputs(List<LegacyAddress> addresses) throws UTXOProviderException { public List<UTXO> getOpenTransactionOutputs(List<ECKey> keys) throws UTXOProviderException {
// Run this on a snapshot of database so internally consistent result // Run this on a snapshot of database so internally consistent result
// This is critical or if one address paid another could get incorrect // This is critical or if one address paid another could get incorrect
// results // results
List<UTXO> results = new LinkedList<>(); List<UTXO> results = new LinkedList<>();
for (LegacyAddress a : addresses) { for (ECKey key : keys) {
ByteBuffer bb = ByteBuffer.allocate(21); ByteBuffer bb = ByteBuffer.allocate(21);
bb.put((byte) KeyType.ADDRESS_HASHINDEX.ordinal()); bb.put((byte) KeyType.ADDRESS_HASHINDEX.ordinal());
bb.put(a.getHash()); bb.put(key.getPubKeyHash());
ReadOptions ro = new ReadOptions(); ReadOptions ro = new ReadOptions();
Snapshot sn = db.getSnapshot(); Snapshot sn = db.getSnapshot();
@ -443,7 +444,7 @@ public class LevelDBFullPrunedBlockStore implements FullPrunedBlockStore {
bbKey.get(); // remove the address_hashindex byte. bbKey.get(); // remove the address_hashindex byte.
byte[] addressKey = new byte[20]; byte[] addressKey = new byte[20];
bbKey.get(addressKey); bbKey.get(addressKey);
if (!Arrays.equals(addressKey, a.getHash())) { if (!Arrays.equals(addressKey, key.getPubKeyHash())) {
break; break;
} }
byte[] hashBytes = new byte[32]; byte[] hashBytes = new byte[32];

View File

@ -412,13 +412,15 @@ public class MemoryFullPrunedBlockStore implements FullPrunedBlockStore {
} }
@Override @Override
public List<UTXO> getOpenTransactionOutputs(List<LegacyAddress> addresses) throws UTXOProviderException { public List<UTXO> getOpenTransactionOutputs(List<ECKey> keys) throws UTXOProviderException {
// This is *NOT* optimal: We go through all the outputs and select the ones we are looking for. // This is *NOT* optimal: We go through all the outputs and select the ones we are looking for.
// If someone uses this store for production then they have a lot more to worry about than an inefficient impl :) // If someone uses this store for production then they have a lot more to worry about than an inefficient impl :)
List<UTXO> foundOutputs = new ArrayList<>(); List<UTXO> foundOutputs = new ArrayList<>();
List<UTXO> outputsList = transactionOutputMap.values(); List<UTXO> outputsList = transactionOutputMap.values();
for (UTXO output : outputsList) { for (UTXO output : outputsList) {
for (LegacyAddress address : addresses) { for (ECKey key : keys) {
// TODO switch to pubKeyHash in order to support native segwit addresses
Address address = LegacyAddress.fromKey(params, key);
if (output.getAddress().equals(address.toString())) { if (output.getAddress().equals(address.toString())) {
foundOutputs.add(output); foundOutputs.add(output);
} }

View File

@ -4300,12 +4300,7 @@ public class Wallet extends BaseTaggableObject
List<UTXO> candidates = new ArrayList<>(); List<UTXO> candidates = new ArrayList<>();
List<ECKey> keys = getImportedKeys(); List<ECKey> keys = getImportedKeys();
keys.addAll(getActiveKeyChain().getLeafKeys()); keys.addAll(getActiveKeyChain().getLeafKeys());
List<LegacyAddress> addresses = new ArrayList<>(); candidates.addAll(utxoProvider.getOpenTransactionOutputs(keys));
for (ECKey key : keys) {
LegacyAddress address = LegacyAddress.fromKey(params, key);
addresses.add(address);
}
candidates.addAll(utxoProvider.getOpenTransactionOutputs(addresses));
return candidates; return candidates;
} }

View File

@ -272,7 +272,7 @@ public abstract class AbstractFullPrunedBlockChainTest {
chain.add(rollingBlock); chain.add(rollingBlock);
totalAmount = totalAmount.add(amount); totalAmount = totalAmount.add(amount);
List<UTXO> outputs = store.getOpenTransactionOutputs(Lists.newArrayList(address)); List<UTXO> outputs = store.getOpenTransactionOutputs(Lists.newArrayList(toKey));
assertNotNull(outputs); assertNotNull(outputs);
assertEquals("Wrong Number of Outputs", 1, outputs.size()); assertEquals("Wrong Number of Outputs", 1, outputs.size());
UTXO output = outputs.get(0); UTXO output = outputs.get(0);

View File

@ -69,7 +69,7 @@ public class TransactionInputTest {
} }
@Override @Override
public List<UTXO> getOpenTransactionOutputs(List<LegacyAddress> addresses) throws UTXOProviderException { public List<UTXO> getOpenTransactionOutputs(List<ECKey> addresses) throws UTXOProviderException {
return Lists.newArrayList(utxo); return Lists.newArrayList(utxo);
} }