mirror of
https://github.com/Qortal/qortal.git
synced 2025-06-21 22:51:22 +00:00
Merge branch 'master' into Abstract-and-Update-Deps
This commit is contained in:
commit
47e5c473b3
15
README.md
15
README.md
@ -15,20 +15,31 @@ Building the future one block at a time. Welcome to Qortal.
|
|||||||
|
|
||||||
# Building the Qortal Core from Source
|
# Building the Qortal Core from Source
|
||||||
|
|
||||||
## Build / run
|
## Build / Run
|
||||||
|
|
||||||
- Requires Java 11. OpenJDK 11 recommended over Java SE.
|
- Requires Java 11. OpenJDK 11 recommended over Java SE.
|
||||||
- Install Maven
|
- Install Maven
|
||||||
- Use Maven to fetch dependencies and build: `mvn clean package`
|
- Use Maven to fetch dependencies and build: `mvn clean package`
|
||||||
|
- Update Maven dependencies: `mvn install`
|
||||||
- Built JAR should be something like `target/qortal-1.0.jar`
|
- Built JAR should be something like `target/qortal-1.0.jar`
|
||||||
- Create basic *settings.json* file: `echo '{}' > settings.json`
|
- Create basic *settings.json* file: `echo '{}' > settings.json`
|
||||||
- Run JAR in same working directory as *settings.json*: `java -jar target/qortal-1.0.jar`
|
- Run JAR in same working directory as *settings.json*: `java -jar target/qortal-1.0.jar`
|
||||||
- Wrap in shell script, add JVM flags, redirection, backgrounding, etc. as necessary.
|
- Wrap in shell script, add JVM flags, redirection, backgrounding, etc. as necessary.
|
||||||
- Or use supplied example shell script: *start.sh*
|
- Or use supplied example shell script: *start.sh*
|
||||||
|
|
||||||
|
## IntelliJ IDEA Configuration
|
||||||
|
|
||||||
|
- Run -> Edit Configurations
|
||||||
|
- Add New Application
|
||||||
|
- Name: qortal
|
||||||
|
- SDK: java 11
|
||||||
|
- Main Class: org.qortal.controller.Controller
|
||||||
|
- Program arguments: settings.json -Dlog4j.configurationFile=log4j2.properties -ea
|
||||||
|
- Environment variables: Djava.net.preferIPv4Stack=false
|
||||||
|
|
||||||
# Using a pre-built Qortal 'jar' binary
|
# Using a pre-built Qortal 'jar' binary
|
||||||
|
|
||||||
If you would prefer to utilize a released version of Qortal, you may do so by downloading one of the available releases from the releases page, that are also linked on https://qortal.org and https://qortal.dev.
|
If you prefer to utilize a released version of Qortal, you may do so by downloading one of the available releases from the releases page, that are also linked on https://qortal.org and https://qortal.dev.
|
||||||
|
|
||||||
# Learning Q-App Development
|
# Learning Q-App Development
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -45,10 +45,10 @@ SYNCHRONIZING_BLOCKCHAIN = Bezig met synchronizeren
|
|||||||
|
|
||||||
SYNCHRONIZING_CLOCK = Klok wordt gesynchronizeerd
|
SYNCHRONIZING_CLOCK = Klok wordt gesynchronizeerd
|
||||||
|
|
||||||
RESTARTING_NODE = Knooppunt opnieuw starten
|
RESTARTING_NODE = Node opnieuw starten
|
||||||
|
|
||||||
APPLYING_RESTARTING_NODE = Herstartknooppunt toepassen. Wees alstublieft geduldig...
|
APPLYING_RESTARTING_NODE = Node wordt herstart. Even geduld alstublieft...
|
||||||
|
|
||||||
BOOTSTRAP_NODE = Opstartknooppunt
|
BOOTSTRAP_NODE = Opstarten van node (bootstrap)
|
||||||
|
|
||||||
APPLYING_BOOTSTRAP_AND_RESTARTING = Bootstrap toepassen en knooppunt opnieuw starten. Wees alstublieft geduldig...
|
APPLYING_BOOTSTRAP_AND_RESTARTING = Bootstrap toepassen en node opnieuw starten. Even geduld alstublieft...
|
||||||
|
@ -196,6 +196,7 @@ TX_GROUP_ID_MISMATCH = groep-ID komt niet overeen
|
|||||||
|
|
||||||
TRANSFER_PRIVS_DISABLED = overdrachtsrechten uitgeschakeld
|
TRANSFER_PRIVS_DISABLED = overdrachtsrechten uitgeschakeld
|
||||||
|
|
||||||
TEMPORARY_DISABLED = Naamregistratie tijdelijk uitgeschakeld
|
TEMPORARY_DISABLED = naamregistratie tijdelijk uitgeschakeld
|
||||||
|
|
||||||
GENERAL_TEMPORARY_DISABLED = Tijdelijk uitgeschakeld
|
GENERAL_TEMPORARY_DISABLED = Tijdelijk uitgeschakeld
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user