From 24f141b6aa2419770f1ba305b08d861c2d52d902 Mon Sep 17 00:00:00 2001 From: zhang0125 Date: Wed, 26 Oct 2022 16:04:13 +0800 Subject: [PATCH] feat(freezeV2): optimize unfreeze vote 1. clear all votes at once when new resource model start 2. If there is not enough power to vote, reduce the votes proportionally --- .../actuator/UnfreezeBalanceV2Actuator.java | 134 ++++++++++++------ .../UnfreezeBalanceV2ActuatorTest.java | 59 ++++---- 2 files changed, 121 insertions(+), 72 deletions(-) diff --git a/actuator/src/main/java/org/tron/core/actuator/UnfreezeBalanceV2Actuator.java b/actuator/src/main/java/org/tron/core/actuator/UnfreezeBalanceV2Actuator.java index 43b61ad125b..df139730e3c 100755 --- a/actuator/src/main/java/org/tron/core/actuator/UnfreezeBalanceV2Actuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/UnfreezeBalanceV2Actuator.java @@ -1,8 +1,15 @@ package org.tron.core.actuator; +import static org.tron.core.actuator.ActuatorConstant.ACCOUNT_EXCEPTION_STR; +import static org.tron.core.config.Parameter.ChainConstant.FROZEN_PERIOD; +import static org.tron.core.config.Parameter.ChainConstant.TRX_PRECISION; + import com.google.common.collect.Lists; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.tron.common.utils.DecodeUtil; @@ -19,17 +26,10 @@ import org.tron.protos.Protocol; import org.tron.protos.Protocol.Transaction.Contract.ContractType; import org.tron.protos.Protocol.Transaction.Result.code; +import org.tron.protos.Protocol.Vote; import org.tron.protos.contract.BalanceContract.UnfreezeBalanceV2Contract; import org.tron.protos.contract.Common; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; - -import static org.tron.core.actuator.ActuatorConstant.ACCOUNT_EXCEPTION_STR; -import static org.tron.core.config.Parameter.ChainConstant.FROZEN_PERIOD; -import static org.tron.core.config.Parameter.ChainConstant.TRX_PRECISION; - @Slf4j(topic = "actuator") public class UnfreezeBalanceV2Actuator extends AbstractActuator { @@ -81,7 +81,7 @@ public boolean execute(Object result) throws ContractExeException { accountCapsule.addUnfrozenV2List(freezeType, unfreezeBalance, expireTime); this.updateTotalResourceWeight(unfreezeBalanceV2Contract, unfreezeBalance); - this.clearVotes(accountCapsule,unfreezeBalanceV2Contract, ownerAddress); + this.updateVote(accountCapsule, unfreezeBalanceV2Contract, ownerAddress); if (dynamicStore.supportAllowNewResourceModel() && !accountCapsule.oldTronPowerIsInvalid()) { @@ -154,7 +154,7 @@ public boolean validate() throws ContractValidateException { throw new ContractValidateException("no frozenBalance(TronPower)"); } } else { - throw new ContractValidateException("ResourceCode error.valid ResourceCode[BANDWIDTH、Energy]"); + throw new ContractValidateException("ResourceCode error.valid ResourceCode[BANDWIDTH、Energy]"); } break; default: @@ -167,7 +167,7 @@ public boolean validate() throws ContractValidateException { if (!checkUnfreezeBalance(accountCapsule, unfreezeBalanceV2Contract, unfreezeBalanceV2Contract.getResource())) { throw new ContractValidateException( - "Invalid unfreeze_balance, [" + unfreezeBalanceV2Contract.getUnfreezeBalance() + "] is error" + "Invalid unfreeze_balance, [" + unfreezeBalanceV2Contract.getUnfreezeBalance() + "] is error" ); } @@ -208,8 +208,8 @@ public boolean checkExistFreezedBalance(AccountCapsule accountCapsule, Common.Re } public boolean checkUnfreezeBalance(AccountCapsule accountCapsule, - final UnfreezeBalanceV2Contract unfreezeBalanceV2Contract, - Common.ResourceCode freezeType) { + final UnfreezeBalanceV2Contract unfreezeBalanceV2Contract, + Common.ResourceCode freezeType) { boolean checkOk = false; long frozenAmount = 0L; @@ -222,7 +222,7 @@ public boolean checkUnfreezeBalance(AccountCapsule accountCapsule, } if (unfreezeBalanceV2Contract.getUnfreezeBalance() > 0 - && unfreezeBalanceV2Contract.getUnfreezeBalance() <= frozenAmount) { + && unfreezeBalanceV2Contract.getUnfreezeBalance() <= frozenAmount) { checkOk = true; } @@ -240,10 +240,10 @@ public void updateAccountFrozenInfo(Common.ResourceCode freezeType, AccountCapsu List freezeV2List = accountCapsule.getFrozenV2List(); for (int i = 0; i < freezeV2List.size(); i++) { if (freezeV2List.get(i).getType().equals(freezeType)) { - Protocol.Account.FreezeV2 freezeV2 = Protocol.Account.FreezeV2.newBuilder() - .setAmount(freezeV2List.get(i).getAmount() - unfreezeBalance) - .setType(freezeV2List.get(i).getType()) - .build(); + Protocol.Account.FreezeV2 freezeV2 = Protocol.Account.FreezeV2.newBuilder() + .setAmount(freezeV2List.get(i).getAmount() - unfreezeBalance) + .setType(freezeV2List.get(i).getType()) + .build(); accountCapsule.updateFrozenV2List(i, freezeV2); break; } @@ -266,7 +266,7 @@ public void unfreezeExpire(AccountCapsule accountCapsule, long now) { } accountCapsule.setInstance( - accountCapsule.getInstance().toBuilder() + accountCapsule.getInstance().toBuilder() .setBalance(accountCapsule.getBalance() + unfreezeBalance) .clearUnfrozenV2() .addAllUnfrozenV2(unFrozenV2List).build() @@ -274,7 +274,7 @@ public void unfreezeExpire(AccountCapsule accountCapsule, long now) { } public void updateTotalResourceWeight(final UnfreezeBalanceV2Contract unfreezeBalanceV2Contract, - long unfreezeBalance) { + long unfreezeBalance) { DynamicPropertiesStore dynamicStore = chainBaseManager.getDynamicPropertiesStore(); switch (unfreezeBalanceV2Contract.getResource()) { case BANDWIDTH: @@ -292,38 +292,86 @@ public void updateTotalResourceWeight(final UnfreezeBalanceV2Contract unfreezeBa } } - private void clearVotes(AccountCapsule accountCapsule, + private void updateVote(AccountCapsule accountCapsule, final UnfreezeBalanceV2Contract unfreezeBalanceV2Contract, byte[] ownerAddress) { DynamicPropertiesStore dynamicStore = chainBaseManager.getDynamicPropertiesStore(); VotesStore votesStore = chainBaseManager.getVotesStore(); - boolean needToClearVote = true; - if (dynamicStore.supportAllowNewResourceModel() - && accountCapsule.oldTronPowerIsInvalid()) { - switch (unfreezeBalanceV2Contract.getResource()) { - case BANDWIDTH: - case ENERGY: - needToClearVote = false; - break; - default: - break; + if (accountCapsule.getVotesList().isEmpty()) { + return; + } + if (dynamicStore.supportAllowNewResourceModel()) { + if (accountCapsule.oldTronPowerIsInvalid()) { + switch (unfreezeBalanceV2Contract.getResource()) { + case BANDWIDTH: + case ENERGY: + // there is no need to change votes + return; + default: + break; + } + } else { + // clear all votes at once when new resource model start + VotesCapsule votesCapsule; + if (!votesStore.has(ownerAddress)) { + votesCapsule = new VotesCapsule( + unfreezeBalanceV2Contract.getOwnerAddress(), + accountCapsule.getVotesList() + ); + } else { + votesCapsule = votesStore.get(ownerAddress); + } + accountCapsule.clearVotes(); + votesCapsule.clearNewVotes(); + votesStore.put(ownerAddress, votesCapsule); + return; } } - if (needToClearVote) { - VotesCapsule votesCapsule; - if (!votesStore.has(ownerAddress)) { - votesCapsule = new VotesCapsule( - unfreezeBalanceV2Contract.getOwnerAddress(), - accountCapsule.getVotesList() - ); - } else { - votesCapsule = votesStore.get(ownerAddress); + long totalVote = 0; + for (Protocol.Vote vote : accountCapsule.getVotesList()) { + totalVote += vote.getVoteCount(); + } + long ownedTronPower; + if (dynamicStore.supportAllowNewResourceModel()) { + ownedTronPower = accountCapsule.getAllTronPower(); + } else { + ownedTronPower = accountCapsule.getTronPower(); + } + + // tron power is enough to total votes + if (ownedTronPower >= totalVote * TRX_PRECISION) { + return; + } + if (totalVote == 0) { + return; + } + + VotesCapsule votesCapsule; + if (!votesStore.has(ownerAddress)) { + votesCapsule = new VotesCapsule( + unfreezeBalanceV2Contract.getOwnerAddress(), + accountCapsule.getVotesList() + ); + } else { + votesCapsule = votesStore.get(ownerAddress); + } + + // Update Owner Voting + votesCapsule.clearNewVotes(); + for (Vote vote : accountCapsule.getVotesList()) { + long newVoteCount = (long) + ((double) vote.getVoteCount() / totalVote * ownedTronPower / TRX_PRECISION); + if (newVoteCount > 0) { + votesCapsule.addNewVotes(vote.getVoteAddress(), newVoteCount); } - accountCapsule.clearVotes(); - votesCapsule.clearNewVotes(); - votesStore.put(ownerAddress, votesCapsule); + } + votesStore.put(ownerAddress, votesCapsule); + + accountCapsule.clearVotes(); + for (Vote vote : votesCapsule.getNewVotes()) { + accountCapsule.addVotes(vote.getVoteAddress(), vote.getVoteCount()); } } } \ No newline at end of file diff --git a/framework/src/test/java/org/tron/core/actuator/UnfreezeBalanceV2ActuatorTest.java b/framework/src/test/java/org/tron/core/actuator/UnfreezeBalanceV2ActuatorTest.java index 004a9476ff1..07d7f3a6def 100644 --- a/framework/src/test/java/org/tron/core/actuator/UnfreezeBalanceV2ActuatorTest.java +++ b/framework/src/test/java/org/tron/core/actuator/UnfreezeBalanceV2ActuatorTest.java @@ -7,8 +7,6 @@ import com.google.protobuf.Any; import com.google.protobuf.ByteString; import java.io.File; -import java.util.ArrayList; -import java.util.List; import lombok.extern.slf4j.Slf4j; import org.junit.AfterClass; import org.junit.Assert; @@ -318,57 +316,60 @@ public void noFrozenBalance() { } @Test - public void testClearVotes() { + public void testVotes() { byte[] ownerAddressBytes = ByteArray.fromHexString(OWNER_ADDRESS); - ByteString ownerAddress = ByteString.copyFrom(ownerAddressBytes); - long unfreezeBalance = frozenBalance; + long unfreezeBalance = frozenBalance / 2; long now = System.currentTimeMillis(); dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(now); - + dbManager.getDynamicPropertiesStore().saveAllowNewResourceModel(0); AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddressBytes); accountCapsule.addFrozenBalanceForBandwidthV2(1_000_000_000L); - + accountCapsule.addVotes(ByteString.copyFrom(RECEIVER_ADDRESS.getBytes()), 500); + accountCapsule.addVotes(ByteString.copyFrom(OWNER_ACCOUNT_INVALID.getBytes()), 500); dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule); + UnfreezeBalanceV2Actuator actuator = new UnfreezeBalanceV2Actuator(); actuator.setChainBaseManager(dbManager.getChainBaseManager()) .setAny(getContractForBandwidthV2(OWNER_ADDRESS, unfreezeBalance)); TransactionResultCapsule ret = new TransactionResultCapsule(); - dbManager.getVotesStore().reset(); - Assert.assertNull(dbManager.getVotesStore().get(ownerAddressBytes)); try { actuator.validate(); actuator.execute(ret); VotesCapsule votesCapsule = dbManager.getVotesStore().get(ownerAddressBytes); Assert.assertNotNull(votesCapsule); - Assert.assertEquals(0, votesCapsule.getNewVotes().size()); - } catch (ContractValidateException e) { - Assert.assertFalse(e instanceof ContractValidateException); - } catch (ContractExeException e) { - Assert.assertFalse(e instanceof ContractExeException); + for (Vote vote : votesCapsule.getOldVotes()) { + Assert.assertEquals(vote.getVoteCount(), 500); + } + for (Vote vote : votesCapsule.getNewVotes()) { + Assert.assertEquals(vote.getVoteCount(), 250); + } + accountCapsule = dbManager.getAccountStore().get(ownerAddressBytes); + for (Vote vote : accountCapsule.getVotesList()) { + Assert.assertEquals(vote.getVoteCount(), 250); + } + } catch (ContractValidateException | ContractExeException e) { + Assert.fail("cannot run here."); } - // if had votes - List oldVotes = new ArrayList(); - VotesCapsule votesCapsule = new VotesCapsule( - ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)), oldVotes); - votesCapsule.addNewVotes( - ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)), 100); - dbManager.getVotesStore().put(ByteArray.fromHexString(OWNER_ADDRESS), votesCapsule); - accountCapsule.addFrozenBalanceForBandwidthV2(1_000_000_000L); - dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule); + // clear for new resource model + dbManager.getDynamicPropertiesStore().saveAllowNewResourceModel(1); + actuator.setChainBaseManager(dbManager.getChainBaseManager()) + .setAny(getContractForBandwidthV2(OWNER_ADDRESS, unfreezeBalance / 2)); try { actuator.validate(); actuator.execute(ret); - votesCapsule = dbManager.getVotesStore().get(ownerAddressBytes); + VotesCapsule votesCapsule = dbManager.getVotesStore().get(ownerAddressBytes); Assert.assertNotNull(votesCapsule); + for (Vote vote : votesCapsule.getOldVotes()) { + Assert.assertEquals(vote.getVoteCount(), 500); + } Assert.assertEquals(0, votesCapsule.getNewVotes().size()); - } catch (ContractValidateException e) { - Assert.assertFalse(e instanceof ContractValidateException); - } catch (ContractExeException e) { - Assert.assertFalse(e instanceof ContractExeException); + accountCapsule = dbManager.getAccountStore().get(ownerAddressBytes); + Assert.assertEquals(0, accountCapsule.getVotesList().size()); + } catch (ContractValidateException | ContractExeException e) { + Assert.fail("cannot run here."); } - } @Test