Compare commits

..

23 Commits

Author SHA1 Message Date
CalDescent
166f9bd079 Bump version to 3.8.2 2022-12-24 21:28:02 +00:00
CalDescent
2f8f896077 Merge remote-tracking branch 'catbref/bugfix-deploy-at' 2022-12-24 16:01:23 +00:00
CalDescent
9a77aff0a6 Reduced difficulty of PUBLICIZE transactions from 15 to 14 (it is now the same as ARBITRARY transactions) 2022-12-24 14:10:49 +00:00
CalDescent
c6d65a88dc Increase mempow difficulty and threshold in ChatTransaction, to match the values in the UI. 2022-12-22 18:19:27 +00:00
CalDescent
4aea29a91b Improved PublicizeTransaction validation. 2022-12-22 18:03:29 +00:00
CalDescent
0e81665a36 Revert "Filter out peers of divergent or significantly inferior chains when syncing."
This reverts commit 1dc7f056f9. To be un-reverted in future when there is more time available for testing.
2022-12-22 15:10:19 +00:00
CalDescent
2a4ac1ed24 Limit to 250 CHAT messages per hour per account. 2022-12-22 15:09:04 +00:00
CalDescent
bb74b2d4f6 MAX_AVG_RESPONSE_TIME for ElectrumX servers increased from 0.5s to 1s. 2022-12-22 14:25:10 +00:00
CalDescent
758a02d71a Log Pirate light client server address if the wallet unable to be initialized. 2022-12-22 14:23:30 +00:00
CalDescent
7ae142fa64 Improved transaction validation. 2022-12-22 14:20:42 +00:00
CalDescent
a75ed0e634 Bump additional expandedAccount level references held in memory. 2022-12-22 14:18:39 +00:00
CalDescent
e40dc4af59 Fixed group ban expiry. 2022-12-22 14:16:57 +00:00
CalDescent
e678ea22e0 Fixed NPE in unit tests. Still need to work out how/when this was introduced. 2022-12-18 18:33:51 +00:00
CalDescent
cf3195cb83 Set "minAccountsToActivateShareBin" to 0 for certain tests. 2022-12-18 18:32:06 +00:00
CalDescent
80048208d1 Moved some test sponsorship utility methods to AccountUtils, so they can be used in other test classes too. 2022-12-15 12:14:42 +00:00
CalDescent
08de1fb4ec Disallow CHAT transactions with timestamps more than 5 minutes in the future. 2022-12-14 16:40:57 +00:00
CalDescent
99d5bf9103 Disallow transactions with timestamps more than 30 mins in the future (reduced from 24 hours) 2022-12-14 16:40:11 +00:00
CalDescent
1dc7f056f9 Filter out peers of divergent or significantly inferior chains when syncing. 2022-12-14 16:39:43 +00:00
CalDescent
cdeb2052b0 Bump version to 3.8.1 2022-12-08 18:26:34 +00:00
CalDescent
5c9109aca9 minPeerVersion set to 3.8.0 2022-12-08 18:25:19 +00:00
CalDescent
ccc1976d00 Added defensiveness 2022-12-08 18:25:03 +00:00
CalDescent
12fb6cd0ad onlineAccountMinterLevelValidationHeight moved forward to block 1092000 2022-12-08 18:24:34 +00:00
catbref
ae991dda4d Fix creatorPublicKey not being unmarshaled when calling POST /at to deploy an AT 2022-11-28 21:52:37 +00:00
22 changed files with 412 additions and 163 deletions

View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.qortal</groupId>
<artifactId>qortal</artifactId>
<version>3.8.0</version>
<version>3.8.2</version>
<packaging>jar</packaging>
<properties>
<skipTests>true</skipTests>

View File

@@ -52,6 +52,11 @@ public class SelfSponsorshipAlgoV1 {
public void run() throws DataException {
if (this.accountData == null) {
// Nothing to do
return;
}
this.fetchSponsorshipRewardShares();
if (this.sponsorshipRewardShares.isEmpty()) {
// Nothing to do

View File

@@ -1522,6 +1522,9 @@ public class Block {
// Batch update in repository
repository.getAccountRepository().modifyMintedBlockCounts(allUniqueExpandedAccounts.stream().map(AccountData::getAddress).collect(Collectors.toList()), +1);
// Keep track of level bumps in case we need to apply to other entries
Map<String, Integer> bumpedAccounts = new HashMap<>();
// Local changes and also checks for level bump
for (AccountData accountData : allUniqueExpandedAccounts) {
// Adjust count locally (in Java)
@@ -1535,6 +1538,7 @@ public class Block {
if (newLevel > accountData.getLevel()) {
// Account has increased in level!
accountData.setLevel(newLevel);
bumpedAccounts.put(accountData.getAddress(), newLevel);
repository.getAccountRepository().setLevel(accountData);
LOGGER.trace(() -> String.format("Block minter %s bumped to level %d", accountData.getAddress(), accountData.getLevel()));
}
@@ -1542,6 +1546,25 @@ public class Block {
break;
}
}
// Also bump other entries if need be
if (!bumpedAccounts.isEmpty()) {
for (ExpandedAccount expandedAccount : expandedAccounts) {
Integer newLevel = bumpedAccounts.get(expandedAccount.mintingAccountData.getAddress());
if (newLevel != null && expandedAccount.mintingAccountData.getLevel() != newLevel) {
expandedAccount.mintingAccountData.setLevel(newLevel);
LOGGER.trace("Also bumped {} to level {}", expandedAccount.mintingAccountData.getAddress(), newLevel);
}
if (!expandedAccount.isRecipientAlsoMinter) {
newLevel = bumpedAccounts.get(expandedAccount.recipientAccountData.getAddress());
if (newLevel != null && expandedAccount.recipientAccountData.getLevel() != newLevel) {
expandedAccount.recipientAccountData.setLevel(newLevel);
LOGGER.trace("Also bumped {} to level {}", expandedAccount.recipientAccountData.getAddress(), newLevel);
}
}
}
}
}
protected void processBlockRewards() throws DataException {

View File

@@ -40,7 +40,7 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
private static final String VERBOSE_TRANSACTIONS_UNSUPPORTED_MESSAGE = "verbose transactions are currently unsupported";
private static final int RESPONSE_TIME_READINGS = 5;
private static final long MAX_AVG_RESPONSE_TIME = 500L; // ms
private static final long MAX_AVG_RESPONSE_TIME = 1000L; // ms
public static class Server {
String hostname;

View File

@@ -117,7 +117,7 @@ public class PirateWallet {
// Restore existing wallet
String response = LiteWalletJni.initfromb64(serverUri, params, wallet, saplingOutput64, saplingSpend64);
if (response != null && !response.contains("\"initalized\":true")) {
LOGGER.info("Unable to initialize Pirate Chain wallet: {}", response);
LOGGER.info("Unable to initialize Pirate Chain wallet at {}: {}", serverUri, response);
return false;
}
this.seedPhrase = inputSeedPhrase;

View File

@@ -2,6 +2,7 @@ package org.qortal.data.transaction;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.qortal.transaction.Transaction.TransactionType;
@@ -90,4 +91,17 @@ public class DeployAtTransactionData extends TransactionData {
this.aTAddress = AtAddress;
}
// Re-expose creatorPublicKey for this transaction type for JAXB
@XmlElement(name = "creatorPublicKey")
@Schema(name = "creatorPublicKey", description = "AT creator's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP")
public byte[] getAtCreatorPublicKey() {
return this.creatorPublicKey;
}
@XmlElement(name = "creatorPublicKey")
@Schema(name = "creatorPublicKey", description = "AT creator's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP")
public void setAtCreatorPublicKey(byte[] creatorPublicKey) {
this.creatorPublicKey = creatorPublicKey;
}
}

View File

@@ -131,7 +131,14 @@ public interface GroupRepository {
public GroupBanData getBan(int groupId, String member) throws DataException;
public boolean banExists(int groupId, String offender) throws DataException;
/**
* IMPORTANT: when using banExists() as part of validation, the timestamp must be that of the transaction that
* is calling banExists() as part of its validation. It must NOT be the current time, unless this is being
* called outside of validation, as part of an on demand check for a ban existing (such as via an API call).
* This is because we need to evaluate a ban's status based on the time of the subsequent transaction, as
* validation will not occur at a fixed time for every node. For some, it could be months into the future.
*/
public boolean banExists(int groupId, String offender, long timestamp) throws DataException;
public List<GroupBanData> getGroupBans(int groupId, Integer limit, Integer offset, Boolean reverse) throws DataException;

View File

@@ -777,9 +777,9 @@ public class HSQLDBGroupRepository implements GroupRepository {
}
@Override
public boolean banExists(int groupId, String offender) throws DataException {
public boolean banExists(int groupId, String offender, long timestamp) throws DataException {
try {
return this.repository.exists("GroupBans", "group_id = ? AND offender = ?", groupId, offender);
return this.repository.exists("GroupBans", "group_id = ? AND offender = ? AND (expires_when IS NULL OR expires_when > ?)", groupId, offender, timestamp);
} catch (SQLException e) {
throw new DataException("Unable to check for group ban in repository", e);
}

View File

@@ -110,7 +110,13 @@ public class Settings {
/** Maximum number of unconfirmed transactions allowed per account */
private int maxUnconfirmedPerAccount = 25;
/** Max milliseconds into future for accepting new, unconfirmed transactions */
private int maxTransactionTimestampFuture = 24 * 60 * 60 * 1000; // milliseconds
private int maxTransactionTimestampFuture = 30 * 60 * 1000; // milliseconds
/** Maximum number of CHAT transactions allowed per account in recent timeframe */
private int maxRecentChatMessagesPerAccount = 250;
/** Maximum age of a CHAT transaction to be considered 'recent' */
private long recentChatMessagesMaxAge = 60 * 60 * 1000L; // milliseconds
/** Whether we check, fetch and install auto-updates */
private boolean autoUpdateEnabled = true;
/** How long between repository backups (ms), or 0 if disabled. */
@@ -209,7 +215,7 @@ public class Settings {
public long recoveryModeTimeout = 10 * 60 * 1000L;
/** Minimum peer version number required in order to sync with them */
private String minPeerVersion = "3.7.0";
private String minPeerVersion = "3.8.0";
/** 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 false, sync will be blocked both ways, and they will not appear in the peers list */
@@ -640,6 +646,14 @@ public class Settings {
return this.maxTransactionTimestampFuture;
}
public int getMaxRecentChatMessagesPerAccount() {
return this.maxRecentChatMessagesPerAccount;
}
public long getRecentChatMessagesMaxAge() {
return recentChatMessagesMaxAge;
}
public int getBlockCacheSize() {
return this.blockCacheSize;
}

View File

@@ -73,7 +73,7 @@ public class CancelGroupBanTransaction extends Transaction {
Account member = getMember();
// Check ban actually exists
if (!this.repository.getGroupRepository().banExists(groupId, member.getAddress()))
if (!this.repository.getGroupRepository().banExists(groupId, member.getAddress(), this.groupUnbanTransactionData.getTimestamp()))
return ValidationResult.BAN_UNKNOWN;
// Check admin has enough funds

View File

@@ -1,7 +1,9 @@
package org.qortal.transaction;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import org.qortal.account.Account;
import org.qortal.account.PublicKeyAccount;
@@ -16,9 +18,11 @@ import org.qortal.list.ResourceListManager;
import org.qortal.repository.DataException;
import org.qortal.repository.GroupRepository;
import org.qortal.repository.Repository;
import org.qortal.settings.Settings;
import org.qortal.transform.TransformationException;
import org.qortal.transform.transaction.ChatTransactionTransformer;
import org.qortal.transform.transaction.TransactionTransformer;
import org.qortal.utils.NTP;
public class ChatTransaction extends Transaction {
@@ -28,8 +32,9 @@ public class ChatTransaction extends Transaction {
// Other useful constants
public static final int MAX_DATA_SIZE = 1024;
public static final int POW_BUFFER_SIZE = 8 * 1024 * 1024; // bytes
public static final int POW_DIFFICULTY_WITH_QORT = 8; // leading zero bits
public static final int POW_DIFFICULTY_NO_QORT = 12; // leading zero bits
public static final int POW_DIFFICULTY_ABOVE_QORT_THRESHOLD = 8; // leading zero bits
public static final int POW_DIFFICULTY_BELOW_QORT_THRESHOLD = 18; // leading zero bits
public static final long POW_QORT_THRESHOLD = 400000000L;
// Constructors
@@ -78,7 +83,7 @@ public class ChatTransaction extends Transaction {
// Clear nonce from transactionBytes
ChatTransactionTransformer.clearNonce(transactionBytes);
int difficulty = this.getSender().getConfirmedBalance(Asset.QORT) > 0 ? POW_DIFFICULTY_WITH_QORT : POW_DIFFICULTY_NO_QORT;
int difficulty = this.getSender().getConfirmedBalance(Asset.QORT) >= POW_QORT_THRESHOLD ? POW_DIFFICULTY_ABOVE_QORT_THRESHOLD : POW_DIFFICULTY_BELOW_QORT_THRESHOLD;
// Calculate nonce
this.chatTransactionData.setNonce(MemoryPoW.compute2(transactionBytes, POW_BUFFER_SIZE, difficulty));
@@ -145,6 +150,11 @@ public class ChatTransaction extends Transaction {
public ValidationResult isValid() throws DataException {
// Nonce checking is done via isSignatureValid() as that method is only called once per import
// Disregard messages with timestamp too far in the future (we have stricter limits for CHAT transactions)
if (this.chatTransactionData.getTimestamp() > NTP.getTime() + (5 * 60 * 1000L)) {
return ValidationResult.TIMESTAMP_TOO_NEW;
}
// Check for blocked author by address
ResourceListManager listManager = ResourceListManager.getInstance();
if (listManager.listContains("blockedAddresses", this.chatTransactionData.getSender(), true)) {
@@ -163,6 +173,14 @@ public class ChatTransaction extends Transaction {
}
}
PublicKeyAccount creator = this.getCreator();
if (creator == null)
return ValidationResult.MISSING_CREATOR;
// Reject if unconfirmed pile already has X recent CHAT transactions from same creator
if (countRecentChatTransactionsByCreator(creator) >= Settings.getInstance().getMaxRecentChatMessagesPerAccount())
return ValidationResult.TOO_MANY_UNCONFIRMED;
// If we exist in the repository then we've been imported as unconfirmed,
// but we don't want to make it into a block, so return fake non-OK result.
if (this.repository.getTransactionRepository().exists(this.chatTransactionData.getSignature()))
@@ -204,7 +222,7 @@ public class ChatTransaction extends Transaction {
int difficulty;
try {
difficulty = this.getSender().getConfirmedBalance(Asset.QORT) > 0 ? POW_DIFFICULTY_WITH_QORT : POW_DIFFICULTY_NO_QORT;
difficulty = this.getSender().getConfirmedBalance(Asset.QORT) >= POW_QORT_THRESHOLD ? POW_DIFFICULTY_ABOVE_QORT_THRESHOLD : POW_DIFFICULTY_BELOW_QORT_THRESHOLD;
} catch (DataException e) {
return false;
}
@@ -213,6 +231,26 @@ public class ChatTransaction extends Transaction {
return MemoryPoW.verify2(transactionBytes, POW_BUFFER_SIZE, difficulty, nonce);
}
private int countRecentChatTransactionsByCreator(PublicKeyAccount creator) throws DataException {
List<TransactionData> unconfirmedTransactions = repository.getTransactionRepository().getUnconfirmedTransactions();
final Long now = NTP.getTime();
long recentThreshold = Settings.getInstance().getRecentChatMessagesMaxAge();
// We only care about chat transactions, and only those that are considered 'recent'
Predicate<TransactionData> hasSameCreatorAndIsRecentChat = transactionData -> {
if (transactionData.getType() != TransactionType.CHAT)
return false;
if (transactionData.getTimestamp() < now - recentThreshold)
return false;
return Arrays.equals(creator.getPublicKey(), transactionData.getCreatorPublicKey());
};
return (int) unconfirmedTransactions.stream().filter(hasSameCreatorAndIsRecentChat).count();
}
/**
* Ensure there's at least a skeleton account so people
* can retrieve sender's public key using address, even if all their messages

View File

@@ -78,7 +78,7 @@ public class GroupInviteTransaction extends Transaction {
return ValidationResult.ALREADY_GROUP_MEMBER;
// Check invitee is not banned
if (this.repository.getGroupRepository().banExists(groupId, invitee.getAddress()))
if (this.repository.getGroupRepository().banExists(groupId, invitee.getAddress(), this.groupInviteTransactionData.getTimestamp()))
return ValidationResult.BANNED_FROM_GROUP;
// Check creator has enough funds

View File

@@ -53,7 +53,7 @@ public class JoinGroupTransaction extends Transaction {
return ValidationResult.ALREADY_GROUP_MEMBER;
// Check member is not banned
if (this.repository.getGroupRepository().banExists(groupId, joiner.getAddress()))
if (this.repository.getGroupRepository().banExists(groupId, joiner.getAddress(), this.joinGroupTransactionData.getTimestamp()))
return ValidationResult.BANNED_FROM_GROUP;
// Check join request doesn't already exist

View File

@@ -4,7 +4,9 @@ import java.util.Collections;
import java.util.List;
import org.qortal.account.Account;
import org.qortal.account.PublicKeyAccount;
import org.qortal.api.resource.TransactionsResource.ConfirmationStatus;
import org.qortal.asset.Asset;
import org.qortal.crypto.MemoryPoW;
import org.qortal.data.transaction.PublicizeTransactionData;
import org.qortal.data.transaction.TransactionData;
@@ -26,7 +28,7 @@ public class PublicizeTransaction extends Transaction {
/** If time difference between transaction and now is greater than this then we don't verify proof-of-work. */
public static final long HISTORIC_THRESHOLD = 2 * 7 * 24 * 60 * 60 * 1000L;
public static final int POW_BUFFER_SIZE = 8 * 1024 * 1024; // bytes
public static final int POW_DIFFICULTY = 15; // leading zero bits
public static final int POW_DIFFICULTY = 14; // leading zero bits
// Constructors
@@ -102,6 +104,12 @@ public class PublicizeTransaction extends Transaction {
if (!verifyNonce())
return ValidationResult.INCORRECT_NONCE;
// Validate fee if one has been included
PublicKeyAccount creator = this.getCreator();
if (this.transactionData.getFee() > 0)
if (creator.getConfirmedBalance(Asset.QORT) < this.transactionData.getFee())
return ValidationResult.NO_BALANCE;
return ValidationResult.OK;
}

View File

@@ -163,11 +163,9 @@ public class RewardShareTransaction extends Transaction {
return ValidationResult.SELF_SHARE_EXISTS;
}
// Fee checking needed if not setting up new self-share
if (!(isRecipientAlsoMinter && existingRewardShareData == null))
// Check creator has enough funds
if (creator.getConfirmedBalance(Asset.QORT) < this.rewardShareTransactionData.getFee())
return ValidationResult.NO_BALANCE;
// Check creator has enough funds
if (creator.getConfirmedBalance(Asset.QORT) < this.rewardShareTransactionData.getFee())
return ValidationResult.NO_BALANCE;
return ValidationResult.OK;
}

View File

@@ -103,7 +103,7 @@ public class UpdateGroupTransaction extends Transaction {
Account newOwner = getNewOwner();
// Check new owner is not banned
if (this.repository.getGroupRepository().banExists(this.updateGroupTransactionData.getGroupId(), newOwner.getAddress()))
if (this.repository.getGroupRepository().banExists(this.updateGroupTransactionData.getGroupId(), newOwner.getAddress(), this.updateGroupTransactionData.getTimestamp()))
return ValidationResult.BANNED_FROM_GROUP;
return ValidationResult.OK;

View File

@@ -82,7 +82,7 @@
"transactionV6Timestamp": 9999999999999,
"disableReferenceTimestamp": 1655222400000,
"increaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"onlineAccountMinterLevelValidationHeight": 1093400,
"onlineAccountMinterLevelValidationHeight": 1092000,
"selfSponsorshipAlgoV1Height": 1092400
},
"genesisInfo": {

View File

@@ -50,8 +50,8 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
// Bob self sponsors 10 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
// Mint blocks
@@ -73,7 +73,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertTrue(new Account(repository, bobSponsee.getAddress()).getLevel() > 0);
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> bobSponseeSelfShares = generateSelfShares(repository, bobSponsees);
List<PrivateKeyAccount> bobSponseeSelfShares = AccountUtils.generateSelfShares(repository, bobSponsees);
onlineAccounts.addAll(bobSponseeSelfShares);
// Mint blocks
@@ -139,18 +139,18 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount dilbertAccount = Common.getTestAccount(repository, "dilbert");
// Bob sponsors 10 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
// Chloe sponsors 10 accounts
List<PrivateKeyAccount> chloeSponsees = generateSponsorshipRewardShares(repository, chloeAccount, 10);
List<PrivateKeyAccount> chloeSponseesOnlineAccounts = toRewardShares(repository, chloeAccount, chloeSponsees);
List<PrivateKeyAccount> chloeSponsees = AccountUtils.generateSponsorshipRewardShares(repository, chloeAccount, 10);
List<PrivateKeyAccount> chloeSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, chloeAccount, chloeSponsees);
onlineAccounts.addAll(chloeSponseesOnlineAccounts);
// Dilbert sponsors 5 accounts
List<PrivateKeyAccount> dilbertSponsees = generateSponsorshipRewardShares(repository, dilbertAccount, 5);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = toRewardShares(repository, dilbertAccount, dilbertSponsees);
List<PrivateKeyAccount> dilbertSponsees = AccountUtils.generateSponsorshipRewardShares(repository, dilbertAccount, 5);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, dilbertAccount, dilbertSponsees);
onlineAccounts.addAll(dilbertSponseesOnlineAccounts);
// Mint blocks
@@ -172,7 +172,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertTrue(new Account(repository, bobSponsee.getAddress()).getLevel() > 0);
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> bobSponseeSelfShares = generateSelfShares(repository, bobSponsees);
List<PrivateKeyAccount> bobSponseeSelfShares = AccountUtils.generateSelfShares(repository, bobSponsees);
onlineAccounts.addAll(bobSponseeSelfShares);
// Mint blocks
@@ -270,20 +270,20 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount dilbertAccount = Common.getTestAccount(repository, "dilbert");
// Bob sponsors 10 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccountsAliceSigner.addAll(bobSponseesOnlineAccounts);
onlineAccountsBobSigner.addAll(bobSponseesOnlineAccounts);
// Chloe sponsors 10 accounts
List<PrivateKeyAccount> chloeSponsees = generateSponsorshipRewardShares(repository, chloeAccount, 10);
List<PrivateKeyAccount> chloeSponseesOnlineAccounts = toRewardShares(repository, chloeAccount, chloeSponsees);
List<PrivateKeyAccount> chloeSponsees = AccountUtils.generateSponsorshipRewardShares(repository, chloeAccount, 10);
List<PrivateKeyAccount> chloeSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, chloeAccount, chloeSponsees);
onlineAccountsAliceSigner.addAll(chloeSponseesOnlineAccounts);
onlineAccountsBobSigner.addAll(chloeSponseesOnlineAccounts);
// Dilbert sponsors 5 accounts
List<PrivateKeyAccount> dilbertSponsees = generateSponsorshipRewardShares(repository, dilbertAccount, 5);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = toRewardShares(repository, dilbertAccount, dilbertSponsees);
List<PrivateKeyAccount> dilbertSponsees = AccountUtils.generateSponsorshipRewardShares(repository, dilbertAccount, 5);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, dilbertAccount, dilbertSponsees);
onlineAccountsAliceSigner.addAll(dilbertSponseesOnlineAccounts);
onlineAccountsBobSigner.addAll(dilbertSponseesOnlineAccounts);
@@ -306,7 +306,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertTrue(new Account(repository, bobSponsee.getAddress()).getLevel() > 0);
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> bobSponseeSelfShares = generateSelfShares(repository, bobSponsees);
List<PrivateKeyAccount> bobSponseeSelfShares = AccountUtils.generateSelfShares(repository, bobSponsees);
onlineAccountsAliceSigner.addAll(bobSponseeSelfShares);
onlineAccountsBobSigner.addAll(bobSponseeSelfShares);
@@ -382,14 +382,14 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
// Alice sponsors 10 accounts
List<PrivateKeyAccount> aliceSponsees = generateSponsorshipRewardShares(repository, aliceAccount, 10);
List<PrivateKeyAccount> aliceSponseesOnlineAccounts = toRewardShares(repository, aliceAccount, aliceSponsees);
List<PrivateKeyAccount> aliceSponsees = AccountUtils.generateSponsorshipRewardShares(repository, aliceAccount, 10);
List<PrivateKeyAccount> aliceSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, aliceAccount, aliceSponsees);
onlineAccountsAliceSigner.addAll(aliceSponseesOnlineAccounts);
onlineAccountsBobSigner.addAll(aliceSponseesOnlineAccounts);
// Bob sponsors 9 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 9);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 9);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccountsAliceSigner.addAll(bobSponseesOnlineAccounts);
onlineAccountsBobSigner.addAll(bobSponseesOnlineAccounts);
@@ -412,7 +412,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertTrue(new Account(repository, aliceSponsee.getAddress()).getLevel() > 0);
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> aliceSponseeSelfShares = generateSelfShares(repository, aliceSponsees);
List<PrivateKeyAccount> aliceSponseeSelfShares = AccountUtils.generateSelfShares(repository, aliceSponsees);
onlineAccountsAliceSigner.addAll(aliceSponseeSelfShares);
onlineAccountsBobSigner.addAll(aliceSponseeSelfShares);
@@ -483,18 +483,18 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount dilbertAccount = Common.getTestAccount(repository, "dilbert");
// Bob sponsors 10 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
// Chloe sponsors 10 accounts
List<PrivateKeyAccount> chloeSponsees = generateSponsorshipRewardShares(repository, chloeAccount, 10);
List<PrivateKeyAccount> chloeSponseesOnlineAccounts = toRewardShares(repository, chloeAccount, chloeSponsees);
List<PrivateKeyAccount> chloeSponsees = AccountUtils.generateSponsorshipRewardShares(repository, chloeAccount, 10);
List<PrivateKeyAccount> chloeSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, chloeAccount, chloeSponsees);
onlineAccounts.addAll(chloeSponseesOnlineAccounts);
// Dilbert sponsors 5 accounts
List<PrivateKeyAccount> dilbertSponsees = generateSponsorshipRewardShares(repository, dilbertAccount, 5);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = toRewardShares(repository, dilbertAccount, dilbertSponsees);
List<PrivateKeyAccount> dilbertSponsees = AccountUtils.generateSponsorshipRewardShares(repository, dilbertAccount, 5);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, dilbertAccount, dilbertSponsees);
onlineAccounts.addAll(dilbertSponseesOnlineAccounts);
// Mint blocks
@@ -516,7 +516,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertTrue(new Account(repository, bobSponsee.getAddress()).getLevel() > 0);
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> bobSponseeSelfShares = generateSelfShares(repository, bobSponsees);
List<PrivateKeyAccount> bobSponseeSelfShares = AccountUtils.generateSelfShares(repository, bobSponsees);
onlineAccounts.addAll(bobSponseeSelfShares);
// Mint blocks
@@ -597,14 +597,14 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
// Alice sponsors 10 accounts
List<PrivateKeyAccount> aliceSponsees = generateSponsorshipRewardShares(repository, aliceAccount, 10);
List<PrivateKeyAccount> aliceSponseesOnlineAccounts = toRewardShares(repository, aliceAccount, aliceSponsees);
List<PrivateKeyAccount> aliceSponsees = AccountUtils.generateSponsorshipRewardShares(repository, aliceAccount, 10);
List<PrivateKeyAccount> aliceSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, aliceAccount, aliceSponsees);
onlineAccounts.addAll(aliceSponseesOnlineAccounts);
onlineAccounts.addAll(aliceSponseesOnlineAccounts);
// Bob sponsors 9 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 9);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 9);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
@@ -627,7 +627,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertTrue(new Account(repository, aliceSponsee.getAddress()).getLevel() > 0);
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> aliceSponseeSelfShares = generateSelfShares(repository, aliceSponsees);
List<PrivateKeyAccount> aliceSponseeSelfShares = AccountUtils.generateSelfShares(repository, aliceSponsees);
onlineAccounts.addAll(aliceSponseeSelfShares);
// Mint blocks (Bob is the signer)
@@ -706,13 +706,13 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount chloeAccount = Common.getTestAccount(repository, "chloe");
// Bob sponsors 10 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
// Chloe sponsors 10 accounts
List<PrivateKeyAccount> chloeSponsees = generateSponsorshipRewardShares(repository, chloeAccount, 10);
List<PrivateKeyAccount> chloeSponseesOnlineAccounts = toRewardShares(repository, chloeAccount, chloeSponsees);
List<PrivateKeyAccount> chloeSponsees = AccountUtils.generateSponsorshipRewardShares(repository, chloeAccount, 10);
List<PrivateKeyAccount> chloeSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, chloeAccount, chloeSponsees);
onlineAccounts.addAll(chloeSponseesOnlineAccounts);
// Mint blocks
@@ -728,7 +728,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> bobSponseeSelfShares = generateSelfShares(repository, bobSponsees);
List<PrivateKeyAccount> bobSponseeSelfShares = AccountUtils.generateSelfShares(repository, bobSponsees);
onlineAccounts.addAll(bobSponseeSelfShares);
// Mint blocks
@@ -744,22 +744,22 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertEquals(19, (int) block.getBlockData().getHeight());
// Bob creates a valid reward share transaction
assertEquals(Transaction.ValidationResult.OK, createRandomRewardShare(repository, bobAccount));
assertEquals(Transaction.ValidationResult.OK, AccountUtils.createRandomRewardShare(repository, bobAccount));
// Mint a block, so the algo runs
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
// Bob can no longer create a reward share transaction
assertEquals(Transaction.ValidationResult.ACCOUNT_CANNOT_REWARD_SHARE, createRandomRewardShare(repository, bobAccount));
assertEquals(Transaction.ValidationResult.ACCOUNT_CANNOT_REWARD_SHARE, AccountUtils.createRandomRewardShare(repository, bobAccount));
// ... but Chloe still can
assertEquals(Transaction.ValidationResult.OK, createRandomRewardShare(repository, chloeAccount));
assertEquals(Transaction.ValidationResult.OK, AccountUtils.createRandomRewardShare(repository, chloeAccount));
// Orphan last block
BlockUtils.orphanLastBlock(repository);
// Bob creates another valid reward share transaction
assertEquals(Transaction.ValidationResult.OK, createRandomRewardShare(repository, bobAccount));
assertEquals(Transaction.ValidationResult.OK, AccountUtils.createRandomRewardShare(repository, bobAccount));
// Run orphan check - this can't be in afterTest() because some tests access the live db
Common.orphanCheck();
@@ -780,13 +780,13 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
// Alice sponsors 10 accounts
List<PrivateKeyAccount> aliceSponsees = generateSponsorshipRewardShares(repository, aliceAccount, 10);
List<PrivateKeyAccount> aliceSponseesOnlineAccounts = toRewardShares(repository, aliceAccount, aliceSponsees);
List<PrivateKeyAccount> aliceSponsees = AccountUtils.generateSponsorshipRewardShares(repository, aliceAccount, 10);
List<PrivateKeyAccount> aliceSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, aliceAccount, aliceSponsees);
onlineAccounts.addAll(aliceSponseesOnlineAccounts);
// Bob sponsors 10 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
// Mint blocks
@@ -802,7 +802,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> aliceSponseeSelfShares = generateSelfShares(repository, aliceSponsees);
List<PrivateKeyAccount> aliceSponseeSelfShares = AccountUtils.generateSelfShares(repository, aliceSponsees);
onlineAccounts.addAll(aliceSponseeSelfShares);
// Mint blocks
@@ -818,7 +818,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertEquals(19, (int) block.getBlockData().getHeight());
// Alice creates a valid reward share transaction
assertEquals(Transaction.ValidationResult.OK, createRandomRewardShare(repository, aliceAccount));
assertEquals(Transaction.ValidationResult.OK, AccountUtils.createRandomRewardShare(repository, aliceAccount));
// Mint a block, so the algo runs
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
@@ -830,16 +830,16 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertEquals(0, (int) new Account(repository, aliceAccount.getAddress()).getLevel());
// Alice can no longer create a reward share transaction
assertEquals(Transaction.ValidationResult.ACCOUNT_CANNOT_REWARD_SHARE, createRandomRewardShare(repository, aliceAccount));
assertEquals(Transaction.ValidationResult.ACCOUNT_CANNOT_REWARD_SHARE, AccountUtils.createRandomRewardShare(repository, aliceAccount));
// ... but Bob still can
assertEquals(Transaction.ValidationResult.OK, createRandomRewardShare(repository, bobAccount));
assertEquals(Transaction.ValidationResult.OK, AccountUtils.createRandomRewardShare(repository, bobAccount));
// Orphan last block
BlockUtils.orphanLastBlock(repository);
// Alice creates another valid reward share transaction
assertEquals(Transaction.ValidationResult.OK, createRandomRewardShare(repository, aliceAccount));
assertEquals(Transaction.ValidationResult.OK, AccountUtils.createRandomRewardShare(repository, aliceAccount));
// Run orphan check - this can't be in afterTest() because some tests access the live db
Common.orphanCheck();
@@ -867,8 +867,8 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount dilbertAccount = Common.getTestAccount(repository, "dilbert");
// Dilbert sponsors 10 accounts
List<PrivateKeyAccount> dilbertSponsees = generateSponsorshipRewardShares(repository, dilbertAccount, 10);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = toRewardShares(repository, dilbertAccount, dilbertSponsees);
List<PrivateKeyAccount> dilbertSponsees = AccountUtils.generateSponsorshipRewardShares(repository, dilbertAccount, 10);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, dilbertAccount, dilbertSponsees);
onlineAccounts.addAll(dilbertSponseesOnlineAccounts);
// Mint blocks
@@ -921,8 +921,8 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount dilbertAccount = Common.getTestAccount(repository, "dilbert");
// Dilbert sponsors 10 accounts
List<PrivateKeyAccount> dilbertSponsees = generateSponsorshipRewardShares(repository, dilbertAccount, 10);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = toRewardShares(repository, dilbertAccount, dilbertSponsees);
List<PrivateKeyAccount> dilbertSponsees = AccountUtils.generateSponsorshipRewardShares(repository, dilbertAccount, 10);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, dilbertAccount, dilbertSponsees);
onlineAccounts.addAll(dilbertSponseesOnlineAccounts);
// Mint blocks
@@ -935,7 +935,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
block = BlockMinter.mintTestingBlock(repository, onlineAccounts.toArray(new PrivateKeyAccount[0]));
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> dilbertSponseeSelfShares = generateSelfShares(repository, dilbertSponsees);
List<PrivateKeyAccount> dilbertSponseeSelfShares = AccountUtils.generateSelfShares(repository, dilbertSponsees);
onlineAccounts.addAll(dilbertSponseeSelfShares);
// Mint blocks
@@ -985,8 +985,8 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount dilbertAccount = Common.getTestAccount(repository, "dilbert");
// Bob sponsors 10 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
// Chloe sponsors THE SAME 10 accounts
@@ -996,12 +996,12 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
TransactionUtils.signAndImportValid(repository, transactionData, chloeAccount);
}
List<PrivateKeyAccount> chloeSponsees = new ArrayList<>(bobSponsees);
List<PrivateKeyAccount> chloeSponseesOnlineAccounts = toRewardShares(repository, chloeAccount, chloeSponsees);
List<PrivateKeyAccount> chloeSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, chloeAccount, chloeSponsees);
onlineAccounts.addAll(chloeSponseesOnlineAccounts);
// Dilbert sponsors 5 accounts
List<PrivateKeyAccount> dilbertSponsees = generateSponsorshipRewardShares(repository, dilbertAccount, 5);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = toRewardShares(repository, dilbertAccount, dilbertSponsees);
List<PrivateKeyAccount> dilbertSponsees = AccountUtils.generateSponsorshipRewardShares(repository, dilbertAccount, 5);
List<PrivateKeyAccount> dilbertSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, dilbertAccount, dilbertSponsees);
onlineAccounts.addAll(dilbertSponseesOnlineAccounts);
// Mint blocks
@@ -1023,7 +1023,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertTrue(new Account(repository, bobSponsee.getAddress()).getLevel() > 0);
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> bobSponseeSelfShares = generateSelfShares(repository, bobSponsees);
List<PrivateKeyAccount> bobSponseeSelfShares = AccountUtils.generateSelfShares(repository, bobSponsees);
onlineAccounts.addAll(bobSponseeSelfShares);
// Mint blocks
@@ -1108,8 +1108,8 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
// Bob sponsors 10 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
// Mint blocks
@@ -1128,7 +1128,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertTrue(new Account(repository, bobSponsee.getAddress()).getLevel() > 0);
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> bobSponseeSelfShares = generateSelfShares(repository, bobSponsees);
List<PrivateKeyAccount> bobSponseeSelfShares = AccountUtils.generateSelfShares(repository, bobSponsees);
onlineAccounts.addAll(bobSponseeSelfShares);
// Mint blocks
@@ -1220,8 +1220,8 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
// Bob sponsors 10 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
// Mint blocks
@@ -1240,7 +1240,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertTrue(new Account(repository, bobSponsee.getAddress()).getLevel() > 0);
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> bobSponseeSelfShares = generateSelfShares(repository, bobSponsees);
List<PrivateKeyAccount> bobSponseeSelfShares = AccountUtils.generateSelfShares(repository, bobSponsees);
onlineAccounts.addAll(bobSponseeSelfShares);
// Mint blocks
@@ -1316,8 +1316,8 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
// Bob sponsors 10 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
// Mint blocks
@@ -1336,7 +1336,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertTrue(new Account(repository, bobSponsee.getAddress()).getLevel() > 0);
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> bobSponseeSelfShares = generateSelfShares(repository, bobSponsees);
List<PrivateKeyAccount> bobSponseeSelfShares = AccountUtils.generateSelfShares(repository, bobSponsees);
onlineAccounts.addAll(bobSponseeSelfShares);
// Mint blocks
@@ -1392,8 +1392,8 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
PrivateKeyAccount bobAccount = Common.getTestAccount(repository, "bob");
// Bob sponsors 10 accounts
List<PrivateKeyAccount> bobSponsees = generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = toRewardShares(repository, bobAccount, bobSponsees);
List<PrivateKeyAccount> bobSponsees = AccountUtils.generateSponsorshipRewardShares(repository, bobAccount, 10);
List<PrivateKeyAccount> bobSponseesOnlineAccounts = AccountUtils.toRewardShares(repository, bobAccount, bobSponsees);
onlineAccounts.addAll(bobSponseesOnlineAccounts);
// Mint blocks
@@ -1412,7 +1412,7 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertTrue(new Account(repository, bobSponsee.getAddress()).getLevel() > 0);
// Generate self shares so the sponsees can start minting
List<PrivateKeyAccount> bobSponseeSelfShares = generateSelfShares(repository, bobSponsees);
List<PrivateKeyAccount> bobSponseeSelfShares = AccountUtils.generateSelfShares(repository, bobSponsees);
onlineAccounts.addAll(bobSponseeSelfShares);
// Mint blocks
@@ -1543,61 +1543,6 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
return new TransferPrivsTransaction(repository, transactionData);
}
private static List<PrivateKeyAccount> generateSponsorshipRewardShares(Repository repository, PrivateKeyAccount sponsorAccount, int accountsCount) throws DataException {
final int sharePercent = 0;
Random random = new Random();
List<PrivateKeyAccount> sponsees = new ArrayList<>();
for (int i = 0; i < accountsCount; i++) {
// Generate random sponsee account
byte[] randomPrivateKey = new byte[32];
random.nextBytes(randomPrivateKey);
PrivateKeyAccount sponseeAccount = new PrivateKeyAccount(repository, randomPrivateKey);
sponsees.add(sponseeAccount);
// Create reward-share
TransactionData transactionData = AccountUtils.createRewardShare(repository, sponsorAccount, sponseeAccount, sharePercent, fee);
TransactionUtils.signAndImportValid(repository, transactionData, sponsorAccount);
}
return sponsees;
}
private static Transaction.ValidationResult createRandomRewardShare(Repository repository, PrivateKeyAccount account) throws DataException {
// Bob attempts to create a reward share transaction
byte[] randomPrivateKey = new byte[32];
new Random().nextBytes(randomPrivateKey);
PrivateKeyAccount sponseeAccount = new PrivateKeyAccount(repository, randomPrivateKey);
TransactionData transactionData = AccountUtils.createRewardShare(repository, account, sponseeAccount, 0, fee);
return TransactionUtils.signAndImport(repository, transactionData, account);
}
private static List<PrivateKeyAccount> generateSelfShares(Repository repository, List<PrivateKeyAccount> accounts) throws DataException {
final int sharePercent = 0;
for (PrivateKeyAccount account : accounts) {
// Create reward-share
TransactionData transactionData = AccountUtils.createRewardShare(repository, account, account, sharePercent, 0L);
TransactionUtils.signAndImportValid(repository, transactionData, account);
}
return toRewardShares(repository, null, accounts);
}
private static List<PrivateKeyAccount> toRewardShares(Repository repository, PrivateKeyAccount parentAccount, List<PrivateKeyAccount> accounts) {
List<PrivateKeyAccount> rewardShares = new ArrayList<>();
for (PrivateKeyAccount account : accounts) {
PrivateKeyAccount sponsor = (parentAccount != null) ? parentAccount : account;
byte[] rewardSharePrivateKey = sponsor.getRewardSharePrivateKey(account.getPublicKey());
PrivateKeyAccount rewardShareAccount = new PrivateKeyAccount(repository, rewardSharePrivateKey);
rewardShares.add(rewardShareAccount);
}
return rewardShares;
}
private boolean areAllAccountsPresentInBlock(List<PrivateKeyAccount> accounts, Block block) throws DataException {
for (PrivateKeyAccount bobSponsee : accounts) {
boolean foundOnlineAccountInBlock = false;

View File

@@ -8,7 +8,6 @@ import java.util.*;
import com.google.common.primitives.Longs;
import org.qortal.account.PrivateKeyAccount;
import org.qortal.block.BlockChain;
import org.qortal.crypto.Crypto;
import org.qortal.crypto.Qortal25519Extras;
import org.qortal.data.network.OnlineAccountData;
@@ -19,6 +18,7 @@ import org.qortal.data.transaction.TransactionData;
import org.qortal.group.Group;
import org.qortal.repository.DataException;
import org.qortal.repository.Repository;
import org.qortal.transaction.Transaction;
import org.qortal.transform.Transformer;
import org.qortal.utils.Amounts;
@@ -86,6 +86,61 @@ public class AccountUtils {
return rewardSharePrivateKey;
}
public static List<PrivateKeyAccount> generateSponsorshipRewardShares(Repository repository, PrivateKeyAccount sponsorAccount, int accountsCount) throws DataException {
final int sharePercent = 0;
Random random = new Random();
List<PrivateKeyAccount> sponsees = new ArrayList<>();
for (int i = 0; i < accountsCount; i++) {
// Generate random sponsee account
byte[] randomPrivateKey = new byte[32];
random.nextBytes(randomPrivateKey);
PrivateKeyAccount sponseeAccount = new PrivateKeyAccount(repository, randomPrivateKey);
sponsees.add(sponseeAccount);
// Create reward-share
TransactionData transactionData = AccountUtils.createRewardShare(repository, sponsorAccount, sponseeAccount, sharePercent, fee);
TransactionUtils.signAndImportValid(repository, transactionData, sponsorAccount);
}
return sponsees;
}
public static Transaction.ValidationResult createRandomRewardShare(Repository repository, PrivateKeyAccount account) throws DataException {
// Bob attempts to create a reward share transaction
byte[] randomPrivateKey = new byte[32];
new Random().nextBytes(randomPrivateKey);
PrivateKeyAccount sponseeAccount = new PrivateKeyAccount(repository, randomPrivateKey);
TransactionData transactionData = createRewardShare(repository, account, sponseeAccount, 0, fee);
return TransactionUtils.signAndImport(repository, transactionData, account);
}
public static List<PrivateKeyAccount> generateSelfShares(Repository repository, List<PrivateKeyAccount> accounts) throws DataException {
final int sharePercent = 0;
for (PrivateKeyAccount account : accounts) {
// Create reward-share
TransactionData transactionData = createRewardShare(repository, account, account, sharePercent, 0L);
TransactionUtils.signAndImportValid(repository, transactionData, account);
}
return toRewardShares(repository, null, accounts);
}
public static List<PrivateKeyAccount> toRewardShares(Repository repository, PrivateKeyAccount parentAccount, List<PrivateKeyAccount> accounts) {
List<PrivateKeyAccount> rewardShares = new ArrayList<>();
for (PrivateKeyAccount account : accounts) {
PrivateKeyAccount sponsor = (parentAccount != null) ? parentAccount : account;
byte[] rewardSharePrivateKey = sponsor.getRewardSharePrivateKey(account.getPublicKey());
PrivateKeyAccount rewardShareAccount = new PrivateKeyAccount(repository, rewardSharePrivateKey);
rewardShares.add(rewardShareAccount);
}
return rewardShares;
}
public static Map<String, Map<Long, Long>> getBalances(Repository repository, long... assetIds) throws DataException {
Map<String, Map<Long, Long>> balances = new HashMap<>();

View File

@@ -120,7 +120,9 @@ public class Common {
}
public static void useSettingsAndDb(String settingsFilename, boolean dbInMemory) throws DataException {
closeRepository();
if (RepositoryManager.getRepositoryFactory() != null) {
closeRepository();
}
// Load/check settings, which potentially sets up blockchain config, etc.
LOGGER.debug(String.format("Using setting file: %s", settingsFilename));

View File

@@ -135,7 +135,8 @@ public class AdminTests extends Common {
assertNotSame(ValidationResult.OK, result);
// Attempt to ban Bob
result = groupBan(repository, alice, groupId, bob.getAddress());
int timeToLive = 0;
result = groupBan(repository, alice, groupId, bob.getAddress(), timeToLive);
// Should be OK
assertEquals(ValidationResult.OK, result);
@@ -158,7 +159,7 @@ public class AdminTests extends Common {
assertTrue(isMember(repository, bob.getAddress(), groupId));
// Attempt to ban Bob
result = groupBan(repository, alice, groupId, bob.getAddress());
result = groupBan(repository, alice, groupId, bob.getAddress(), timeToLive);
// Should be OK
assertEquals(ValidationResult.OK, result);
@@ -205,6 +206,144 @@ public class AdminTests extends Common {
}
}
@Test
public void testGroupBanMemberWithExpiry() throws DataException, InterruptedException {
try (final Repository repository = RepositoryManager.getRepository()) {
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
PrivateKeyAccount bob = Common.getTestAccount(repository, "bob");
// Create group
int groupId = createGroup(repository, alice, "open-group", true);
// Confirm Bob is not a member
assertFalse(isMember(repository, bob.getAddress(), groupId));
// Attempt to cancel non-existent Bob ban
ValidationResult result = cancelGroupBan(repository, alice, groupId, bob.getAddress());
// Should NOT be OK
assertNotSame(ValidationResult.OK, result);
// Attempt to ban Bob for 2 seconds
int timeToLive = 2;
result = groupBan(repository, alice, groupId, bob.getAddress(), timeToLive);
// Should be OK
assertEquals(ValidationResult.OK, result);
// Confirm Bob no longer a member
assertFalse(isMember(repository, bob.getAddress(), groupId));
// Bob attempts to rejoin
result = joinGroup(repository, bob, groupId);
// Should NOT be OK
assertNotSame(ValidationResult.OK, result);
// Wait for 2 seconds to pass
Thread.sleep(2000L);
// Bob attempts to rejoin again
result = joinGroup(repository, bob, groupId);
// Should be OK, as the ban has expired
assertSame(ValidationResult.OK, result);
// Confirm Bob is now a member
assertTrue(isMember(repository, bob.getAddress(), groupId));
// Orphan last block (Bob join)
BlockUtils.orphanLastBlock(repository);
// Confirm Bob is not a member
assertFalse(isMember(repository, bob.getAddress(), groupId));
// Orphan last block (Bob ban)
BlockUtils.orphanLastBlock(repository);
// Delete unconfirmed group-ban transaction
TransactionUtils.deleteUnconfirmedTransactions(repository);
// Bob to join
result = joinGroup(repository, bob, groupId);
// Should be OK
assertEquals(ValidationResult.OK, result);
// Confirm Bob now a member
assertTrue(isMember(repository, bob.getAddress(), groupId));
// Attempt to ban Bob for 2 seconds
result = groupBan(repository, alice, groupId, bob.getAddress(), 2);
// Should be OK
assertEquals(ValidationResult.OK, result);
// Confirm Bob no longer a member
assertFalse(isMember(repository, bob.getAddress(), groupId));
// Wait for 2 seconds to pass
Thread.sleep(2000L);
// Cancel Bob's ban
result = cancelGroupBan(repository, alice, groupId, bob.getAddress());
// Should NOT be OK, as ban has already expired
assertNotSame(ValidationResult.OK, result);
// Confirm Bob still not a member
assertFalse(isMember(repository, bob.getAddress(), groupId));
// Bob attempts to rejoin
result = joinGroup(repository, bob, groupId);
// Should be OK, as no longer banned
assertSame(ValidationResult.OK, result);
// Confirm Bob is now a member
assertTrue(isMember(repository, bob.getAddress(), groupId));
// Attempt to ban Bob for 10 seconds
result = groupBan(repository, alice, groupId, bob.getAddress(), 10);
// Should be OK
assertEquals(ValidationResult.OK, result);
// Confirm Bob no longer a member
assertFalse(isMember(repository, bob.getAddress(), groupId));
// Bob attempts to rejoin
result = joinGroup(repository, bob, groupId);
// Should NOT be OK, as ban still exists
assertNotSame(ValidationResult.OK, result);
// Cancel Bob's ban
result = cancelGroupBan(repository, alice, groupId, bob.getAddress());
// Should be OK, as ban still exists
assertEquals(ValidationResult.OK, result);
// Bob attempts to rejoin
result = joinGroup(repository, bob, groupId);
// Should be OK, as no longer banned
assertEquals(ValidationResult.OK, result);
// Orphan last block (Bob join)
BlockUtils.orphanLastBlock(repository);
// Delete unconfirmed join-group transaction
TransactionUtils.deleteUnconfirmedTransactions(repository);
// Orphan last block (Cancel Bob ban)
BlockUtils.orphanLastBlock(repository);
// Delete unconfirmed cancel-ban transaction
TransactionUtils.deleteUnconfirmedTransactions(repository);
// Bob attempts to rejoin
result = joinGroup(repository, bob, groupId);
// Should NOT be OK
assertNotSame(ValidationResult.OK, result);
// Orphan last block (Bob ban)
BlockUtils.orphanLastBlock(repository);
// Delete unconfirmed group-ban transaction
TransactionUtils.deleteUnconfirmedTransactions(repository);
// Confirm Bob now a member
assertTrue(isMember(repository, bob.getAddress(), groupId));
}
}
@Test
public void testGroupBanAdmin() throws DataException {
try (final Repository repository = RepositoryManager.getRepository()) {
@@ -226,7 +365,8 @@ public class AdminTests extends Common {
assertTrue(isAdmin(repository, bob.getAddress(), groupId));
// Attempt to ban Bob
result = groupBan(repository, alice, groupId, bob.getAddress());
int timeToLive = 0;
result = groupBan(repository, alice, groupId, bob.getAddress(), timeToLive);
// Should be OK
assertEquals(ValidationResult.OK, result);
@@ -272,12 +412,12 @@ public class AdminTests extends Common {
assertTrue(isAdmin(repository, bob.getAddress(), groupId));
// Have Alice (owner) try to ban herself!
result = groupBan(repository, alice, groupId, alice.getAddress());
result = groupBan(repository, alice, groupId, alice.getAddress(), timeToLive);
// Should NOT be OK
assertNotSame(ValidationResult.OK, result);
// Have Bob try to ban Alice (owner)
result = groupBan(repository, bob, groupId, alice.getAddress());
result = groupBan(repository, bob, groupId, alice.getAddress(), timeToLive);
// Should NOT be OK
assertNotSame(ValidationResult.OK, result);
}
@@ -316,8 +456,8 @@ public class AdminTests extends Common {
return result;
}
private ValidationResult groupBan(Repository repository, PrivateKeyAccount admin, int groupId, String member) throws DataException {
GroupBanTransactionData transactionData = new GroupBanTransactionData(TestTransaction.generateBase(admin), groupId, member, "testing", 0);
private ValidationResult groupBan(Repository repository, PrivateKeyAccount admin, int groupId, String member, int timeToLive) throws DataException {
GroupBanTransactionData transactionData = new GroupBanTransactionData(TestTransaction.generateBase(admin), groupId, member, "testing", timeToLive);
ValidationResult result = TransactionUtils.signAndImport(repository, transactionData, admin);
if (result == ValidationResult.OK)

View File

@@ -44,7 +44,7 @@
{ "height": 1000000, "share": 0.01 }
],
"qoraPerQortReward": 250,
"minAccountsToActivateShareBin": 30,
"minAccountsToActivateShareBin": 0,
"shareBinActivationMinLevel": 7,
"blocksNeededByLevel": [ 5, 20, 30, 40, 50, 60, 18, 80, 90, 100 ],
"blockTimingsByHeight": [