Skip to content

Commit

Permalink
Merge pull request #4838 from lxcmyf/release_v4.7.0
Browse files Browse the repository at this point in the history
feat(freezeV2): merge feature ‘stake 2.0’ into release v4.7.0
  • Loading branch information
zhang0125 authored Dec 13, 2022
2 parents 9c897cd + 77ab2bb commit 2fe10e3
Show file tree
Hide file tree
Showing 93 changed files with 10,720 additions and 174 deletions.
14 changes: 14 additions & 0 deletions Tron protobuf protocol document.md
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,13 @@ Transaction and transaction-related messages.
ClearABIContract = 48;
UpdateBrokerageContract = 49;
ShieldedTransferContract = 51;
MarketSellAssetContract = 52;
MarketCancelOrderContract = 53;
FreezeBalanceV2Contract = 54;
UnfreezeBalanceV2Contract = 55;
WithdrawExpireUnfreezeContract = 56;
DelegateResourceContract = 57;
UnDelegateResourceContract = 58;
}
ContractType type = 1;
google.protobuf.Any parameter = 2;
Expand Down Expand Up @@ -873,6 +880,13 @@ Contract and contract-related messages.
ClearABIContract = 48;
UpdateBrokerageContract = 49;
ShieldedTransferContract = 51;
MarketSellAssetContract = 52;
MarketCancelOrderContract = 53;
FreezeBalanceV2Contract = 54;
UnfreezeBalanceV2Contract = 55;
WithdrawExpireUnfreezeContract = 56;
DelegateResourceContract = 57;
UnDelegateResourceContract = 58;
}
ContractType type = 1;
google.protobuf.Any parameter = 2;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
package org.tron.core.actuator;

import static org.tron.core.actuator.ActuatorConstant.NOT_EXIST_STR;
import static org.tron.core.config.Parameter.ChainConstant.DELEGATE_PERIOD;
import static org.tron.core.config.Parameter.ChainConstant.TRX_PRECISION;

import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.Arrays;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.tron.common.utils.DecodeUtil;
import org.tron.common.utils.StringUtil;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.DelegatedResourceCapsule;
import org.tron.core.capsule.TransactionResultCapsule;
import org.tron.core.db.BandwidthProcessor;
import org.tron.core.db.EnergyProcessor;
import org.tron.core.exception.ContractExeException;
import org.tron.core.exception.ContractValidateException;
import org.tron.core.store.AccountStore;
import org.tron.core.store.DelegatedResourceAccountIndexStore;
import org.tron.core.store.DelegatedResourceStore;
import org.tron.core.store.DynamicPropertiesStore;
import org.tron.core.utils.TransactionUtil;
import org.tron.protos.Protocol.AccountType;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
import org.tron.protos.Protocol.Transaction.Result.code;
import org.tron.protos.contract.BalanceContract.DelegateResourceContract;

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

public DelegateResourceActuator() {
super(ContractType.DelegateResourceContract, DelegateResourceContract.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();
final DelegateResourceContract delegateResourceContract;
AccountStore accountStore = chainBaseManager.getAccountStore();
try {
delegateResourceContract = any.unpack(DelegateResourceContract.class);
} catch (InvalidProtocolBufferException e) {
logger.debug(e.getMessage(), e);
ret.setStatus(fee, code.FAILED);
throw new ContractExeException(e.getMessage());
}

AccountCapsule ownerCapsule = accountStore
.get(delegateResourceContract.getOwnerAddress().toByteArray());

long delegateBalance = delegateResourceContract.getBalance();
boolean lock = delegateResourceContract.getLock();
byte[] ownerAddress = delegateResourceContract.getOwnerAddress().toByteArray();
byte[] receiverAddress = delegateResourceContract.getReceiverAddress().toByteArray();

// delegate resource to receiver
switch (delegateResourceContract.getResource()) {
case BANDWIDTH:
delegateResource(ownerAddress, receiverAddress, true,
delegateBalance, lock);

ownerCapsule.addDelegatedFrozenV2BalanceForBandwidth(delegateBalance);
ownerCapsule.addFrozenBalanceForBandwidthV2(-delegateBalance);
break;
case ENERGY:
delegateResource(ownerAddress, receiverAddress, false,
delegateBalance, lock);

ownerCapsule.addDelegatedFrozenV2BalanceForEnergy(delegateBalance);
ownerCapsule.addFrozenBalanceForEnergyV2(-delegateBalance);
break;
default:
logger.debug("Resource Code Error.");
}

accountStore.put(ownerCapsule.createDbKey(), ownerCapsule);

ret.setStatus(fee, code.SUCESS);

return true;
}


@Override
public boolean validate() throws ContractValidateException {
if (this.any == null) {
throw new ContractValidateException(ActuatorConstant.CONTRACT_NOT_EXIST);
}
if (chainBaseManager == null) {
throw new ContractValidateException(ActuatorConstant.STORE_NOT_EXIST);
}
AccountStore accountStore = chainBaseManager.getAccountStore();
DynamicPropertiesStore dynamicStore = chainBaseManager.getDynamicPropertiesStore();
if (!any.is(DelegateResourceContract.class)) {
throw new ContractValidateException(
"contract type error,expected type [DelegateResourceContract],real type["
+ any.getClass() + "]");
}

if (!dynamicStore.supportDR()) {
throw new ContractValidateException("No support for resource delegate");
}

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

final DelegateResourceContract delegateResourceContract;
try {
delegateResourceContract = this.any.unpack(DelegateResourceContract.class);
} catch (InvalidProtocolBufferException e) {
logger.debug(e.getMessage(), e);
throw new ContractValidateException(e.getMessage());
}
byte[] ownerAddress = delegateResourceContract.getOwnerAddress().toByteArray();
if (!DecodeUtil.addressValid(ownerAddress)) {
throw new ContractValidateException("Invalid address");
}

AccountCapsule ownerCapsule = accountStore.get(ownerAddress);
if (ownerCapsule == null) {
String readableOwnerAddress = StringUtil.createReadableString(ownerAddress);
throw new ContractValidateException(
ActuatorConstant.ACCOUNT_EXCEPTION_STR + readableOwnerAddress + NOT_EXIST_STR);
}

long delegateBalance = delegateResourceContract.getBalance();
if (delegateBalance < TRX_PRECISION) {
throw new ContractValidateException("delegateBalance must be more than 1TRX");
}

switch (delegateResourceContract.getResource()) {
case BANDWIDTH: {
BandwidthProcessor processor = new BandwidthProcessor(chainBaseManager);
processor.updateUsageForDelegated(ownerCapsule);

long accountNetUsage = ownerCapsule.getNetUsage();
if (null != this.getTx() && this.getTx().isTransactionCreate()) {
accountNetUsage += TransactionUtil.estimateConsumeBandWidthSize(ownerCapsule,
chainBaseManager);
}
long netUsage = (long) (accountNetUsage * TRX_PRECISION * ((double)
(dynamicStore.getTotalNetWeight()) / dynamicStore.getTotalNetLimit()));

long remainNetUsage = netUsage
- ownerCapsule.getFrozenBalance()
- ownerCapsule.getAcquiredDelegatedFrozenBalanceForBandwidth()
- ownerCapsule.getAcquiredDelegatedFrozenV2BalanceForBandwidth();

remainNetUsage = Math.max(0, remainNetUsage);

if (ownerCapsule.getFrozenV2BalanceForBandwidth() - remainNetUsage < delegateBalance) {
throw new ContractValidateException(
"delegateBalance must be less than available FreezeBandwidthV2 balance");
}
}
break;
case ENERGY: {
EnergyProcessor processor = new EnergyProcessor(dynamicStore, accountStore);
processor.updateUsage(ownerCapsule);

long energyUsage = (long) (ownerCapsule.getEnergyUsage() * TRX_PRECISION * ((double)
(dynamicStore.getTotalEnergyWeight()) / dynamicStore.getTotalEnergyCurrentLimit()));

long remainEnergyUsage = energyUsage
- ownerCapsule.getEnergyFrozenBalance()
- ownerCapsule.getAcquiredDelegatedFrozenBalanceForEnergy()
- ownerCapsule.getAcquiredDelegatedFrozenV2BalanceForEnergy();

remainEnergyUsage = Math.max(0, remainEnergyUsage);

if (ownerCapsule.getFrozenV2BalanceForEnergy() - remainEnergyUsage < delegateBalance) {
throw new ContractValidateException(
"delegateBalance must be less than available FreezeEnergyV2 balance");
}
}
break;
default:
throw new ContractValidateException(
"ResourceCode error, valid ResourceCode[BANDWIDTH、ENERGY]");
}

byte[] receiverAddress = delegateResourceContract.getReceiverAddress().toByteArray();

if (ArrayUtils.isEmpty(receiverAddress) || !DecodeUtil.addressValid(receiverAddress)) {
throw new ContractValidateException("Invalid receiverAddress");
}


if (Arrays.equals(receiverAddress, ownerAddress)) {
throw new ContractValidateException(
"receiverAddress must not be the same as ownerAddress");
}

AccountCapsule receiverCapsule = accountStore.get(receiverAddress);
if (receiverCapsule == null) {
String readableOwnerAddress = StringUtil.createReadableString(receiverAddress);
throw new ContractValidateException(
ActuatorConstant.ACCOUNT_EXCEPTION_STR
+ readableOwnerAddress + NOT_EXIST_STR);
}

if (receiverCapsule.getType() == AccountType.Contract) {
throw new ContractValidateException(
"Do not allow delegate resources to contract addresses");
}

return true;
}

@Override
public ByteString getOwnerAddress() throws InvalidProtocolBufferException {
return any.unpack(DelegateResourceContract.class).getOwnerAddress();
}

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

private void delegateResource(byte[] ownerAddress, byte[] receiverAddress, boolean isBandwidth,
long balance, boolean lock) {
AccountStore accountStore = chainBaseManager.getAccountStore();
DynamicPropertiesStore dynamicPropertiesStore = chainBaseManager.getDynamicPropertiesStore();
DelegatedResourceStore delegatedResourceStore = chainBaseManager.getDelegatedResourceStore();
DelegatedResourceAccountIndexStore delegatedResourceAccountIndexStore = chainBaseManager
.getDelegatedResourceAccountIndexStore();

// 1. unlock the expired delegate resource
long now = chainBaseManager.getDynamicPropertiesStore().getLatestBlockHeaderTimestamp();
delegatedResourceStore.unLockExpireResource(ownerAddress, receiverAddress, now);

//modify DelegatedResourceStore
byte[] key;
long expireTime = 0;
if (lock) {
expireTime = now + DELEGATE_PERIOD;
}
key = DelegatedResourceCapsule.createDbKeyV2(ownerAddress, receiverAddress, lock);
DelegatedResourceCapsule delegatedResourceCapsule = delegatedResourceStore.get(key);
if (delegatedResourceCapsule == null) {
delegatedResourceCapsule = new DelegatedResourceCapsule(ByteString.copyFrom(ownerAddress),
ByteString.copyFrom(receiverAddress));
}

if (isBandwidth) {
delegatedResourceCapsule.addFrozenBalanceForBandwidth(balance, expireTime);
} else {
delegatedResourceCapsule.addFrozenBalanceForEnergy(balance, expireTime);
}
delegatedResourceStore.put(key, delegatedResourceCapsule);

//modify DelegatedResourceAccountIndexStore
delegatedResourceAccountIndexStore.delegateV2(ownerAddress, receiverAddress,
dynamicPropertiesStore.getLatestBlockHeaderTimestamp());

//modify AccountStore for receiver
AccountCapsule receiverCapsule = accountStore.get(receiverAddress);
if (isBandwidth) {
receiverCapsule.addAcquiredDelegatedFrozenV2BalanceForBandwidth(balance);
} else {
receiverCapsule.addAcquiredDelegatedFrozenV2BalanceForEnergy(balance);
}
accountStore.put(receiverCapsule.createDbKey(), receiverCapsule);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,7 @@ public boolean validate() throws ContractValidateException {
//If the receiver is included in the contract, the receiver will receive the resource.
if (!ArrayUtils.isEmpty(receiverAddress) && dynamicStore.supportDR()) {
if (Arrays.equals(receiverAddress, ownerAddress)) {
throw new ContractValidateException(
"receiverAddress must not be the same as ownerAddress");
throw new ContractValidateException("receiverAddress must not be the same as ownerAddress");
}

if (!DecodeUtil.addressValid(receiverAddress)) {
Expand All @@ -269,6 +268,11 @@ public boolean validate() throws ContractValidateException {

}

if (dynamicStore.supportUnfreezeDelay()) {
throw new ContractValidateException(
"freeze v2 is open, old freeze is closed");
}

return true;
}

Expand Down
Loading

0 comments on commit 2fe10e3

Please sign in to comment.