Skip to content

Commit

Permalink
Merge pull request #34 from uniworld-io/fixTokenFeeOnNonExistAccount
Browse files Browse the repository at this point in the history
Fix token fee on non exist account
  • Loading branch information
elonkusk authored Dec 27, 2021
2 parents 66f40f5 + 3383272 commit 377cf93
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ public boolean execute(TransactionResultCapsule ret) throws ContractExeException
var toAddress = ctx.getToAddress().toByteArray();

var toAccountCap = dbManager.getAccountStore().get(toAddress);
var createAccFee = 0L;
if (toAccountCap == null) {
var withDefaultPermission = dbManager.getDynamicPropertiesStore().getAllowMultiSign() == 1;
toAccountCap = new AccountCapsule(ByteString.copyFrom(toAddress), Protocol.AccountType.Normal, dbManager.getHeadBlockTimeStamp(), withDefaultPermission, dbManager);
fee += dbManager.getDynamicPropertiesStore().getCreateNewAccountFeeInSystemContract();
createAccFee = dbManager.getDynamicPropertiesStore().getCreateNewAccountFeeInSystemContract();
dbManager.adjustBalanceNoPut(ownerAccountCap, -createAccFee);
}

if(Arrays.equals(ownerAddr, tokenPoolOwnerAddr)){
Expand Down Expand Up @@ -103,8 +105,9 @@ public boolean execute(TransactionResultCapsule ret) throws ContractExeException
tokenPool.setFeePool(tokenPool.getFeePool() - fee);
tokenPool.setLatestOperationTime(dbManager.getHeadBlockTimeStamp());
dbManager.getTokenPoolStore().put(tokenKey, tokenPool);
dbManager.burnFee(fee);

fee += createAccFee;
dbManager.burnFee(fee);
ret.setStatus(fee, code.SUCESS);
return true;
} catch (Exception e) {
Expand Down Expand Up @@ -152,21 +155,12 @@ public boolean validate() throws ContractValidateException {

var toAccountCap = dbManager.getAccountStore().get(toAddress);
if (toAccountCap == null) {
fee += dbManager.getDynamicPropertiesStore().getCreateNewAccountFeeInSystemContract();
var createAccountFee = dbManager.getDynamicPropertiesStore().getCreateNewAccountFeeInSystemContract();
Assert.isTrue(ownerAccountCap.getBalance() >= createAccountFee, "Not enough balance in owner account to create new account");
}

Assert.isTrue(tokenPool.getFeePool() >= fee, "Not enough token pool fee balance");

Assert.isTrue (ctx.getAmount() > 0, "Invalid transfer amount, expect positive number");

//estimate new fee
long tokenFee;
if (Arrays.equals(ownerAddress, tokenPool.getOwnerAddress().toByteArray())) {
tokenFee = 0;
} else {
tokenFee = tokenPool.getFee() + LongMath.divide(ctx.getAmount() * tokenPool.getExtraFeeRate(), 100, RoundingMode.CEILING);
}

Assert.isTrue(ownerAccountCap.getTokenAvailable(tokenKey) >= ctx.getAmount(), "Not enough token balance");

//after UvmSolidity059 proposal, send unx to smartContract by actuator is not allowed.
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/unichain/core/config/Parameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public class ChainConstant {
/**
* Critical: all available block version must declare here
*/
public static final int BLOCK_VERSION_0 = 0;
public static final int BLOCK_VERSION_1 = 1;
public static final int BLOCK_VERSION_2 = 2;
public static final int BLOCK_VERSION_3 = 3;
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/org/unichain/core/db/BandwidthProcessorV2.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public void consume(TransactionCapsule tx, TransactionTrace trace) throws Contra
try {
if (isContractCreateNewAccount(contract)) {
if (contract.getType() == ContractType.TransferTokenContract)
consumeForCreateNewAccount4TokenTransfer(contract, trace);
consumeForCreateNewAccountIfTokenTransfer(ownerAccountCap, contract, trace);
else
consumeForCreateNewAccount(ownerAccountCap, trace);
continue;
Expand Down Expand Up @@ -133,7 +133,7 @@ public void consume(TransactionCapsule tx, TransactionTrace trace) throws Contra
}
}

private boolean useTransactionFee(AccountCapsule accountCapsule, long bytes, TransactionTrace trace) {
protected boolean useTransactionFee(AccountCapsule accountCapsule, long bytes, TransactionTrace trace) {
long bwFee = dbManager.getDynamicPropertiesStore().getTransactionFee() * bytes;
if (consumeFee(accountCapsule, bwFee)) {
trace.setNetBill(0, bwFee);
Expand All @@ -144,7 +144,7 @@ private boolean useTransactionFee(AccountCapsule accountCapsule, long bytes, Tra
}
}

private boolean useTransactionFee4TokenPool(byte[] tokenKey, long bytes, TransactionTrace trace) {
protected boolean useTransactionFee4TokenPool(byte[] tokenKey, long bytes, TransactionTrace trace) {
long bwFee = dbManager.getDynamicPropertiesStore().getTransactionFee() * bytes;
if (consumeFeeTokenPool(tokenKey, bwFee)) {
trace.setNetBill(0, bwFee);
Expand All @@ -155,9 +155,9 @@ private boolean useTransactionFee4TokenPool(byte[] tokenKey, long bytes, Transac
}
}

private void consumeForCreateNewAccount(AccountCapsule accountCapsule, TransactionTrace trace) throws AccountResourceInsufficientException {
protected void consumeForCreateNewAccount(AccountCapsule ownerAccountCapsule, TransactionTrace trace) throws AccountResourceInsufficientException {
long fee = dbManager.getDynamicPropertiesStore().getCreateAccountFee();
if (consumeFee(accountCapsule, fee)) {
if (consumeFee(ownerAccountCapsule, fee)) {
trace.setNetBill(0, fee);
dbManager.getDynamicPropertiesStore().addTotalCreateAccountCost(fee);
return;
Expand All @@ -166,7 +166,7 @@ private void consumeForCreateNewAccount(AccountCapsule accountCapsule, Transacti
}
}

private void consumeForCreateNewAccount4TokenTransfer(Contract contract, TransactionTrace trace) throws AccountResourceInsufficientException, ContractValidateException {
protected void consumeForCreateNewAccountIfTokenTransfer(AccountCapsule ownerAccountCapsule, Contract contract, TransactionTrace trace) throws AccountResourceInsufficientException, ContractValidateException {
try {
var ctx = contract.getParameter().unpack(TransferTokenContract.class);
long fee = dbManager.getDynamicPropertiesStore().getCreateAccountFee();
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/org/unichain/core/db/BandwidthProcessorV3.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.unichain.core.db;

import lombok.extern.slf4j.Slf4j;
import org.unichain.core.capsule.AccountCapsule;
import org.unichain.core.exception.AccountResourceInsufficientException;
import org.unichain.core.exception.ContractValidateException;
import org.unichain.protos.Protocol.Transaction.Contract;

/**
* With block v3: create new account while transferring token to non-exist account
* charged on owner account.
*/
@Slf4j(topic = "DB")
public class BandwidthProcessorV3 extends BandwidthProcessorV2 {

public BandwidthProcessorV3(Manager manager) {
super(manager);
}

@Override
protected void consumeForCreateNewAccountIfTokenTransfer(AccountCapsule ownerAccountCapsule, Contract contract, TransactionTrace trace) throws AccountResourceInsufficientException, ContractValidateException {
consumeForCreateNewAccount(ownerAccountCapsule, trace);
}
}
29 changes: 25 additions & 4 deletions src/main/java/org/unichain/core/db/Manager.java
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,18 @@ public void adjustBalance(AccountCapsule account, long amount) throws BalanceIns
this.getAccountStore().put(account.getAddress().toByteArray(), account);
}

public void adjustBalanceNoPut(AccountCapsule account, long amount) throws BalanceInsufficientException {
long balance = account.getBalance();
if (amount == 0) {
return;
}

if (amount < 0 && balance < -amount) {
throw new BalanceInsufficientException(StringUtil.createReadableString(account.createDbKey()) + " insufficient balance");
}
account.setBalance(Math.addExact(balance, amount));
}


public void adjustAllowance(byte[] accountAddress, long amount) throws BalanceInsufficientException {
AccountCapsule account = getAccountStore().getUnchecked(accountAddress);
Expand Down Expand Up @@ -843,10 +855,19 @@ public void consumeMultiSignFeeV1(TransactionCapsule unx, TransactionTrace trace
}

public void consumeBandwidth(TransactionCapsule unx, TransactionTrace trace, BlockCapsule block) throws ContractValidateException, AccountResourceInsufficientException, TooBigTransactionResultException {
if(findBlockVersion(block) <= BLOCK_VERSION_1)
(new BandwidthProcessor(this)).consume(unx, trace);
else
(new BandwidthProcessorV2(this)).consume(unx, trace);
int blockVer = findBlockVersion(block);
switch (blockVer){
case BLOCK_VERSION_0:
case BLOCK_VERSION_1:
(new BandwidthProcessor(this)).consume(unx, trace);
break;
case BLOCK_VERSION_2:
(new BandwidthProcessorV2(this)).consume(unx, trace);
break;
default:
(new BandwidthProcessorV3(this)).consume(unx, trace);
break;
}
}

/**
Expand Down

0 comments on commit 377cf93

Please sign in to comment.