mirror of
https://github.com/Qortal/qortal.git
synced 2025-02-11 17:55:50 +00:00
For Balance Recorder, reward recordings only, that is the default.
This commit is contained in:
parent
c71f5fa8bf
commit
4f0aabfb36
@ -283,7 +283,7 @@ public class AssetsResource {
|
||||
Optional<HSQLDBBalanceRecorder> recorder = HSQLDBBalanceRecorder.getInstance();
|
||||
|
||||
if( recorder.isPresent()) {
|
||||
Optional<BlockHeightRangeAddressAmounts> addressAmounts = recorder.get().getAddressAmounts(new BlockHeightRange(begin, end));
|
||||
Optional<BlockHeightRangeAddressAmounts> addressAmounts = recorder.get().getAddressAmounts(new BlockHeightRange(begin, end, false));
|
||||
|
||||
if( addressAmounts.isPresent() ) {
|
||||
return addressAmounts.get().getAmounts().stream()
|
||||
|
@ -12,12 +12,15 @@ public class BlockHeightRange {
|
||||
|
||||
private int end;
|
||||
|
||||
private boolean isRewardDistribution;
|
||||
|
||||
public BlockHeightRange() {
|
||||
}
|
||||
|
||||
public BlockHeightRange(int begin, int end) {
|
||||
public BlockHeightRange(int begin, int end, boolean isRewardDistribution) {
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
this.isRewardDistribution = isRewardDistribution;
|
||||
}
|
||||
|
||||
public int getBegin() {
|
||||
@ -28,6 +31,10 @@ public class BlockHeightRange {
|
||||
return end;
|
||||
}
|
||||
|
||||
public boolean isRewardDistribution() {
|
||||
return isRewardDistribution;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@ -46,6 +53,7 @@ public class BlockHeightRange {
|
||||
return "BlockHeightRange{" +
|
||||
"begin=" + begin +
|
||||
", end=" + end +
|
||||
", isRewardDistribution=" + isRewardDistribution +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package org.qortal.repository.hsqldb;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.api.SearchMode;
|
||||
import org.qortal.api.resource.TransactionsResource;
|
||||
import org.qortal.arbitrary.misc.Category;
|
||||
import org.qortal.arbitrary.misc.Service;
|
||||
import org.qortal.controller.Controller;
|
||||
@ -14,7 +15,10 @@ import org.qortal.data.arbitrary.ArbitraryResourceCache;
|
||||
import org.qortal.data.arbitrary.ArbitraryResourceData;
|
||||
import org.qortal.data.arbitrary.ArbitraryResourceMetadata;
|
||||
import org.qortal.data.arbitrary.ArbitraryResourceStatus;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.Repository;
|
||||
import org.qortal.repository.RepositoryManager;
|
||||
import org.qortal.settings.Settings;
|
||||
import org.qortal.utils.BalanceRecorderUtils;
|
||||
|
||||
@ -434,17 +438,44 @@ public class HSQLDBCacheUtils {
|
||||
// if there is a prior height
|
||||
if(priorHeight.isPresent()) {
|
||||
|
||||
BlockHeightRange blockHeightRange = new BlockHeightRange(priorHeight.get(), currentHeight);
|
||||
boolean isRewardDistribution = BalanceRecorderUtils.isRewardDistributionRange(priorHeight.get(), currentHeight);
|
||||
|
||||
// if this range has a reward recording block or if other blocks are enabled for recording
|
||||
if( isRewardDistribution || !Settings.getInstance().isRewardRecordingOnly() ) {
|
||||
produceBalanceDynamics(currentHeight, priorHeight, isRewardDistribution, balancesByHeight, balanceDynamics, capacity);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOGGER.warn("Expecting prior height and nothing was discovered, current height = " + currentHeight);
|
||||
}
|
||||
}
|
||||
// else this should be the first recording
|
||||
else {
|
||||
LOGGER.info("first balance recording completed");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// wait 5 minutes
|
||||
timer.scheduleAtFixedRate(task, 300_000, frequency * 60_000);
|
||||
}
|
||||
|
||||
private static void produceBalanceDynamics(int currentHeight, Optional<Integer> priorHeight, boolean isRewardDistribution, ConcurrentHashMap<Integer, List<AccountBalanceData>> balancesByHeight, CopyOnWriteArrayList<BlockHeightRangeAddressAmounts> balanceDynamics, int capacity) {
|
||||
BlockHeightRange blockHeightRange = new BlockHeightRange(priorHeight.get(), currentHeight, isRewardDistribution);
|
||||
|
||||
LOGGER.debug("building dynamics for block heights: range = " + blockHeightRange);
|
||||
|
||||
List<AccountBalanceData> currentBalances = balancesByHeight.get(currentHeight);
|
||||
|
||||
ArrayList<TransactionData> transactions = getTransactionDataForBlocks(blockHeightRange);
|
||||
|
||||
LOGGER.info("transactions counted for balance adjustments: count = " + transactions.size());
|
||||
List<AddressAmountData> currentDynamics
|
||||
= BalanceRecorderUtils.buildBalanceDynamics(
|
||||
currentBalances,
|
||||
balancesByHeight.get(priorHeight.get()),
|
||||
Settings.getInstance().getMinimumBalanceRecording());
|
||||
Settings.getInstance().getMinimumBalanceRecording(),
|
||||
transactions);
|
||||
|
||||
LOGGER.debug("dynamics built: count = " + currentDynamics.size());
|
||||
|
||||
@ -467,19 +498,29 @@ public class HSQLDBCacheUtils {
|
||||
LOGGER.debug("removing oldest dynamics: range " + oldestDynamics.getRange());
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOGGER.warn("Expecting prior height and nothing was discovered, current height = " + currentHeight);
|
||||
}
|
||||
}
|
||||
// else this should be the first recording
|
||||
else {
|
||||
LOGGER.info("first balance recording completed");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// wait 5 minutes
|
||||
timer.scheduleAtFixedRate(task, 300_000, frequency * 60_000);
|
||||
private static ArrayList<TransactionData> getTransactionDataForBlocks(BlockHeightRange blockHeightRange) {
|
||||
ArrayList<TransactionData> transactions;
|
||||
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
List<byte[]> signatures
|
||||
= repository.getTransactionRepository().getSignaturesMatchingCriteria(
|
||||
blockHeightRange.getBegin() + 1, blockHeightRange.getEnd() - blockHeightRange.getBegin(),
|
||||
null, null,null, null, null,
|
||||
TransactionsResource.ConfirmationStatus.CONFIRMED,
|
||||
null, null, null);
|
||||
|
||||
transactions = new ArrayList<>(signatures.size());
|
||||
for (byte[] signature : signatures) {
|
||||
transactions.add(repository.getTransactionRepository().fromSignature(signature));
|
||||
}
|
||||
|
||||
LOGGER.debug(String.format("Found %s transactions for " + blockHeightRange, transactions.size()));
|
||||
} catch (Exception e) {
|
||||
transactions = new ArrayList<>(0);
|
||||
LOGGER.warn("Problems getting transactions for balance recording: " + e.getMessage());
|
||||
}
|
||||
return transactions;
|
||||
}
|
||||
|
||||
private static int recordCurrentBalances(ConcurrentHashMap<Integer, List<AccountBalanceData>> balancesByHeight) {
|
||||
|
@ -494,6 +494,13 @@ public class Settings {
|
||||
*/
|
||||
private int balanceRecorderRollbackAllowance = 100;
|
||||
|
||||
/**
|
||||
* Is Reward Recording Only
|
||||
*
|
||||
* Set true to only retain the recordings that cover reward distributions, otherwise set false.
|
||||
*/
|
||||
private boolean rewardRecordingOnly = true;
|
||||
|
||||
// Domain mapping
|
||||
public static class ThreadLimit {
|
||||
private String messageType;
|
||||
@ -1311,4 +1318,8 @@ public class Settings {
|
||||
public int getBalanceRecorderRollbackAllowance() {
|
||||
return balanceRecorderRollbackAllowance;
|
||||
}
|
||||
|
||||
public boolean isRewardRecordingOnly() {
|
||||
return rewardRecordingOnly;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,26 @@
|
||||
package org.qortal.utils;
|
||||
|
||||
import org.qortal.block.Block;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.PaymentData;
|
||||
import org.qortal.data.account.AccountBalanceData;
|
||||
import org.qortal.data.account.AddressAmountData;
|
||||
import org.qortal.data.account.BlockHeightRange;
|
||||
import org.qortal.data.account.BlockHeightRangeAddressAmounts;
|
||||
import org.qortal.data.transaction.ATTransactionData;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.BuyNameTransactionData;
|
||||
import org.qortal.data.transaction.CreateAssetOrderTransactionData;
|
||||
import org.qortal.data.transaction.DeployAtTransactionData;
|
||||
import org.qortal.data.transaction.MultiPaymentTransactionData;
|
||||
import org.qortal.data.transaction.PaymentTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.TransferAssetTransactionData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
@ -67,22 +80,190 @@ public class BalanceRecorderUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static List<AddressAmountData> buildBalanceDynamics(final List<AccountBalanceData> balances, final List<AccountBalanceData> priorBalances, long minimum) {
|
||||
public static List<AddressAmountData> buildBalanceDynamics(
|
||||
final List<AccountBalanceData> balances,
|
||||
final List<AccountBalanceData> priorBalances,
|
||||
long minimum,
|
||||
List<TransactionData> transactions) {
|
||||
|
||||
List<AddressAmountData> addressAmounts = new ArrayList<>(balances.size());
|
||||
Map<String, Long> amountsByAddress = new HashMap<>(transactions.size());
|
||||
|
||||
// prior balance
|
||||
addressAmounts.addAll(
|
||||
balances.stream()
|
||||
for( TransactionData transactionData : transactions ) {
|
||||
|
||||
mapBalanceModificationsForTransaction(amountsByAddress, transactionData);
|
||||
}
|
||||
|
||||
List<AddressAmountData> addressAmounts
|
||||
= balances.stream()
|
||||
.map(balance -> buildBalanceDynamicsForAccount(priorBalances, balance))
|
||||
.map( data -> adjustAddressAmount(amountsByAddress.getOrDefault(data.getAddress(), 0L), data))
|
||||
.filter(ADDRESS_AMOUNT_DATA_NOT_ZERO)
|
||||
.filter( data -> data.getAmount() >= minimum)
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
.filter(data -> data.getAmount() >= minimum)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return addressAmounts;
|
||||
}
|
||||
|
||||
public static AddressAmountData adjustAddressAmount(long adjustment, AddressAmountData data) {
|
||||
|
||||
return new AddressAmountData(data.getAddress(), data.getAmount() - adjustment);
|
||||
}
|
||||
|
||||
public static void mapBalanceModificationsForTransaction(Map<String, Long> amountsByAddress, TransactionData transactionData) {
|
||||
String creatorAddress;
|
||||
|
||||
// AT Transaction
|
||||
if( transactionData instanceof ATTransactionData) {
|
||||
creatorAddress = mapBalanceModificationsForAtTransaction(amountsByAddress, (ATTransactionData) transactionData);
|
||||
}
|
||||
// Buy Name Transaction
|
||||
else if( transactionData instanceof BuyNameTransactionData) {
|
||||
creatorAddress = mapBalanceModificationsForBuyNameTransaction(amountsByAddress, (BuyNameTransactionData) transactionData);
|
||||
}
|
||||
// Create Asset Order Transaction
|
||||
else if( transactionData instanceof CreateAssetOrderTransactionData) {
|
||||
//TODO I'm not sure how to handle this one. This hasn't been used at this point in the blockchain.
|
||||
|
||||
creatorAddress = Crypto.toAddress(transactionData.getCreatorPublicKey());
|
||||
}
|
||||
// Deploy AT Transaction
|
||||
else if( transactionData instanceof DeployAtTransactionData ) {
|
||||
creatorAddress = mapBalanceModificationsForDeployAtTransaction(amountsByAddress, (DeployAtTransactionData) transactionData);
|
||||
}
|
||||
// Multi Payment Transaction
|
||||
else if( transactionData instanceof MultiPaymentTransactionData) {
|
||||
creatorAddress = mapBalanceModificationsForMultiPaymentTransaction(amountsByAddress, (MultiPaymentTransactionData) transactionData);
|
||||
}
|
||||
// Payment Transaction
|
||||
else if( transactionData instanceof PaymentTransactionData ) {
|
||||
creatorAddress = mapBalanceModicationsForPaymentTransaction(amountsByAddress, (PaymentTransactionData) transactionData);
|
||||
}
|
||||
// Transfer Asset Transaction
|
||||
else if( transactionData instanceof TransferAssetTransactionData) {
|
||||
creatorAddress = mapBalanceModificationsForTransferAssetTransaction(amountsByAddress, (TransferAssetTransactionData) transactionData);
|
||||
}
|
||||
// Other Transactions
|
||||
else {
|
||||
creatorAddress = Crypto.toAddress(transactionData.getCreatorPublicKey());
|
||||
}
|
||||
|
||||
// all transactions modify the balance for fees
|
||||
mapBalanceModifications(amountsByAddress, transactionData.getFee(), creatorAddress, Optional.empty());
|
||||
}
|
||||
|
||||
public static String mapBalanceModificationsForTransferAssetTransaction(Map<String, Long> amountsByAddress, TransferAssetTransactionData transferAssetData) {
|
||||
String creatorAddress = Crypto.toAddress(transferAssetData.getSenderPublicKey());
|
||||
|
||||
if( transferAssetData.getAssetId() == 0) {
|
||||
mapBalanceModifications(
|
||||
amountsByAddress,
|
||||
transferAssetData.getAmount(),
|
||||
creatorAddress,
|
||||
Optional.of(transferAssetData.getRecipient())
|
||||
);
|
||||
}
|
||||
return creatorAddress;
|
||||
}
|
||||
|
||||
public static String mapBalanceModicationsForPaymentTransaction(Map<String, Long> amountsByAddress, PaymentTransactionData paymentData) {
|
||||
String creatorAddress = Crypto.toAddress(paymentData.getCreatorPublicKey());
|
||||
|
||||
mapBalanceModifications(amountsByAddress,
|
||||
paymentData.getAmount(),
|
||||
creatorAddress,
|
||||
Optional.of(paymentData.getRecipient())
|
||||
);
|
||||
return creatorAddress;
|
||||
}
|
||||
|
||||
public static String mapBalanceModificationsForMultiPaymentTransaction(Map<String, Long> amountsByAddress, MultiPaymentTransactionData multiPaymentData) {
|
||||
String creatorAddress = Crypto.toAddress(multiPaymentData.getCreatorPublicKey());
|
||||
|
||||
for(PaymentData payment : multiPaymentData.getPayments() ) {
|
||||
mapBalanceModificationsForTransaction(
|
||||
amountsByAddress,
|
||||
getPaymentTransactionData(multiPaymentData, payment)
|
||||
);
|
||||
}
|
||||
return creatorAddress;
|
||||
}
|
||||
|
||||
public static String mapBalanceModificationsForDeployAtTransaction(Map<String, Long> amountsByAddress, DeployAtTransactionData transactionData) {
|
||||
String creatorAddress;
|
||||
DeployAtTransactionData deployAtData = transactionData;
|
||||
|
||||
creatorAddress = Crypto.toAddress(deployAtData.getCreatorPublicKey());
|
||||
|
||||
if( deployAtData.getAssetId() == 0 ) {
|
||||
mapBalanceModifications(
|
||||
amountsByAddress,
|
||||
deployAtData.getAmount(),
|
||||
creatorAddress,
|
||||
Optional.of(deployAtData.getAtAddress())
|
||||
);
|
||||
}
|
||||
return creatorAddress;
|
||||
}
|
||||
|
||||
public static String mapBalanceModificationsForBuyNameTransaction(Map<String, Long> amountsByAddress, BuyNameTransactionData transactionData) {
|
||||
String creatorAddress;
|
||||
BuyNameTransactionData buyNameData = transactionData;
|
||||
|
||||
creatorAddress = Crypto.toAddress(buyNameData.getCreatorPublicKey());
|
||||
|
||||
mapBalanceModifications(
|
||||
amountsByAddress,
|
||||
buyNameData.getAmount(),
|
||||
creatorAddress,
|
||||
Optional.of(buyNameData.getSeller())
|
||||
);
|
||||
return creatorAddress;
|
||||
}
|
||||
|
||||
public static String mapBalanceModificationsForAtTransaction(Map<String, Long> amountsByAddress, ATTransactionData transactionData) {
|
||||
String creatorAddress;
|
||||
ATTransactionData atData = transactionData;
|
||||
creatorAddress = atData.getATAddress();
|
||||
|
||||
if( atData.getAssetId() != null && atData.getAssetId() == 0) {
|
||||
mapBalanceModifications(
|
||||
amountsByAddress,
|
||||
atData.getAmount(),
|
||||
creatorAddress,
|
||||
Optional.of(atData.getRecipient())
|
||||
);
|
||||
}
|
||||
return creatorAddress;
|
||||
}
|
||||
|
||||
public static PaymentTransactionData getPaymentTransactionData(MultiPaymentTransactionData multiPaymentData, PaymentData payment) {
|
||||
return new PaymentTransactionData(
|
||||
new BaseTransactionData(
|
||||
multiPaymentData.getTimestamp(),
|
||||
multiPaymentData.getTxGroupId(),
|
||||
multiPaymentData.getReference(),
|
||||
multiPaymentData.getCreatorPublicKey(),
|
||||
0L,
|
||||
multiPaymentData.getSignature()
|
||||
),
|
||||
payment.getRecipient(),
|
||||
payment.getAmount()
|
||||
);
|
||||
}
|
||||
|
||||
public static void mapBalanceModifications(Map<String, Long> amountsByAddress, Long amount, String sender, Optional<String> recipient) {
|
||||
amountsByAddress.put(
|
||||
sender,
|
||||
amountsByAddress.getOrDefault(sender, 0L) - amount
|
||||
);
|
||||
|
||||
if( recipient.isPresent() )
|
||||
amountsByAddress.put(
|
||||
recipient.get(),
|
||||
amountsByAddress.getOrDefault(recipient.get(), 0L) + amount
|
||||
);
|
||||
}
|
||||
|
||||
public static void removeRecordingsAboveHeight(int currentHeight, ConcurrentHashMap<Integer, List<AccountBalanceData>> balancesByHeight) {
|
||||
balancesByHeight.entrySet().stream()
|
||||
.filter(heightWithBalances -> heightWithBalances.getKey() > currentHeight)
|
||||
@ -116,4 +297,23 @@ public class BalanceRecorderUtils {
|
||||
.sorted(Comparator.reverseOrder()).findFirst();
|
||||
return priorHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Reward Distribution Range?
|
||||
*
|
||||
* @param start start height, exclusive
|
||||
* @param end end height, inclusive
|
||||
*
|
||||
* @return true there is a reward distribution block within this block range
|
||||
*/
|
||||
public static boolean isRewardDistributionRange(int start, int end) {
|
||||
|
||||
// iterate through the block height until a reward distribution block or the end of the range
|
||||
for( int i = start + 1; i <= end; i++) {
|
||||
if( Block.isRewardDistributionBlock(i) ) return true;
|
||||
}
|
||||
|
||||
// no reward distribution blocks found within range
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,27 @@ package org.qortal.test.utils;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.block.Block;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.data.PaymentData;
|
||||
import org.qortal.data.account.AccountBalanceData;
|
||||
import org.qortal.data.account.AddressAmountData;
|
||||
import org.qortal.data.account.BlockHeightRange;
|
||||
import org.qortal.data.account.BlockHeightRangeAddressAmounts;
|
||||
import org.qortal.data.transaction.ATTransactionData;
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.BuyNameTransactionData;
|
||||
import org.qortal.data.transaction.DeployAtTransactionData;
|
||||
import org.qortal.data.transaction.MultiPaymentTransactionData;
|
||||
import org.qortal.data.transaction.PaymentTransactionData;
|
||||
import org.qortal.data.transaction.RegisterNameTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.data.transaction.TransferAssetTransactionData;
|
||||
import org.qortal.utils.BalanceRecorderUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -18,6 +32,10 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class BalanceRecorderUtilsTests {
|
||||
|
||||
public static final String RECIPIENT_ADDRESS = "recipient";
|
||||
public static final String AT_ADDRESS = "atAddress";
|
||||
public static final String OTHER = "Other";
|
||||
|
||||
@Test
|
||||
public void testNotZeroForZero() {
|
||||
boolean test = BalanceRecorderUtils.ADDRESS_AMOUNT_DATA_NOT_ZERO.test( new AddressAmountData("", 0));
|
||||
@ -42,8 +60,8 @@ public class BalanceRecorderUtilsTests {
|
||||
@Test
|
||||
public void testAddressAmountComparatorReverseOrder() {
|
||||
|
||||
BlockHeightRangeAddressAmounts addressAmounts1 = new BlockHeightRangeAddressAmounts(new BlockHeightRange(2, 3), new ArrayList<>(0));
|
||||
BlockHeightRangeAddressAmounts addressAmounts2 = new BlockHeightRangeAddressAmounts(new BlockHeightRange(1, 2), new ArrayList<>(0));
|
||||
BlockHeightRangeAddressAmounts addressAmounts1 = new BlockHeightRangeAddressAmounts(new BlockHeightRange(2, 3, false), new ArrayList<>(0));
|
||||
BlockHeightRangeAddressAmounts addressAmounts2 = new BlockHeightRangeAddressAmounts(new BlockHeightRange(1, 2, false), new ArrayList<>(0));
|
||||
|
||||
int compare = BalanceRecorderUtils.BLOCK_HEIGHT_RANGE_ADDRESS_AMOUNTS_COMPARATOR.compare(addressAmounts1, addressAmounts2);
|
||||
|
||||
@ -53,8 +71,8 @@ public class BalanceRecorderUtilsTests {
|
||||
@Test
|
||||
public void testAddressAmountComparatorForwardOrder() {
|
||||
|
||||
BlockHeightRangeAddressAmounts addressAmounts1 = new BlockHeightRangeAddressAmounts(new BlockHeightRange(1, 2), new ArrayList<>(0));
|
||||
BlockHeightRangeAddressAmounts addressAmounts2 = new BlockHeightRangeAddressAmounts(new BlockHeightRange(2, 3), new ArrayList<>(0));
|
||||
BlockHeightRangeAddressAmounts addressAmounts1 = new BlockHeightRangeAddressAmounts(new BlockHeightRange(1, 2, false), new ArrayList<>(0));
|
||||
BlockHeightRangeAddressAmounts addressAmounts2 = new BlockHeightRangeAddressAmounts(new BlockHeightRange(2, 3, false), new ArrayList<>(0));
|
||||
|
||||
int compare = BalanceRecorderUtils.BLOCK_HEIGHT_RANGE_ADDRESS_AMOUNTS_COMPARATOR.compare(addressAmounts1, addressAmounts2);
|
||||
|
||||
@ -124,7 +142,7 @@ public class BalanceRecorderUtilsTests {
|
||||
List<AccountBalanceData> priorBalances = new ArrayList<>(1);
|
||||
priorBalances.add(new AccountBalanceData(address, 0, 1));
|
||||
|
||||
List<AddressAmountData> dynamics = BalanceRecorderUtils.buildBalanceDynamics(balances, priorBalances, 0);
|
||||
List<AddressAmountData> dynamics = BalanceRecorderUtils.buildBalanceDynamics(balances, priorBalances, 0, new ArrayList<>(0));
|
||||
|
||||
Assert.assertNotNull(dynamics);
|
||||
Assert.assertEquals(1, dynamics.size());
|
||||
@ -145,7 +163,7 @@ public class BalanceRecorderUtilsTests {
|
||||
|
||||
List<AccountBalanceData> priorBalances = new ArrayList<>(0);
|
||||
|
||||
List<AddressAmountData> dynamics = BalanceRecorderUtils.buildBalanceDynamics(balances, priorBalances, 0);
|
||||
List<AddressAmountData> dynamics = BalanceRecorderUtils.buildBalanceDynamics(balances, priorBalances, 0, new ArrayList<>(0));
|
||||
|
||||
Assert.assertNotNull(dynamics);
|
||||
Assert.assertEquals(1, dynamics.size());
|
||||
@ -156,6 +174,55 @@ public class BalanceRecorderUtilsTests {
|
||||
Assert.assertEquals(2, addressAmountData.getAmount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildBalanceDynamicOneAccountAdjustment() {
|
||||
List<AccountBalanceData> balances = new ArrayList<>(1);
|
||||
balances.add(new AccountBalanceData(RECIPIENT_ADDRESS, 0, 20));
|
||||
|
||||
List<AccountBalanceData> priorBalances = new ArrayList<>(0);
|
||||
priorBalances.add(new AccountBalanceData(RECIPIENT_ADDRESS, 0, 12));
|
||||
|
||||
List<TransactionData> transactions = new ArrayList<>();
|
||||
|
||||
final long amount = 5L;
|
||||
final long fee = 1L;
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
|
||||
try {
|
||||
byte[] creatorPublicKey = TestUtils.generatePublicKey();
|
||||
|
||||
PaymentTransactionData paymentData
|
||||
= new PaymentTransactionData(
|
||||
new BaseTransactionData(0L, 0, null, creatorPublicKey, fee, null),
|
||||
RECIPIENT_ADDRESS,
|
||||
amount
|
||||
);
|
||||
|
||||
transactions.add(paymentData);
|
||||
|
||||
List<AddressAmountData> dynamics
|
||||
= BalanceRecorderUtils.buildBalanceDynamics(
|
||||
balances,
|
||||
priorBalances,
|
||||
0,
|
||||
transactions
|
||||
);
|
||||
|
||||
Assert.assertNotNull(dynamics);
|
||||
Assert.assertEquals(1, dynamics.size());
|
||||
|
||||
AddressAmountData addressAmountData = dynamics.get(0);
|
||||
Assert.assertNotNull(addressAmountData);
|
||||
Assert.assertEquals(RECIPIENT_ADDRESS, addressAmountData.getAddress());
|
||||
Assert.assertEquals(3, addressAmountData.getAmount());
|
||||
} catch( Exception e ) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
|
||||
Assert.assertFalse(exceptionThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildBalanceDynamicsTwoAccountsNegativeValues() {
|
||||
|
||||
@ -170,7 +237,7 @@ public class BalanceRecorderUtilsTests {
|
||||
priorBalances.add(new AccountBalanceData(address2, 0, 200));
|
||||
priorBalances.add(new AccountBalanceData(address1, 0, 5000));
|
||||
|
||||
List<AddressAmountData> dynamics = BalanceRecorderUtils.buildBalanceDynamics(balances, priorBalances, -100L);
|
||||
List<AddressAmountData> dynamics = BalanceRecorderUtils.buildBalanceDynamics(balances, priorBalances, -100L, new ArrayList<>(0));
|
||||
|
||||
Assert.assertNotNull(dynamics);
|
||||
Assert.assertEquals(2, dynamics.size());
|
||||
@ -304,10 +371,10 @@ public class BalanceRecorderUtilsTests {
|
||||
|
||||
CopyOnWriteArrayList<BlockHeightRangeAddressAmounts> dynamics = new CopyOnWriteArrayList<>();
|
||||
|
||||
BlockHeightRange range1 = new BlockHeightRange(10, 20);
|
||||
BlockHeightRange range1 = new BlockHeightRange(10, 20, false);
|
||||
dynamics.add(new BlockHeightRangeAddressAmounts(range1, new ArrayList<>()));
|
||||
|
||||
BlockHeightRange range2 = new BlockHeightRange(1, 4);
|
||||
BlockHeightRange range2 = new BlockHeightRange(1, 4, false);
|
||||
dynamics.add(new BlockHeightRangeAddressAmounts(range2, new ArrayList<>()));
|
||||
|
||||
Assert.assertEquals(2, dynamics.size());
|
||||
@ -323,13 +390,13 @@ public class BalanceRecorderUtilsTests {
|
||||
|
||||
CopyOnWriteArrayList<BlockHeightRangeAddressAmounts> dynamics = new CopyOnWriteArrayList<>();
|
||||
|
||||
BlockHeightRange range1 = new BlockHeightRange(1,5);
|
||||
BlockHeightRange range1 = new BlockHeightRange(1,5, false);
|
||||
dynamics.add(new BlockHeightRangeAddressAmounts(range1, new ArrayList<>()));
|
||||
|
||||
BlockHeightRange range2 = new BlockHeightRange(6, 11);
|
||||
BlockHeightRange range2 = new BlockHeightRange(6, 11, false);
|
||||
dynamics.add((new BlockHeightRangeAddressAmounts(range2, new ArrayList<>())));
|
||||
|
||||
BlockHeightRange range3 = new BlockHeightRange(22, 16);
|
||||
BlockHeightRange range3 = new BlockHeightRange(22, 16, false);
|
||||
dynamics.add(new BlockHeightRangeAddressAmounts(range3, new ArrayList<>()));
|
||||
|
||||
Assert.assertEquals(3, dynamics.size());
|
||||
@ -344,18 +411,353 @@ public class BalanceRecorderUtilsTests {
|
||||
public void testRemoveOldestDynamicsTwice() {
|
||||
CopyOnWriteArrayList<BlockHeightRangeAddressAmounts> dynamics = new CopyOnWriteArrayList<>();
|
||||
|
||||
dynamics.add(new BlockHeightRangeAddressAmounts(new BlockHeightRange(1, 5), new ArrayList<>()));
|
||||
dynamics.add(new BlockHeightRangeAddressAmounts(new BlockHeightRange(5, 9), new ArrayList<>()));
|
||||
dynamics.add(new BlockHeightRangeAddressAmounts(new BlockHeightRange(1, 5, false), new ArrayList<>()));
|
||||
dynamics.add(new BlockHeightRangeAddressAmounts(new BlockHeightRange(5, 9, false), new ArrayList<>()));
|
||||
|
||||
Assert.assertEquals(2, dynamics.size());
|
||||
|
||||
BalanceRecorderUtils.removeOldestDynamics(dynamics);
|
||||
|
||||
Assert.assertEquals(1, dynamics.size());
|
||||
Assert.assertTrue(dynamics.get(0).getRange().equals(new BlockHeightRange(5, 9)));
|
||||
Assert.assertTrue(dynamics.get(0).getRange().equals(new BlockHeightRange(5, 9, false)));
|
||||
|
||||
BalanceRecorderUtils.removeOldestDynamics(dynamics);
|
||||
|
||||
Assert.assertEquals(0, dynamics.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapBalanceModificationsForPaymentTransaction() {
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
|
||||
try {
|
||||
final long amount = 1L;
|
||||
final long fee = 1L;
|
||||
|
||||
byte[] creatorPublicKey = TestUtils.generatePublicKey();
|
||||
|
||||
PaymentTransactionData paymentData
|
||||
= new PaymentTransactionData(
|
||||
new BaseTransactionData(0L, 0, null, creatorPublicKey, fee, null),
|
||||
RECIPIENT_ADDRESS,
|
||||
amount
|
||||
);
|
||||
|
||||
// map balance modifications for addresses in the transaction
|
||||
Map<String, Long> amountsByAddress = new HashMap<>();
|
||||
BalanceRecorderUtils.mapBalanceModicationsForPaymentTransaction(amountsByAddress, paymentData);
|
||||
|
||||
// this will not add the fee, that is done in a different place
|
||||
assertAmountsByAddress(amountsByAddress, amount, creatorPublicKey, RECIPIENT_ADDRESS);
|
||||
} catch (Exception e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
|
||||
Assert.assertFalse(exceptionThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapBalanceModificationsForAssetOrderTransaction() {
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
|
||||
try{
|
||||
final long amount = 1L;
|
||||
final long fee = 1L;
|
||||
|
||||
byte[] creatorPublicKey = TestUtils.generatePublicKey();
|
||||
|
||||
TransferAssetTransactionData transferAssetData
|
||||
= new TransferAssetTransactionData(
|
||||
new BaseTransactionData(0L, 0, null, creatorPublicKey, fee, null),
|
||||
RECIPIENT_ADDRESS,
|
||||
amount,
|
||||
0
|
||||
);
|
||||
|
||||
// map balance modifications for addresses in the transaction
|
||||
Map<String, Long> amountsByAddress = new HashMap<>();
|
||||
BalanceRecorderUtils.mapBalanceModificationsForTransferAssetTransaction(amountsByAddress, transferAssetData);
|
||||
|
||||
assertAmountsByAddress(amountsByAddress, amount, creatorPublicKey, RECIPIENT_ADDRESS);
|
||||
} catch( Exception e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
|
||||
Assert.assertFalse(exceptionThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapBalanceModificationsForATTransactionMessageType() {
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
|
||||
try {
|
||||
|
||||
final long fee = 1L;
|
||||
|
||||
byte[] creatorPublicKey = TestUtils.generatePublicKey();
|
||||
Map<String, Long> amountsByAddress = new HashMap<>();
|
||||
|
||||
ATTransactionData atTransactionData = new ATTransactionData(new BaseTransactionData(0L, 0, null, creatorPublicKey, fee, null),
|
||||
AT_ADDRESS,
|
||||
RECIPIENT_ADDRESS,
|
||||
new byte[0]);
|
||||
BalanceRecorderUtils.mapBalanceModificationsForAtTransaction( amountsByAddress, atTransactionData);
|
||||
|
||||
// no balance changes for AT message
|
||||
Assert.assertTrue(amountsByAddress.size() == 0);
|
||||
} catch( Exception e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
|
||||
Assert.assertFalse(exceptionThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapBalanceModificationsForATTransactionPaymentType() {
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
|
||||
try{
|
||||
final long amount = 1L;
|
||||
final long fee = 1L;
|
||||
|
||||
byte[] creatorPublicKey = TestUtils.generatePublicKey();
|
||||
|
||||
Map<String, Long> amountsByAddress = new HashMap<>();
|
||||
|
||||
ATTransactionData atTransactionData
|
||||
= new ATTransactionData(
|
||||
new BaseTransactionData(0L, 0, null, creatorPublicKey, fee, null),
|
||||
AT_ADDRESS,
|
||||
RECIPIENT_ADDRESS,
|
||||
amount,
|
||||
0
|
||||
);
|
||||
|
||||
BalanceRecorderUtils.mapBalanceModificationsForAtTransaction( amountsByAddress, atTransactionData);
|
||||
|
||||
assertAmountByAddress(amountsByAddress, amount, RECIPIENT_ADDRESS);
|
||||
|
||||
assertAmountByAddress(amountsByAddress, -amount, AT_ADDRESS);
|
||||
} catch( Exception e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
|
||||
Assert.assertFalse(exceptionThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapBalanceModificationsForBuyNameTransaction() {
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
|
||||
try{
|
||||
final long amount = 100L;
|
||||
final long fee = 1L;
|
||||
|
||||
byte[] creatorPublicKey = TestUtils.generatePublicKey();
|
||||
Map<String, Long> amountsByAddress = new HashMap<>();
|
||||
|
||||
BuyNameTransactionData buyNameData
|
||||
= new BuyNameTransactionData(
|
||||
new BaseTransactionData(0L, 0, null, creatorPublicKey, fee, null),
|
||||
"null",
|
||||
amount,
|
||||
RECIPIENT_ADDRESS
|
||||
);
|
||||
|
||||
BalanceRecorderUtils.mapBalanceModificationsForBuyNameTransaction(amountsByAddress, buyNameData);
|
||||
|
||||
assertAmountsByAddress(amountsByAddress, amount, creatorPublicKey, RECIPIENT_ADDRESS);
|
||||
} catch( Exception e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
|
||||
Assert.assertFalse(exceptionThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapBalanceModificationsForMultiPaymentTransaction() {
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
|
||||
try{
|
||||
final long amount = 100L;
|
||||
final long fee = 1L;
|
||||
|
||||
byte[] creatorPublicKey = TestUtils.generatePublicKey();
|
||||
Map<String, Long> amountsByAddress = new HashMap<>();
|
||||
|
||||
List<PaymentData> payments = new ArrayList<>();
|
||||
|
||||
payments.add(new PaymentData(RECIPIENT_ADDRESS, 0, amount));
|
||||
|
||||
MultiPaymentTransactionData multiPayment
|
||||
= new MultiPaymentTransactionData(new BaseTransactionData(0L, 0, null, creatorPublicKey, fee, null),
|
||||
payments);
|
||||
BalanceRecorderUtils.mapBalanceModificationsForMultiPaymentTransaction(amountsByAddress,multiPayment);
|
||||
assertAmountsByAddress(amountsByAddress, amount, creatorPublicKey, RECIPIENT_ADDRESS);
|
||||
} catch( Exception e ) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
|
||||
Assert.assertFalse(exceptionThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapBalanceModificationsForMultiPaymentTransaction2PaymentsOneAddress() {
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
|
||||
try{
|
||||
final long amount = 100L;
|
||||
final long fee = 1L;
|
||||
|
||||
byte[] creatorPublicKey = TestUtils.generatePublicKey();
|
||||
Map<String, Long> amountsByAddress = new HashMap<>();
|
||||
|
||||
List<PaymentData> payments = new ArrayList<>();
|
||||
|
||||
payments.add(new PaymentData(RECIPIENT_ADDRESS, 0, amount));
|
||||
payments.add(new PaymentData(RECIPIENT_ADDRESS, 0, amount));
|
||||
|
||||
MultiPaymentTransactionData multiPayment
|
||||
= new MultiPaymentTransactionData(new BaseTransactionData(0L, 0, null, creatorPublicKey, fee, null),
|
||||
payments);
|
||||
BalanceRecorderUtils.mapBalanceModificationsForMultiPaymentTransaction(amountsByAddress,multiPayment);
|
||||
assertAmountsByAddress(amountsByAddress, 2*amount, creatorPublicKey, RECIPIENT_ADDRESS);
|
||||
} catch( Exception e ) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
|
||||
Assert.assertFalse(exceptionThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapBalanceModificationsForMultiPaymentTransaction2PaymentsTwoAddresses() {
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
|
||||
try{
|
||||
final long amount = 100L;
|
||||
final long fee = 1L;
|
||||
|
||||
byte[] creatorPublicKey = TestUtils.generatePublicKey();
|
||||
Map<String, Long> amountsByAddress = new HashMap<>();
|
||||
|
||||
List<PaymentData> payments = new ArrayList<>();
|
||||
|
||||
payments.add(new PaymentData(RECIPIENT_ADDRESS, 0, amount));
|
||||
payments.add(new PaymentData(OTHER, 0, amount));
|
||||
|
||||
MultiPaymentTransactionData multiPayment
|
||||
= new MultiPaymentTransactionData(new BaseTransactionData(0L, 0, null, creatorPublicKey, fee, null),
|
||||
payments);
|
||||
BalanceRecorderUtils.mapBalanceModificationsForMultiPaymentTransaction(amountsByAddress,multiPayment);
|
||||
assertAmountByAddress(amountsByAddress, amount, RECIPIENT_ADDRESS);
|
||||
assertAmountByAddress(amountsByAddress, amount, OTHER);
|
||||
|
||||
String creatorAddress = Crypto.toAddress(creatorPublicKey);
|
||||
|
||||
assertAmountByAddress(amountsByAddress, 2*-amount, creatorAddress);
|
||||
} catch( Exception e ) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
|
||||
Assert.assertFalse(exceptionThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapBalanceModificationsForDeployAtTransaction() {
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
|
||||
try{
|
||||
final long amount = 3L;
|
||||
final long fee = 1L;
|
||||
|
||||
byte[] creatorPublicKey = TestUtils.generatePublicKey();
|
||||
Map<String, Long> amountsByAddress = new HashMap<>();
|
||||
|
||||
DeployAtTransactionData deployAt
|
||||
= new DeployAtTransactionData(
|
||||
new BaseTransactionData(0L, 0, null, creatorPublicKey, fee, null),
|
||||
AT_ADDRESS, "name", "description", "type", "tags", new byte[0], amount, Asset.QORT
|
||||
);
|
||||
|
||||
BalanceRecorderUtils.mapBalanceModificationsForDeployAtTransaction(amountsByAddress,deployAt);
|
||||
assertAmountsByAddress(amountsByAddress, amount, creatorPublicKey, AT_ADDRESS);
|
||||
} catch( Exception e) {
|
||||
exceptionThrown = true;
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Assert.assertFalse(exceptionThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMapBalanceModificationsForTransaction() {
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
|
||||
try {
|
||||
final long fee = 2;
|
||||
|
||||
byte[] creatorPublicKey = TestUtils.generatePublicKey();
|
||||
Map<String, Long> amountsByAddress = new HashMap<>();
|
||||
|
||||
BalanceRecorderUtils.mapBalanceModificationsForTransaction(
|
||||
amountsByAddress,
|
||||
new RegisterNameTransactionData(
|
||||
new BaseTransactionData(0L, 0, null, creatorPublicKey, fee, null),
|
||||
"aaa", "data", "aaa")
|
||||
);
|
||||
|
||||
String creatorAddress = Crypto.toAddress(creatorPublicKey);
|
||||
|
||||
assertAmountByAddress(amountsByAddress, -fee, creatorAddress);
|
||||
} catch(Exception e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
|
||||
Assert.assertFalse(exceptionThrown);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockHeightRangeEqualityTrue() {
|
||||
|
||||
BlockHeightRange range1 = new BlockHeightRange(2, 4, false);
|
||||
BlockHeightRange range2 = new BlockHeightRange(2, 4, true);
|
||||
|
||||
Assert.assertTrue(range1.equals(range2));
|
||||
Assert.assertEquals(range1, range2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBloHeightRangeEqualityFalse() {
|
||||
|
||||
BlockHeightRange range1 = new BlockHeightRange(2, 3, true);
|
||||
BlockHeightRange range2 = new BlockHeightRange(2, 4, true);
|
||||
|
||||
Assert.assertFalse(range1.equals(range2));
|
||||
}
|
||||
|
||||
private static void assertAmountsByAddress(Map<String, Long> amountsByAddress, long amount, byte[] creatorPublicKey, String recipientAddress) {
|
||||
assertAmountByAddress(amountsByAddress, amount, recipientAddress);
|
||||
|
||||
String creatorAddress = Crypto.toAddress(creatorPublicKey);
|
||||
|
||||
assertAmountByAddress(amountsByAddress, -amount, creatorAddress);
|
||||
}
|
||||
|
||||
private static void assertAmountByAddress(Map<String, Long> amountsByAddress, long amount, String address) {
|
||||
Long amountForAddress = amountsByAddress.get(address);
|
||||
|
||||
Assert.assertTrue(amountsByAddress.containsKey(address));
|
||||
Assert.assertNotNull(amountForAddress);
|
||||
Assert.assertEquals(amount, amountForAddress.longValue());
|
||||
}
|
||||
}
|
48
src/test/java/org/qortal/test/utils/TestUtils.java
Normal file
48
src/test/java/org/qortal/test/utils/TestUtils.java
Normal file
@ -0,0 +1,48 @@
|
||||
package org.qortal.test.utils;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Security;
|
||||
|
||||
public class TestUtils {
|
||||
public static byte[] generatePublicKey() throws Exception {
|
||||
// Add the Bouncy Castle provider
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
// Generate a key pair
|
||||
KeyPair keyPair = generateKeyPair();
|
||||
|
||||
// Get the public key
|
||||
PublicKey publicKey = keyPair.getPublic();
|
||||
|
||||
// Get the public key as a byte array
|
||||
byte[] publicKeyBytes = publicKey.getEncoded();
|
||||
|
||||
// Generate a RIPEMD160 message digest from the public key
|
||||
byte[] ripeMd160Digest = generateRipeMd160Digest(publicKeyBytes);
|
||||
|
||||
return ripeMd160Digest;
|
||||
}
|
||||
|
||||
public static KeyPair generateKeyPair() throws Exception {
|
||||
// Generate a key pair using the RSA algorithm
|
||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
keyGen.initialize(2048); // Key size (bits)
|
||||
return keyGen.generateKeyPair();
|
||||
}
|
||||
|
||||
public static byte[] generateRipeMd160Digest(byte[] input) throws Exception {
|
||||
// Create a RIPEMD160 message digest instance
|
||||
MessageDigest ripeMd160 = MessageDigest.getInstance("RIPEMD160", new BouncyCastleProvider());
|
||||
|
||||
// Update the message digest with the input bytes
|
||||
ripeMd160.update(input);
|
||||
|
||||
// Get the message digest bytes
|
||||
return ripeMd160.digest();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user