forked from Qortal/qortal
Proxy forging improvements + account flags fixes
Proxy forging recipient no longer needs a public key on the blockchain at the point PROXY_FORGING transaction is submitted. Proxy forging recipient is given a last-reference, if they don't have one, when they receive their first block rewards. Split block fees in proxy forging scenario, using same share proportion. 100% proxy sharing is now allowed. Fixed account flags processing for accounts in genesis block.
This commit is contained in:
parent
3ffcf50d7c
commit
7a318c9fc7
@ -1050,10 +1050,8 @@ public class Block {
|
|||||||
for (Transaction transaction : transactions)
|
for (Transaction transaction : transactions)
|
||||||
transaction.process();
|
transaction.process();
|
||||||
|
|
||||||
// If fees are non-zero then add fees to generator's balance
|
// Give transaction fees to generator/proxy
|
||||||
BigDecimal blockFee = this.blockData.getTotalFees();
|
rewardTransactionFees();
|
||||||
if (blockFee.compareTo(BigDecimal.ZERO) > 0)
|
|
||||||
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).add(blockFee));
|
|
||||||
|
|
||||||
// Process AT fees and save AT states into repository
|
// Process AT fees and save AT states into repository
|
||||||
ATRepository atRepository = this.repository.getATRepository();
|
ATRepository atRepository = this.repository.getATRepository();
|
||||||
@ -1102,7 +1100,7 @@ public class Block {
|
|||||||
// Is generator public key actually a proxy forge key?
|
// Is generator public key actually a proxy forge key?
|
||||||
ProxyForgerData proxyForgerData = this.repository.getAccountRepository().getProxyForgeData(this.blockData.getGeneratorPublicKey());
|
ProxyForgerData proxyForgerData = this.repository.getAccountRepository().getProxyForgeData(this.blockData.getGeneratorPublicKey());
|
||||||
if (proxyForgerData != null) {
|
if (proxyForgerData != null) {
|
||||||
// Split reward to forger and recipient;
|
// Split reward between forger and recipient
|
||||||
Account recipient = new Account(this.repository, proxyForgerData.getRecipient());
|
Account recipient = new Account(this.repository, proxyForgerData.getRecipient());
|
||||||
BigDecimal recipientShare = reward.multiply(proxyForgerData.getShare().movePointLeft(2)).setScale(8, RoundingMode.DOWN);
|
BigDecimal recipientShare = reward.multiply(proxyForgerData.getShare().movePointLeft(2)).setScale(8, RoundingMode.DOWN);
|
||||||
recipient.setConfirmedBalance(Asset.QORA, recipient.getConfirmedBalance(Asset.QORA).add(recipientShare));
|
recipient.setConfirmedBalance(Asset.QORA, recipient.getConfirmedBalance(Asset.QORA).add(recipientShare));
|
||||||
@ -1117,6 +1115,31 @@ public class Block {
|
|||||||
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).add(reward));
|
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).add(reward));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void rewardTransactionFees() throws DataException {
|
||||||
|
BigDecimal blockFees = this.blockData.getTotalFees();
|
||||||
|
|
||||||
|
// No transaction fees?
|
||||||
|
if (blockFees.compareTo(BigDecimal.ZERO) <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Is generator public key actually a proxy forge key?
|
||||||
|
ProxyForgerData proxyForgerData = this.repository.getAccountRepository().getProxyForgeData(this.blockData.getGeneratorPublicKey());
|
||||||
|
if (proxyForgerData != null) {
|
||||||
|
// Split fees between forger and recipient
|
||||||
|
Account recipient = new Account(this.repository, proxyForgerData.getRecipient());
|
||||||
|
BigDecimal recipientShare = blockFees.multiply(proxyForgerData.getShare().movePointLeft(2)).setScale(8, RoundingMode.DOWN);
|
||||||
|
recipient.setConfirmedBalance(Asset.QORA, recipient.getConfirmedBalance(Asset.QORA).add(recipientShare));
|
||||||
|
|
||||||
|
Account forger = new PublicKeyAccount(this.repository, proxyForgerData.getForgerPublicKey());
|
||||||
|
BigDecimal forgerShare = blockFees.subtract(recipientShare);
|
||||||
|
forger.setConfirmedBalance(Asset.QORA, forger.getConfirmedBalance(Asset.QORA).add(forgerShare));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give transaction fees to generator
|
||||||
|
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).add(blockFees));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes block from blockchain undoing transactions and adding them to unconfirmed pile.
|
* Removes block from blockchain undoing transactions and adding them to unconfirmed pile.
|
||||||
*
|
*
|
||||||
@ -1145,10 +1168,8 @@ public class Block {
|
|||||||
// Block rewards removed after transactions undone
|
// Block rewards removed after transactions undone
|
||||||
orphanBlockRewards();
|
orphanBlockRewards();
|
||||||
|
|
||||||
// If fees are non-zero then remove fees from generator's balance
|
// Deduct any transaction fees from generator/proxy
|
||||||
BigDecimal blockFee = this.blockData.getTotalFees();
|
deductTransactionFees();
|
||||||
if (blockFee.compareTo(BigDecimal.ZERO) > 0)
|
|
||||||
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).subtract(blockFee));
|
|
||||||
|
|
||||||
// Return AT fees and delete AT states from repository
|
// Return AT fees and delete AT states from repository
|
||||||
ATRepository atRepository = this.repository.getATRepository();
|
ATRepository atRepository = this.repository.getATRepository();
|
||||||
@ -1175,7 +1196,7 @@ public class Block {
|
|||||||
// Is generator public key actually a proxy forge key?
|
// Is generator public key actually a proxy forge key?
|
||||||
ProxyForgerData proxyForgerData = this.repository.getAccountRepository().getProxyForgeData(this.blockData.getGeneratorPublicKey());
|
ProxyForgerData proxyForgerData = this.repository.getAccountRepository().getProxyForgeData(this.blockData.getGeneratorPublicKey());
|
||||||
if (proxyForgerData != null) {
|
if (proxyForgerData != null) {
|
||||||
// Split reward from forger and recipient;
|
// Split reward between forger and recipient
|
||||||
Account recipient = new Account(this.repository, proxyForgerData.getRecipient());
|
Account recipient = new Account(this.repository, proxyForgerData.getRecipient());
|
||||||
BigDecimal recipientShare = reward.multiply(proxyForgerData.getShare().movePointLeft(2)).setScale(8, RoundingMode.DOWN);
|
BigDecimal recipientShare = reward.multiply(proxyForgerData.getShare().movePointLeft(2)).setScale(8, RoundingMode.DOWN);
|
||||||
recipient.setConfirmedBalance(Asset.QORA, recipient.getConfirmedBalance(Asset.QORA).subtract(recipientShare));
|
recipient.setConfirmedBalance(Asset.QORA, recipient.getConfirmedBalance(Asset.QORA).subtract(recipientShare));
|
||||||
@ -1190,6 +1211,31 @@ public class Block {
|
|||||||
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).subtract(reward));
|
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).subtract(reward));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void deductTransactionFees() throws DataException {
|
||||||
|
BigDecimal blockFees = this.blockData.getTotalFees();
|
||||||
|
|
||||||
|
// No transaction fees?
|
||||||
|
if (blockFees.compareTo(BigDecimal.ZERO) <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Is generator public key actually a proxy forge key?
|
||||||
|
ProxyForgerData proxyForgerData = this.repository.getAccountRepository().getProxyForgeData(this.blockData.getGeneratorPublicKey());
|
||||||
|
if (proxyForgerData != null) {
|
||||||
|
// Split fees between forger and recipient
|
||||||
|
Account recipient = new Account(this.repository, proxyForgerData.getRecipient());
|
||||||
|
BigDecimal recipientShare = blockFees.multiply(proxyForgerData.getShare().movePointLeft(2)).setScale(8, RoundingMode.DOWN);
|
||||||
|
recipient.setConfirmedBalance(Asset.QORA, recipient.getConfirmedBalance(Asset.QORA).subtract(recipientShare));
|
||||||
|
|
||||||
|
Account forger = new PublicKeyAccount(this.repository, proxyForgerData.getForgerPublicKey());
|
||||||
|
BigDecimal forgerShare = blockFees.subtract(recipientShare);
|
||||||
|
forger.setConfirmedBalance(Asset.QORA, forger.getConfirmedBalance(Asset.QORA).subtract(forgerShare));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deduct transaction fees to generator
|
||||||
|
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).subtract(blockFees));
|
||||||
|
}
|
||||||
|
|
||||||
protected BigDecimal getRewardAtHeight(int ourHeight) {
|
protected BigDecimal getRewardAtHeight(int ourHeight) {
|
||||||
List<RewardByHeight> rewardsByHeight = BlockChain.getInstance().getBlockRewardsByHeight();
|
List<RewardByHeight> rewardsByHeight = BlockChain.getInstance().getBlockRewardsByHeight();
|
||||||
|
|
||||||
|
@ -78,7 +78,6 @@ public class HSQLDBAccountRepository implements AccountRepository {
|
|||||||
if (resultSet == null)
|
if (resultSet == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Column is NOT NULL so this should never implicitly convert to 0
|
|
||||||
return resultSet.getInt(1);
|
return resultSet.getInt(1);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DataException("Unable to fetch account's flags from repository", e);
|
throw new DataException("Unable to fetch account's flags from repository", e);
|
||||||
|
@ -91,13 +91,17 @@ public class AccountFlagsTransaction extends Transaction {
|
|||||||
@Override
|
@Override
|
||||||
public void process() throws DataException {
|
public void process() throws DataException {
|
||||||
Account target = getTarget();
|
Account target = getTarget();
|
||||||
int previousFlags = target.getFlags();
|
Integer previousFlags = target.getFlags();
|
||||||
|
|
||||||
accountFlagsTransactionData.setPreviousFlags(previousFlags);
|
accountFlagsTransactionData.setPreviousFlags(previousFlags);
|
||||||
|
|
||||||
// Save this transaction with target account's previous flags value
|
// Save this transaction with target account's previous flags value
|
||||||
this.repository.getTransactionRepository().save(accountFlagsTransactionData);
|
this.repository.getTransactionRepository().save(accountFlagsTransactionData);
|
||||||
|
|
||||||
|
// If account doesn't have entry in database yet (e.g. genesis block) then flags are zero
|
||||||
|
if (previousFlags == null)
|
||||||
|
previousFlags = 0;
|
||||||
|
|
||||||
// Set account's new flags
|
// Set account's new flags
|
||||||
int newFlags = previousFlags & accountFlagsTransactionData.getAndMask()
|
int newFlags = previousFlags & accountFlagsTransactionData.getAndMask()
|
||||||
| accountFlagsTransactionData.getOrMask() ^ accountFlagsTransactionData.getXorMask();
|
| accountFlagsTransactionData.getOrMask() ^ accountFlagsTransactionData.getXorMask();
|
||||||
@ -117,7 +121,13 @@ public class AccountFlagsTransaction extends Transaction {
|
|||||||
// Revert
|
// Revert
|
||||||
Account target = getTarget();
|
Account target = getTarget();
|
||||||
|
|
||||||
target.setFlags(accountFlagsTransactionData.getPreviousFlags());
|
Integer previousFlags = accountFlagsTransactionData.getPreviousFlags();
|
||||||
|
|
||||||
|
// If previousFlags are null then account didn't exist before this transaction
|
||||||
|
if (previousFlags == null)
|
||||||
|
this.repository.getAccountRepository().delete(target.getAddress());
|
||||||
|
else
|
||||||
|
target.setFlags(previousFlags);
|
||||||
|
|
||||||
// Delete this transaction itself
|
// Delete this transaction itself
|
||||||
this.repository.getTransactionRepository().delete(accountFlagsTransactionData);
|
this.repository.getTransactionRepository().delete(accountFlagsTransactionData);
|
||||||
|
@ -10,7 +10,6 @@ import org.qora.account.Forging;
|
|||||||
import org.qora.account.PublicKeyAccount;
|
import org.qora.account.PublicKeyAccount;
|
||||||
import org.qora.asset.Asset;
|
import org.qora.asset.Asset;
|
||||||
import org.qora.crypto.Crypto;
|
import org.qora.crypto.Crypto;
|
||||||
import org.qora.data.account.AccountData;
|
|
||||||
import org.qora.data.account.ProxyForgerData;
|
import org.qora.data.account.ProxyForgerData;
|
||||||
import org.qora.data.transaction.ProxyForgingTransactionData;
|
import org.qora.data.transaction.ProxyForgingTransactionData;
|
||||||
import org.qora.data.transaction.TransactionData;
|
import org.qora.data.transaction.TransactionData;
|
||||||
@ -80,7 +79,7 @@ public class ProxyForgingTransaction extends Transaction {
|
|||||||
public ValidationResult isValid() throws DataException {
|
public ValidationResult isValid() throws DataException {
|
||||||
// Check reward share given to recipient
|
// Check reward share given to recipient
|
||||||
if (this.proxyForgingTransactionData.getShare().compareTo(BigDecimal.ZERO) <= 0
|
if (this.proxyForgingTransactionData.getShare().compareTo(BigDecimal.ZERO) <= 0
|
||||||
|| this.proxyForgingTransactionData.getShare().compareTo(MAX_SHARE) >= 0)
|
|| this.proxyForgingTransactionData.getShare().compareTo(MAX_SHARE) > 0)
|
||||||
return ValidationResult.INVALID_FORGE_SHARE;
|
return ValidationResult.INVALID_FORGE_SHARE;
|
||||||
|
|
||||||
PublicKeyAccount creator = getCreator();
|
PublicKeyAccount creator = getCreator();
|
||||||
@ -97,10 +96,12 @@ public class ProxyForgingTransaction extends Transaction {
|
|||||||
if (!Crypto.isValidAddress(recipient.getAddress()))
|
if (!Crypto.isValidAddress(recipient.getAddress()))
|
||||||
return ValidationResult.INVALID_ADDRESS;
|
return ValidationResult.INVALID_ADDRESS;
|
||||||
|
|
||||||
|
/* Not needed?
|
||||||
// Check recipient has known public key
|
// Check recipient has known public key
|
||||||
AccountData recipientData = this.repository.getAccountRepository().getAccount(recipient.getAddress());
|
AccountData recipientData = this.repository.getAccountRepository().getAccount(recipient.getAddress());
|
||||||
if (recipientData == null || recipientData.getPublicKey() == null)
|
if (recipientData == null || recipientData.getPublicKey() == null)
|
||||||
return ValidationResult.PUBLIC_KEY_UNKNOWN;
|
return ValidationResult.PUBLIC_KEY_UNKNOWN;
|
||||||
|
*/
|
||||||
|
|
||||||
// Check fee is positive
|
// Check fee is positive
|
||||||
if (proxyForgingTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
if (proxyForgingTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||||
@ -140,6 +141,11 @@ public class ProxyForgingTransaction extends Transaction {
|
|||||||
|
|
||||||
// Update forger's reference
|
// Update forger's reference
|
||||||
forger.setLastReference(proxyForgingTransactionData.getSignature());
|
forger.setLastReference(proxyForgingTransactionData.getSignature());
|
||||||
|
|
||||||
|
// If proxy recipient has no last-reference then use this transaction's signature as last-reference so they can spend their block rewards
|
||||||
|
Account recipient = new Account(this.repository, proxyForgingTransactionData.getRecipient());
|
||||||
|
if (recipient.getLastReference() == null)
|
||||||
|
recipient.setLastReference(proxyForgingTransactionData.getSignature());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -166,6 +172,11 @@ public class ProxyForgingTransaction extends Transaction {
|
|||||||
|
|
||||||
// Update forger's reference
|
// Update forger's reference
|
||||||
forger.setLastReference(proxyForgingTransactionData.getReference());
|
forger.setLastReference(proxyForgingTransactionData.getReference());
|
||||||
|
|
||||||
|
// If recipient didn't have a last-reference prior to this transaction then remove it
|
||||||
|
Account recipient = new Account(this.repository, proxyForgingTransactionData.getRecipient());
|
||||||
|
if (Arrays.equals(recipient.getLastReference(), proxyForgingTransactionData.getSignature()))
|
||||||
|
recipient.setLastReference(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user