Merge branch 'Qortal:master' into master

This commit is contained in:
kennycud 2025-05-25 12:20:58 -07:00 committed by GitHub
commit 61c010754e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 295 additions and 120 deletions

View File

@ -747,12 +747,12 @@
<!-- BouncyCastle for crypto, including TLS secure networking --> <!-- BouncyCastle for crypto, including TLS secure networking -->
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId> <artifactId>bcprov-jdk15to18</artifactId>
<version>${bouncycastle.version}</version> <version>${bouncycastle.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>bctls-jdk15on</artifactId> <artifactId>bctls-jdk15to18</artifactId>
<version>${bouncycastle.version}</version> <version>${bouncycastle.version}</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -5,8 +5,10 @@ import org.qortal.utils.Base58;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Arrays; import java.util.Arrays;
@ -44,12 +46,22 @@ public class ArbitraryDataDigest {
continue; continue;
} }
// Account for \ VS / : Linux VS Windows
String pathString = relativePath.toString();
if(relativePath.getFileSystem().toString().contains("Windows")) {
pathString = pathString.replace("\\","/");
}
// Hash path // Hash path
byte[] filePathBytes = relativePath.toString().getBytes(StandardCharsets.UTF_8); byte[] filePathBytes = pathString.getBytes(StandardCharsets.UTF_8);
System.out.printf("Path: %s \n", pathString);
System.out.printf("Path Byte Array: %s \n", Arrays.toString(filePathBytes));
sha256.update(filePathBytes); sha256.update(filePathBytes);
// Hash contents // Hash contents
byte[] fileContent = Files.readAllBytes(path); byte[] fileContent = Files.readAllBytes(path);
System.out.printf("File Content: %s \n", Arrays.toString(fileContent));
sha256.update(fileContent); sha256.update(fileContent);
} }
this.hash = sha256.digest(); this.hash = sha256.digest();

View File

@ -37,7 +37,7 @@ public enum Service {
if (files != null && files[0] != null) { if (files != null && files[0] != null) {
final String extension = FilenameUtils.getExtension(files[0].getName()).toLowerCase(); final String extension = FilenameUtils.getExtension(files[0].getName()).toLowerCase();
// We must allow blank file extensions because these are used by data published from a plaintext or base64-encoded string // We must allow blank file extensions because these are used by data published from a plaintext or base64-encoded string
final List<String> allowedExtensions = Arrays.asList("zip", "pdf", "txt", "odt", "ods", "doc", "docx", "xls", "xlsx", "ppt", "pptx", ""); final List<String> allowedExtensions = Arrays.asList("qortal", "zip", "pdf", "txt", "odt", "ods", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "");
if (extension == null || !allowedExtensions.contains(extension)) { if (extension == null || !allowedExtensions.contains(extension)) {
return ValidationResult.INVALID_FILE_EXTENSION; return ValidationResult.INVALID_FILE_EXTENSION;
} }

View File

@ -644,8 +644,10 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
} }
/** /**
* Performs RPC call, with automatic reconnection to different server if needed. * <p>Performs RPC call, with automatic reconnection to different server if needed.
* <p> * </p>
* @param method String representation of the RPC call value
* @param params a list of Objects passed to the method of the Remote Server
* @return "result" object from within JSON output * @return "result" object from within JSON output
* @throws ForeignBlockchainException if server returns error or something goes wrong * @throws ForeignBlockchainException if server returns error or something goes wrong
*/ */

View File

@ -22,28 +22,23 @@ public class CancelSellNameTransaction extends Transaction {
private CancelSellNameTransactionData cancelSellNameTransactionData; private CancelSellNameTransactionData cancelSellNameTransactionData;
// Constructors // Constructors
public CancelSellNameTransaction(Repository repository, TransactionData transactionData) { public CancelSellNameTransaction(Repository repository, TransactionData transactionData) {
super(repository, transactionData); super(repository, transactionData);
this.cancelSellNameTransactionData = (CancelSellNameTransactionData) this.transactionData; this.cancelSellNameTransactionData = (CancelSellNameTransactionData) this.transactionData;
} }
// More information // More information
@Override @Override
public List<String> getRecipientAddresses() throws DataException { public List<String> getRecipientAddresses() throws DataException {
return Collections.emptyList(); return Collections.emptyList(); // No recipient address for this transaction
} }
// Navigation // Navigation
public Account getOwner() { public Account getOwner() {
return this.getCreator(); return this.getCreator(); // The creator of the transaction is the owner
} }
// Processing // Processing
@Override @Override
public ValidationResult isValid() throws DataException { public ValidationResult isValid() throws DataException {
String name = this.cancelSellNameTransactionData.getName(); String name = this.cancelSellNameTransactionData.getName();
@ -57,61 +52,56 @@ public class CancelSellNameTransaction extends Transaction {
if (!name.equals(Unicode.normalize(name))) if (!name.equals(Unicode.normalize(name)))
return ValidationResult.NAME_NOT_NORMALIZED; return ValidationResult.NAME_NOT_NORMALIZED;
// Retrieve name data from repository
NameData nameData = this.repository.getNameRepository().fromName(name); NameData nameData = this.repository.getNameRepository().fromName(name);
// Check name exists // Check if name exists
if (nameData == null) if (nameData == null)
return ValidationResult.NAME_DOES_NOT_EXIST; return ValidationResult.NAME_DOES_NOT_EXIST;
// Check name is currently for sale // Check name is currently for sale
if (!nameData.isForSale()) { if (!nameData.isForSale()) {
// Only validate after feature-trigger timestamp, due to a small number of double cancelations in the chain history // Validate after feature-trigger timestamp, due to potential double cancellations
if (this.cancelSellNameTransactionData.getTimestamp() > BlockChain.getInstance().getCancelSellNameValidationTimestamp()) if (this.cancelSellNameTransactionData.getTimestamp() > BlockChain.getInstance().getCancelSellNameValidationTimestamp())
return ValidationResult.NAME_NOT_FOR_SALE; return ValidationResult.NAME_NOT_FOR_SALE;
} }
// Check transaction creator matches name's current owner // Check if transaction creator matches the name's current owner
Account owner = getOwner(); Account owner = getOwner();
if (!owner.getAddress().equals(nameData.getOwner())) if (!owner.getAddress().equals(nameData.getOwner()))
return ValidationResult.INVALID_NAME_OWNER; return ValidationResult.INVALID_NAME_OWNER;
// Check issuer has enough funds // Check if issuer has enough balance for the transaction fee
if (owner.getConfirmedBalance(Asset.QORT) < cancelSellNameTransactionData.getFee()) if (owner.getConfirmedBalance(Asset.QORT) < cancelSellNameTransactionData.getFee())
return ValidationResult.NO_BALANCE; return ValidationResult.NO_BALANCE;
return ValidationResult.OK; return ValidationResult.OK; // All validations passed
} }
@Override @Override
public void preProcess() throws DataException { public void preProcess() throws DataException {
CancelSellNameTransactionData cancelSellNameTransactionData = (CancelSellNameTransactionData) transactionData; // Direct access to class field, no need to redeclare
// Rebuild this name in the Names table from the transaction history
// This is necessary because in some rare cases names can be missing from the Names table after registration
// but we have been unable to reproduce the issue and track down the root cause
NamesDatabaseIntegrityCheck namesDatabaseIntegrityCheck = new NamesDatabaseIntegrityCheck(); NamesDatabaseIntegrityCheck namesDatabaseIntegrityCheck = new NamesDatabaseIntegrityCheck();
namesDatabaseIntegrityCheck.rebuildName(cancelSellNameTransactionData.getName(), this.repository); namesDatabaseIntegrityCheck.rebuildName(this.cancelSellNameTransactionData.getName(), this.repository);
} }
@Override @Override
public void process() throws DataException { public void process() throws DataException {
// Update Name // Update the Name to reflect the cancellation of the sale
Name name = new Name(this.repository, cancelSellNameTransactionData.getName()); Name name = new Name(this.repository, cancelSellNameTransactionData.getName());
name.cancelSell(cancelSellNameTransactionData); name.cancelSell(cancelSellNameTransactionData);
// Save this transaction, with updated "name reference" to previous transaction that updated name // Save this transaction with updated "name reference"
this.repository.getTransactionRepository().save(cancelSellNameTransactionData); this.repository.getTransactionRepository().save(cancelSellNameTransactionData);
} }
@Override @Override
public void orphan() throws DataException { public void orphan() throws DataException {
// Revert name // Revert the cancellation of the name sale
Name name = new Name(this.repository, cancelSellNameTransactionData.getName()); Name name = new Name(this.repository, cancelSellNameTransactionData.getName());
name.uncancelSell(cancelSellNameTransactionData); name.uncancelSell(cancelSellNameTransactionData);
// Save this transaction, with removed "name reference" // Save the transaction with the reverted "name reference"
this.repository.getTransactionRepository().save(cancelSellNameTransactionData); this.repository.getTransactionRepository().save(cancelSellNameTransactionData);
} }
} }

View File

@ -24,28 +24,23 @@ public class SellNameTransaction extends Transaction {
private SellNameTransactionData sellNameTransactionData; private SellNameTransactionData sellNameTransactionData;
// Constructors // Constructors
public SellNameTransaction(Repository repository, TransactionData transactionData) { public SellNameTransaction(Repository repository, TransactionData transactionData) {
super(repository, transactionData); super(repository, transactionData);
this.sellNameTransactionData = (SellNameTransactionData) this.transactionData; this.sellNameTransactionData = (SellNameTransactionData) this.transactionData;
} }
// More information // More information
@Override @Override
public List<String> getRecipientAddresses() throws DataException { public List<String> getRecipientAddresses() throws DataException {
return Collections.emptyList(); return Collections.emptyList(); // No direct recipient address for this transaction
} }
// Navigation // Navigation
public Account getOwner() { public Account getOwner() {
return this.getCreator(); return this.getCreator(); // Owner is the creator of the transaction
} }
// Processing // Processing
@Override @Override
public ValidationResult isValid() throws DataException { public ValidationResult isValid() throws DataException {
String name = this.sellNameTransactionData.getName(); String name = this.sellNameTransactionData.getName();
@ -59,59 +54,54 @@ public class SellNameTransaction extends Transaction {
if (!name.equals(Unicode.normalize(name))) if (!name.equals(Unicode.normalize(name)))
return ValidationResult.NAME_NOT_NORMALIZED; return ValidationResult.NAME_NOT_NORMALIZED;
// Retrieve name data from repository
NameData nameData = this.repository.getNameRepository().fromName(name); NameData nameData = this.repository.getNameRepository().fromName(name);
// Check name exists // Check if name exists
if (nameData == null) if (nameData == null)
return ValidationResult.NAME_DOES_NOT_EXIST; return ValidationResult.NAME_DOES_NOT_EXIST;
// Check name isn't currently for sale // Check name is not already for sale
if (nameData.isForSale()) if (nameData.isForSale())
return ValidationResult.NAME_ALREADY_FOR_SALE; return ValidationResult.NAME_ALREADY_FOR_SALE;
// Check transaction's public key matches name's current owner // Validate transaction's public key matches name's current owner
Account owner = getOwner(); Account owner = getOwner();
if (!owner.getAddress().equals(nameData.getOwner())) if (!owner.getAddress().equals(nameData.getOwner()))
return ValidationResult.INVALID_NAME_OWNER; return ValidationResult.INVALID_NAME_OWNER;
// Check amount is positive // Check amount is positive and within valid range
if (this.sellNameTransactionData.getAmount() <= 0) long amount = this.sellNameTransactionData.getAmount();
if (amount <= 0)
return ValidationResult.NEGATIVE_AMOUNT; return ValidationResult.NEGATIVE_AMOUNT;
if (amount >= MAX_AMOUNT)
// Check amount within bounds
if (this.sellNameTransactionData.getAmount() >= MAX_AMOUNT)
return ValidationResult.INVALID_AMOUNT; return ValidationResult.INVALID_AMOUNT;
// Check issuer has enough funds // Check if owner has enough balance for the transaction fee
if (owner.getConfirmedBalance(Asset.QORT) < this.sellNameTransactionData.getFee()) if (owner.getConfirmedBalance(Asset.QORT) < this.sellNameTransactionData.getFee())
return ValidationResult.NO_BALANCE; return ValidationResult.NO_BALANCE;
return ValidationResult.OK; return ValidationResult.OK; // All validation checks passed
} }
@Override @Override
public void preProcess() throws DataException { public void preProcess() throws DataException {
SellNameTransactionData sellNameTransactionData = (SellNameTransactionData) transactionData; // Directly access class field rather than local variable for clarity
// Rebuild this name in the Names table from the transaction history
// This is necessary because in some rare cases names can be missing from the Names table after registration
// but we have been unable to reproduce the issue and track down the root cause
NamesDatabaseIntegrityCheck namesDatabaseIntegrityCheck = new NamesDatabaseIntegrityCheck(); NamesDatabaseIntegrityCheck namesDatabaseIntegrityCheck = new NamesDatabaseIntegrityCheck();
namesDatabaseIntegrityCheck.rebuildName(sellNameTransactionData.getName(), this.repository); namesDatabaseIntegrityCheck.rebuildName(this.sellNameTransactionData.getName(), this.repository);
} }
@Override @Override
public void process() throws DataException { public void process() throws DataException {
// Sell Name // Sell the name
Name name = new Name(this.repository, this.sellNameTransactionData.getName()); Name name = new Name(this.repository, this.sellNameTransactionData.getName());
name.sell(this.sellNameTransactionData); name.sell(this.sellNameTransactionData);
} }
@Override @Override
public void orphan() throws DataException { public void orphan() throws DataException {
// Revert name // Revert the name sale in case of orphaning
Name name = new Name(this.repository, this.sellNameTransactionData.getName()); Name name = new Name(this.repository, this.sellNameTransactionData.getName());
name.unsell(this.sellNameTransactionData); name.unsell(this.sellNameTransactionData);
} }
} }

View File

@ -15,10 +15,7 @@ import org.qortal.repository.DataException;
import org.qortal.repository.Repository; import org.qortal.repository.Repository;
import org.qortal.repository.RepositoryManager; import org.qortal.repository.RepositoryManager;
import org.qortal.settings.Settings; import org.qortal.settings.Settings;
import org.qortal.test.common.AccountUtils; import org.qortal.test.common.*;
import org.qortal.test.common.BlockUtils;
import org.qortal.test.common.Common;
import org.qortal.test.common.TransactionUtils;
import org.qortal.test.common.transaction.TestTransaction; import org.qortal.test.common.transaction.TestTransaction;
import org.qortal.transaction.Transaction; import org.qortal.transaction.Transaction;
import org.qortal.transaction.TransferPrivsTransaction; import org.qortal.transaction.TransferPrivsTransaction;
@ -28,6 +25,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.qortal.test.common.AccountUtils.fee; import static org.qortal.test.common.AccountUtils.fee;
import static org.qortal.transaction.Transaction.ValidationResult.ACCOUNT_NOT_TRANSFERABLE; import static org.qortal.transaction.Transaction.ValidationResult.ACCOUNT_NOT_TRANSFERABLE;
@ -836,7 +834,10 @@ public class SelfSponsorshipAlgoV1Tests extends Common {
assertEquals(0, (int) new Account(repository, aliceAccount.getAddress()).getLevel()); assertEquals(0, (int) new Account(repository, aliceAccount.getAddress()).getLevel());
// Alice can no longer create a reward share transaction // Alice can no longer create a reward share transaction
assertEquals(Transaction.ValidationResult.ACCOUNT_CANNOT_REWARD_SHARE, AccountUtils.createRandomRewardShare(repository, aliceAccount)); // Used to Chehck for ACCOUNT_CANNOT_REWARD_SHARE / Updated post canMint() function changes
// canMint returns False because reward penality != 0 (account.java:240)
// Causes trip in RewardShareTransaction.java:126, Returns NOT_MINTING_ACCOUNT
assertThat(Transaction.ValidationResult.OK, not(AccountUtils.createRandomRewardShare(repository, aliceAccount)));
// ... but Bob still can // ... but Bob still can
assertEquals(Transaction.ValidationResult.OK, AccountUtils.createRandomRewardShare(repository, bobAccount)); assertEquals(Transaction.ValidationResult.OK, AccountUtils.createRandomRewardShare(repository, bobAccount));

View File

@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.qortal.test.common.AccountUtils.fee; import static org.qortal.test.common.AccountUtils.fee;
import static org.qortal.transaction.Transaction.ValidationResult.ACCOUNT_NOT_TRANSFERABLE; import static org.qortal.transaction.Transaction.ValidationResult.ACCOUNT_NOT_TRANSFERABLE;
@ -840,7 +841,7 @@ public class SelfSponsorshipAlgoV3Tests extends Common {
assertEquals(0, (int) new Account(repository, aliceAccount.getAddress()).getLevel()); assertEquals(0, (int) new Account(repository, aliceAccount.getAddress()).getLevel());
// Alice can no longer create a reward share transaction // Alice can no longer create a reward share transaction
assertEquals(Transaction.ValidationResult.ACCOUNT_CANNOT_REWARD_SHARE, AccountUtils.createRandomRewardShare(repository, aliceAccount)); assertThat(Transaction.ValidationResult.OK, not(AccountUtils.createRandomRewardShare(repository, aliceAccount)));
// Bob can no longer create a reward share transaction (disabled at Block 15) // Bob can no longer create a reward share transaction (disabled at Block 15)
assertEquals(Transaction.ValidationResult.OK, AccountUtils.createRandomRewardShare(repository, bobAccount)); assertEquals(Transaction.ValidationResult.OK, AccountUtils.createRandomRewardShare(repository, bobAccount));

View File

@ -25,9 +25,19 @@ public class AddressesApiTests extends ApiCommon {
} }
@Test @Test
@Ignore(value = "Doesn't work, to be fixed later") @Ignore(value = "No Logic Coded")
public void testGetOnlineAccounts() { public void testGetOnlineAccounts() {
// Add and remove users as online checking count after minting
// TODO: Need to construct logic
// this.addressesResource.getOnlineAccounts(), empty Array, Size = 0
assertNotNull(this.addressesResource.getOnlineAccounts()); assertNotNull(this.addressesResource.getOnlineAccounts());
int blocksToMint = 5;
// Add 2 accounts to the online array, mint some blocks
// Assert number of accountsOnline == 2
// Remove an account from onlineStatus, mint some blocks
// Assert number of accountsOnline == 1
// Add two accounts as online, mint some blocks
// Asset number of accountsOnline == 3
} }
@Test @Test

View File

@ -6,11 +6,13 @@ import org.qortal.arbitrary.ArbitraryDataDigest;
import org.qortal.repository.DataException; import org.qortal.repository.DataException;
import org.qortal.test.common.Common; import org.qortal.test.common.Common;
import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Arrays;
import java.util.UUID; import java.util.UUID;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -25,7 +27,10 @@ public class ArbitraryDataDigestTests extends Common {
@Test @Test
public void testDirectoryDigest() throws IOException, DataException { public void testDirectoryDigest() throws IOException, DataException {
Path dataPath = Paths.get("src/test/resources/arbitrary/demo1"); String dataPathString = "src" + File.separator + "test" + File.separator + "resources" + File.separator + "arbitrary" + File.separator + "demo1";
Path dataPath = Paths.get(dataPathString);
// expectedHash is calculated for Linux
String expectedHash58 = "DKyMuonWKoneJqiVHgw26Vk1ytrZG9PGsE9xfBg3GKDp"; String expectedHash58 = "DKyMuonWKoneJqiVHgw26Vk1ytrZG9PGsE9xfBg3GKDp";
// Ensure directory exists // Ensure directory exists
@ -35,6 +40,13 @@ public class ArbitraryDataDigestTests extends Common {
// Compute a hash // Compute a hash
ArbitraryDataDigest digest = new ArbitraryDataDigest(dataPath); ArbitraryDataDigest digest = new ArbitraryDataDigest(dataPath);
digest.compute(); digest.compute();
// Assert Fails, Expected: DKyMuonWKoneJqiVHgw26Vk1ytrZG9PGsE9xfBg3GKDp
// Actual : HbvgC6sfhFtDvmDXfPXVUcCUyZ5rM1NzX488qHmMpMB4
// This might be failing because Windows turns "/" (47) to "\" (92)
// Or maybe a fail due to \n [13] VS \r\n [13,10] in .txt files
// Confirmed the read in windows has \r\n
// Could be a combination of both
System.out.printf("Hash: %s \n", Arrays.toString(digest.getHash()));
assertEquals(expectedHash58, digest.getHash58()); assertEquals(expectedHash58, digest.getHash58());
// Write a random file to .qortal/cache to ensure it isn't being included in the digest function // Write a random file to .qortal/cache to ensure it isn't being included in the digest function

View File

@ -15,9 +15,7 @@ import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.file.Files; import java.nio.file.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
import java.util.Random; import java.util.Random;
@ -242,7 +240,7 @@ public class ArbitraryDataMergeTests extends Common {
BufferedWriter file1Writer = new BufferedWriter(new FileWriter(file1)); BufferedWriter file1Writer = new BufferedWriter(new FileWriter(file1));
String initialString = ArbitraryUtils.generateRandomString(1024); String initialString = ArbitraryUtils.generateRandomString(1024);
// Add a newline every 50 chars // Add a newline every 50 chars
initialString = initialString.replaceAll("(.{50})", "$1\n"); initialString = initialString.replaceAll("(.{50})", "$1" + System.lineSeparator());
file1Writer.write(initialString); file1Writer.write(initialString);
file1Writer.newLine(); file1Writer.newLine();
file1Writer.close(); file1Writer.close();
@ -307,23 +305,23 @@ public class ArbitraryDataMergeTests extends Common {
file1.deleteOnExit(); file1.deleteOnExit();
file2.deleteOnExit(); file2.deleteOnExit();
// Write a random string to the first file // Write a random string to the first file, 1024 characters, \n every 50 chars
BufferedWriter file1Writer = new BufferedWriter(new FileWriter(file1)); BufferedWriter file1Writer = new BufferedWriter(new FileWriter(file1));
String initialString = ArbitraryUtils.generateRandomString(1024); String initialString = ArbitraryUtils.generateRandomString(1024);
// Add a newline every 50 chars // Add a newline every 50 chars
initialString = initialString.replaceAll("(.{50})", "$1\n"); initialString = initialString.replaceAll("(.{50})", "$1" + System.lineSeparator());
// Remove newline at end of string // Remove newline at end of string
initialString = initialString.stripTrailing(); initialString = initialString.stripTrailing(); // Remove Trailing White Space
file1Writer.write(initialString); file1Writer.write(initialString);
// No newline // No newline
file1Writer.close(); file1Writer.close();
byte[] file1Digest = Crypto.digest(file1); byte[] file1Digest = Crypto.digest(file1);
// Write a slightly modified string to the second file // Write a slightly modified string to the second file, append "-edit" to the string
BufferedWriter file2Writer = new BufferedWriter(new FileWriter(file2)); BufferedWriter file2Writer = new BufferedWriter(new FileWriter(file2));
String updatedString = initialString.concat("-edit"); String updatedString = initialString.concat("-edit");
file2Writer.write(updatedString); file2Writer.write(updatedString);
// No newline // No newline - This is wrong, both files contain \n every 50 chars
file2Writer.close(); file2Writer.close();
byte[] file2Digest = Crypto.digest(file2); byte[] file2Digest = Crypto.digest(file2);
@ -342,6 +340,7 @@ public class ArbitraryDataMergeTests extends Common {
ArbitraryDataCreatePatch patch = new ArbitraryDataCreatePatch(tempDir1, tempDir2, signature); ArbitraryDataCreatePatch patch = new ArbitraryDataCreatePatch(tempDir1, tempDir2, signature);
patch.create(); patch.create();
Path patchPath = patch.getFinalPath(); Path patchPath = patch.getFinalPath();
assertTrue(Files.exists(patchPath)); assertTrue(Files.exists(patchPath));
// Check that the patch file exists // Check that the patch file exists
@ -353,6 +352,7 @@ public class ArbitraryDataMergeTests extends Common {
assertFalse(Arrays.equals(patchDigest, file1Digest)); assertFalse(Arrays.equals(patchDigest, file1Digest));
// Make sure that the patch file is different from file2 // Make sure that the patch file is different from file2
// This assert fails, patchFile and file2 have the same contents so the digest will match
assertFalse(Arrays.equals(patchDigest, file2Digest)); assertFalse(Arrays.equals(patchDigest, file2Digest));
// Now merge the patch with the original path // Now merge the patch with the original path
@ -384,7 +384,7 @@ public class ArbitraryDataMergeTests extends Common {
BufferedWriter file1Writer = new BufferedWriter(new FileWriter(file1)); BufferedWriter file1Writer = new BufferedWriter(new FileWriter(file1));
String initialString = ArbitraryUtils.generateRandomString(110 * 1024); String initialString = ArbitraryUtils.generateRandomString(110 * 1024);
// Add a newline every 50 chars // Add a newline every 50 chars
initialString = initialString.replaceAll("(.{50})", "$1\n"); initialString = initialString.replaceAll("(.{50})", "$1" + System.lineSeparator());
file1Writer.write(initialString); file1Writer.write(initialString);
file1Writer.newLine(); file1Writer.newLine();
file1Writer.close(); file1Writer.close();

View File

@ -27,6 +27,7 @@ import org.qortal.transaction.RegisterNameTransaction;
import org.qortal.utils.Base58; import org.qortal.utils.Base58;
import org.qortal.utils.NTP; import org.qortal.utils.NTP;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -410,13 +411,13 @@ public class ArbitraryTransactionMetadataTests extends Common {
assertEquals(3, arbitraryDataFile.getMetadata().getFiles().size()); assertEquals(3, arbitraryDataFile.getMetadata().getFiles().size());
assertTrue(arbitraryDataFile.getMetadata().getFiles().contains("file.txt")); assertTrue(arbitraryDataFile.getMetadata().getFiles().contains("file.txt"));
assertTrue(arbitraryDataFile.getMetadata().getFiles().contains("image1.jpg")); assertTrue(arbitraryDataFile.getMetadata().getFiles().contains("image1.jpg"));
assertTrue(arbitraryDataFile.getMetadata().getFiles().contains("subdirectory/config.json")); assertTrue(arbitraryDataFile.getMetadata().getFiles().contains("subdirectory" + File.separator + "config.json"));
// Ensure the file list can be read back out again, when specified to be included // Ensure the file list can be read back out again, when specified to be included
ArbitraryResourceMetadata resourceMetadata = ArbitraryResourceMetadata.fromTransactionMetadata(arbitraryDataFile.getMetadata(), true); ArbitraryResourceMetadata resourceMetadata = ArbitraryResourceMetadata.fromTransactionMetadata(arbitraryDataFile.getMetadata(), true);
assertTrue(resourceMetadata.getFiles().contains("file.txt")); assertTrue(resourceMetadata.getFiles().contains("file.txt"));
assertTrue(resourceMetadata.getFiles().contains("image1.jpg")); assertTrue(resourceMetadata.getFiles().contains("image1.jpg"));
assertTrue(resourceMetadata.getFiles().contains("subdirectory/config.json")); assertTrue(resourceMetadata.getFiles().contains("subdirectory" + File.separator + "config.json"));
// Ensure it's not returned when specified to be excluded // Ensure it's not returned when specified to be excluded
// The entire object will be null because there is no metadata // The entire object will be null because there is no metadata

View File

@ -440,7 +440,7 @@ public class ArbitraryTransactionTests extends Common {
PrivateKeyAccount alice = Common.getTestAccount(repository, "alice"); PrivateKeyAccount alice = Common.getTestAccount(repository, "alice");
String publicKey58 = Base58.encode(alice.getPublicKey()); String publicKey58 = Base58.encode(alice.getPublicKey());
String name = "TEST"; // Can be anything for this test String name = "TEST-testOnChainData"; // Can be anything for this test
String identifier = null; // Not used for this test String identifier = null; // Not used for this test
Service service = Service.ARBITRARY_DATA; Service service = Service.ARBITRARY_DATA;
int chunkSize = 1000; int chunkSize = 1000;

View File

@ -6,6 +6,7 @@ import org.qortal.group.Group;
import org.qortal.group.Group.ApprovalThreshold; import org.qortal.group.Group.ApprovalThreshold;
import org.qortal.repository.DataException; import org.qortal.repository.DataException;
import org.qortal.repository.Repository; import org.qortal.repository.Repository;
import org.qortal.test.common.transaction.TestTransaction;
import org.qortal.transaction.Transaction.ApprovalStatus; import org.qortal.transaction.Transaction.ApprovalStatus;
import org.qortal.utils.Amounts; import org.qortal.utils.Amounts;
@ -14,9 +15,18 @@ public class GroupUtils {
public static final int txGroupId = Group.NO_GROUP; public static final int txGroupId = Group.NO_GROUP;
public static final long fee = 1L * Amounts.MULTIPLIER; public static final long fee = 1L * Amounts.MULTIPLIER;
public static int createGroup(Repository repository, String creatorAccountName, String groupName, boolean isOpen, ApprovalThreshold approvalThreshold, public static int createGroup(Repository repository, Object creatorAccountName, String groupName, boolean isOpen, ApprovalThreshold approvalThreshold,
int minimumBlockDelay, int maximumBlockDelay) throws DataException { int minimumBlockDelay, int maximumBlockDelay) throws DataException {
PrivateKeyAccount account = Common.getTestAccount(repository, creatorAccountName);
PrivateKeyAccount account;
if (creatorAccountName instanceof java.lang.String) {
account = Common.getTestAccount(repository, (String) creatorAccountName);
}
else if (creatorAccountName instanceof PrivateKeyAccount) {
account = (PrivateKeyAccount) creatorAccountName;
} else {
account = null;
}
byte[] reference = account.getLastReference(); byte[] reference = account.getLastReference();
long timestamp = repository.getTransactionRepository().fromSignature(reference).getTimestamp() + 1; long timestamp = repository.getTransactionRepository().fromSignature(reference).getTimestamp() + 1;
@ -30,16 +40,49 @@ public class GroupUtils {
return repository.getGroupRepository().fromGroupName(groupName).getGroupId(); return repository.getGroupRepository().fromGroupName(groupName).getGroupId();
} }
/**
* <p> Simplified GroupCreation for Testing - less parameters required
* </p>
* @param repository The blockchain database
* @param owner Who will own the group, type PrivateKeyAccount
* @param groupName String representing the published name
* @param isOpen Boolean to allow anyone to join
* @return groupID as an integer
* @throws DataException when error occurs
* @since v4.71
*/
public static int createGroup(Repository repository, PrivateKeyAccount owner, String groupName, boolean isOpen) throws DataException {
String description = groupName + " (description)";
Group.ApprovalThreshold approvalThreshold = Group.ApprovalThreshold.ONE;
int minimumBlockDelay = 10;
int maximumBlockDelay = 1440;
return createGroup(repository, owner, groupName, isOpen, approvalThreshold, minimumBlockDelay, maximumBlockDelay);
} // End Simplified Group Creation
/**
*
* @param repository The block chain database
* @param joinerAccount Account of the person joining the group
* @param groupId Integer of the Group mapping
* @throws DataException
* @since v4.7.1
*/
public static void joinGroup(Repository repository, PrivateKeyAccount joinerAccount, int groupId) throws DataException {
byte[] reference = joinerAccount.getLastReference();
long timestamp = repository.getTransactionRepository().fromSignature(reference).getTimestamp() + 1;
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, Group.NO_GROUP, reference, joinerAccount.getPublicKey(), GroupUtils.fee, null);
TransactionData transactionData = new JoinGroupTransactionData(baseTransactionData, groupId);
TransactionUtils.signAndMint(repository, transactionData, joinerAccount);
}
public static void joinGroup(Repository repository, String joinerAccountName, int groupId) throws DataException { public static void joinGroup(Repository repository, String joinerAccountName, int groupId) throws DataException {
PrivateKeyAccount account = Common.getTestAccount(repository, joinerAccountName); PrivateKeyAccount account = Common.getTestAccount(repository, joinerAccountName);
byte[] reference = account.getLastReference(); joinGroup(repository, account, groupId);
long timestamp = repository.getTransactionRepository().fromSignature(reference).getTimestamp() + 1;
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, Group.NO_GROUP, reference, account.getPublicKey(), GroupUtils.fee, null);
TransactionData transactionData = new JoinGroupTransactionData(baseTransactionData, groupId);
TransactionUtils.signAndMint(repository, transactionData, account);
} }
public static void approveTransaction(Repository repository, String accountName, byte[] pendingSignature, boolean decision) throws DataException { public static void approveTransaction(Repository repository, String accountName, byte[] pendingSignature, boolean decision) throws DataException {

View File

@ -11,6 +11,7 @@ import org.qortal.repository.Repository;
import org.qortal.repository.RepositoryManager; import org.qortal.repository.RepositoryManager;
import org.qortal.test.common.BlockUtils; import org.qortal.test.common.BlockUtils;
import org.qortal.test.common.Common; import org.qortal.test.common.Common;
import org.qortal.test.common.GroupUtils;
import org.qortal.test.common.TransactionUtils; import org.qortal.test.common.TransactionUtils;
import org.qortal.test.common.transaction.TestTransaction; import org.qortal.test.common.transaction.TestTransaction;
import org.qortal.transaction.Transaction.ValidationResult; import org.qortal.transaction.Transaction.ValidationResult;
@ -78,7 +79,7 @@ public class AdminTests extends Common {
int groupId = createGroup(repository, alice, "open-group", true); int groupId = createGroup(repository, alice, "open-group", true);
// Bob to join // Bob to join
joinGroup(repository, bob, groupId); GroupUtils.joinGroup(repository, bob, groupId);
// Promote Bob to admin // Promote Bob to admin
addGroupAdmin(repository, alice, groupId, bob.getAddress()); addGroupAdmin(repository, alice, groupId, bob.getAddress());

View File

@ -5,15 +5,14 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.qortal.account.PrivateKeyAccount; import org.qortal.account.PrivateKeyAccount;
import org.qortal.data.transaction.AddGroupAdminTransactionData; import org.qortal.data.transaction.AddGroupAdminTransactionData;
import org.qortal.data.transaction.CreateGroupTransactionData;
import org.qortal.data.transaction.JoinGroupTransactionData; import org.qortal.data.transaction.JoinGroupTransactionData;
import org.qortal.data.transaction.RemoveGroupAdminTransactionData; import org.qortal.data.transaction.RemoveGroupAdminTransactionData;
import org.qortal.group.Group.ApprovalThreshold;
import org.qortal.repository.DataException; import org.qortal.repository.DataException;
import org.qortal.repository.Repository; import org.qortal.repository.Repository;
import org.qortal.repository.RepositoryManager; import org.qortal.repository.RepositoryManager;
import org.qortal.test.common.BlockUtils; import org.qortal.test.common.BlockUtils;
import org.qortal.test.common.Common; import org.qortal.test.common.Common;
import org.qortal.test.common.GroupUtils;
import org.qortal.test.common.TransactionUtils; import org.qortal.test.common.TransactionUtils;
import org.qortal.test.common.transaction.TestTransaction; import org.qortal.test.common.transaction.TestTransaction;
import org.qortal.transaction.Transaction.ValidationResult; import org.qortal.transaction.Transaction.ValidationResult;
@ -39,7 +38,7 @@ public class OwnerTests extends Common {
PrivateKeyAccount bob = Common.getTestAccount(repository, "bob"); PrivateKeyAccount bob = Common.getTestAccount(repository, "bob");
// Create group // Create group
int groupId = createGroup(repository, alice, "open-group", true); int groupId = GroupUtils.createGroup(repository, alice, "open-group", true);
// Attempt to promote non-member // Attempt to promote non-member
ValidationResult result = addGroupAdmin(repository, alice, groupId, bob.getAddress()); ValidationResult result = addGroupAdmin(repository, alice, groupId, bob.getAddress());
@ -83,7 +82,7 @@ public class OwnerTests extends Common {
PrivateKeyAccount bob = Common.getTestAccount(repository, "bob"); PrivateKeyAccount bob = Common.getTestAccount(repository, "bob");
// Create group // Create group
int groupId = createGroup(repository, alice, "open-group", true); int groupId = GroupUtils.createGroup(repository, alice, "open-group", true);
// Attempt to demote non-member // Attempt to demote non-member
ValidationResult result = removeGroupAdmin(repository, alice, groupId, bob.getAddress()); ValidationResult result = removeGroupAdmin(repository, alice, groupId, bob.getAddress());
@ -133,19 +132,6 @@ public class OwnerTests extends Common {
} }
} }
private Integer createGroup(Repository repository, PrivateKeyAccount owner, String groupName, boolean isOpen) throws DataException {
String description = groupName + " (description)";
ApprovalThreshold approvalThreshold = ApprovalThreshold.ONE;
int minimumBlockDelay = 10;
int maximumBlockDelay = 1440;
CreateGroupTransactionData transactionData = new CreateGroupTransactionData(TestTransaction.generateBase(owner), groupName, description, isOpen, approvalThreshold, minimumBlockDelay, maximumBlockDelay);
TransactionUtils.signAndMint(repository, transactionData, owner);
return repository.getGroupRepository().fromGroupName(groupName).getGroupId();
}
private ValidationResult joinGroup(Repository repository, PrivateKeyAccount joiner, int groupId) throws DataException { private ValidationResult joinGroup(Repository repository, PrivateKeyAccount joiner, int groupId) throws DataException {
JoinGroupTransactionData transactionData = new JoinGroupTransactionData(TestTransaction.generateBase(joiner), groupId); JoinGroupTransactionData transactionData = new JoinGroupTransactionData(TestTransaction.generateBase(joiner), groupId);
ValidationResult result = TransactionUtils.signAndImport(repository, transactionData, joiner); ValidationResult result = TransactionUtils.signAndImport(repository, transactionData, joiner);

View File

@ -25,6 +25,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -98,7 +101,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -29,6 +29,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -101,7 +104,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -30,6 +30,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -102,7 +105,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -30,6 +30,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -102,7 +105,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -30,6 +30,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -102,7 +105,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -28,6 +28,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -101,7 +104,12 @@
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999, "removeOnlyMintWithNameHeight": 9999999999999,
"penaltyFixHeight": 5 "penaltyFixHeight": 5,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -30,6 +30,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -102,7 +105,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -30,6 +30,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -103,7 +106,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -30,6 +30,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -102,7 +105,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -30,6 +30,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -102,7 +105,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -30,6 +30,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -102,7 +105,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -29,6 +29,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -102,7 +105,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -30,6 +30,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 2 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -102,7 +105,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,
@ -118,8 +126,12 @@
{ "type": "GENESIS", "recipient": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "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": "CREATE_GROUP", "creatorPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "groupName": "dev-group", "description": "developer group", "isOpen": false, "approvalThreshold": "PCT100", "minimumBlockDelay": 0, "maximumBlockDelay": 1440 },
{ "type": "CREATE_GROUP", "creatorPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "groupName": "MINTER", "description": "Minter 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": "UPDATE_GROUP", "ownerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "groupId": 1, "newOwner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "newDescription": "developer group", "newIsOpen": false, "newApprovalThreshold": "PCT40", "minimumBlockDelay": 10, "maximumBlockDelay": 1440 },
{ "type": "UPDATE_GROUP", "ownerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "groupId": 2, "newOwner": "QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG", "newDescription": "Minter group", "newIsOpen": true, "newApprovalThreshold": "PCT40", "minimumBlockDelay": 1, "maximumBlockDelay": 1440 },
{ "type": "JOIN_GROUP", "joinerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "groupId": 2},
{ "type": "ISSUE_ASSET", "issuerPublicKey": "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP", "assetName": "TEST", "description": "test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 }, { "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": "C6wuddsBV3HzRrXUtezE7P5MoRXp5m3mEDokRDGZB6ry", "assetName": "OTHER", "description": "other test asset", "data": "", "quantity": "1000000", "isDivisible": true, "fee": 0 },
@ -134,6 +146,7 @@
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 5 }, { "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 5 },
{ "type": "ACCOUNT_LEVEL", "target": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "level": 5 }, { "type": "ACCOUNT_LEVEL", "target": "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "level": 5 },
{ "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 6 } { "type": "ACCOUNT_LEVEL", "target": "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "level": 6 }
] ]
} }
} }

View File

@ -30,6 +30,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -102,7 +105,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -30,6 +30,9 @@
"blockRewardBatchStartHeight": 999999000, "blockRewardBatchStartHeight": 999999000,
"blockRewardBatchSize": 10, "blockRewardBatchSize": 10,
"blockRewardBatchAccountsBlockCount": 3, "blockRewardBatchAccountsBlockCount": 3,
"mintingGroupIds": [
{ "height": 0, "ids": [ 1 ]}
],
"rewardsByHeight": [ "rewardsByHeight": [
{ "height": 1, "reward": 100 }, { "height": 1, "reward": 100 },
{ "height": 11, "reward": 10 }, { "height": 11, "reward": 10 },
@ -102,7 +105,12 @@
"onlyMintWithNameHeight": 9999999999990, "onlyMintWithNameHeight": 9999999999990,
"groupMemberCheckHeight": 9999999999999, "groupMemberCheckHeight": 9999999999999,
"decreaseOnlineAccountsDifficultyTimestamp": 9999999999999, "decreaseOnlineAccountsDifficultyTimestamp": 9999999999999,
"removeOnlyMintWithNameHeight": 9999999999999 "removeOnlyMintWithNameHeight": 9999999999999,
"fixBatchRewardHeight": 9999999999999,
"adminsReplaceFoundersHeight": 9999999999999,
"ignoreLevelForRewardShareHeight": 9999999999999,
"nullGroupMembershipHeight": 20,
"adminQueryFixHeight": 9999999999999
}, },
"genesisInfo": { "genesisInfo": {
"version": 4, "version": 4,

View File

@ -16,5 +16,6 @@
"listsPath": "lists-test", "listsPath": "lists-test",
"storagePolicy": "FOLLOWED_OR_VIEWED", "storagePolicy": "FOLLOWED_OR_VIEWED",
"maxStorageCapacity": 104857600, "maxStorageCapacity": 104857600,
"arrrDefaultBirthday": 1900000 "arrrDefaultBirthday": 1900000,
"archivingPause": 5
} }