forked from Qortal/qortal
Merge branch 'Qortal:master' into master
This commit is contained in:
commit
92d589a1ca
10
pom.xml
10
pom.xml
@ -3,7 +3,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.qortal</groupId>
|
<groupId>org.qortal</groupId>
|
||||||
<artifactId>qortal</artifactId>
|
<artifactId>qortal</artifactId>
|
||||||
<version>4.5.0</version>
|
<version>4.5.1</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<properties>
|
<properties>
|
||||||
<skipTests>true</skipTests>
|
<skipTests>true</skipTests>
|
||||||
@ -21,7 +21,7 @@
|
|||||||
<dagger.version>1.2.2</dagger.version>
|
<dagger.version>1.2.2</dagger.version>
|
||||||
<extendedset.version>0.12.3</extendedset.version>
|
<extendedset.version>0.12.3</extendedset.version>
|
||||||
<git-commit-id-plugin.version>4.9.10</git-commit-id-plugin.version>
|
<git-commit-id-plugin.version>4.9.10</git-commit-id-plugin.version>
|
||||||
<grpc.version>1.61.0</grpc.version>
|
<grpc.version>1.61.1</grpc.version>
|
||||||
<guava.version>33.0.0-jre</guava.version>
|
<guava.version>33.0.0-jre</guava.version>
|
||||||
<hamcrest-library.version>2.2</hamcrest-library.version>
|
<hamcrest-library.version>2.2</hamcrest-library.version>
|
||||||
<homoglyph.version>1.2.1</homoglyph.version>
|
<homoglyph.version>1.2.1</homoglyph.version>
|
||||||
@ -31,9 +31,9 @@
|
|||||||
<javax.servlet-api.version>4.0.1</javax.servlet-api.version>
|
<javax.servlet-api.version>4.0.1</javax.servlet-api.version>
|
||||||
<jaxb-runtime.version>2.3.9</jaxb-runtime.version>
|
<jaxb-runtime.version>2.3.9</jaxb-runtime.version>
|
||||||
<jersey.version>2.41</jersey.version>
|
<jersey.version>2.41</jersey.version>
|
||||||
<jetty.version>9.4.53.v20231009</jetty.version>
|
<jetty.version>9.4.54.v20240208</jetty.version>
|
||||||
<json-simple.version>1.1.1</json-simple.version>
|
<json-simple.version>1.1.1</json-simple.version>
|
||||||
<json.version>20231013</json.version>
|
<json.version>20240205</json.version>
|
||||||
<jsoup.version>1.17.2</jsoup.version>
|
<jsoup.version>1.17.2</jsoup.version>
|
||||||
<junit-jupiter-engine.version>5.10.0</junit-jupiter-engine.version>
|
<junit-jupiter-engine.version>5.10.0</junit-jupiter-engine.version>
|
||||||
<lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>
|
<lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>
|
||||||
@ -46,7 +46,7 @@
|
|||||||
<maven-surefire-plugin.version>3.2.5</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>3.2.5</maven-surefire-plugin.version>
|
||||||
<package-info-maven-plugin.version>1.1.0</package-info-maven-plugin.version>
|
<package-info-maven-plugin.version>1.1.0</package-info-maven-plugin.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<protobuf.version>3.25.1</protobuf.version>
|
<protobuf.version>3.25.2</protobuf.version>
|
||||||
<replacer.version>1.5.3</replacer.version>
|
<replacer.version>1.5.3</replacer.version>
|
||||||
<reproducible-build-maven-plugin.version>0.16</reproducible-build-maven-plugin.version>
|
<reproducible-build-maven-plugin.version>0.16</reproducible-build-maven-plugin.version>
|
||||||
<simplemagic.version>1.17</simplemagic.version>
|
<simplemagic.version>1.17</simplemagic.version>
|
||||||
|
249
src/main/java/org/qortal/account/SelfSponsorshipAlgoV2.java
Normal file
249
src/main/java/org/qortal/account/SelfSponsorshipAlgoV2.java
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
package org.qortal.account;
|
||||||
|
|
||||||
|
import org.qortal.api.resource.TransactionsResource;
|
||||||
|
import org.qortal.asset.Asset;
|
||||||
|
import org.qortal.block.BlockChain;
|
||||||
|
import org.qortal.data.account.AccountData;
|
||||||
|
import org.qortal.data.transaction.*;
|
||||||
|
import org.qortal.repository.DataException;
|
||||||
|
import org.qortal.repository.Repository;
|
||||||
|
import org.qortal.transaction.Transaction.TransactionType;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class SelfSponsorshipAlgoV2 {
|
||||||
|
|
||||||
|
private final long snapshotTimestampV1 = BlockChain.getInstance().getSelfSponsorshipAlgoV1SnapshotTimestamp();
|
||||||
|
private final long snapshotTimestampV2 = BlockChain.getInstance().getSelfSponsorshipAlgoV2SnapshotTimestamp();
|
||||||
|
private final long referenceTimestamp = BlockChain.getInstance().getReferenceTimestampBlock();
|
||||||
|
|
||||||
|
private final boolean override;
|
||||||
|
private final Repository repository;
|
||||||
|
private final String address;
|
||||||
|
|
||||||
|
private int recentAssetSendCount = 0;
|
||||||
|
private int recentSponsorshipCount = 0;
|
||||||
|
|
||||||
|
private final Set<String> assetAddresses = new LinkedHashSet<>();
|
||||||
|
private final Set<String> penaltyAddresses = new LinkedHashSet<>();
|
||||||
|
private final Set<String> sponsorAddresses = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
private List<RewardShareTransactionData> sponsorshipRewardShares = new ArrayList<>();
|
||||||
|
private List<TransferAssetTransactionData> transferAssetForAddress = new ArrayList<>();
|
||||||
|
|
||||||
|
public SelfSponsorshipAlgoV2(Repository repository, String address, boolean override) {
|
||||||
|
this.repository = repository;
|
||||||
|
this.address = address;
|
||||||
|
this.override = override;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return this.address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getPenaltyAddresses() {
|
||||||
|
return this.penaltyAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() throws DataException {
|
||||||
|
if (!override) {
|
||||||
|
this.getAccountPrivs(this.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (override) {
|
||||||
|
this.fetchTransferAssetForAddress(this.address);
|
||||||
|
this.findRecentAssetSendCount();
|
||||||
|
|
||||||
|
if (this.recentAssetSendCount >= 6) {
|
||||||
|
this.penaltyAddresses.add(this.address);
|
||||||
|
this.penaltyAddresses.addAll(this.assetAddresses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getAccountPrivs(String address) throws DataException {
|
||||||
|
AccountData accountData = this.repository.getAccountRepository().getAccount(address);
|
||||||
|
List<TransactionData> transferPrivsTransactions = fetchTransferPrivsForAddress(address);
|
||||||
|
transferPrivsTransactions.removeIf(t -> t.getTimestamp() > this.referenceTimestamp || accountData.getAddress().equals(t.getRecipient()));
|
||||||
|
|
||||||
|
if (transferPrivsTransactions.isEmpty()) {
|
||||||
|
// Nothing to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TransactionData transactionData : transferPrivsTransactions) {
|
||||||
|
TransferPrivsTransactionData transferPrivsTransactionData = (TransferPrivsTransactionData) transactionData;
|
||||||
|
this.penaltyAddresses.add(transferPrivsTransactionData.getRecipient());
|
||||||
|
this.fetchSponsorshipRewardShares(transferPrivsTransactionData.getRecipient());
|
||||||
|
this.findRecentSponsorshipCount();
|
||||||
|
|
||||||
|
if (this.recentSponsorshipCount >= 1) {
|
||||||
|
this.penaltyAddresses.addAll(this.sponsorAddresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
String newAddress = this.getDestinationAccount(transferPrivsTransactionData.getRecipient());
|
||||||
|
|
||||||
|
while (newAddress != null) {
|
||||||
|
// Found destination account
|
||||||
|
this.penaltyAddresses.add(newAddress);
|
||||||
|
this.fetchSponsorshipRewardShares(newAddress);
|
||||||
|
this.findRecentSponsorshipCount();
|
||||||
|
|
||||||
|
if (this.recentSponsorshipCount >= 1) {
|
||||||
|
this.penaltyAddresses.addAll(this.sponsorAddresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
newAddress = this.getDestinationAccount(newAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDestinationAccount(String address) throws DataException {
|
||||||
|
AccountData accountData = this.repository.getAccountRepository().getAccount(address);
|
||||||
|
List<TransactionData> transferPrivsTransactions = fetchTransferPrivsForAddress(address);
|
||||||
|
transferPrivsTransactions.removeIf(t -> t.getTimestamp() > this.referenceTimestamp || accountData.getAddress().equals(t.getRecipient()));
|
||||||
|
|
||||||
|
if (transferPrivsTransactions.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountData == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TransactionData transactionData : transferPrivsTransactions) {
|
||||||
|
TransferPrivsTransactionData transferPrivsTransactionData = (TransferPrivsTransactionData) transactionData;
|
||||||
|
if (Arrays.equals(transferPrivsTransactionData.getSenderPublicKey(), accountData.getPublicKey())) {
|
||||||
|
return transferPrivsTransactionData.getRecipient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchSponsorshipRewardShares(String address) throws DataException {
|
||||||
|
AccountData accountDataRs = this.repository.getAccountRepository().getAccount(address);
|
||||||
|
List<RewardShareTransactionData> sponsorshipRewardShares = new ArrayList<>();
|
||||||
|
|
||||||
|
// Define relevant transactions
|
||||||
|
List<TransactionType> txTypes = List.of(TransactionType.REWARD_SHARE);
|
||||||
|
List<TransactionData> transactionDataList = fetchTransactions(repository, txTypes, address, false);
|
||||||
|
|
||||||
|
for (TransactionData transactionData : transactionDataList) {
|
||||||
|
if (transactionData.getType() != TransactionType.REWARD_SHARE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RewardShareTransactionData rewardShareTransactionData = (RewardShareTransactionData) transactionData;
|
||||||
|
|
||||||
|
// Skip removals
|
||||||
|
if (rewardShareTransactionData.getSharePercent() < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if not sponsored by this account
|
||||||
|
if (!Arrays.equals(rewardShareTransactionData.getCreatorPublicKey(), accountDataRs.getPublicKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip self shares
|
||||||
|
if (Objects.equals(rewardShareTransactionData.getRecipient(), address)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean duplicateFound = false;
|
||||||
|
for (RewardShareTransactionData existingRewardShare : sponsorshipRewardShares) {
|
||||||
|
if (Objects.equals(existingRewardShare.getRecipient(), rewardShareTransactionData.getRecipient())) {
|
||||||
|
// Duplicate
|
||||||
|
duplicateFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!duplicateFound) {
|
||||||
|
sponsorshipRewardShares.add(rewardShareTransactionData);
|
||||||
|
this.sponsorAddresses.add(rewardShareTransactionData.getRecipient());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sponsorshipRewardShares = sponsorshipRewardShares;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchTransferAssetForAddress(String address) throws DataException {
|
||||||
|
List<TransferAssetTransactionData> transferAssetForAddress = new ArrayList<>();
|
||||||
|
|
||||||
|
// Define relevant transactions
|
||||||
|
List<TransactionType> txTypes = List.of(TransactionType.TRANSFER_ASSET);
|
||||||
|
List<TransactionData> transactionDataList = fetchTransactions(repository, txTypes, address, false);
|
||||||
|
transactionDataList.removeIf(t -> t.getTimestamp() <= this.snapshotTimestampV1 || t.getTimestamp() >= this.snapshotTimestampV2);
|
||||||
|
|
||||||
|
for (TransactionData transactionData : transactionDataList) {
|
||||||
|
if (transactionData.getType() != TransactionType.TRANSFER_ASSET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransferAssetTransactionData transferAssetTransactionData = (TransferAssetTransactionData) transactionData;
|
||||||
|
|
||||||
|
if (transferAssetTransactionData.getAssetId() == Asset.QORT) {
|
||||||
|
if (!Objects.equals(transferAssetTransactionData.getRecipient(), address)) {
|
||||||
|
// Outgoing transfer asset for this account
|
||||||
|
transferAssetForAddress.add(transferAssetTransactionData);
|
||||||
|
this.assetAddresses.add(transferAssetTransactionData.getRecipient());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.transferAssetForAddress = transferAssetForAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findRecentSponsorshipCount() {
|
||||||
|
int recentSponsorshipCount = 0;
|
||||||
|
|
||||||
|
for (RewardShareTransactionData rewardShare : sponsorshipRewardShares) {
|
||||||
|
if (rewardShare.getTimestamp() >= this.snapshotTimestampV1) {
|
||||||
|
recentSponsorshipCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.recentSponsorshipCount = recentSponsorshipCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findRecentAssetSendCount() {
|
||||||
|
int recentAssetSendCount = 0;
|
||||||
|
|
||||||
|
for (TransferAssetTransactionData assetSend : transferAssetForAddress) {
|
||||||
|
if (assetSend.getTimestamp() >= this.snapshotTimestampV1) {
|
||||||
|
recentAssetSendCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.recentAssetSendCount = recentAssetSendCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TransactionData> fetchTransferPrivsForAddress(String address) throws DataException {
|
||||||
|
return fetchTransactions(repository,
|
||||||
|
List.of(TransactionType.TRANSFER_PRIVS),
|
||||||
|
address, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<TransactionData> fetchTransactions(Repository repository, List<TransactionType> txTypes, String address, boolean reverse) throws DataException {
|
||||||
|
// Fetch all relevant transactions for this account
|
||||||
|
List<byte[]> signatures = repository.getTransactionRepository()
|
||||||
|
.getSignaturesMatchingCriteria(null, null, null, txTypes,
|
||||||
|
null, null, address, TransactionsResource.ConfirmationStatus.CONFIRMED,
|
||||||
|
null, null, reverse);
|
||||||
|
|
||||||
|
List<TransactionData> transactionDataList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (byte[] signature : signatures) {
|
||||||
|
// Fetch transaction data
|
||||||
|
TransactionData transactionData = repository.getTransactionRepository().fromSignature(signature);
|
||||||
|
if (transactionData == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
transactionDataList.add(transactionData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return transactionDataList;
|
||||||
|
}
|
||||||
|
}
|
370
src/main/java/org/qortal/account/SelfSponsorshipAlgoV3.java
Normal file
370
src/main/java/org/qortal/account/SelfSponsorshipAlgoV3.java
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
package org.qortal.account;
|
||||||
|
|
||||||
|
import org.qortal.api.resource.TransactionsResource;
|
||||||
|
import org.qortal.asset.Asset;
|
||||||
|
import org.qortal.data.account.AccountData;
|
||||||
|
import org.qortal.data.naming.NameData;
|
||||||
|
import org.qortal.data.transaction.*;
|
||||||
|
import org.qortal.repository.DataException;
|
||||||
|
import org.qortal.repository.Repository;
|
||||||
|
import org.qortal.transaction.Transaction.TransactionType;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class SelfSponsorshipAlgoV3 {
|
||||||
|
|
||||||
|
private final Repository repository;
|
||||||
|
private final String address;
|
||||||
|
private final AccountData accountData;
|
||||||
|
private final long snapshotTimestampV1;
|
||||||
|
private final long snapshotTimestampV3;
|
||||||
|
private final boolean override;
|
||||||
|
|
||||||
|
private int registeredNameCount = 0;
|
||||||
|
private int suspiciousCount = 0;
|
||||||
|
private int suspiciousPercent = 0;
|
||||||
|
private int consolidationCount = 0;
|
||||||
|
private int bulkIssuanceCount = 0;
|
||||||
|
private int recentSponsorshipCount = 0;
|
||||||
|
|
||||||
|
private List<RewardShareTransactionData> sponsorshipRewardShares = new ArrayList<>();
|
||||||
|
private final Map<String, List<TransactionData>> paymentsByAddress = new HashMap<>();
|
||||||
|
private final Set<String> sponsees = new LinkedHashSet<>();
|
||||||
|
private Set<String> consolidatedAddresses = new LinkedHashSet<>();
|
||||||
|
private final Set<String> zeroTransactionAddreses = new LinkedHashSet<>();
|
||||||
|
private final Set<String> penaltyAddresses = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
public SelfSponsorshipAlgoV3(Repository repository, String address, long snapshotTimestampV1, long snapshotTimestampV3, boolean override) throws DataException {
|
||||||
|
this.repository = repository;
|
||||||
|
this.address = address;
|
||||||
|
this.accountData = this.repository.getAccountRepository().getAccount(this.address);
|
||||||
|
this.snapshotTimestampV1 = snapshotTimestampV1;
|
||||||
|
this.snapshotTimestampV3 = snapshotTimestampV3;
|
||||||
|
this.override = override;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return this.address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getPenaltyAddresses() {
|
||||||
|
return this.penaltyAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void run() throws DataException {
|
||||||
|
if (this.accountData == null) {
|
||||||
|
// Nothing to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fetchSponsorshipRewardShares();
|
||||||
|
if (this.sponsorshipRewardShares.isEmpty()) {
|
||||||
|
// Nothing to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.findConsolidatedRewards();
|
||||||
|
this.findBulkIssuance();
|
||||||
|
this.findRegisteredNameCount();
|
||||||
|
this.findRecentSponsorshipCount();
|
||||||
|
|
||||||
|
int score = this.calculateScore();
|
||||||
|
if (score <= 0 && !override) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String newAddress = this.getDestinationAccount(this.address);
|
||||||
|
while (newAddress != null) {
|
||||||
|
// Found destination account
|
||||||
|
this.penaltyAddresses.add(newAddress);
|
||||||
|
|
||||||
|
// Run algo for this address, but in "override" mode because it has already been flagged
|
||||||
|
SelfSponsorshipAlgoV3 algoV3 = new SelfSponsorshipAlgoV3(this.repository, newAddress, this.snapshotTimestampV1, this.snapshotTimestampV3, true);
|
||||||
|
algoV3.run();
|
||||||
|
this.penaltyAddresses.addAll(algoV3.getPenaltyAddresses());
|
||||||
|
|
||||||
|
newAddress = this.getDestinationAccount(newAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.penaltyAddresses.add(this.address);
|
||||||
|
|
||||||
|
if (this.override || this.recentSponsorshipCount < 20) {
|
||||||
|
this.penaltyAddresses.addAll(this.consolidatedAddresses);
|
||||||
|
this.penaltyAddresses.addAll(this.zeroTransactionAddreses);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.penaltyAddresses.addAll(this.sponsees);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDestinationAccount(String address) throws DataException {
|
||||||
|
List<TransactionData> transferPrivsTransactions = fetchTransferPrivsForAddress(address);
|
||||||
|
if (transferPrivsTransactions.isEmpty()) {
|
||||||
|
// No TRANSFER_PRIVS transactions for this address
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountData accountData = this.repository.getAccountRepository().getAccount(address);
|
||||||
|
if (accountData == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TransactionData transactionData : transferPrivsTransactions) {
|
||||||
|
TransferPrivsTransactionData transferPrivsTransactionData = (TransferPrivsTransactionData) transactionData;
|
||||||
|
if (Arrays.equals(transferPrivsTransactionData.getSenderPublicKey(), accountData.getPublicKey())) {
|
||||||
|
return transferPrivsTransactionData.getRecipient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findConsolidatedRewards() throws DataException {
|
||||||
|
List<String> sponseesThatSentRewards = new ArrayList<>();
|
||||||
|
Map<String, Integer> paymentRecipients = new HashMap<>();
|
||||||
|
|
||||||
|
// Collect outgoing payments of each sponsee
|
||||||
|
for (String sponseeAddress : this.sponsees) {
|
||||||
|
|
||||||
|
// Firstly fetch all payments for address, since the functions below depend on this data
|
||||||
|
this.fetchPaymentsForAddress(sponseeAddress);
|
||||||
|
|
||||||
|
// Check if the address has zero relevant transactions
|
||||||
|
if (this.hasZeroTransactions(sponseeAddress)) {
|
||||||
|
this.zeroTransactionAddreses.add(sponseeAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get payment recipients
|
||||||
|
List<String> allPaymentRecipients = this.fetchOutgoingPaymentRecipientsForAddress(sponseeAddress);
|
||||||
|
if (allPaymentRecipients.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sponseesThatSentRewards.add(sponseeAddress);
|
||||||
|
|
||||||
|
List<String> addressesPaidByThisSponsee = new ArrayList<>();
|
||||||
|
for (String paymentRecipient : allPaymentRecipients) {
|
||||||
|
if (addressesPaidByThisSponsee.contains(paymentRecipient)) {
|
||||||
|
// We already tracked this association - don't allow multiple to stack up
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addressesPaidByThisSponsee.add(paymentRecipient);
|
||||||
|
|
||||||
|
// Increment count for this recipient, or initialize to 1 if not present
|
||||||
|
if (paymentRecipients.computeIfPresent(paymentRecipient, (k, v) -> v + 1) == null) {
|
||||||
|
paymentRecipients.put(paymentRecipient, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude addresses with a low number of payments
|
||||||
|
Map<String, Integer> filteredPaymentRecipients = paymentRecipients.entrySet().stream()
|
||||||
|
.filter(p -> p.getValue() != null && p.getValue() >= 10)
|
||||||
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
|
|
||||||
|
// Now check how many sponsees have sent to this subset of addresses
|
||||||
|
Map<String, Integer> sponseesThatConsolidatedRewards = new HashMap<>();
|
||||||
|
for (String sponseeAddress : sponseesThatSentRewards) {
|
||||||
|
List<String> allPaymentRecipients = this.fetchOutgoingPaymentRecipientsForAddress(sponseeAddress);
|
||||||
|
// Remove any that aren't to one of the flagged recipients (i.e. consolidation)
|
||||||
|
allPaymentRecipients.removeIf(r -> !filteredPaymentRecipients.containsKey(r));
|
||||||
|
|
||||||
|
int count = allPaymentRecipients.size();
|
||||||
|
if (count == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (sponseesThatConsolidatedRewards.computeIfPresent(sponseeAddress, (k, v) -> v + count) == null) {
|
||||||
|
sponseesThatConsolidatedRewards.put(sponseeAddress, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove sponsees that have only sent a low number of payments to the filtered addresses
|
||||||
|
Map<String, Integer> filteredSponseesThatConsolidatedRewards = sponseesThatConsolidatedRewards.entrySet().stream()
|
||||||
|
.filter(p -> p.getValue() != null && p.getValue() >= 2)
|
||||||
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
|
|
||||||
|
this.consolidationCount = sponseesThatConsolidatedRewards.size();
|
||||||
|
this.consolidatedAddresses = new LinkedHashSet<>(filteredSponseesThatConsolidatedRewards.keySet());
|
||||||
|
this.suspiciousCount = this.consolidationCount + this.zeroTransactionAddreses.size();
|
||||||
|
this.suspiciousPercent = (int)(this.suspiciousCount / (float) this.sponsees.size() * 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findBulkIssuance() {
|
||||||
|
Long lastTimestamp = null;
|
||||||
|
for (RewardShareTransactionData rewardShareTransactionData : sponsorshipRewardShares) {
|
||||||
|
long timestamp = rewardShareTransactionData.getTimestamp();
|
||||||
|
if (timestamp >= this.snapshotTimestampV3) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastTimestamp != null) {
|
||||||
|
if (timestamp - lastTimestamp < 3*60*1000L) {
|
||||||
|
this.bulkIssuanceCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastTimestamp = timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findRegisteredNameCount() throws DataException {
|
||||||
|
int registeredNameCount = 0;
|
||||||
|
for (String sponseeAddress : sponsees) {
|
||||||
|
List<NameData> names = repository.getNameRepository().getNamesByOwner(sponseeAddress);
|
||||||
|
for (NameData name : names) {
|
||||||
|
if (name.getRegistered() < this.snapshotTimestampV3) {
|
||||||
|
registeredNameCount++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.registeredNameCount = registeredNameCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findRecentSponsorshipCount() {
|
||||||
|
int recentSponsorshipCount = 0;
|
||||||
|
for (RewardShareTransactionData rewardShare : sponsorshipRewardShares) {
|
||||||
|
if (rewardShare.getTimestamp() >= this.snapshotTimestampV1) {
|
||||||
|
recentSponsorshipCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.recentSponsorshipCount = recentSponsorshipCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int calculateScore() {
|
||||||
|
final int suspiciousMultiplier = (this.suspiciousCount >= 100) ? this.suspiciousPercent : 1;
|
||||||
|
final int nameMultiplier = (this.sponsees.size() >= 25 && this.registeredNameCount <= 1) ? 21 :
|
||||||
|
(this.sponsees.size() >= 15 && this.registeredNameCount <= 1) ? 11 :
|
||||||
|
(this.sponsees.size() >= 5 && this.registeredNameCount <= 1) ? 5 : 1;
|
||||||
|
final int consolidationMultiplier = Math.max(this.consolidationCount, 1);
|
||||||
|
final int bulkIssuanceMultiplier = Math.max(this.bulkIssuanceCount / 2, 1);
|
||||||
|
final int offset = 20;
|
||||||
|
return suspiciousMultiplier * nameMultiplier * consolidationMultiplier * bulkIssuanceMultiplier - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchSponsorshipRewardShares() throws DataException {
|
||||||
|
List<RewardShareTransactionData> sponsorshipRewardShares = new ArrayList<>();
|
||||||
|
|
||||||
|
// Define relevant transactions
|
||||||
|
List<TransactionType> txTypes = List.of(TransactionType.REWARD_SHARE);
|
||||||
|
List<TransactionData> transactionDataList = fetchTransactions(repository, txTypes, this.address, false);
|
||||||
|
transactionDataList.removeIf(t -> t.getTimestamp() <= this.snapshotTimestampV1 || t.getTimestamp() >= this.snapshotTimestampV3);
|
||||||
|
|
||||||
|
for (TransactionData transactionData : transactionDataList) {
|
||||||
|
if (transactionData.getType() != TransactionType.REWARD_SHARE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RewardShareTransactionData rewardShareTransactionData = (RewardShareTransactionData) transactionData;
|
||||||
|
|
||||||
|
// Skip removals
|
||||||
|
if (rewardShareTransactionData.getSharePercent() < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if not sponsored by this account
|
||||||
|
if (!Arrays.equals(rewardShareTransactionData.getCreatorPublicKey(), accountData.getPublicKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip self shares
|
||||||
|
if (Objects.equals(rewardShareTransactionData.getRecipient(), this.address)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean duplicateFound = false;
|
||||||
|
for (RewardShareTransactionData existingRewardShare : sponsorshipRewardShares) {
|
||||||
|
if (Objects.equals(existingRewardShare.getRecipient(), rewardShareTransactionData.getRecipient())) {
|
||||||
|
// Duplicate
|
||||||
|
duplicateFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!duplicateFound) {
|
||||||
|
sponsorshipRewardShares.add(rewardShareTransactionData);
|
||||||
|
this.sponsees.add(rewardShareTransactionData.getRecipient());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sponsorshipRewardShares = sponsorshipRewardShares;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TransactionData> fetchTransferPrivsForAddress(String address) throws DataException {
|
||||||
|
return fetchTransactions(repository,
|
||||||
|
List.of(TransactionType.TRANSFER_PRIVS),
|
||||||
|
address, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchPaymentsForAddress(String address) throws DataException {
|
||||||
|
List<TransactionData> payments = fetchTransactions(repository,
|
||||||
|
Arrays.asList(TransactionType.PAYMENT, TransactionType.TRANSFER_ASSET),
|
||||||
|
address, false);
|
||||||
|
this.paymentsByAddress.put(address, payments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> fetchOutgoingPaymentRecipientsForAddress(String address) {
|
||||||
|
List<String> outgoingPaymentRecipients = new ArrayList<>();
|
||||||
|
|
||||||
|
List<TransactionData> transactionDataList = this.paymentsByAddress.get(address);
|
||||||
|
if (transactionDataList == null) transactionDataList = new ArrayList<>();
|
||||||
|
transactionDataList.removeIf(t -> t.getTimestamp() <= this.snapshotTimestampV1 || t.getTimestamp() >= this.snapshotTimestampV3);
|
||||||
|
for (TransactionData transactionData : transactionDataList) {
|
||||||
|
switch (transactionData.getType()) {
|
||||||
|
|
||||||
|
case PAYMENT:
|
||||||
|
PaymentTransactionData paymentTransactionData = (PaymentTransactionData) transactionData;
|
||||||
|
if (!Objects.equals(paymentTransactionData.getRecipient(), address)) {
|
||||||
|
// Outgoing payment from this account
|
||||||
|
outgoingPaymentRecipients.add(paymentTransactionData.getRecipient());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRANSFER_ASSET:
|
||||||
|
TransferAssetTransactionData transferAssetTransactionData = (TransferAssetTransactionData) transactionData;
|
||||||
|
if (transferAssetTransactionData.getAssetId() == Asset.QORT) {
|
||||||
|
if (!Objects.equals(transferAssetTransactionData.getRecipient(), address)) {
|
||||||
|
// Outgoing payment from this account
|
||||||
|
outgoingPaymentRecipients.add(transferAssetTransactionData.getRecipient());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outgoingPaymentRecipients;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasZeroTransactions(String address) {
|
||||||
|
List<TransactionData> transactionDataList = this.paymentsByAddress.get(address);
|
||||||
|
if (transactionDataList == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
transactionDataList.removeIf(t -> t.getTimestamp() <= this.snapshotTimestampV1 || t.getTimestamp() >= this.snapshotTimestampV3);
|
||||||
|
return transactionDataList.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<TransactionData> fetchTransactions(Repository repository, List<TransactionType> txTypes, String address, boolean reverse) throws DataException {
|
||||||
|
// Fetch all relevant transactions for this account
|
||||||
|
List<byte[]> signatures = repository.getTransactionRepository()
|
||||||
|
.getSignaturesMatchingCriteria(null, null, null, txTypes,
|
||||||
|
null, null, address, TransactionsResource.ConfirmationStatus.CONFIRMED,
|
||||||
|
null, null, reverse);
|
||||||
|
|
||||||
|
List<TransactionData> transactionDataList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (byte[] signature : signatures) {
|
||||||
|
// Fetch transaction data
|
||||||
|
TransactionData transactionData = repository.getTransactionRepository().fromSignature(signature);
|
||||||
|
if (transactionData == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
transactionDataList.add(transactionData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return transactionDataList;
|
||||||
|
}
|
||||||
|
}
|
@ -1061,8 +1061,10 @@ public class Block {
|
|||||||
return ValidationResult.MINTER_NOT_ACCEPTED;
|
return ValidationResult.MINTER_NOT_ACCEPTED;
|
||||||
|
|
||||||
long expectedTimestamp = calcTimestamp(parentBlockData, this.blockData.getMinterPublicKey(), minterLevel);
|
long expectedTimestamp = calcTimestamp(parentBlockData, this.blockData.getMinterPublicKey(), minterLevel);
|
||||||
if (this.blockData.getTimestamp() != expectedTimestamp)
|
if (this.blockData.getTimestamp() != expectedTimestamp) {
|
||||||
|
LOGGER.debug(String.format("timestamp mismatch! block had %s but we expected %s", this.blockData.getTimestamp(), expectedTimestamp));
|
||||||
return ValidationResult.TIMESTAMP_INCORRECT;
|
return ValidationResult.TIMESTAMP_INCORRECT;
|
||||||
|
}
|
||||||
|
|
||||||
return ValidationResult.OK;
|
return ValidationResult.OK;
|
||||||
}
|
}
|
||||||
@ -1556,6 +1558,14 @@ public class Block {
|
|||||||
if (this.blockData.getHeight() == BlockChain.getInstance().getSelfSponsorshipAlgoV1Height()) {
|
if (this.blockData.getHeight() == BlockChain.getInstance().getSelfSponsorshipAlgoV1Height()) {
|
||||||
SelfSponsorshipAlgoV1Block.processAccountPenalties(this);
|
SelfSponsorshipAlgoV1Block.processAccountPenalties(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.blockData.getHeight() == BlockChain.getInstance().getSelfSponsorshipAlgoV2Height()) {
|
||||||
|
SelfSponsorshipAlgoV2Block.processAccountPenalties(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.blockData.getHeight() == BlockChain.getInstance().getSelfSponsorshipAlgoV3Height()) {
|
||||||
|
SelfSponsorshipAlgoV3Block.processAccountPenalties(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're about to (test-)process a batch of transactions,
|
// We're about to (test-)process a batch of transactions,
|
||||||
@ -1849,6 +1859,14 @@ public class Block {
|
|||||||
SelfSponsorshipAlgoV1Block.orphanAccountPenalties(this);
|
SelfSponsorshipAlgoV1Block.orphanAccountPenalties(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.blockData.getHeight() == BlockChain.getInstance().getSelfSponsorshipAlgoV2Height()) {
|
||||||
|
SelfSponsorshipAlgoV2Block.orphanAccountPenalties(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.blockData.getHeight() == BlockChain.getInstance().getSelfSponsorshipAlgoV3Height()) {
|
||||||
|
SelfSponsorshipAlgoV3Block.orphanAccountPenalties(this);
|
||||||
|
}
|
||||||
|
|
||||||
// Account levels and block rewards are only processed/orphaned on block reward distribution blocks
|
// Account levels and block rewards are only processed/orphaned on block reward distribution blocks
|
||||||
if (this.isRewardDistributionBlock()) {
|
if (this.isRewardDistributionBlock()) {
|
||||||
// Block rewards, including transaction fees, removed after transactions undone
|
// Block rewards, including transaction fees, removed after transactions undone
|
||||||
|
@ -74,6 +74,7 @@ public class BlockChain {
|
|||||||
onlineAccountMinterLevelValidationHeight,
|
onlineAccountMinterLevelValidationHeight,
|
||||||
selfSponsorshipAlgoV1Height,
|
selfSponsorshipAlgoV1Height,
|
||||||
selfSponsorshipAlgoV2Height,
|
selfSponsorshipAlgoV2Height,
|
||||||
|
selfSponsorshipAlgoV3Height,
|
||||||
feeValidationFixTimestamp,
|
feeValidationFixTimestamp,
|
||||||
chatReferenceTimestamp,
|
chatReferenceTimestamp,
|
||||||
arbitraryOptionalFeeTimestamp,
|
arbitraryOptionalFeeTimestamp,
|
||||||
@ -216,6 +217,12 @@ public class BlockChain {
|
|||||||
/** Snapshot timestamp for self sponsorship algo V2 */
|
/** Snapshot timestamp for self sponsorship algo V2 */
|
||||||
private long selfSponsorshipAlgoV2SnapshotTimestamp;
|
private long selfSponsorshipAlgoV2SnapshotTimestamp;
|
||||||
|
|
||||||
|
/** Snapshot timestamp for self sponsorship algo V3 */
|
||||||
|
private long selfSponsorshipAlgoV3SnapshotTimestamp;
|
||||||
|
|
||||||
|
/** Reference timestamp for self sponsorship algo V1 block height */
|
||||||
|
private long referenceTimestampBlock;
|
||||||
|
|
||||||
/** Feature-trigger timestamp to modify behaviour of various transactions that support mempow */
|
/** Feature-trigger timestamp to modify behaviour of various transactions that support mempow */
|
||||||
private long mempowTransactionUpdatesTimestamp;
|
private long mempowTransactionUpdatesTimestamp;
|
||||||
|
|
||||||
@ -418,6 +425,15 @@ public class BlockChain {
|
|||||||
return this.selfSponsorshipAlgoV2SnapshotTimestamp;
|
return this.selfSponsorshipAlgoV2SnapshotTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Self sponsorship algo V3
|
||||||
|
public long getSelfSponsorshipAlgoV3SnapshotTimestamp() {
|
||||||
|
return this.selfSponsorshipAlgoV3SnapshotTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Self sponsorship algo V3
|
||||||
|
public long getReferenceTimestampBlock() {
|
||||||
|
return this.referenceTimestampBlock;
|
||||||
|
}
|
||||||
// Feature-trigger timestamp to modify behaviour of various transactions that support mempow
|
// Feature-trigger timestamp to modify behaviour of various transactions that support mempow
|
||||||
public long getMemPoWTransactionUpdatesTimestamp() {
|
public long getMemPoWTransactionUpdatesTimestamp() {
|
||||||
return this.mempowTransactionUpdatesTimestamp;
|
return this.mempowTransactionUpdatesTimestamp;
|
||||||
@ -562,6 +578,10 @@ public class BlockChain {
|
|||||||
return this.featureTriggers.get(FeatureTrigger.selfSponsorshipAlgoV2Height.name()).intValue();
|
return this.featureTriggers.get(FeatureTrigger.selfSponsorshipAlgoV2Height.name()).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSelfSponsorshipAlgoV3Height() {
|
||||||
|
return this.featureTriggers.get(FeatureTrigger.selfSponsorshipAlgoV3Height.name()).intValue();
|
||||||
|
}
|
||||||
|
|
||||||
public long getOnlineAccountMinterLevelValidationHeight() {
|
public long getOnlineAccountMinterLevelValidationHeight() {
|
||||||
return this.featureTriggers.get(FeatureTrigger.onlineAccountMinterLevelValidationHeight.name()).intValue();
|
return this.featureTriggers.get(FeatureTrigger.onlineAccountMinterLevelValidationHeight.name()).intValue();
|
||||||
}
|
}
|
||||||
|
143
src/main/java/org/qortal/block/SelfSponsorshipAlgoV2Block.java
Normal file
143
src/main/java/org/qortal/block/SelfSponsorshipAlgoV2Block.java
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
package org.qortal.block;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.qortal.account.SelfSponsorshipAlgoV2;
|
||||||
|
import org.qortal.api.model.AccountPenaltyStats;
|
||||||
|
import org.qortal.crypto.Crypto;
|
||||||
|
import org.qortal.data.account.AccountData;
|
||||||
|
import org.qortal.data.account.AccountPenaltyData;
|
||||||
|
import org.qortal.repository.DataException;
|
||||||
|
import org.qortal.repository.Repository;
|
||||||
|
import org.qortal.utils.Base58;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Self Sponsorship AlgoV2 Block
|
||||||
|
* <p>
|
||||||
|
* Selected block for the initial run on the "self sponsorship detection algorithm"
|
||||||
|
*/
|
||||||
|
public final class SelfSponsorshipAlgoV2Block {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(SelfSponsorshipAlgoV2Block.class);
|
||||||
|
|
||||||
|
private SelfSponsorshipAlgoV2Block() {
|
||||||
|
/* Do not instantiate */
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void processAccountPenalties(Block block) throws DataException {
|
||||||
|
LOGGER.info("Process Self Sponsorship Algo V2 - this will take a while...");
|
||||||
|
logPenaltyStats(block.repository);
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
Set<AccountPenaltyData> penalties = getAccountPenalties(block.repository, -5000000);
|
||||||
|
block.repository.getAccountRepository().updateBlocksMintedPenalties(penalties);
|
||||||
|
long totalTime = System.currentTimeMillis() - startTime;
|
||||||
|
String hash = getHash(penalties.stream().map(p -> p.getAddress()).collect(Collectors.toList()));
|
||||||
|
LOGGER.info("{} penalty addresses processed (hash: {}). Total time taken: {} seconds", penalties.size(), hash, (int)(totalTime / 1000.0f));
|
||||||
|
logPenaltyStats(block.repository);
|
||||||
|
|
||||||
|
int updatedCount = updateAccountLevels(block.repository, penalties);
|
||||||
|
LOGGER.info("Account levels updated for {} penalty addresses", updatedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void orphanAccountPenalties(Block block) throws DataException {
|
||||||
|
LOGGER.info("Orphan Self Sponsorship Algo V2 - this will take a while...");
|
||||||
|
logPenaltyStats(block.repository);
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
Set<AccountPenaltyData> penalties = getAccountPenalties(block.repository, 5000000);
|
||||||
|
block.repository.getAccountRepository().updateBlocksMintedPenalties(penalties);
|
||||||
|
long totalTime = System.currentTimeMillis() - startTime;
|
||||||
|
String hash = getHash(penalties.stream().map(p -> p.getAddress()).collect(Collectors.toList()));
|
||||||
|
LOGGER.info("{} penalty addresses orphaned (hash: {}). Total time taken: {} seconds", penalties.size(), hash, (int)(totalTime / 1000.0f));
|
||||||
|
logPenaltyStats(block.repository);
|
||||||
|
|
||||||
|
int updatedCount = updateAccountLevels(block.repository, penalties);
|
||||||
|
LOGGER.info("Account levels updated for {} penalty addresses", updatedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<AccountPenaltyData> getAccountPenalties(Repository repository, int penalty) throws DataException {
|
||||||
|
Set<AccountPenaltyData> penalties = new LinkedHashSet<>();
|
||||||
|
List<AccountData> penalizedAddresses = repository.getAccountRepository().getPenaltyAccounts();
|
||||||
|
List<String> assetAddresses = repository.getTransactionRepository().getConfirmedTransferAssetCreators();
|
||||||
|
|
||||||
|
for (AccountData penalizedAddress : penalizedAddresses) {
|
||||||
|
//System.out.println(String.format("address: %s", address));
|
||||||
|
SelfSponsorshipAlgoV2 selfSponsorshipAlgoV2 = new SelfSponsorshipAlgoV2(repository, penalizedAddress.getAddress(), false);
|
||||||
|
selfSponsorshipAlgoV2.run();
|
||||||
|
//System.out.println(String.format("Penalty addresses: %d", selfSponsorshipAlgoV2.getPenaltyAddresses().size()));
|
||||||
|
for (String penaltyAddress : selfSponsorshipAlgoV2.getPenaltyAddresses()) {
|
||||||
|
penalties.add(new AccountPenaltyData(penaltyAddress, penalty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String assetAddress : assetAddresses) {
|
||||||
|
//System.out.println(String.format("address: %s", address));
|
||||||
|
SelfSponsorshipAlgoV2 selfSponsorshipAlgoV2 = new SelfSponsorshipAlgoV2(repository, assetAddress, true);
|
||||||
|
selfSponsorshipAlgoV2.run();
|
||||||
|
//System.out.println(String.format("Penalty addresses: %d", selfSponsorshipAlgoV2.getPenaltyAddresses().size()));
|
||||||
|
for (String penaltyAddress : selfSponsorshipAlgoV2.getPenaltyAddresses()) {
|
||||||
|
penalties.add(new AccountPenaltyData(penaltyAddress, penalty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return penalties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int updateAccountLevels(Repository repository, Set<AccountPenaltyData> accountPenalties) throws DataException {
|
||||||
|
final List<Integer> cumulativeBlocksByLevel = BlockChain.getInstance().getCumulativeBlocksByLevel();
|
||||||
|
final int maximumLevel = cumulativeBlocksByLevel.size() - 1;
|
||||||
|
|
||||||
|
int updatedCount = 0;
|
||||||
|
|
||||||
|
for (AccountPenaltyData penaltyData : accountPenalties) {
|
||||||
|
AccountData accountData = repository.getAccountRepository().getAccount(penaltyData.getAddress());
|
||||||
|
final int effectiveBlocksMinted = accountData.getBlocksMinted() + accountData.getBlocksMintedAdjustment() + accountData.getBlocksMintedPenalty();
|
||||||
|
|
||||||
|
// Shortcut for penalties
|
||||||
|
if (effectiveBlocksMinted < 0) {
|
||||||
|
accountData.setLevel(0);
|
||||||
|
repository.getAccountRepository().setLevel(accountData);
|
||||||
|
updatedCount++;
|
||||||
|
LOGGER.trace(() -> String.format("Block minter %s dropped to level %d", accountData.getAddress(), accountData.getLevel()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int newLevel = maximumLevel; newLevel >= 0; --newLevel) {
|
||||||
|
if (effectiveBlocksMinted >= cumulativeBlocksByLevel.get(newLevel)) {
|
||||||
|
accountData.setLevel(newLevel);
|
||||||
|
repository.getAccountRepository().setLevel(accountData);
|
||||||
|
updatedCount++;
|
||||||
|
LOGGER.trace(() -> String.format("Block minter %s increased to level %d", accountData.getAddress(), accountData.getLevel()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void logPenaltyStats(Repository repository) {
|
||||||
|
try {
|
||||||
|
LOGGER.info(getPenaltyStats(repository));
|
||||||
|
|
||||||
|
} catch (DataException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AccountPenaltyStats getPenaltyStats(Repository repository) throws DataException {
|
||||||
|
List<AccountData> accounts = repository.getAccountRepository().getPenaltyAccounts();
|
||||||
|
return AccountPenaltyStats.fromAccounts(accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getHash(List<String> penaltyAddresses) {
|
||||||
|
if (penaltyAddresses == null || penaltyAddresses.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Collections.sort(penaltyAddresses);
|
||||||
|
return Base58.encode(Crypto.digest(StringUtils.join(penaltyAddresses).getBytes(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
136
src/main/java/org/qortal/block/SelfSponsorshipAlgoV3Block.java
Normal file
136
src/main/java/org/qortal/block/SelfSponsorshipAlgoV3Block.java
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package org.qortal.block;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.qortal.account.SelfSponsorshipAlgoV3;
|
||||||
|
import org.qortal.api.model.AccountPenaltyStats;
|
||||||
|
import org.qortal.crypto.Crypto;
|
||||||
|
import org.qortal.data.account.AccountData;
|
||||||
|
import org.qortal.data.account.AccountPenaltyData;
|
||||||
|
import org.qortal.repository.DataException;
|
||||||
|
import org.qortal.repository.Repository;
|
||||||
|
import org.qortal.utils.Base58;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Self Sponsorship AlgoV3 Block
|
||||||
|
* <p>
|
||||||
|
* Selected block for the initial run on the "self sponsorship detection algorithm"
|
||||||
|
*/
|
||||||
|
public final class SelfSponsorshipAlgoV3Block {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger(SelfSponsorshipAlgoV3Block.class);
|
||||||
|
|
||||||
|
private SelfSponsorshipAlgoV3Block() {
|
||||||
|
/* Do not instantiate */
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void processAccountPenalties(Block block) throws DataException {
|
||||||
|
LOGGER.info("Process Self Sponsorship Algo V3 - this will take a while...");
|
||||||
|
logPenaltyStats(block.repository);
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
Set<AccountPenaltyData> penalties = getAccountPenalties(block.repository, -5000000);
|
||||||
|
block.repository.getAccountRepository().updateBlocksMintedPenalties(penalties);
|
||||||
|
long totalTime = System.currentTimeMillis() - startTime;
|
||||||
|
String hash = getHash(penalties.stream().map(p -> p.getAddress()).collect(Collectors.toList()));
|
||||||
|
LOGGER.info("{} penalty addresses processed (hash: {}). Total time taken: {} seconds", penalties.size(), hash, (int)(totalTime / 1000.0f));
|
||||||
|
logPenaltyStats(block.repository);
|
||||||
|
|
||||||
|
int updatedCount = updateAccountLevels(block.repository, penalties);
|
||||||
|
LOGGER.info("Account levels updated for {} penalty addresses", updatedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void orphanAccountPenalties(Block block) throws DataException {
|
||||||
|
LOGGER.info("Orphan Self Sponsorship Algo V3 - this will take a while...");
|
||||||
|
logPenaltyStats(block.repository);
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
Set<AccountPenaltyData> penalties = getAccountPenalties(block.repository, 5000000);
|
||||||
|
block.repository.getAccountRepository().updateBlocksMintedPenalties(penalties);
|
||||||
|
long totalTime = System.currentTimeMillis() - startTime;
|
||||||
|
String hash = getHash(penalties.stream().map(p -> p.getAddress()).collect(Collectors.toList()));
|
||||||
|
LOGGER.info("{} penalty addresses orphaned (hash: {}). Total time taken: {} seconds", penalties.size(), hash, (int)(totalTime / 1000.0f));
|
||||||
|
logPenaltyStats(block.repository);
|
||||||
|
|
||||||
|
int updatedCount = updateAccountLevels(block.repository, penalties);
|
||||||
|
LOGGER.info("Account levels updated for {} penalty addresses", updatedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<AccountPenaltyData> getAccountPenalties(Repository repository, int penalty) throws DataException {
|
||||||
|
final long snapshotTimestampV1 = BlockChain.getInstance().getSelfSponsorshipAlgoV1SnapshotTimestamp();
|
||||||
|
final long snapshotTimestampV3 = BlockChain.getInstance().getSelfSponsorshipAlgoV3SnapshotTimestamp();
|
||||||
|
Set<AccountPenaltyData> penalties = new LinkedHashSet<>();
|
||||||
|
List<String> addresses = repository.getTransactionRepository().getConfirmedRewardShareCreatorsExcludingSelfShares();
|
||||||
|
for (String address : addresses) {
|
||||||
|
//System.out.println(String.format("address: %s", address));
|
||||||
|
SelfSponsorshipAlgoV3 selfSponsorshipAlgoV3 = new SelfSponsorshipAlgoV3(repository, address, snapshotTimestampV1, snapshotTimestampV3, false);
|
||||||
|
selfSponsorshipAlgoV3.run();
|
||||||
|
//System.out.println(String.format("Penalty addresses: %d", selfSponsorshipAlgoV3.getPenaltyAddresses().size()));
|
||||||
|
|
||||||
|
for (String penaltyAddress : selfSponsorshipAlgoV3.getPenaltyAddresses()) {
|
||||||
|
penalties.add(new AccountPenaltyData(penaltyAddress, penalty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return penalties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int updateAccountLevels(Repository repository, Set<AccountPenaltyData> accountPenalties) throws DataException {
|
||||||
|
final List<Integer> cumulativeBlocksByLevel = BlockChain.getInstance().getCumulativeBlocksByLevel();
|
||||||
|
final int maximumLevel = cumulativeBlocksByLevel.size() - 1;
|
||||||
|
|
||||||
|
int updatedCount = 0;
|
||||||
|
|
||||||
|
for (AccountPenaltyData penaltyData : accountPenalties) {
|
||||||
|
AccountData accountData = repository.getAccountRepository().getAccount(penaltyData.getAddress());
|
||||||
|
final int effectiveBlocksMinted = accountData.getBlocksMinted() + accountData.getBlocksMintedAdjustment() + accountData.getBlocksMintedPenalty();
|
||||||
|
|
||||||
|
// Shortcut for penalties
|
||||||
|
if (effectiveBlocksMinted < 0) {
|
||||||
|
accountData.setLevel(0);
|
||||||
|
repository.getAccountRepository().setLevel(accountData);
|
||||||
|
updatedCount++;
|
||||||
|
LOGGER.trace(() -> String.format("Block minter %s dropped to level %d", accountData.getAddress(), accountData.getLevel()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int newLevel = maximumLevel; newLevel >= 0; --newLevel) {
|
||||||
|
if (effectiveBlocksMinted >= cumulativeBlocksByLevel.get(newLevel)) {
|
||||||
|
accountData.setLevel(newLevel);
|
||||||
|
repository.getAccountRepository().setLevel(accountData);
|
||||||
|
updatedCount++;
|
||||||
|
LOGGER.trace(() -> String.format("Block minter %s increased to level %d", accountData.getAddress(), accountData.getLevel()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void logPenaltyStats(Repository repository) {
|
||||||
|
try {
|
||||||
|
LOGGER.info(getPenaltyStats(repository));
|
||||||
|
|
||||||
|
} catch (DataException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AccountPenaltyStats getPenaltyStats(Repository repository) throws DataException {
|
||||||
|
List<AccountData> accounts = repository.getAccountRepository().getPenaltyAccounts();
|
||||||
|
return AccountPenaltyStats.fromAccounts(accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getHash(List<String> penaltyAddresses) {
|
||||||
|
if (penaltyAddresses == null || penaltyAddresses.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Collections.sort(penaltyAddresses);
|
||||||
|
return Base58.encode(Crypto.digest(StringUtils.join(penaltyAddresses).getBytes(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -51,7 +51,12 @@ public class PirateChain extends Bitcoiny {
|
|||||||
public Collection<Server> getServers() {
|
public Collection<Server> getServers() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
// Servers chosen on NO BASIS WHATSOEVER from various sources!
|
// Servers chosen on NO BASIS WHATSOEVER from various sources!
|
||||||
new Server("lightd.pirate.black", Server.ConnectionType.SSL, 443)
|
new Server("lightd.pirate.black", Server.ConnectionType.SSL, 443),
|
||||||
|
new Server("wallet-arrr1.qortal.online", Server.ConnectionType.SSL, 443),
|
||||||
|
new Server("wallet-arrr2.qortal.online", Server.ConnectionType.SSL, 443),
|
||||||
|
new Server("wallet-arrr3.qortal.online", Server.ConnectionType.SSL, 443),
|
||||||
|
new Server("wallet-arrr4.qortal.online", Server.ConnectionType.SSL, 443),
|
||||||
|
new Server("wallet-arrr5.qortal.online", Server.ConnectionType.SSL, 443)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,6 +205,15 @@ public interface TransactionRepository {
|
|||||||
*/
|
*/
|
||||||
public List<String> getConfirmedRewardShareCreatorsExcludingSelfShares() throws DataException;
|
public List<String> getConfirmedRewardShareCreatorsExcludingSelfShares() throws DataException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns list of transfer asset transaction creators.
|
||||||
|
* This uses confirmed transactions only.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @throws DataException
|
||||||
|
*/
|
||||||
|
public List<String> getConfirmedTransferAssetCreators() throws DataException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns list of transactions pending approval, with optional txGgroupId filtering.
|
* Returns list of transactions pending approval, with optional txGgroupId filtering.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -1043,6 +1043,33 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getConfirmedTransferAssetCreators() throws DataException {
|
||||||
|
List<String> transferAssetCreators = new ArrayList<>();
|
||||||
|
|
||||||
|
String sql = "SELECT account "
|
||||||
|
+ "FROM TransferAssetTransactions "
|
||||||
|
+ "JOIN Accounts ON Accounts.public_key = TransferAssetTransactions.sender "
|
||||||
|
+ "JOIN Transactions ON Transactions.signature = TransferAssetTransactions.signature "
|
||||||
|
+ "WHERE block_height IS NOT NULL AND TransferAssetTransactions.recipient != Accounts.account "
|
||||||
|
+ "GROUP BY account "
|
||||||
|
+ "ORDER BY account";
|
||||||
|
|
||||||
|
try (ResultSet resultSet = this.repository.checkedExecute(sql)) {
|
||||||
|
if (resultSet == null)
|
||||||
|
return transferAssetCreators;
|
||||||
|
|
||||||
|
do {
|
||||||
|
String address = resultSet.getString(1);
|
||||||
|
|
||||||
|
transferAssetCreators.add(address);
|
||||||
|
} while (resultSet.next());
|
||||||
|
|
||||||
|
return transferAssetCreators;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new DataException("Unable to fetch transfer asset from repository", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TransactionData> getApprovalPendingTransactions(Integer txGroupId, Integer limit, Integer offset, Boolean reverse) throws DataException {
|
public List<TransactionData> getApprovalPendingTransactions(Integer txGroupId, Integer limit, Integer offset, Boolean reverse) throws DataException {
|
||||||
StringBuilder sql = new StringBuilder(512);
|
StringBuilder sql = new StringBuilder(512);
|
||||||
|
@ -211,7 +211,7 @@ public class Settings {
|
|||||||
public long recoveryModeTimeout = 9999999999999L;
|
public long recoveryModeTimeout = 9999999999999L;
|
||||||
|
|
||||||
/** Minimum peer version number required in order to sync with them */
|
/** Minimum peer version number required in order to sync with them */
|
||||||
private String minPeerVersion = "4.4.2";
|
private String minPeerVersion = "4.5.0";
|
||||||
/** Whether to allow connections with peers below minPeerVersion
|
/** Whether to allow connections with peers below minPeerVersion
|
||||||
* If true, we won't sync with them but they can still sync with us, and will show in the peers list
|
* If true, we won't sync with them but they can still sync with us, and will show in the peers list
|
||||||
* If false, sync will be blocked both ways, and they will not appear in the peers list */
|
* If false, sync will be blocked both ways, and they will not appear in the peers list */
|
||||||
|
@ -54,6 +54,10 @@ public class RegisterNameTransaction extends Transaction {
|
|||||||
Account registrant = getRegistrant();
|
Account registrant = getRegistrant();
|
||||||
String name = this.registerNameTransactionData.getName();
|
String name = this.registerNameTransactionData.getName();
|
||||||
|
|
||||||
|
int blockchainHeight = this.repository.getBlockRepository().getBlockchainHeight();
|
||||||
|
final int start = BlockChain.getInstance().getSelfSponsorshipAlgoV2Height() - 1180;
|
||||||
|
final int end = BlockChain.getInstance().getSelfSponsorshipAlgoV3Height();
|
||||||
|
|
||||||
// Check name size bounds
|
// Check name size bounds
|
||||||
int nameLength = Utf8.encodedLength(name);
|
int nameLength = Utf8.encodedLength(name);
|
||||||
if (nameLength < Name.MIN_NAME_SIZE || nameLength > Name.MAX_NAME_SIZE)
|
if (nameLength < Name.MIN_NAME_SIZE || nameLength > Name.MAX_NAME_SIZE)
|
||||||
@ -76,6 +80,10 @@ public class RegisterNameTransaction extends Transaction {
|
|||||||
if (registrant.getConfirmedBalance(Asset.QORT) < this.registerNameTransactionData.getFee())
|
if (registrant.getConfirmedBalance(Asset.QORT) < this.registerNameTransactionData.getFee())
|
||||||
return ValidationResult.NO_BALANCE;
|
return ValidationResult.NO_BALANCE;
|
||||||
|
|
||||||
|
// Check if we are on algo runs
|
||||||
|
if (blockchainHeight >= start && blockchainHeight <= end)
|
||||||
|
return ValidationResult.TEMPORARY_DISABLED;
|
||||||
|
|
||||||
return ValidationResult.OK;
|
return ValidationResult.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,12 +183,28 @@ public class RewardShareTransaction extends Transaction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConfirmableAtHeight(int height) {
|
public boolean isConfirmableAtHeight(int height) {
|
||||||
|
final int startV2 = BlockChain.getInstance().getSelfSponsorshipAlgoV2Height() - 15;
|
||||||
|
final int startV3 = BlockChain.getInstance().getSelfSponsorshipAlgoV3Height() - 15;
|
||||||
|
final int endV2 = BlockChain.getInstance().getSelfSponsorshipAlgoV2Height() + 10;
|
||||||
|
final int endV3 = BlockChain.getInstance().getSelfSponsorshipAlgoV3Height() + 10;
|
||||||
|
|
||||||
if (height >= BlockChain.getInstance().getUnconfirmableRewardSharesHeight()) {
|
if (height >= BlockChain.getInstance().getUnconfirmableRewardSharesHeight()) {
|
||||||
// Not confirmable in online accounts or distribution blocks
|
// Not confirmable in online accounts or distribution blocks
|
||||||
if (Block.isOnlineAccountsBlock(height) || Block.isBatchRewardDistributionBlock(height)) {
|
if (Block.isOnlineAccountsBlock(height) || Block.isBatchRewardDistributionBlock(height)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (height >= startV2 && height <= endV2) {
|
||||||
|
// Not confirmable on algo V2 run
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height >= startV3 && height <= endV3) {
|
||||||
|
// Not confirmable on algo V3 run
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,6 +173,7 @@ public abstract class Transaction {
|
|||||||
INVALID_OPTION_LENGTH(20),
|
INVALID_OPTION_LENGTH(20),
|
||||||
DUPLICATE_OPTION(21),
|
DUPLICATE_OPTION(21),
|
||||||
POLL_ALREADY_EXISTS(22),
|
POLL_ALREADY_EXISTS(22),
|
||||||
|
POLL_ALREADY_HAS_VOTES(23),
|
||||||
POLL_DOES_NOT_EXIST(24),
|
POLL_DOES_NOT_EXIST(24),
|
||||||
POLL_OPTION_DOES_NOT_EXIST(25),
|
POLL_OPTION_DOES_NOT_EXIST(25),
|
||||||
ALREADY_VOTED_FOR_THAT_OPTION(26),
|
ALREADY_VOTED_FOR_THAT_OPTION(26),
|
||||||
@ -247,6 +248,7 @@ public abstract class Transaction {
|
|||||||
GROUP_APPROVAL_REQUIRED(98),
|
GROUP_APPROVAL_REQUIRED(98),
|
||||||
ACCOUNT_NOT_TRANSFERABLE(99),
|
ACCOUNT_NOT_TRANSFERABLE(99),
|
||||||
TRANSFER_PRIVS_DISABLED(100),
|
TRANSFER_PRIVS_DISABLED(100),
|
||||||
|
TEMPORARY_DISABLED(101),
|
||||||
INVALID_BUT_OK(999),
|
INVALID_BUT_OK(999),
|
||||||
NOT_YET_RELEASED(1000),
|
NOT_YET_RELEASED(1000),
|
||||||
NOT_SUPPORTED(1001);
|
NOT_SUPPORTED(1001);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.qortal.transaction;
|
package org.qortal.transaction;
|
||||||
|
|
||||||
import org.qortal.account.Account;
|
import org.qortal.account.Account;
|
||||||
|
import org.qortal.block.BlockChain;
|
||||||
import org.qortal.data.PaymentData;
|
import org.qortal.data.PaymentData;
|
||||||
import org.qortal.data.transaction.TransactionData;
|
import org.qortal.data.transaction.TransactionData;
|
||||||
import org.qortal.data.transaction.TransferAssetTransactionData;
|
import org.qortal.data.transaction.TransferAssetTransactionData;
|
||||||
@ -51,6 +52,14 @@ public class TransferAssetTransaction extends Transaction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValidationResult isValid() throws DataException {
|
public ValidationResult isValid() throws DataException {
|
||||||
|
int blockchainHeight = this.repository.getBlockRepository().getBlockchainHeight();
|
||||||
|
final int start = BlockChain.getInstance().getSelfSponsorshipAlgoV2Height();
|
||||||
|
final int end = BlockChain.getInstance().getSelfSponsorshipAlgoV3Height();
|
||||||
|
|
||||||
|
// Check if we are on algo runs
|
||||||
|
if (blockchainHeight >= start && blockchainHeight <= end)
|
||||||
|
return ValidationResult.ASSET_NOT_SPENDABLE;
|
||||||
|
|
||||||
// Wrap asset transfer as a payment and delegate final payment checks to Payment class
|
// Wrap asset transfer as a payment and delegate final payment checks to Payment class
|
||||||
return new Payment(this.repository).isValid(this.transferAssetTransactionData.getSenderPublicKey(), getPaymentData(), this.transferAssetTransactionData.getFee());
|
return new Payment(this.repository).isValid(this.transferAssetTransactionData.getSenderPublicKey(), getPaymentData(), this.transferAssetTransactionData.getFee());
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,9 @@
|
|||||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||||
"onlineAccountsModulusV2Timestamp": 1659801600000,
|
"onlineAccountsModulusV2Timestamp": 1659801600000,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 1670230000000,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 1670230000000,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 1706745600000,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 1708360200000,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 1708432200000,
|
||||||
|
"referenceTimestampBlock": 1670684455220,
|
||||||
"mempowTransactionUpdatesTimestamp": 1693558800000,
|
"mempowTransactionUpdatesTimestamp": 1693558800000,
|
||||||
"blockRewardBatchStartHeight": 1508000,
|
"blockRewardBatchStartHeight": 1508000,
|
||||||
"blockRewardBatchSize": 1000,
|
"blockRewardBatchSize": 1000,
|
||||||
@ -94,7 +96,8 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 1092000,
|
"onlineAccountMinterLevelValidationHeight": 1092000,
|
||||||
"selfSponsorshipAlgoV1Height": 1092400,
|
"selfSponsorshipAlgoV1Height": 1092400,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
"selfSponsorshipAlgoV2Height": 1611200,
|
||||||
|
"selfSponsorshipAlgoV3Height": 1612200,
|
||||||
"feeValidationFixTimestamp": 1671918000000,
|
"feeValidationFixTimestamp": 1671918000000,
|
||||||
"chatReferenceTimestamp": 1674316800000,
|
"chatReferenceTimestamp": 1674316800000,
|
||||||
"arbitraryOptionalFeeTimestamp": 1680278400000,
|
"arbitraryOptionalFeeTimestamp": 1680278400000,
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = Transaktion unbekannt
|
|||||||
TX_GROUP_ID_MISMATCH = die Gruppen-ID der Transaktion stimmt nicht überein
|
TX_GROUP_ID_MISMATCH = die Gruppen-ID der Transaktion stimmt nicht überein
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = Übertragungsberechtigungen deaktiviert
|
TRANSFER_PRIVS_DISABLED = Übertragungsberechtigungen deaktiviert
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = Namensregistrierung vorübergehend deaktiviert
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = transaction unknown
|
|||||||
TX_GROUP_ID_MISMATCH = transaction's group ID does not match
|
TX_GROUP_ID_MISMATCH = transaction's group ID does not match
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = transfer privileges disabled
|
TRANSFER_PRIVS_DISABLED = transfer privileges disabled
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = Name registration temporary disabled
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = transacción desconocida
|
|||||||
TX_GROUP_ID_MISMATCH = el ID de grupo de la transacción no coincide
|
TX_GROUP_ID_MISMATCH = el ID de grupo de la transacción no coincide
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = privilegios de transferencia deshabilitados
|
TRANSFER_PRIVS_DISABLED = privilegios de transferencia deshabilitados
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = Registro de nombre temporalmente deshabilitado
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = tuntematon transaktio
|
|||||||
TX_GROUP_ID_MISMATCH = transaktion ryhmä-ID:n vastaavuusvirhe
|
TX_GROUP_ID_MISMATCH = transaktion ryhmä-ID:n vastaavuusvirhe
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = siirtooikeudet poistettu käytöstä
|
TRANSFER_PRIVS_DISABLED = siirtooikeudet poistettu käytöstä
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = Nimen rekisteröinti tilapäisesti poistettu käytöstä
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = transaction inconnue
|
|||||||
TX_GROUP_ID_MISMATCH = l'identifiant du groupe de transaction ne correspond pas
|
TX_GROUP_ID_MISMATCH = l'identifiant du groupe de transaction ne correspond pas
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = privilèges de transfert désactivés
|
TRANSFER_PRIVS_DISABLED = privilèges de transfert désactivés
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = Enregistrement du nom temporairement désactivé
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = עסקה לא ידועה
|
|||||||
TX_GROUP_ID_MISMATCH = מזהה הקבוצה של העסקה אינו תואם
|
TX_GROUP_ID_MISMATCH = מזהה הקבוצה של העסקה אינו תואם
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = הרשאות העברה מושבתות
|
TRANSFER_PRIVS_DISABLED = הרשאות העברה מושבתות
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = רישום שמות מושבת זמנית
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = ismeretlen tranzakció
|
|||||||
TX_GROUP_ID_MISMATCH = a tranzakció csoportazonosítója nem egyezik
|
TX_GROUP_ID_MISMATCH = a tranzakció csoportazonosítója nem egyezik
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = átviteli jogosultságok letiltva
|
TRANSFER_PRIVS_DISABLED = átviteli jogosultságok letiltva
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = A névregisztráció ideiglenesen le van tiltva
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = transazione sconosciuta
|
|||||||
TX_GROUP_ID_MISMATCH = identificazione di gruppo della transazione non corrisponde
|
TX_GROUP_ID_MISMATCH = identificazione di gruppo della transazione non corrisponde
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = privilegi di trasferimento disabilitati
|
TRANSFER_PRIVS_DISABLED = privilegi di trasferimento disabilitati
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = Registrazione del nome temporaneamente disabilitata
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = 不明なトランザクション
|
|||||||
TX_GROUP_ID_MISMATCH = トランザクションのグループIDが一致しません
|
TX_GROUP_ID_MISMATCH = トランザクションのグループIDが一致しません
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = 転送権限が無効になっています
|
TRANSFER_PRIVS_DISABLED = 転送権限が無効になっています
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = 名前の登録が一時的に無効になっています
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = 알 수 없는 거래
|
|||||||
TX_GROUP_ID_MISMATCH = 트랜잭션의 그룹 ID가 일치하지 않습니다
|
TX_GROUP_ID_MISMATCH = 트랜잭션의 그룹 ID가 일치하지 않습니다
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = 권한 이전이 비활성화되었습니다.
|
TRANSFER_PRIVS_DISABLED = 권한 이전이 비활성화되었습니다.
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = 이름 등록이 일시적으로 비활성화되었습니다.
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = transactie onbekend
|
|||||||
TX_GROUP_ID_MISMATCH = groep-ID komt niet overeen
|
TX_GROUP_ID_MISMATCH = groep-ID komt niet overeen
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = overdrachtsrechten uitgeschakeld
|
TRANSFER_PRIVS_DISABLED = overdrachtsrechten uitgeschakeld
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = Naamregistratie tijdelijk uitgeschakeld
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = transakcja nieznana
|
|||||||
TX_GROUP_ID_MISMATCH = niezgodność ID grupy transakcji
|
TX_GROUP_ID_MISMATCH = niezgodność ID grupy transakcji
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = uprawnienia do przenoszenia wyłączone
|
TRANSFER_PRIVS_DISABLED = uprawnienia do przenoszenia wyłączone
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = Rejestracja nazwy tymczasowo wyłączona
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = tranzactie necunoscuta
|
|||||||
TX_GROUP_ID_MISMATCH = ID-ul de grup al tranzactiei nu se potriveste
|
TX_GROUP_ID_MISMATCH = ID-ul de grup al tranzactiei nu se potriveste
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = privilegii de transfer dezactivate
|
TRANSFER_PRIVS_DISABLED = privilegii de transfer dezactivate
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = Înregistrarea numelui a fost temporar dezactivată
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = неизвестная транзакция
|
|||||||
TX_GROUP_ID_MISMATCH = не соответствие идентификатора группы в хэш транзации
|
TX_GROUP_ID_MISMATCH = не соответствие идентификатора группы в хэш транзации
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = права на передачу отключены
|
TRANSFER_PRIVS_DISABLED = права на передачу отключены
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = Регистрация имени временно отключена
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = okänd transaktion
|
|||||||
TX_GROUP_ID_MISMATCH = transaktionens grupp-ID matchar inte
|
TX_GROUP_ID_MISMATCH = transaktionens grupp-ID matchar inte
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = överföringsprivilegier inaktiverade
|
TRANSFER_PRIVS_DISABLED = överföringsprivilegier inaktiverade
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = Namnregistrering tillfälligt inaktiverad
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = 未知的交易
|
|||||||
TX_GROUP_ID_MISMATCH = 群组ID交易不吻合
|
TX_GROUP_ID_MISMATCH = 群组ID交易不吻合
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = 传输权限已禁用
|
TRANSFER_PRIVS_DISABLED = 传输权限已禁用
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = 名称注册暂时禁用
|
||||||
|
@ -195,3 +195,5 @@ TRANSACTION_UNKNOWN = 未知的交易
|
|||||||
TX_GROUP_ID_MISMATCH = 群組ID交易不吻合
|
TX_GROUP_ID_MISMATCH = 群組ID交易不吻合
|
||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = 傳輸權限已停用
|
TRANSFER_PRIVS_DISABLED = 傳輸權限已停用
|
||||||
|
|
||||||
|
TEMPORARY_DISABLED = 名稱註冊暫時停用
|
||||||
|
342
src/test/java/org/qortal/test/SelfSponsorshipAlgoV2Tests.java
Normal file
342
src/test/java/org/qortal/test/SelfSponsorshipAlgoV2Tests.java
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
package org.qortal.test;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.qortal.account.Account;
|
||||||
|
import org.qortal.account.PrivateKeyAccount;
|
||||||
|
import org.qortal.asset.Asset;
|
||||||
|
import org.qortal.block.Block;
|
||||||
|
import org.qortal.controller.BlockMinter;
|
||||||
|
import org.qortal.data.account.AccountPenaltyData;
|
||||||
|
import org.qortal.data.transaction.*;
|
||||||
|
import org.qortal.repository.DataException;
|
||||||
|
import org.qortal.repository.Repository;
|
||||||
|
import org.qortal.repository.RepositoryManager;
|
||||||
|
import org.qortal.settings.Settings;
|
||||||
|
import org.qortal.test.common.BlockUtils;
|
||||||
|
import org.qortal.test.common.Common;
|
||||||
|
import org.qortal.test.common.TransactionUtils;
|
||||||
|
import org.qortal.utils.NTP;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.qortal.test.common.AccountUtils.fee;
|
||||||
|
|
||||||
|
public class SelfSponsorshipAlgoV2Tests extends Common {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void beforeTest() throws DataException {
|
||||||
|
Common.useSettings("test-settings-v2-self-sponsorship-algo-v2.json");
|
||||||
|
NTP.setFixedOffset(Settings.getInstance().getTestNtpOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tesTransferAssetsQort() throws DataException {
|
||||||
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
|
|
||||||
|
// Alice self share online, and will be used to mint the blocks
|
||||||
|
PrivateKeyAccount aliceSelfShare = Common.getTestAccount(repository, "alice-reward-share");
|
||||||
|
List<PrivateKeyAccount> onlineAccounts = new ArrayList<>();
|
||||||
|
onlineAccounts.add(aliceSelfShare);
|
||||||
|
|
||||||
|
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
|
||||||
|
PrivateKeyAccount chloeAccount = Common.getTestAccount(repository, "chloe");
|
||||||
|
PrivateKeyAccount dilbertAccount = Common.getTestAccount(repository, "dilbert");
|
||||||
|
|
||||||
|
// Mint blocks
|
||||||
|
Block block = null;
|
||||||
|
for (int i = 0; i <= 1; i++)
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Ensure that Bob, Chloe and Dilbert are greater than level 0
|
||||||
|
assertTrue(new Account(repository, bobAccount.getAddress()).getLevel() > 0);
|
||||||
|
assertTrue(new Account(repository, chloeAccount.getAddress()).getLevel() > 0);
|
||||||
|
assertTrue(new Account(repository, dilbertAccount.getAddress()).getLevel() > 0);
|
||||||
|
|
||||||
|
// Mint some blocks, until accounts have leveled up
|
||||||
|
for (int i = 0; i <= 5; i++)
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Ensure that Chloe and Dilbert have more than 20 qort
|
||||||
|
assertTrue(new Account(repository, chloeAccount.getAddress()).getConfirmedBalance(Asset.QORT) > 20); // 10 for transfer asset, 10 for fee
|
||||||
|
assertTrue(new Account(repository, dilbertAccount.getAddress()).getConfirmedBalance(Asset.QORT) > 20); // 10 for transfer asset, 10 for fee
|
||||||
|
|
||||||
|
// Mint until block 10
|
||||||
|
while (block.getBlockData().getHeight() < 10)
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
assertEquals(10, (int) block.getBlockData().getHeight());
|
||||||
|
|
||||||
|
// Chloe transfer assets to Bob and Dilbert
|
||||||
|
transferAssets(repository, chloeAccount, bobAccount);
|
||||||
|
transferAssets(repository, chloeAccount, dilbertAccount);
|
||||||
|
|
||||||
|
// Dilbert transfer assets to Bob and Chloe
|
||||||
|
transferAssets(repository, dilbertAccount, bobAccount);
|
||||||
|
transferAssets(repository, dilbertAccount, chloeAccount);
|
||||||
|
|
||||||
|
// Mint until block 29 (the algo runs at block 30)
|
||||||
|
while (block.getBlockData().getHeight() < 29)
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
assertEquals(29, (int) block.getBlockData().getHeight());
|
||||||
|
|
||||||
|
// Ensure that Bob have no penalties and level 5
|
||||||
|
assertEquals(0, (int) new Account(repository, bobAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(5, (int)bobAccount.getLevel());
|
||||||
|
|
||||||
|
// Ensure that Chloe have no penalties and level 5
|
||||||
|
assertEquals(0, (int) new Account(repository, chloeAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(5, (int)chloeAccount.getLevel());
|
||||||
|
|
||||||
|
// Ensure that Dilbert have no penalties and level6
|
||||||
|
assertEquals(0, (int) new Account(repository, dilbertAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(6, (int)dilbertAccount.getLevel());
|
||||||
|
|
||||||
|
// Mint a block, so the algo runs
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Ensure that Bob, Chloe and Dilbert are now have penalties
|
||||||
|
assertEquals(-5000000, (int) new Account(repository, bobAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(-5000000, (int) new Account(repository, chloeAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(-5000000, (int) new Account(repository, dilbertAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
|
||||||
|
// Ensure that Bob, Chloe and Dilbert are now level 0
|
||||||
|
assertEquals(0, (int) new Account(repository, bobAccount.getAddress()).getLevel());
|
||||||
|
assertEquals(0, (int) new Account(repository, chloeAccount.getAddress()).getLevel());
|
||||||
|
assertEquals(0, (int) new Account(repository, dilbertAccount.getAddress()).getLevel());
|
||||||
|
|
||||||
|
// Orphan last block
|
||||||
|
BlockUtils.orphanLastBlock(repository);
|
||||||
|
|
||||||
|
// Ensure that Bob, Chloe and Dilbert are now greater than level 0
|
||||||
|
assertTrue(new Account(repository, bobAccount.getAddress()).getLevel() > 0);
|
||||||
|
assertTrue(new Account(repository, chloeAccount.getAddress()).getLevel() > 0);
|
||||||
|
assertTrue(new Account(repository, dilbertAccount.getAddress()).getLevel() > 0);
|
||||||
|
|
||||||
|
// Ensure that Bob, Chloe and Dilbert have no penalties again
|
||||||
|
assertEquals(0, (int) new Account(repository, bobAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(0, (int) new Account(repository, chloeAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(0, (int) new Account(repository, dilbertAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
|
||||||
|
// Run orphan check - this can't be in afterTest() because some tests access the live db
|
||||||
|
Common.orphanCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleTransferPrivsBeforeAlgoBlock() throws DataException {
|
||||||
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
|
|
||||||
|
// Alice self share online, and will be used to mint the blocks
|
||||||
|
PrivateKeyAccount aliceSelfShare = Common.getTestAccount(repository, "alice-reward-share");
|
||||||
|
List<PrivateKeyAccount> onlineAccounts = new ArrayList<>();
|
||||||
|
onlineAccounts.add(aliceSelfShare);
|
||||||
|
|
||||||
|
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
|
||||||
|
|
||||||
|
// Mint blocks
|
||||||
|
Block block = null;
|
||||||
|
for (int i = 0; i <= 5; i++)
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Ensure that Bob have more than 20 qort
|
||||||
|
assertTrue(new Account(repository, bobAccount.getAddress()).getConfirmedBalance(Asset.QORT) > 20);
|
||||||
|
|
||||||
|
// Mint until block 17 (the algo runs at block 20)
|
||||||
|
while (block.getBlockData().getHeight() < 26)
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
assertEquals(26, (int) block.getBlockData().getHeight());
|
||||||
|
|
||||||
|
// Bob then issues a TRANSFER_PRIVS
|
||||||
|
PrivateKeyAccount recipientAccount = randomTransferPrivs(repository, bobAccount);
|
||||||
|
|
||||||
|
// Ensure recipient has no level (actually, no account record) at this point (pre-confirmation)
|
||||||
|
assertNull(recipientAccount.getLevel());
|
||||||
|
|
||||||
|
// Mint a block, so that the TRANSFER_PRIVS confirms
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Now ensure that the TRANSFER_PRIVS recipient has inherited Bob's level, and Bob is at level 0
|
||||||
|
assertTrue(recipientAccount.getLevel() > 0);
|
||||||
|
assertEquals(0, (int)bobAccount.getLevel());
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
|
||||||
|
// Mint a block, so that we can penalize Bob after transfer privs
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Update blocks minted penalty for Bob
|
||||||
|
Set<AccountPenaltyData> penalties = new LinkedHashSet<>();
|
||||||
|
penalties.add(new AccountPenaltyData(bobAccount.getAddress(), -5000000));
|
||||||
|
repository.getAccountRepository().updateBlocksMintedPenalties(penalties);
|
||||||
|
|
||||||
|
// Mint a block, so that we check if Bob got penalized before algo runs
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Ensure Bob got penalized
|
||||||
|
assertEquals(-5000000, (int) new Account(repository, bobAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
|
||||||
|
// Mint a block, so the algo runs
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Ensure recipient account has penalty too
|
||||||
|
assertEquals(-5000000, (int) new Account(repository, recipientAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount.getAddress()).getLevel());
|
||||||
|
|
||||||
|
// Orphan last block
|
||||||
|
BlockUtils.orphanLastBlock(repository);
|
||||||
|
|
||||||
|
// Ensure recipient account has no penalty again and has a level greater than 0
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertTrue(new Account(repository, recipientAccount.getAddress()).getLevel() > 0);
|
||||||
|
|
||||||
|
// Run orphan check - this can't be in afterTest() because some tests access the live db
|
||||||
|
Common.orphanCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleTransferPrivsBeforeAlgoBlock() throws DataException {
|
||||||
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
|
|
||||||
|
// Alice self share online, and will be used to mint the blocks
|
||||||
|
PrivateKeyAccount aliceSelfShare = Common.getTestAccount(repository, "alice-reward-share");
|
||||||
|
List<PrivateKeyAccount> onlineAccounts = new ArrayList<>();
|
||||||
|
onlineAccounts.add(aliceSelfShare);
|
||||||
|
|
||||||
|
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
|
||||||
|
PrivateKeyAccount chloeAccount = Common.getTestAccount(repository, "chloe");
|
||||||
|
PrivateKeyAccount dilbertAccount = Common.getTestAccount(repository, "dilbert");
|
||||||
|
|
||||||
|
// Mint blocks
|
||||||
|
Block block = null;
|
||||||
|
for (int i = 0; i <= 5; i++)
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Ensure that Bob, Chloe and Dilbert have more than 20 qort
|
||||||
|
assertTrue(new Account(repository, bobAccount.getAddress()).getConfirmedBalance(Asset.QORT) > 20);
|
||||||
|
assertTrue(new Account(repository, chloeAccount.getAddress()).getConfirmedBalance(Asset.QORT) > 20);
|
||||||
|
assertTrue(new Account(repository, dilbertAccount.getAddress()).getConfirmedBalance(Asset.QORT) > 20);
|
||||||
|
|
||||||
|
// Mint until block 12 (the algo runs at block 20)
|
||||||
|
while (block.getBlockData().getHeight() < 22)
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
assertEquals(22, (int) block.getBlockData().getHeight());
|
||||||
|
|
||||||
|
// Bob then issues a TRANSFER_PRIVS
|
||||||
|
PrivateKeyAccount recipientAccount1 = randomTransferPrivs(repository, bobAccount);
|
||||||
|
|
||||||
|
// Ensure Bob's recipient has no level (actually, no account record) at this point (pre-confirmation)
|
||||||
|
assertNull(recipientAccount1.getLevel());
|
||||||
|
|
||||||
|
// Mint a block, so that Bob's TRANSFER_PRIVS confirms
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Now ensure that the Bob's TRANSFER_PRIVS recipient has inherited Bob's level, and Bob is at level 0
|
||||||
|
assertTrue(recipientAccount1.getLevel() > 0);
|
||||||
|
assertEquals(0, (int)bobAccount.getLevel());
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount1.getAddress()).getBlocksMintedPenalty());
|
||||||
|
|
||||||
|
// Mint a block, so that Chloe can issue a TRANSFER_PRIVS
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Chloe then issues a TRANSFER_PRIVS
|
||||||
|
PrivateKeyAccount recipientAccount2 = randomTransferPrivs(repository, chloeAccount);
|
||||||
|
|
||||||
|
// Ensure Chloe's recipient has no level (actually, no account record) at this point (pre-confirmation)
|
||||||
|
assertNull(recipientAccount2.getLevel());
|
||||||
|
|
||||||
|
// Mint a block, so that Chloe's TRANSFER_PRIVS confirms
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Now ensure that the Chloe's TRANSFER_PRIVS recipient has inherited Chloe's level, and Chloe is at level 0
|
||||||
|
assertTrue(recipientAccount2.getLevel() > 0);
|
||||||
|
assertEquals(0, (int)chloeAccount.getLevel());
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount2.getAddress()).getBlocksMintedPenalty());
|
||||||
|
|
||||||
|
// Mint a block, so that Dilbert can issue a TRANSFER_PRIVS
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Dilbert then issues a TRANSFER_PRIVS
|
||||||
|
PrivateKeyAccount recipientAccount3 = randomTransferPrivs(repository, dilbertAccount);
|
||||||
|
|
||||||
|
// Ensure Dilbert's recipient has no level (actually, no account record) at this point (pre-confirmation)
|
||||||
|
assertNull(recipientAccount3.getLevel());
|
||||||
|
|
||||||
|
// Mint a block, so that Dilbert's TRANSFER_PRIVS confirms
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Now ensure that the Dilbert's TRANSFER_PRIVS recipient has inherited Dilbert's level, and Dilbert is at level 0
|
||||||
|
assertTrue(recipientAccount3.getLevel() > 0);
|
||||||
|
assertEquals(0, (int)dilbertAccount.getLevel());
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount3.getAddress()).getBlocksMintedPenalty());
|
||||||
|
|
||||||
|
// Mint a block, so that we can penalize Bob, Chloe and Dilbert after transfer privs
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Update blocks minted penalty for Bob, Chloe and Dilbert
|
||||||
|
Set<AccountPenaltyData> penalties = new LinkedHashSet<>();
|
||||||
|
penalties.add(new AccountPenaltyData(bobAccount.getAddress(), -5000000));
|
||||||
|
penalties.add(new AccountPenaltyData(chloeAccount.getAddress(), -5000000));
|
||||||
|
penalties.add(new AccountPenaltyData(dilbertAccount.getAddress(), -5000000));
|
||||||
|
repository.getAccountRepository().updateBlocksMintedPenalties(penalties);
|
||||||
|
|
||||||
|
// Mint a block, so that we check if Bob, Chloe and Dilbert got penalized before algo runs
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Ensure Bob, Chloe and Dilbert got penalized
|
||||||
|
assertEquals(-5000000, (int) new Account(repository, bobAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(-5000000, (int) new Account(repository, chloeAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(-5000000, (int) new Account(repository, dilbertAccount.getAddress()).getBlocksMintedPenalty());
|
||||||
|
|
||||||
|
// Mint a block, so the algo runs
|
||||||
|
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
|
||||||
|
|
||||||
|
// Ensure recipients accounts has penalty too
|
||||||
|
assertEquals(-5000000, (int) new Account(repository, recipientAccount1.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(-5000000, (int) new Account(repository, recipientAccount2.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(-5000000, (int) new Account(repository, recipientAccount3.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount1.getAddress()).getLevel());
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount2.getAddress()).getLevel());
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount3.getAddress()).getLevel());
|
||||||
|
|
||||||
|
// Orphan last block
|
||||||
|
BlockUtils.orphanLastBlock(repository);
|
||||||
|
|
||||||
|
// Ensure recipients accounts has no penalty again and has a level greater than 0
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount1.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount2.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertEquals(0, (int) new Account(repository, recipientAccount3.getAddress()).getBlocksMintedPenalty());
|
||||||
|
assertTrue(new Account(repository, recipientAccount1.getAddress()).getLevel() > 0);
|
||||||
|
assertTrue(new Account(repository, recipientAccount2.getAddress()).getLevel() > 0);
|
||||||
|
assertTrue(new Account(repository, recipientAccount3.getAddress()).getLevel() > 0);
|
||||||
|
|
||||||
|
// Run orphan check - this can't be in afterTest() because some tests access the live db
|
||||||
|
Common.orphanCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void transferAssets(Repository repository, PrivateKeyAccount senderAccount, PrivateKeyAccount recipientAccount) throws DataException {
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
// Generate new asset transfers from sender to recipient
|
||||||
|
BaseTransactionData baseTransactionData = new BaseTransactionData(NTP.getTime(), 0, senderAccount.getLastReference(), senderAccount.getPublicKey(), fee, null);
|
||||||
|
TransactionData transactionData;
|
||||||
|
transactionData = new TransferAssetTransactionData(baseTransactionData, recipientAccount.getAddress(), 1, 0);
|
||||||
|
TransactionUtils.signAndImportValid(repository, transactionData, senderAccount); // updates paymentData's signature
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PrivateKeyAccount randomTransferPrivs(Repository repository, PrivateKeyAccount senderAccount) throws DataException {
|
||||||
|
// Generate random recipient account
|
||||||
|
byte[] randomPrivateKey = new byte[32];
|
||||||
|
new Random().nextBytes(randomPrivateKey);
|
||||||
|
PrivateKeyAccount recipientAccount = new PrivateKeyAccount(repository, randomPrivateKey);
|
||||||
|
|
||||||
|
BaseTransactionData baseTransactionData = new BaseTransactionData(NTP.getTime(), 0, senderAccount.getLastReference(), senderAccount.getPublicKey(), fee, null);
|
||||||
|
TransactionData transactionData = new TransferPrivsTransactionData(baseTransactionData, recipientAccount.getAddress());
|
||||||
|
|
||||||
|
TransactionUtils.signAndImportValid(repository, transactionData, senderAccount);
|
||||||
|
|
||||||
|
return recipientAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1578
src/test/java/org/qortal/test/SelfSponsorshipAlgoV3Tests.java
Normal file
1578
src/test/java/org/qortal/test/SelfSponsorshipAlgoV3Tests.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,8 @@
|
|||||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -82,14 +84,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -85,14 +87,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -86,14 +88,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -86,14 +88,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 9999999999999,
|
"mempowTransactionUpdatesTimestamp": 9999999999999,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -86,14 +88,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 9999999999999,
|
"arbitraryOptionalFeeTimestamp": 9999999999999,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -86,14 +88,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -87,14 +89,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -86,14 +88,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -86,14 +88,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -86,14 +88,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 500,
|
"unconfirmableRewardSharesHeight": 500,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
"onlineAccountSignaturesMaxLifetime": 86400000,
|
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -86,14 +88,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -86,14 +88,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 20,
|
"selfSponsorshipAlgoV1Height": 20,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
132
src/test/resources/test-chain-v2-self-sponsorship-algo-v2.json
Normal file
132
src/test/resources/test-chain-v2-self-sponsorship-algo-v2.json
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
{
|
||||||
|
"isTestChain": true,
|
||||||
|
"blockTimestampMargin": 500,
|
||||||
|
"transactionExpiryPeriod": 86400000,
|
||||||
|
"maxBlockSize": 2097152,
|
||||||
|
"maxBytesPerUnitFee": 0,
|
||||||
|
"unitFees": [
|
||||||
|
{ "timestamp": 0, "fee": "0.00000001" }
|
||||||
|
],
|
||||||
|
"nameRegistrationUnitFees": [
|
||||||
|
{ "timestamp": 0, "fee": "0.00000001" },
|
||||||
|
{ "timestamp": 1645372800000, "fee": "5" }
|
||||||
|
],
|
||||||
|
"requireGroupForApproval": false,
|
||||||
|
"minAccountLevelToRewardShare": 5,
|
||||||
|
"maxRewardSharesPerFounderMintingAccount": 20,
|
||||||
|
"maxRewardSharesByTimestamp": [
|
||||||
|
{ "timestamp": 0, "maxShares": 20 },
|
||||||
|
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||||
|
],
|
||||||
|
"founderEffectiveMintingLevel": 10,
|
||||||
|
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||||
|
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||||
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 0,
|
||||||
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
|
"blockRewardBatchSize": 10,
|
||||||
|
"blockRewardBatchAccountsBlockCount": 3,
|
||||||
|
"rewardsByHeight": [
|
||||||
|
{ "height": 1, "reward": 100 },
|
||||||
|
{ "height": 11, "reward": 10 },
|
||||||
|
{ "height": 21, "reward": 1 }
|
||||||
|
],
|
||||||
|
"sharesByLevelV1": [
|
||||||
|
{ "id": 1, "levels": [ 1, 2 ], "share": 0.05 },
|
||||||
|
{ "id": 2, "levels": [ 3, 4 ], "share": 0.10 },
|
||||||
|
{ "id": 3, "levels": [ 5, 6 ], "share": 0.15 },
|
||||||
|
{ "id": 4, "levels": [ 7, 8 ], "share": 0.20 },
|
||||||
|
{ "id": 5, "levels": [ 9, 10 ], "share": 0.25 }
|
||||||
|
],
|
||||||
|
"sharesByLevelV2": [
|
||||||
|
{ "id": 1, "levels": [ 1, 2 ], "share": 0.06 },
|
||||||
|
{ "id": 2, "levels": [ 3, 4 ], "share": 0.13 },
|
||||||
|
{ "id": 3, "levels": [ 5, 6 ], "share": 0.19 },
|
||||||
|
{ "id": 4, "levels": [ 7, 8 ], "share": 0.26 },
|
||||||
|
{ "id": 5, "levels": [ 9, 10 ], "share": 0.32 }
|
||||||
|
],
|
||||||
|
"qoraHoldersShareByHeight": [
|
||||||
|
{ "height": 1, "share": 0.20 },
|
||||||
|
{ "height": 1000000, "share": 0.01 }
|
||||||
|
],
|
||||||
|
"qoraPerQortReward": 250,
|
||||||
|
"minAccountsToActivateShareBin": 0,
|
||||||
|
"shareBinActivationMinLevel": 7,
|
||||||
|
"blocksNeededByLevel": [ 5, 20, 30, 40, 50, 60, 18, 80, 90, 100 ],
|
||||||
|
"blockTimingsByHeight": [
|
||||||
|
{ "height": 1, "target": 60000, "deviation": 30000, "power": 0.2 }
|
||||||
|
],
|
||||||
|
"ciyamAtSettings": {
|
||||||
|
"feePerStep": "0.0001",
|
||||||
|
"maxStepsPerRound": 500,
|
||||||
|
"stepsPerFunctionCall": 10,
|
||||||
|
"minutesPerBlock": 1
|
||||||
|
},
|
||||||
|
"featureTriggers": {
|
||||||
|
"messageHeight": 0,
|
||||||
|
"atHeight": 0,
|
||||||
|
"assetsTimestamp": 0,
|
||||||
|
"votingTimestamp": 0,
|
||||||
|
"arbitraryTimestamp": 0,
|
||||||
|
"powfixTimestamp": 0,
|
||||||
|
"qortalTimestamp": 0,
|
||||||
|
"newAssetPricingTimestamp": 0,
|
||||||
|
"groupApprovalTimestamp": 0,
|
||||||
|
"atFindNextTransactionFix": 0,
|
||||||
|
"newBlockSigHeight": 999999,
|
||||||
|
"shareBinFix": 999999,
|
||||||
|
"sharesByLevelV2Height": 999999,
|
||||||
|
"rewardShareLimitTimestamp": 9999999999999,
|
||||||
|
"calcChainWeightTimestamp": 0,
|
||||||
|
"transactionV5Timestamp": 0,
|
||||||
|
"transactionV6Timestamp": 0,
|
||||||
|
"disableReferenceTimestamp": 9999999999999,
|
||||||
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 30,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
|
"feeValidationFixTimestamp": 0,
|
||||||
|
"chatReferenceTimestamp": 0,
|
||||||
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
|
},
|
||||||
|
"genesisInfo": {
|
||||||
|
"version": 4,
|
||||||
|
"timestamp": 0,
|
||||||
|
"transactions": [
|
||||||
|
{ "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
|
||||||
|
{ "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
|
||||||
|
{ "type": "ISSUE_ASSET", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
|
||||||
|
|
||||||
|
{ "type": "GENESIS", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "amount": "1000000000" },
|
||||||
|
{ "type": "GENESIS", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "amount": "1000000" },
|
||||||
|
{ "type": "GENESIS", "recipient": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "amount": "1000000" },
|
||||||
|
{ "type": "GENESIS", "recipient": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "amount": "1000000" },
|
||||||
|
|
||||||
|
{ "type": "CREATE_GROUP", "creatorPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "groupName": "dev-group", "description": "developer group", "isOpen": false, "approvalThreshold": "PCT100", "minimumBlockDelay": 0, "maximumBlockDelay": 1440 },
|
||||||
|
|
||||||
|
{ "type": "UPDATE_GROUP", "ownerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "groupId": 1, "newOwner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "newDescription": "developer group", "newIsOpen": false, "newApprovalThreshold": "PCT40", "minimumBlockDelay": 10, "maximumBlockDelay": 1440 },
|
||||||
|
|
||||||
|
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "TEST", "description": "test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
|
||||||
|
{ "type": "ISSUE_ASSET", "issuerPublicKey": "C6wuddsBV3HzRrXUtezE7P5MoRXp5m3mEDokRDGZB6ry", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
|
||||||
|
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "GOLD", "description": "gold test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
|
||||||
|
|
||||||
|
{ "type": "ACCOUNT_FLAGS", "target": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "andMask": -1, "orMask": 1, "xorMask": 0 },
|
||||||
|
{ "type": "REWARD_SHARE", "minterPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "rewardSharePublicKey": "7PpfnvLSG7y4HPh8hE7KoqAjLCkv7Ui6xw4mKAkbZtox", "sharePercent": "100" },
|
||||||
|
|
||||||
|
{ "type": "ACCOUNT_LEVEL", "target": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "level": 5 },
|
||||||
|
{ "type": "REWARD_SHARE", "minterPublicKey": "C6wuddsBV3HzRrXUtezE7P5MoRXp5m3mEDokRDGZB6ry", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "rewardSharePublicKey": "CcABzvk26TFEHG7Yok84jxyd4oBtLkx8RJdGFVz2csvp", "sharePercent": 100 },
|
||||||
|
|
||||||
|
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 5 },
|
||||||
|
{ "type": "ACCOUNT_LEVEL", "target": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "level": 5 },
|
||||||
|
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 6 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
132
src/test/resources/test-chain-v2-self-sponsorship-algo-v3.json
Normal file
132
src/test/resources/test-chain-v2-self-sponsorship-algo-v3.json
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
{
|
||||||
|
"isTestChain": true,
|
||||||
|
"blockTimestampMargin": 500,
|
||||||
|
"transactionExpiryPeriod": 86400000,
|
||||||
|
"maxBlockSize": 2097152,
|
||||||
|
"maxBytesPerUnitFee": 0,
|
||||||
|
"unitFees": [
|
||||||
|
{ "timestamp": 0, "fee": "0.00000001" }
|
||||||
|
],
|
||||||
|
"nameRegistrationUnitFees": [
|
||||||
|
{ "timestamp": 0, "fee": "0.00000001" },
|
||||||
|
{ "timestamp": 1645372800000, "fee": "5" }
|
||||||
|
],
|
||||||
|
"requireGroupForApproval": false,
|
||||||
|
"minAccountLevelToRewardShare": 5,
|
||||||
|
"maxRewardSharesPerFounderMintingAccount": 20,
|
||||||
|
"maxRewardSharesByTimestamp": [
|
||||||
|
{ "timestamp": 0, "maxShares": 20 },
|
||||||
|
{ "timestamp": 9999999999999, "maxShares": 3 }
|
||||||
|
],
|
||||||
|
"founderEffectiveMintingLevel": 10,
|
||||||
|
"onlineAccountSignaturesMinLifetime": 3600000,
|
||||||
|
"onlineAccountSignaturesMaxLifetime": 86400000,
|
||||||
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 0,
|
||||||
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
|
"blockRewardBatchSize": 10,
|
||||||
|
"blockRewardBatchAccountsBlockCount": 3,
|
||||||
|
"rewardsByHeight": [
|
||||||
|
{ "height": 1, "reward": 100 },
|
||||||
|
{ "height": 11, "reward": 10 },
|
||||||
|
{ "height": 21, "reward": 1 }
|
||||||
|
],
|
||||||
|
"sharesByLevelV1": [
|
||||||
|
{ "id": 1, "levels": [ 1, 2 ], "share": 0.05 },
|
||||||
|
{ "id": 2, "levels": [ 3, 4 ], "share": 0.10 },
|
||||||
|
{ "id": 3, "levels": [ 5, 6 ], "share": 0.15 },
|
||||||
|
{ "id": 4, "levels": [ 7, 8 ], "share": 0.20 },
|
||||||
|
{ "id": 5, "levels": [ 9, 10 ], "share": 0.25 }
|
||||||
|
],
|
||||||
|
"sharesByLevelV2": [
|
||||||
|
{ "id": 1, "levels": [ 1, 2 ], "share": 0.06 },
|
||||||
|
{ "id": 2, "levels": [ 3, 4 ], "share": 0.13 },
|
||||||
|
{ "id": 3, "levels": [ 5, 6 ], "share": 0.19 },
|
||||||
|
{ "id": 4, "levels": [ 7, 8 ], "share": 0.26 },
|
||||||
|
{ "id": 5, "levels": [ 9, 10 ], "share": 0.32 }
|
||||||
|
],
|
||||||
|
"qoraHoldersShareByHeight": [
|
||||||
|
{ "height": 1, "share": 0.20 },
|
||||||
|
{ "height": 1000000, "share": 0.01 }
|
||||||
|
],
|
||||||
|
"qoraPerQortReward": 250,
|
||||||
|
"minAccountsToActivateShareBin": 0,
|
||||||
|
"shareBinActivationMinLevel": 7,
|
||||||
|
"blocksNeededByLevel": [ 5, 20, 30, 40, 50, 60, 28, 80, 90, 100 ],
|
||||||
|
"blockTimingsByHeight": [
|
||||||
|
{ "height": 1, "target": 60000, "deviation": 30000, "power": 0.2 }
|
||||||
|
],
|
||||||
|
"ciyamAtSettings": {
|
||||||
|
"feePerStep": "0.0001",
|
||||||
|
"maxStepsPerRound": 500,
|
||||||
|
"stepsPerFunctionCall": 10,
|
||||||
|
"minutesPerBlock": 1
|
||||||
|
},
|
||||||
|
"featureTriggers": {
|
||||||
|
"messageHeight": 0,
|
||||||
|
"atHeight": 0,
|
||||||
|
"assetsTimestamp": 0,
|
||||||
|
"votingTimestamp": 0,
|
||||||
|
"arbitraryTimestamp": 0,
|
||||||
|
"powfixTimestamp": 0,
|
||||||
|
"qortalTimestamp": 0,
|
||||||
|
"newAssetPricingTimestamp": 0,
|
||||||
|
"groupApprovalTimestamp": 0,
|
||||||
|
"atFindNextTransactionFix": 0,
|
||||||
|
"newBlockSigHeight": 999999,
|
||||||
|
"shareBinFix": 999999,
|
||||||
|
"sharesByLevelV2Height": 999999,
|
||||||
|
"rewardShareLimitTimestamp": 9999999999999,
|
||||||
|
"calcChainWeightTimestamp": 0,
|
||||||
|
"transactionV5Timestamp": 0,
|
||||||
|
"transactionV6Timestamp": 0,
|
||||||
|
"disableReferenceTimestamp": 9999999999999,
|
||||||
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 30,
|
||||||
|
"feeValidationFixTimestamp": 0,
|
||||||
|
"chatReferenceTimestamp": 0,
|
||||||
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
|
},
|
||||||
|
"genesisInfo": {
|
||||||
|
"version": 4,
|
||||||
|
"timestamp": 0,
|
||||||
|
"transactions": [
|
||||||
|
{ "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORT native coin", "data": "", "quantity": 0, "isDivisible": true, "fee": 0 },
|
||||||
|
{ "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
|
||||||
|
{ "type": "ISSUE_ASSET", "assetName": "QORT-from-QORA", "description": "QORT gained from holding legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
|
||||||
|
|
||||||
|
{ "type": "GENESIS", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "amount": "1000000000" },
|
||||||
|
{ "type": "GENESIS", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "amount": "1000000" },
|
||||||
|
{ "type": "GENESIS", "recipient": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "amount": "1000000" },
|
||||||
|
{ "type": "GENESIS", "recipient": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "amount": "1000000" },
|
||||||
|
|
||||||
|
{ "type": "CREATE_GROUP", "creatorPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "groupName": "dev-group", "description": "developer group", "isOpen": false, "approvalThreshold": "PCT100", "minimumBlockDelay": 0, "maximumBlockDelay": 1440 },
|
||||||
|
|
||||||
|
{ "type": "UPDATE_GROUP", "ownerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "groupId": 1, "newOwner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "newDescription": "developer group", "newIsOpen": false, "newApprovalThreshold": "PCT40", "minimumBlockDelay": 10, "maximumBlockDelay": 1440 },
|
||||||
|
|
||||||
|
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "TEST", "description": "test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
|
||||||
|
{ "type": "ISSUE_ASSET", "issuerPublicKey": "C6wuddsBV3HzRrXUtezE7P5MoRXp5m3mEDokRDGZB6ry", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
|
||||||
|
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "GOLD", "description": "gold test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
|
||||||
|
|
||||||
|
{ "type": "ACCOUNT_FLAGS", "target": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "andMask": -1, "orMask": 1, "xorMask": 0 },
|
||||||
|
{ "type": "REWARD_SHARE", "minterPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "recipient": "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "rewardSharePublicKey": "7PpfnvLSG7y4HPh8hE7KoqAjLCkv7Ui6xw4mKAkbZtox", "sharePercent": "100" },
|
||||||
|
|
||||||
|
{ "type": "ACCOUNT_LEVEL", "target": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "level": 5 },
|
||||||
|
{ "type": "REWARD_SHARE", "minterPublicKey": "C6wuddsBV3HzRrXUtezE7P5MoRXp5m3mEDokRDGZB6ry", "recipient": "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "rewardSharePublicKey": "CcABzvk26TFEHG7Yok84jxyd4oBtLkx8RJdGFVz2csvp", "sharePercent": 100 },
|
||||||
|
|
||||||
|
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 5 },
|
||||||
|
{ "type": "ACCOUNT_LEVEL", "target": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "level": 5 },
|
||||||
|
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 6 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,8 @@
|
|||||||
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
"onlineAccountsModulusV2Timestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV2SnapshotTimestamp": 9999999999999,
|
||||||
|
"selfSponsorshipAlgoV3SnapshotTimestamp": 9999999999999,
|
||||||
|
"referenceTimestampBlock": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 0,
|
"mempowTransactionUpdatesTimestamp": 0,
|
||||||
"blockRewardBatchStartHeight": 999999000,
|
"blockRewardBatchStartHeight": 999999000,
|
||||||
"blockRewardBatchSize": 10,
|
"blockRewardBatchSize": 10,
|
||||||
@ -87,14 +89,14 @@
|
|||||||
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
|
||||||
"onlineAccountMinterLevelValidationHeight": 0,
|
"onlineAccountMinterLevelValidationHeight": 0,
|
||||||
"selfSponsorshipAlgoV1Height": 999999999,
|
"selfSponsorshipAlgoV1Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV2Height": 999999999,
|
||||||
|
"selfSponsorshipAlgoV3Height": 999999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 0,
|
"arbitraryOptionalFeeTimestamp": 0,
|
||||||
"unconfirmableRewardSharesHeight": 99999999,
|
"unconfirmableRewardSharesHeight": 99999999,
|
||||||
"selfSponsorshipAlgoV2Height": 9999999,
|
|
||||||
"disableTransferPrivsTimestamp": 9999999999500,
|
"disableTransferPrivsTimestamp": 9999999999500,
|
||||||
"enableTransferPrivsTimestamp": 9999999999950,
|
"enableTransferPrivsTimestamp": 9999999999950
|
||||||
"penaltyFixHeight": 9999999
|
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"repositoryPath": "testdb",
|
||||||
|
"bitcoinNet": "TEST3",
|
||||||
|
"litecoinNet": "TEST3",
|
||||||
|
"restrictedApi": false,
|
||||||
|
"blockchainConfig": "src/test/resources/test-chain-v2-self-sponsorship-algo-v2.json",
|
||||||
|
"exportPath": "qortal-backup-test",
|
||||||
|
"bootstrap": false,
|
||||||
|
"wipeUnconfirmedOnStart": false,
|
||||||
|
"testNtpOffset": 0,
|
||||||
|
"minPeers": 0,
|
||||||
|
"pruneBlockLimit": 100,
|
||||||
|
"bootstrapFilenamePrefix": "test-",
|
||||||
|
"dataPath": "data-test",
|
||||||
|
"tempDataPath": "data-test/_temp",
|
||||||
|
"listsPath": "lists-test",
|
||||||
|
"storagePolicy": "FOLLOWED_OR_VIEWED",
|
||||||
|
"maxStorageCapacity": 104857600,
|
||||||
|
"arrrDefaultBirthday": 1900000
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"repositoryPath": "testdb",
|
||||||
|
"bitcoinNet": "TEST3",
|
||||||
|
"litecoinNet": "TEST3",
|
||||||
|
"restrictedApi": false,
|
||||||
|
"blockchainConfig": "src/test/resources/test-chain-v2-self-sponsorship-algo-v3.json",
|
||||||
|
"exportPath": "qortal-backup-test",
|
||||||
|
"bootstrap": false,
|
||||||
|
"wipeUnconfirmedOnStart": false,
|
||||||
|
"testNtpOffset": 0,
|
||||||
|
"minPeers": 0,
|
||||||
|
"pruneBlockLimit": 100,
|
||||||
|
"bootstrapFilenamePrefix": "test-",
|
||||||
|
"dataPath": "data-test",
|
||||||
|
"tempDataPath": "data-test/_temp",
|
||||||
|
"listsPath": "lists-test",
|
||||||
|
"storagePolicy": "FOLLOWED_OR_VIEWED",
|
||||||
|
"maxStorageCapacity": 104857600,
|
||||||
|
"arrrDefaultBirthday": 1900000
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user