Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Tron protobuf protocol document.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ Transaction and transaction-related messages.
WithdrawExpireUnfreezeContract = 56;
DelegateResourceContract = 57;
UnDelegateResourceContract = 58;
CancelUnfreezeV2Contract = 59;
}
ContractType type = 1;
google.protobuf.Any parameter = 2;
Expand Down Expand Up @@ -887,6 +888,7 @@ Contract and contract-related messages.
WithdrawExpireUnfreezeContract = 56;
DelegateResourceContract = 57;
UnDelegateResourceContract = 58;
CancelUnfreezeV2Contract = 59;
}
ContractType type = 1;
google.protobuf.Any parameter = 2;
Expand Down
2 changes: 1 addition & 1 deletion actuator/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description = "actuator – a series of transactions for blockchain."
// Dependency versions
// ---------------------------------------

def junitVersion = "4.12"
def junitVersion = "4.13.2"
def mockitoVersion = "2.1.0"
def testNgVersion = "6.11"
def slf4jVersion = "1.7.25"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
package org.tron.core.actuator;

import static org.tron.core.actuator.ActuatorConstant.ACCOUNT_EXCEPTION_STR;
import static org.tron.core.actuator.ActuatorConstant.NOT_EXIST_STR;
import static org.tron.core.config.Parameter.ChainConstant.TRX_PRECISION;
import static org.tron.protos.contract.Common.ResourceCode.BANDWIDTH;
import static org.tron.protos.contract.Common.ResourceCode.ENERGY;

import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.tron.common.utils.DecodeUtil;
import org.tron.common.utils.StringUtil;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.TransactionResultCapsule;
import org.tron.core.exception.ContractExeException;
import org.tron.core.exception.ContractValidateException;
import org.tron.core.store.AccountStore;
import org.tron.core.store.DynamicPropertiesStore;
import org.tron.protos.Protocol.Account.UnFreezeV2;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
import org.tron.protos.Protocol.Transaction.Result.code;
import org.tron.protos.contract.BalanceContract.CancelUnfreezeV2Contract;

@Slf4j(topic = "actuator")
public class CancelUnfreezeV2Actuator extends AbstractActuator {

public CancelUnfreezeV2Actuator() {
super(ContractType.CancelUnfreezeV2Contract, CancelUnfreezeV2Contract.class);
}

@Override
public boolean execute(Object result) throws ContractExeException {
TransactionResultCapsule ret = (TransactionResultCapsule) result;
if (Objects.isNull(ret)) {
throw new RuntimeException(ActuatorConstant.TX_RESULT_NULL);
}
long fee = calcFee();
AccountStore accountStore = chainBaseManager.getAccountStore();
DynamicPropertiesStore dynamicStore = chainBaseManager.getDynamicPropertiesStore();
final CancelUnfreezeV2Contract cancelUnfreezeV2Contract;
byte[] ownerAddress;
try {
cancelUnfreezeV2Contract = getCancelUnfreezeV2Contract();
ownerAddress = getOwnerAddress().toByteArray();
} catch (InvalidProtocolBufferException e) {
logger.debug(e.getMessage(), e);
ret.setStatus(fee, code.FAILED);
throw new ContractExeException(e.getMessage());
}
List<Integer> indexList = cancelUnfreezeV2Contract.getIndexList()
.stream().sorted().collect(Collectors.toList());
AccountCapsule ownerCapsule = accountStore.get(ownerAddress);
List<UnFreezeV2> unfrozenV2List = ownerCapsule.getUnfrozenV2List();
long now = dynamicStore.getLatestBlockHeaderTimestamp();
AtomicLong atomicWithdrawExpireBalance = new AtomicLong(0L);
AtomicLong atomicCancelBalance = new AtomicLong(0L);
Triple<AtomicLong, AtomicLong, AtomicLong> triple =
Triple.of(new AtomicLong(0L), new AtomicLong(0L), new AtomicLong(0L));
List<UnFreezeV2> newUnFreezeV2List = null;
if (indexList.isEmpty()) {
for (UnFreezeV2 unFreezeV2 : unfrozenV2List) {
updateAndCalculate(triple, ownerCapsule, now, atomicWithdrawExpireBalance,
atomicCancelBalance, unFreezeV2);
}
} else {
indexList.forEach(index -> {
UnFreezeV2 unFreezeV2 = unfrozenV2List.get(index);
updateAndCalculate(triple, ownerCapsule, now, atomicWithdrawExpireBalance,
atomicCancelBalance, unFreezeV2);
});
newUnFreezeV2List = unfrozenV2List.stream()
.filter(o -> !indexList.contains(unfrozenV2List.indexOf(o))).collect(Collectors.toList());
}
ownerCapsule.clearUnfrozenV2();
ownerCapsule.addAllUnfrozenV2(newUnFreezeV2List);
addTotalResourceWeight(dynamicStore, triple);

long withdrawExpireBalance = atomicWithdrawExpireBalance.get();
if (withdrawExpireBalance > 0) {
ownerCapsule.setBalance(ownerCapsule.getBalance() + withdrawExpireBalance);
}

accountStore.put(ownerCapsule.createDbKey(), ownerCapsule);
ret.setWithdrawExpireAmount(withdrawExpireBalance);
ret.setCancelUnfreezeV2Amount(atomicCancelBalance.get());
ret.setStatus(fee, code.SUCESS);
return true;
}

private void addTotalResourceWeight(DynamicPropertiesStore dynamicStore,
Triple<AtomicLong, AtomicLong, AtomicLong> triple) {
dynamicStore.addTotalNetWeight(triple.getLeft().get());
dynamicStore.addTotalEnergyWeight(triple.getMiddle().get());
dynamicStore.addTotalTronPowerWeight(triple.getRight().get());
}

private void updateAndCalculate(Triple<AtomicLong, AtomicLong, AtomicLong> triple,
AccountCapsule ownerCapsule, long now, AtomicLong atomicLong, AtomicLong cancelBalance,
UnFreezeV2 unFreezeV2) {
if (unFreezeV2.getUnfreezeExpireTime() > now) {
updateFrozenInfoAndTotalResourceWeight(ownerCapsule, unFreezeV2, triple);
cancelBalance.addAndGet(unFreezeV2.getUnfreezeAmount());
} else {
atomicLong.addAndGet(unFreezeV2.getUnfreezeAmount());
}
}

@Override
public boolean validate() throws ContractValidateException {
if (Objects.isNull(this.any)) {
throw new ContractValidateException(ActuatorConstant.CONTRACT_NOT_EXIST);
}

if (Objects.isNull(chainBaseManager)) {
throw new ContractValidateException(ActuatorConstant.STORE_NOT_EXIST);
}

AccountStore accountStore = chainBaseManager.getAccountStore();
DynamicPropertiesStore dynamicStore = chainBaseManager.getDynamicPropertiesStore();

if (!this.any.is(CancelUnfreezeV2Contract.class)) {
throw new ContractValidateException("contract type error, expected type " +
"[CancelUnfreezeV2Contract], real type[" + any.getClass() + "]");
}

if (!dynamicStore.supportAllowCancelUnfreezeV2()) {
throw new ContractValidateException("Not support CancelUnfreezeV2 transaction,"
+ " need to be opened by the committee");
}

final CancelUnfreezeV2Contract cancelUnfreezeV2Contract;
byte[] ownerAddress;
try {
cancelUnfreezeV2Contract = getCancelUnfreezeV2Contract();
ownerAddress = getOwnerAddress().toByteArray();
} catch (InvalidProtocolBufferException e) {
logger.debug(e.getMessage(), e);
throw new ContractValidateException(e.getMessage());
}

if (!DecodeUtil.addressValid(ownerAddress)) {
throw new ContractValidateException("Invalid address");
}
AccountCapsule accountCapsule = accountStore.get(ownerAddress);
String readableOwnerAddress = StringUtil.createReadableString(ownerAddress);
if (Objects.isNull(accountCapsule)) {
throw new ContractValidateException(ACCOUNT_EXCEPTION_STR
+ readableOwnerAddress + NOT_EXIST_STR);
}

List<UnFreezeV2> unfrozenV2List = accountCapsule.getUnfrozenV2List();
if (unfrozenV2List.isEmpty()) {
throw new ContractValidateException("No unfreezeV2 list to cancel");
}

List<Integer> indexList = cancelUnfreezeV2Contract.getIndexList();
if (indexList.size() > unfrozenV2List.size()) {
throw new ContractValidateException(
"The size[" + indexList.size() + "] of the index cannot exceed the size["
+ unfrozenV2List.size() + "] of unfreezeV2!");
}

for (Integer i : indexList) {
int maxIndex = unfrozenV2List.size() - 1;
if (i < 0 || i > maxIndex) {
throw new ContractValidateException(
"The input index[" + i + "] cannot be less than 0 and cannot be "
+ "greater than the maximum index[" + maxIndex + "] of unfreezeV2!");
}
}
Set<Integer> set = new HashSet<>();
List<Integer> dps = indexList.stream().filter(n -> !set.add(n)).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(dps)) {
throw new ContractValidateException("The element" + dps + " in the index list is duplicated");
}
return true;
}

@Override
public ByteString getOwnerAddress() throws InvalidProtocolBufferException {
return getCancelUnfreezeV2Contract().getOwnerAddress();
}

private CancelUnfreezeV2Contract getCancelUnfreezeV2Contract()
throws InvalidProtocolBufferException {
return any.unpack(CancelUnfreezeV2Contract.class);
}

@Override
public long calcFee() {
return 0;
}

public void updateFrozenInfoAndTotalResourceWeight(
AccountCapsule accountCapsule, UnFreezeV2 unFreezeV2,
Triple<AtomicLong, AtomicLong, AtomicLong> triple) {
switch (unFreezeV2.getType()) {
case BANDWIDTH:
long oldNetWeight = accountCapsule.getFrozenV2BalanceWithDelegated(BANDWIDTH) / TRX_PRECISION;
accountCapsule.addFrozenBalanceForBandwidthV2(unFreezeV2.getUnfreezeAmount());
long newNetWeight = accountCapsule.getFrozenV2BalanceWithDelegated(BANDWIDTH) / TRX_PRECISION;
triple.getLeft().addAndGet(newNetWeight - oldNetWeight);
break;
case ENERGY:
long oldEnergyWeight = accountCapsule.getFrozenV2BalanceWithDelegated(ENERGY) / TRX_PRECISION;
accountCapsule.addFrozenBalanceForEnergyV2(unFreezeV2.getUnfreezeAmount());
long newEnergyWeight = accountCapsule.getFrozenV2BalanceWithDelegated(ENERGY) / TRX_PRECISION;
triple.getMiddle().addAndGet(newEnergyWeight - oldEnergyWeight);
break;
case TRON_POWER:
long oldTPWeight = accountCapsule.getTronPowerFrozenV2Balance() / TRX_PRECISION;
accountCapsule.addFrozenForTronPowerV2(unFreezeV2.getUnfreezeAmount());
long newTPWeight = accountCapsule.getTronPowerFrozenV2Balance() / TRX_PRECISION;
triple.getRight().addAndGet(newTPWeight - oldTPWeight);
break;
default:
break;
}
}
}
19 changes: 18 additions & 1 deletion actuator/src/main/java/org/tron/core/utils/ProposalUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,22 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore,
}
break;
}
case ALLOW_CANCEL_UNFREEZE_V2: {
if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_7_2)) {
throw new ContractValidateException(
"Bad chain parameter id [ALLOW_CANCEL_UNFREEZE_V2]");
}
if (value != 1) {
throw new ContractValidateException(
"This value[ALLOW_CANCEL_UNFREEZE_V2] is only allowed to be 1");
}
if (dynamicPropertiesStore.getUnfreezeDelayDays() == 0) {
throw new ContractValidateException(
"[UNFREEZE_DELAY_DAYS] proposal must be approved "
+ "before [ALLOW_CANCEL_UNFREEZE_V2] can be proposed");
}
break;
}
default:
break;
}
Expand Down Expand Up @@ -765,7 +781,8 @@ public enum ProposalType { // current value, value range
DYNAMIC_ENERGY_THRESHOLD(73), // 0, [0, LONG]
DYNAMIC_ENERGY_INCREASE_FACTOR(74), // 0, [0, 10_000]
DYNAMIC_ENERGY_MAX_FACTOR(75), // 0, [0, 100_000]
ALLOW_TVM_SHANGHAI(76); // 0, 1
ALLOW_TVM_SHANGHAI(76), // 0, 1
ALLOW_CANCEL_UNFREEZE_V2(77); // 0, 1

private long code;

Expand Down
2 changes: 1 addition & 1 deletion chainbase/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description = "chainbase – a decentralized database for blockchain."
// Dependency versions
// ---------------------------------------

def junitVersion = "4.12"
def junitVersion = "4.13.2"
def mockitoVersion = "2.1.0"
def testNgVersion = "6.11"
def jacocoVersion = "0.8.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ public void setWithdrawExpireAmount(long amount) {
.setWithdrawExpireAmount(amount).build();
}

public long getCancelUnfreezeV2Amount() {
return transactionResult.getCancelUnfreezeV2Amount();
}

public void setCancelUnfreezeV2Amount(long amount) {
this.transactionResult = this.transactionResult.toBuilder()
.setCancelUnfreezeV2Amount(amount).build();
}

public long getExchangeReceivedAmount() {
return transactionResult.getExchangeReceivedAmount();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public static TransactionInfoCapsule buildTransactionInfoInstance(TransactionCap
builder.setExchangeId(programResult.getRet().getExchangeId());
builder.setWithdrawAmount(programResult.getRet().getWithdrawAmount());
builder.setWithdrawExpireAmount(programResult.getRet().getWithdrawExpireAmount());
builder.setCancelUnfreezeV2Amount(programResult.getRet().getCancelUnfreezeV2Amount());
builder.setExchangeReceivedAmount(programResult.getRet().getExchangeReceivedAmount());
builder.setExchangeInjectAnotherAmount(programResult.getRet().getExchangeInjectAnotherAmount());
builder.setExchangeWithdrawAnotherAmount(
Expand Down
Loading