Browse Source

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.
pull/67/head
catbref 5 years ago
parent
commit
7a318c9fc7
  1. 66
      src/main/java/org/qora/block/Block.java
  2. 1
      src/main/java/org/qora/repository/hsqldb/HSQLDBAccountRepository.java
  3. 14
      src/main/java/org/qora/transaction/AccountFlagsTransaction.java
  4. 15
      src/main/java/org/qora/transaction/ProxyForgingTransaction.java

66
src/main/java/org/qora/block/Block.java

@ -1050,10 +1050,8 @@ public class Block {
for (Transaction transaction : transactions)
transaction.process();
// If fees are non-zero then add fees to generator's balance
BigDecimal blockFee = this.blockData.getTotalFees();
if (blockFee.compareTo(BigDecimal.ZERO) > 0)
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).add(blockFee));
// Give transaction fees to generator/proxy
rewardTransactionFees();
// Process AT fees and save AT states into repository
ATRepository atRepository = this.repository.getATRepository();
@ -1102,7 +1100,7 @@ public class Block {
// Is generator public key actually a proxy forge key?
ProxyForgerData proxyForgerData = this.repository.getAccountRepository().getProxyForgeData(this.blockData.getGeneratorPublicKey());
if (proxyForgerData != null) {
// Split reward to forger and recipient;
// Split reward between forger and recipient
Account recipient = new Account(this.repository, proxyForgerData.getRecipient());
BigDecimal recipientShare = reward.multiply(proxyForgerData.getShare().movePointLeft(2)).setScale(8, RoundingMode.DOWN);
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));
}
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.
*
@ -1145,10 +1168,8 @@ public class Block {
// Block rewards removed after transactions undone
orphanBlockRewards();
// If fees are non-zero then remove fees from generator's balance
BigDecimal blockFee = this.blockData.getTotalFees();
if (blockFee.compareTo(BigDecimal.ZERO) > 0)
this.generator.setConfirmedBalance(Asset.QORA, this.generator.getConfirmedBalance(Asset.QORA).subtract(blockFee));
// Deduct any transaction fees from generator/proxy
deductTransactionFees();
// Return AT fees and delete AT states from repository
ATRepository atRepository = this.repository.getATRepository();
@ -1175,7 +1196,7 @@ public class Block {
// Is generator public key actually a proxy forge key?
ProxyForgerData proxyForgerData = this.repository.getAccountRepository().getProxyForgeData(this.blockData.getGeneratorPublicKey());
if (proxyForgerData != null) {
// Split reward from forger and recipient;
// Split reward between forger and recipient
Account recipient = new Account(this.repository, proxyForgerData.getRecipient());
BigDecimal recipientShare = reward.multiply(proxyForgerData.getShare().movePointLeft(2)).setScale(8, RoundingMode.DOWN);
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));
}
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) {
List<RewardByHeight> rewardsByHeight = BlockChain.getInstance().getBlockRewardsByHeight();

1
src/main/java/org/qora/repository/hsqldb/HSQLDBAccountRepository.java

@ -78,7 +78,6 @@ public class HSQLDBAccountRepository implements AccountRepository {
if (resultSet == null)
return null;
// Column is NOT NULL so this should never implicitly convert to 0
return resultSet.getInt(1);
} catch (SQLException e) {
throw new DataException("Unable to fetch account's flags from repository", e);

14
src/main/java/org/qora/transaction/AccountFlagsTransaction.java

@ -91,13 +91,17 @@ public class AccountFlagsTransaction extends Transaction {
@Override
public void process() throws DataException {
Account target = getTarget();
int previousFlags = target.getFlags();
Integer previousFlags = target.getFlags();
accountFlagsTransactionData.setPreviousFlags(previousFlags);
// Save this transaction with target account's previous flags value
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
int newFlags = previousFlags & accountFlagsTransactionData.getAndMask()
| accountFlagsTransactionData.getOrMask() ^ accountFlagsTransactionData.getXorMask();
@ -117,7 +121,13 @@ public class AccountFlagsTransaction extends Transaction {
// Revert
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
this.repository.getTransactionRepository().delete(accountFlagsTransactionData);

15
src/main/java/org/qora/transaction/ProxyForgingTransaction.java

@ -10,7 +10,6 @@ import org.qora.account.Forging;
import org.qora.account.PublicKeyAccount;
import org.qora.asset.Asset;
import org.qora.crypto.Crypto;
import org.qora.data.account.AccountData;
import org.qora.data.account.ProxyForgerData;
import org.qora.data.transaction.ProxyForgingTransactionData;
import org.qora.data.transaction.TransactionData;
@ -80,7 +79,7 @@ public class ProxyForgingTransaction extends Transaction {
public ValidationResult isValid() throws DataException {
// Check reward share given to recipient
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;
PublicKeyAccount creator = getCreator();
@ -97,10 +96,12 @@ public class ProxyForgingTransaction extends Transaction {
if (!Crypto.isValidAddress(recipient.getAddress()))
return ValidationResult.INVALID_ADDRESS;
/* Not needed?
// Check recipient has known public key
AccountData recipientData = this.repository.getAccountRepository().getAccount(recipient.getAddress());
if (recipientData == null || recipientData.getPublicKey() == null)
return ValidationResult.PUBLIC_KEY_UNKNOWN;
*/
// Check fee is positive
if (proxyForgingTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
@ -140,6 +141,11 @@ public class ProxyForgingTransaction extends Transaction {
// Update forger's reference
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
@ -166,6 +172,11 @@ public class ProxyForgingTransaction extends Transaction {
// Update forger's reference
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…
Cancel
Save