Skip to content

Commit b15bcd5

Browse files
authored
Merge pull request #5230 from lxcmyf/release_v4.7.2
feat(freezeV2): add cancel unfreezeV2 interface
2 parents 3c82c2a + 55ca979 commit b15bcd5

20 files changed

Lines changed: 686 additions & 26 deletions

File tree

Tron protobuf protocol document.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,7 @@ Transaction and transaction-related messages.
627627
WithdrawExpireUnfreezeContract = 56;
628628
DelegateResourceContract = 57;
629629
UnDelegateResourceContract = 58;
630+
CancelUnfreezeV2Contract = 59;
630631
}
631632
ContractType type = 1;
632633
google.protobuf.Any parameter = 2;
@@ -887,6 +888,7 @@ Contract and contract-related messages.
887888
WithdrawExpireUnfreezeContract = 56;
888889
DelegateResourceContract = 57;
889890
UnDelegateResourceContract = 58;
891+
CancelUnfreezeV2Contract = 59;
890892
}
891893
ContractType type = 1;
892894
google.protobuf.Any parameter = 2;
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
package org.tron.core.actuator;
2+
3+
import static org.tron.core.actuator.ActuatorConstant.ACCOUNT_EXCEPTION_STR;
4+
import static org.tron.core.actuator.ActuatorConstant.NOT_EXIST_STR;
5+
import static org.tron.core.config.Parameter.ChainConstant.TRX_PRECISION;
6+
import static org.tron.protos.contract.Common.ResourceCode.BANDWIDTH;
7+
import static org.tron.protos.contract.Common.ResourceCode.ENERGY;
8+
9+
import com.google.protobuf.ByteString;
10+
import com.google.protobuf.InvalidProtocolBufferException;
11+
import java.util.HashSet;
12+
import java.util.List;
13+
import java.util.Objects;
14+
import java.util.Set;
15+
import java.util.concurrent.atomic.AtomicLong;
16+
import java.util.stream.Collectors;
17+
import lombok.extern.slf4j.Slf4j;
18+
import org.apache.commons.collections4.CollectionUtils;
19+
import org.apache.commons.lang3.tuple.Triple;
20+
import org.tron.common.utils.DecodeUtil;
21+
import org.tron.common.utils.StringUtil;
22+
import org.tron.core.capsule.AccountCapsule;
23+
import org.tron.core.capsule.TransactionResultCapsule;
24+
import org.tron.core.exception.ContractExeException;
25+
import org.tron.core.exception.ContractValidateException;
26+
import org.tron.core.store.AccountStore;
27+
import org.tron.core.store.DynamicPropertiesStore;
28+
import org.tron.protos.Protocol.Account.UnFreezeV2;
29+
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
30+
import org.tron.protos.Protocol.Transaction.Result.code;
31+
import org.tron.protos.contract.BalanceContract.CancelUnfreezeV2Contract;
32+
33+
@Slf4j(topic = "actuator")
34+
public class CancelUnfreezeV2Actuator extends AbstractActuator {
35+
36+
public CancelUnfreezeV2Actuator() {
37+
super(ContractType.CancelUnfreezeV2Contract, CancelUnfreezeV2Contract.class);
38+
}
39+
40+
@Override
41+
public boolean execute(Object result) throws ContractExeException {
42+
TransactionResultCapsule ret = (TransactionResultCapsule) result;
43+
if (Objects.isNull(ret)) {
44+
throw new RuntimeException(ActuatorConstant.TX_RESULT_NULL);
45+
}
46+
long fee = calcFee();
47+
AccountStore accountStore = chainBaseManager.getAccountStore();
48+
DynamicPropertiesStore dynamicStore = chainBaseManager.getDynamicPropertiesStore();
49+
final CancelUnfreezeV2Contract cancelUnfreezeV2Contract;
50+
byte[] ownerAddress;
51+
try {
52+
cancelUnfreezeV2Contract = getCancelUnfreezeV2Contract();
53+
ownerAddress = getOwnerAddress().toByteArray();
54+
} catch (InvalidProtocolBufferException e) {
55+
logger.debug(e.getMessage(), e);
56+
ret.setStatus(fee, code.FAILED);
57+
throw new ContractExeException(e.getMessage());
58+
}
59+
List<Integer> indexList = cancelUnfreezeV2Contract.getIndexList()
60+
.stream().sorted().collect(Collectors.toList());
61+
AccountCapsule ownerCapsule = accountStore.get(ownerAddress);
62+
List<UnFreezeV2> unfrozenV2List = ownerCapsule.getUnfrozenV2List();
63+
long now = dynamicStore.getLatestBlockHeaderTimestamp();
64+
AtomicLong atomicWithdrawExpireBalance = new AtomicLong(0L);
65+
AtomicLong atomicCancelBalance = new AtomicLong(0L);
66+
Triple<AtomicLong, AtomicLong, AtomicLong> triple =
67+
Triple.of(new AtomicLong(0L), new AtomicLong(0L), new AtomicLong(0L));
68+
List<UnFreezeV2> newUnFreezeV2List = null;
69+
if (indexList.isEmpty()) {
70+
for (UnFreezeV2 unFreezeV2 : unfrozenV2List) {
71+
updateAndCalculate(triple, ownerCapsule, now, atomicWithdrawExpireBalance,
72+
atomicCancelBalance, unFreezeV2);
73+
}
74+
} else {
75+
indexList.forEach(index -> {
76+
UnFreezeV2 unFreezeV2 = unfrozenV2List.get(index);
77+
updateAndCalculate(triple, ownerCapsule, now, atomicWithdrawExpireBalance,
78+
atomicCancelBalance, unFreezeV2);
79+
});
80+
newUnFreezeV2List = unfrozenV2List.stream()
81+
.filter(o -> !indexList.contains(unfrozenV2List.indexOf(o))).collect(Collectors.toList());
82+
}
83+
ownerCapsule.clearUnfrozenV2();
84+
ownerCapsule.addAllUnfrozenV2(newUnFreezeV2List);
85+
addTotalResourceWeight(dynamicStore, triple);
86+
87+
long withdrawExpireBalance = atomicWithdrawExpireBalance.get();
88+
if (withdrawExpireBalance > 0) {
89+
ownerCapsule.setBalance(ownerCapsule.getBalance() + withdrawExpireBalance);
90+
}
91+
92+
accountStore.put(ownerCapsule.createDbKey(), ownerCapsule);
93+
ret.setWithdrawExpireAmount(withdrawExpireBalance);
94+
ret.setCancelUnfreezeV2Amount(atomicCancelBalance.get());
95+
ret.setStatus(fee, code.SUCESS);
96+
return true;
97+
}
98+
99+
private void addTotalResourceWeight(DynamicPropertiesStore dynamicStore,
100+
Triple<AtomicLong, AtomicLong, AtomicLong> triple) {
101+
dynamicStore.addTotalNetWeight(triple.getLeft().get());
102+
dynamicStore.addTotalEnergyWeight(triple.getMiddle().get());
103+
dynamicStore.addTotalTronPowerWeight(triple.getRight().get());
104+
}
105+
106+
private void updateAndCalculate(Triple<AtomicLong, AtomicLong, AtomicLong> triple,
107+
AccountCapsule ownerCapsule, long now, AtomicLong atomicLong, AtomicLong cancelBalance,
108+
UnFreezeV2 unFreezeV2) {
109+
if (unFreezeV2.getUnfreezeExpireTime() > now) {
110+
updateFrozenInfoAndTotalResourceWeight(ownerCapsule, unFreezeV2, triple);
111+
cancelBalance.addAndGet(unFreezeV2.getUnfreezeAmount());
112+
} else {
113+
atomicLong.addAndGet(unFreezeV2.getUnfreezeAmount());
114+
}
115+
}
116+
117+
@Override
118+
public boolean validate() throws ContractValidateException {
119+
if (Objects.isNull(this.any)) {
120+
throw new ContractValidateException(ActuatorConstant.CONTRACT_NOT_EXIST);
121+
}
122+
123+
if (Objects.isNull(chainBaseManager)) {
124+
throw new ContractValidateException(ActuatorConstant.STORE_NOT_EXIST);
125+
}
126+
127+
AccountStore accountStore = chainBaseManager.getAccountStore();
128+
DynamicPropertiesStore dynamicStore = chainBaseManager.getDynamicPropertiesStore();
129+
130+
if (!this.any.is(CancelUnfreezeV2Contract.class)) {
131+
throw new ContractValidateException("contract type error, expected type " +
132+
"[CancelUnfreezeV2Contract], real type[" + any.getClass() + "]");
133+
}
134+
135+
if (!dynamicStore.supportAllowCancelUnfreezeV2()) {
136+
throw new ContractValidateException("Not support CancelUnfreezeV2 transaction,"
137+
+ " need to be opened by the committee");
138+
}
139+
140+
final CancelUnfreezeV2Contract cancelUnfreezeV2Contract;
141+
byte[] ownerAddress;
142+
try {
143+
cancelUnfreezeV2Contract = getCancelUnfreezeV2Contract();
144+
ownerAddress = getOwnerAddress().toByteArray();
145+
} catch (InvalidProtocolBufferException e) {
146+
logger.debug(e.getMessage(), e);
147+
throw new ContractValidateException(e.getMessage());
148+
}
149+
150+
if (!DecodeUtil.addressValid(ownerAddress)) {
151+
throw new ContractValidateException("Invalid address");
152+
}
153+
AccountCapsule accountCapsule = accountStore.get(ownerAddress);
154+
String readableOwnerAddress = StringUtil.createReadableString(ownerAddress);
155+
if (Objects.isNull(accountCapsule)) {
156+
throw new ContractValidateException(ACCOUNT_EXCEPTION_STR
157+
+ readableOwnerAddress + NOT_EXIST_STR);
158+
}
159+
160+
List<UnFreezeV2> unfrozenV2List = accountCapsule.getUnfrozenV2List();
161+
if (unfrozenV2List.isEmpty()) {
162+
throw new ContractValidateException("No unfreezeV2 list to cancel");
163+
}
164+
165+
List<Integer> indexList = cancelUnfreezeV2Contract.getIndexList();
166+
if (indexList.size() > unfrozenV2List.size()) {
167+
throw new ContractValidateException(
168+
"The size[" + indexList.size() + "] of the index cannot exceed the size["
169+
+ unfrozenV2List.size() + "] of unfreezeV2!");
170+
}
171+
172+
for (Integer i : indexList) {
173+
int maxIndex = unfrozenV2List.size() - 1;
174+
if (i < 0 || i > maxIndex) {
175+
throw new ContractValidateException(
176+
"The input index[" + i + "] cannot be less than 0 and cannot be "
177+
+ "greater than the maximum index[" + maxIndex + "] of unfreezeV2!");
178+
}
179+
}
180+
Set<Integer> set = new HashSet<>();
181+
List<Integer> dps = indexList.stream().filter(n -> !set.add(n)).collect(Collectors.toList());
182+
if (CollectionUtils.isNotEmpty(dps)) {
183+
throw new ContractValidateException("The element" + dps + " in the index list is duplicated");
184+
}
185+
return true;
186+
}
187+
188+
@Override
189+
public ByteString getOwnerAddress() throws InvalidProtocolBufferException {
190+
return getCancelUnfreezeV2Contract().getOwnerAddress();
191+
}
192+
193+
private CancelUnfreezeV2Contract getCancelUnfreezeV2Contract()
194+
throws InvalidProtocolBufferException {
195+
return any.unpack(CancelUnfreezeV2Contract.class);
196+
}
197+
198+
@Override
199+
public long calcFee() {
200+
return 0;
201+
}
202+
203+
public void updateFrozenInfoAndTotalResourceWeight(
204+
AccountCapsule accountCapsule, UnFreezeV2 unFreezeV2,
205+
Triple<AtomicLong, AtomicLong, AtomicLong> triple) {
206+
switch (unFreezeV2.getType()) {
207+
case BANDWIDTH:
208+
long oldNetWeight = accountCapsule.getFrozenV2BalanceWithDelegated(BANDWIDTH) / TRX_PRECISION;
209+
accountCapsule.addFrozenBalanceForBandwidthV2(unFreezeV2.getUnfreezeAmount());
210+
long newNetWeight = accountCapsule.getFrozenV2BalanceWithDelegated(BANDWIDTH) / TRX_PRECISION;
211+
triple.getLeft().addAndGet(newNetWeight - oldNetWeight);
212+
break;
213+
case ENERGY:
214+
long oldEnergyWeight = accountCapsule.getFrozenV2BalanceWithDelegated(ENERGY) / TRX_PRECISION;
215+
accountCapsule.addFrozenBalanceForEnergyV2(unFreezeV2.getUnfreezeAmount());
216+
long newEnergyWeight = accountCapsule.getFrozenV2BalanceWithDelegated(ENERGY) / TRX_PRECISION;
217+
triple.getMiddle().addAndGet(newEnergyWeight - oldEnergyWeight);
218+
break;
219+
case TRON_POWER:
220+
long oldTPWeight = accountCapsule.getTronPowerFrozenV2Balance() / TRX_PRECISION;
221+
accountCapsule.addFrozenForTronPowerV2(unFreezeV2.getUnfreezeAmount());
222+
long newTPWeight = accountCapsule.getTronPowerFrozenV2Balance() / TRX_PRECISION;
223+
triple.getRight().addAndGet(newTPWeight - oldTPWeight);
224+
break;
225+
default:
226+
break;
227+
}
228+
}
229+
}

actuator/src/main/java/org/tron/core/utils/ProposalUtil.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,22 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore,
692692
}
693693
break;
694694
}
695+
case ALLOW_CANCEL_UNFREEZE_V2: {
696+
if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_7_2)) {
697+
throw new ContractValidateException(
698+
"Bad chain parameter id [ALLOW_CANCEL_UNFREEZE_V2]");
699+
}
700+
if (value != 1) {
701+
throw new ContractValidateException(
702+
"This value[ALLOW_CANCEL_UNFREEZE_V2] is only allowed to be 1");
703+
}
704+
if (dynamicPropertiesStore.getUnfreezeDelayDays() == 0) {
705+
throw new ContractValidateException(
706+
"[UNFREEZE_DELAY_DAYS] proposal must be approved "
707+
+ "before [ALLOW_CANCEL_UNFREEZE_V2] can be proposed");
708+
}
709+
break;
710+
}
695711
default:
696712
break;
697713
}
@@ -765,7 +781,8 @@ public enum ProposalType { // current value, value range
765781
DYNAMIC_ENERGY_THRESHOLD(73), // 0, [0, LONG]
766782
DYNAMIC_ENERGY_INCREASE_FACTOR(74), // 0, [0, 10_000]
767783
DYNAMIC_ENERGY_MAX_FACTOR(75), // 0, [0, 100_000]
768-
ALLOW_TVM_SHANGHAI(76); // 0, 1
784+
ALLOW_TVM_SHANGHAI(76), // 0, 1
785+
ALLOW_CANCEL_UNFREEZE_V2(77); // 0, 1
769786

770787
private long code;
771788

chainbase/src/main/java/org/tron/core/capsule/TransactionResultCapsule.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ public void setWithdrawExpireAmount(long amount) {
8989
.setWithdrawExpireAmount(amount).build();
9090
}
9191

92+
public long getCancelUnfreezeV2Amount() {
93+
return transactionResult.getCancelUnfreezeV2Amount();
94+
}
95+
96+
public void setCancelUnfreezeV2Amount(long amount) {
97+
this.transactionResult = this.transactionResult.toBuilder()
98+
.setCancelUnfreezeV2Amount(amount).build();
99+
}
100+
92101
public long getExchangeReceivedAmount() {
93102
return transactionResult.getExchangeReceivedAmount();
94103
}

chainbase/src/main/java/org/tron/core/capsule/utils/TransactionUtil.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public static TransactionInfoCapsule buildTransactionInfoInstance(TransactionCap
100100
builder.setExchangeId(programResult.getRet().getExchangeId());
101101
builder.setWithdrawAmount(programResult.getRet().getWithdrawAmount());
102102
builder.setWithdrawExpireAmount(programResult.getRet().getWithdrawExpireAmount());
103+
builder.setCancelUnfreezeV2Amount(programResult.getRet().getCancelUnfreezeV2Amount());
103104
builder.setExchangeReceivedAmount(programResult.getRet().getExchangeReceivedAmount());
104105
builder.setExchangeInjectAnotherAmount(programResult.getRet().getExchangeInjectAnotherAmount());
105106
builder.setExchangeWithdrawAnotherAmount(

chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import org.tron.common.utils.ByteArray;
1515
import org.tron.common.utils.Sha256Hash;
1616
import org.tron.core.capsule.BytesCapsule;
17-
import org.tron.core.config.Parameter;
1817
import org.tron.core.config.Parameter.ChainConstant;
1918
import org.tron.core.db.TronStoreWithRevoking;
2019
import org.tron.core.exception.BadItemException;
@@ -208,6 +207,9 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking<BytesCapsule>
208207

209208
private static final byte[] ALLOW_TVM_SHANGHAI = "ALLOW_TVM_SHANGHAI".getBytes();
210209

210+
private static final byte[] ALLOW_CANCEL_UNFREEZE_V2 = "ALLOW_CANCEL_UNFREEZE_V2"
211+
.getBytes();
212+
211213
@Autowired
212214
private DynamicPropertiesStore(@Value("properties") String dbName) {
213215
super(dbName);
@@ -2192,7 +2194,7 @@ public long getNextMaintenanceTime() {
21922194
}
21932195

21942196
public long getMaintenanceSkipSlots() {
2195-
return Parameter.ChainConstant.MAINTENANCE_SKIP_SLOTS;
2197+
return ChainConstant.MAINTENANCE_SKIP_SLOTS;
21962198
}
21972199

21982200
public void saveNextMaintenanceTime(long nextMaintenanceTime) {
@@ -2218,6 +2220,9 @@ public void updateNextMaintenanceTime(long blockTime) {
22182220

22192221
//The unit is trx
22202222
public void addTotalNetWeight(long amount) {
2223+
if (amount == 0) {
2224+
return;
2225+
}
22212226
long totalNetWeight = getTotalNetWeight();
22222227
totalNetWeight += amount;
22232228
if (allowNewReward()) {
@@ -2228,6 +2233,9 @@ public void addTotalNetWeight(long amount) {
22282233

22292234
//The unit is trx
22302235
public void addTotalEnergyWeight(long amount) {
2236+
if (amount == 0) {
2237+
return;
2238+
}
22312239
long totalEnergyWeight = getTotalEnergyWeight();
22322240
totalEnergyWeight += amount;
22332241
if (allowNewReward()) {
@@ -2238,6 +2246,9 @@ public void addTotalEnergyWeight(long amount) {
22382246

22392247
//The unit is trx
22402248
public void addTotalTronPowerWeight(long amount) {
2249+
if (amount == 0) {
2250+
return;
2251+
}
22412252
long totalWeight = getTotalTronPowerWeight();
22422253
totalWeight += amount;
22432254
if (allowNewReward()) {
@@ -2769,6 +2780,22 @@ public long getAllowTvmShangHai() {
27692780
.orElse(CommonParameter.getInstance().getAllowTvmShangHai());
27702781
}
27712782

2783+
public void saveAllowCancelUnfreezeV2(long allowCancelUnfreezeV2) {
2784+
this.put(DynamicPropertiesStore.ALLOW_CANCEL_UNFREEZE_V2,
2785+
new BytesCapsule(ByteArray.fromLong(allowCancelUnfreezeV2)));
2786+
}
2787+
2788+
public long getAllowCancelUnfreezeV2() {
2789+
return Optional.ofNullable(getUnchecked(ALLOW_CANCEL_UNFREEZE_V2))
2790+
.map(BytesCapsule::getData)
2791+
.map(ByteArray::toLong)
2792+
.orElse(CommonParameter.getInstance().getAllowCancelUnfreezeV2());
2793+
}
2794+
2795+
public boolean supportAllowCancelUnfreezeV2() {
2796+
return getAllowCancelUnfreezeV2() == 1L && getUnfreezeDelayDays() > 0;
2797+
}
2798+
27722799
private static class DynamicResourceProperties {
27732800

27742801
private static final byte[] ONE_DAY_NET_LIMIT = "ONE_DAY_NET_LIMIT".getBytes();

common/src/main/java/org/tron/common/parameter/CommonParameter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,10 @@ public class CommonParameter {
651651
@Setter
652652
public long allowTvmShangHai;
653653

654+
@Getter
655+
@Setter
656+
public long allowCancelUnfreezeV2;
657+
654658
private static double calcMaxTimeRatio() {
655659
//return max(2.0, min(5.0, 5 * 4.0 / max(Runtime.getRuntime().availableProcessors(), 1)));
656660
return 5.0;

0 commit comments

Comments
 (0)