Skip to content

Commit

Permalink
feat(freezeV2): optimize unfreeze vote
Browse files Browse the repository at this point in the history
1. clear all votes at once when new resource model start
2. If there is not enough power to vote, reduce the votes proportionally
  • Loading branch information
zhang0125 committed Oct 28, 2022
1 parent dd5c8a3 commit 24f141b
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {

Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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:
Expand All @@ -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"
);
}

Expand Down Expand Up @@ -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;
Expand All @@ -222,7 +222,7 @@ public boolean checkUnfreezeBalance(AccountCapsule accountCapsule,
}

if (unfreezeBalanceV2Contract.getUnfreezeBalance() > 0
&& unfreezeBalanceV2Contract.getUnfreezeBalance() <= frozenAmount) {
&& unfreezeBalanceV2Contract.getUnfreezeBalance() <= frozenAmount) {
checkOk = true;
}

Expand All @@ -240,10 +240,10 @@ public void updateAccountFrozenInfo(Common.ResourceCode freezeType, AccountCapsu
List<Protocol.Account.FreezeV2> 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;
}
Expand All @@ -266,15 +266,15 @@ public void unfreezeExpire(AccountCapsule accountCapsule, long now) {
}

accountCapsule.setInstance(
accountCapsule.getInstance().toBuilder()
accountCapsule.getInstance().toBuilder()
.setBalance(accountCapsule.getBalance() + unfreezeBalance)
.clearUnfrozenV2()
.addAllUnfrozenV2(unFrozenV2List).build()
);
}

public void updateTotalResourceWeight(final UnfreezeBalanceV2Contract unfreezeBalanceV2Contract,
long unfreezeBalance) {
long unfreezeBalance) {
DynamicPropertiesStore dynamicStore = chainBaseManager.getDynamicPropertiesStore();
switch (unfreezeBalanceV2Contract.getResource()) {
case BANDWIDTH:
Expand All @@ -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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Vote> oldVotes = new ArrayList<Vote>();
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
Expand Down

0 comments on commit 24f141b

Please sign in to comment.