Skip to content

Commit b53576c

Browse files
committed
feat(freezeV2): add cancel unfreezeV2 interface
1 parent dcf8982 commit b53576c

27 files changed

Lines changed: 695 additions & 34 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;

actuator/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description = "actuator – a series of transactions for blockchain."
33
// Dependency versions
44
// ---------------------------------------
55

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

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/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description = "chainbase – a decentralized database for blockchain."
33
// Dependency versions
44
// ---------------------------------------
55

6-
def junitVersion = "4.12"
6+
def junitVersion = "4.13.2"
77
def mockitoVersion = "2.1.0"
88
def testNgVersion = "6.11"
99
def jacocoVersion = "0.8.0"

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(

0 commit comments

Comments
 (0)