-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4838 from lxcmyf/release_v4.7.0
feat(freezeV2): merge feature ‘stake 2.0’ into release v4.7.0
- Loading branch information
Showing
93 changed files
with
10,720 additions
and
174 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
277 changes: 277 additions & 0 deletions
277
actuator/src/main/java/org/tron/core/actuator/DelegateResourceActuator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.