Adjusted bitcoiny to convert transaction info into the new DTO

This commit is contained in:
Istvan Szabo 2021-05-25 23:57:54 +01:00
parent 9a3414aaa7
commit 427a415fbf
4 changed files with 52 additions and 22 deletions

View File

@ -23,8 +23,8 @@ import org.qortal.api.ApiExceptionFactory;
import org.qortal.api.Security; import org.qortal.api.Security;
import org.qortal.api.model.crosschain.BitcoinSendRequest; import org.qortal.api.model.crosschain.BitcoinSendRequest;
import org.qortal.crosschain.Bitcoin; import org.qortal.crosschain.Bitcoin;
import org.qortal.crosschain.BitcoinyTransaction;
import org.qortal.crosschain.ForeignBlockchainException; import org.qortal.crosschain.ForeignBlockchainException;
import org.qortal.crosschain.SimpleTransaction;
@Path("/crosschain/btc") @Path("/crosschain/btc")
@Tag(name = "Cross-Chain (Bitcoin)") @Tag(name = "Cross-Chain (Bitcoin)")
@ -89,12 +89,12 @@ public class CrossChainBitcoinResource {
), ),
responses = { responses = {
@ApiResponse( @ApiResponse(
content = @Content(array = @ArraySchema( schema = @Schema( implementation = BitcoinyTransaction.class ) ) ) content = @Content(array = @ArraySchema( schema = @Schema( implementation = SimpleTransaction.class ) ) )
) )
} }
) )
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) @ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE})
public List<BitcoinyTransaction> getBitcoinWalletTransactions(String key58) { public List<SimpleTransaction> getBitcoinWalletTransactions(String key58) {
Security.checkApiCallAllowed(request); Security.checkApiCallAllowed(request);
Bitcoin bitcoin = Bitcoin.getInstance(); Bitcoin bitcoin = Bitcoin.getInstance();

View File

@ -22,9 +22,9 @@ import org.qortal.api.ApiErrors;
import org.qortal.api.ApiExceptionFactory; import org.qortal.api.ApiExceptionFactory;
import org.qortal.api.Security; import org.qortal.api.Security;
import org.qortal.api.model.crosschain.LitecoinSendRequest; import org.qortal.api.model.crosschain.LitecoinSendRequest;
import org.qortal.crosschain.BitcoinyTransaction;
import org.qortal.crosschain.ForeignBlockchainException; import org.qortal.crosschain.ForeignBlockchainException;
import org.qortal.crosschain.Litecoin; import org.qortal.crosschain.Litecoin;
import org.qortal.crosschain.SimpleTransaction;
@Path("/crosschain/ltc") @Path("/crosschain/ltc")
@Tag(name = "Cross-Chain (Litecoin)") @Tag(name = "Cross-Chain (Litecoin)")
@ -89,12 +89,12 @@ public class CrossChainLitecoinResource {
), ),
responses = { responses = {
@ApiResponse( @ApiResponse(
content = @Content(array = @ArraySchema( schema = @Schema( implementation = BitcoinyTransaction.class ) ) ) content = @Content(array = @ArraySchema( schema = @Schema( implementation = SimpleTransaction.class ) ) )
) )
} }
) )
@ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) @ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE})
public List<BitcoinyTransaction> getLitecoinWalletTransactions(String key58) { public List<SimpleTransaction> getLitecoinWalletTransactions(String key58) {
Security.checkApiCallAllowed(request); Security.checkApiCallAllowed(request);
Litecoin litecoin = Litecoin.getInstance(); Litecoin litecoin = Litecoin.getInstance();

View File

@ -91,7 +91,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
return this.params; return this.params;
} }
// Interface obligations // Interface obligations
@Override @Override
public boolean isValidAddress(String address) { public boolean isValidAddress(String address) {
@ -171,7 +171,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
/** /**
* Returns fixed P2SH spending fee, in sats per 1000bytes, optionally for historic timestamp. * Returns fixed P2SH spending fee, in sats per 1000bytes, optionally for historic timestamp.
* *
* @param timestamp optional milliseconds since epoch, or null for 'now' * @param timestamp optional milliseconds since epoch, or null for 'now'
* @return sats per 1000bytes * @return sats per 1000bytes
* @throws ForeignBlockchainException if something went wrong * @throws ForeignBlockchainException if something went wrong
@ -271,7 +271,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
/** /**
* Returns bitcoinj transaction sending <tt>amount</tt> to <tt>recipient</tt>. * Returns bitcoinj transaction sending <tt>amount</tt> to <tt>recipient</tt>.
* *
* @param xprv58 BIP32 private key * @param xprv58 BIP32 private key
* @param recipient P2PKH address * @param recipient P2PKH address
* @param amount unscaled amount * @param amount unscaled amount
@ -303,7 +303,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
/** /**
* Returns bitcoinj transaction sending <tt>amount</tt> to <tt>recipient</tt> using default fees. * Returns bitcoinj transaction sending <tt>amount</tt> to <tt>recipient</tt> using default fees.
* *
* @param xprv58 BIP32 private key * @param xprv58 BIP32 private key
* @param recipient P2PKH address * @param recipient P2PKH address
* @param amount unscaled amount * @param amount unscaled amount
@ -332,7 +332,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
return balance.value; return balance.value;
} }
public List<BitcoinyTransaction> getWalletTransactions(String key58) throws ForeignBlockchainException { public List<SimpleTransaction> getWalletTransactions(String key58) throws ForeignBlockchainException {
Context.propagate(bitcoinjContext); Context.propagate(bitcoinjContext);
Wallet wallet = walletFromDeterministicKey58(key58); Wallet wallet = walletFromDeterministicKey58(key58);
@ -344,6 +344,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
List<DeterministicKey> keys = new ArrayList<>(keyChain.getLeafKeys()); List<DeterministicKey> keys = new ArrayList<>(keyChain.getLeafKeys());
Set<BitcoinyTransaction> walletTransactions = new HashSet<>(); Set<BitcoinyTransaction> walletTransactions = new HashSet<>();
Set<String> keySet = new HashSet<>();
int ki = 0; int ki = 0;
do { do {
@ -354,6 +355,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
// Check for transactions // Check for transactions
Address address = Address.fromKey(this.params, dKey, ScriptType.P2PKH); Address address = Address.fromKey(this.params, dKey, ScriptType.P2PKH);
keySet.add(address.toString());
byte[] script = ScriptBuilder.createOutputScript(address).getProgram(); byte[] script = ScriptBuilder.createOutputScript(address).getProgram();
// Ask for transaction history - if it's empty then key has never been used // Ask for transaction history - if it's empty then key has never been used
@ -377,9 +379,41 @@ public abstract class Bitcoiny implements ForeignBlockchain {
// Process new keys // Process new keys
} while (true); } while (true);
Comparator<BitcoinyTransaction> newestTimestampFirstComparator = Comparator.comparingInt((BitcoinyTransaction txn) -> txn.timestamp).reversed(); Comparator<SimpleTransaction> newestTimestampFirstComparator = Comparator.comparingInt(SimpleTransaction::getTimestamp).reversed();
return walletTransactions.stream().sorted(newestTimestampFirstComparator).collect(Collectors.toList()); return walletTransactions.stream().map(t -> convertToSimpleTransaction(t, keySet)).sorted(newestTimestampFirstComparator).collect(Collectors.toList());
}
protected SimpleTransaction convertToSimpleTransaction(BitcoinyTransaction t, Set<String> keySet) {
long amount = 0;
long total = 0L;
for (BitcoinyTransaction.Input input : t.inputs) {
try {
BitcoinyTransaction t2 = getTransaction(input.outputTxHash);
List<String> senders = t2.outputs.get(input.outputVout).addresses;
for (String sender : senders) {
if (keySet.contains(sender)) {
total += t2.outputs.get(input.outputVout).value;
}
}
} catch (ForeignBlockchainException e) {
LOGGER.trace("Failed to retrieve transaction information {}", input.outputTxHash);
}
}
if (t.outputs != null && !t.outputs.isEmpty()) {
for (BitcoinyTransaction.Output output : t.outputs) {
for (String address : output.addresses) {
if (keySet.contains(address)) {
if (total > 0L) {
amount -= (total - output.value);
} else {
amount += output.value;
}
}
}
}
}
return new SimpleTransaction(t.txHash, t.timestamp, amount);
} }
/** /**
@ -421,7 +455,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
* If there are no unspent outputs then either: * If there are no unspent outputs then either:
* a) all the outputs have been spent * a) all the outputs have been spent
* b) address has never been used * b) address has never been used
* *
* For case (a) we want to remember not to check this address (key) again. * For case (a) we want to remember not to check this address (key) again.
*/ */
@ -501,7 +535,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
* If there are no unspent outputs then either: * If there are no unspent outputs then either:
* a) all the outputs have been spent * a) all the outputs have been spent
* b) address has never been used * b) address has never been used
* *
* For case (a) we want to remember not to check this address (key) again. * For case (a) we want to remember not to check this address (key) again.
*/ */

View File

@ -8,11 +8,7 @@ import java.util.stream.Collectors;
import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.AddressFormatException;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
import org.qortal.crosschain.Bitcoin; import org.qortal.crosschain.*;
import org.qortal.crosschain.Bitcoiny;
import org.qortal.crosschain.BitcoinyTransaction;
import org.qortal.crosschain.ForeignBlockchainException;
import org.qortal.crosschain.Litecoin;
import org.qortal.settings.Settings; import org.qortal.settings.Settings;
public class GetWalletTransactions { public class GetWalletTransactions {
@ -69,7 +65,7 @@ public class GetWalletTransactions {
System.out.println(String.format("Using %s", bitcoiny.getBlockchainProvider().getNetId())); System.out.println(String.format("Using %s", bitcoiny.getBlockchainProvider().getNetId()));
// Grab all outputs from transaction // Grab all outputs from transaction
List<BitcoinyTransaction> transactions = null; List<SimpleTransaction> transactions = null;
try { try {
transactions = bitcoiny.getWalletTransactions(key58); transactions = bitcoiny.getWalletTransactions(key58);
} catch (ForeignBlockchainException e) { } catch (ForeignBlockchainException e) {
@ -79,7 +75,7 @@ public class GetWalletTransactions {
System.out.println(String.format("Found %d transaction%s", transactions.size(), (transactions.size() != 1 ? "s" : ""))); System.out.println(String.format("Found %d transaction%s", transactions.size(), (transactions.size() != 1 ? "s" : "")));
for (BitcoinyTransaction transaction : transactions.stream().sorted(Comparator.comparingInt(t -> t.timestamp)).collect(Collectors.toList())) for (SimpleTransaction transaction : transactions.stream().sorted(Comparator.comparingInt(SimpleTransaction::getTimestamp)).collect(Collectors.toList()))
System.out.println(String.format("%s", transaction)); System.out.println(String.format("%s", transaction));
} }