Skip to content

Commit feb4087

Browse files
author
ramonliu
committed
feat(tvm): tip-6780: selfdestruct in same transaction
1 parent 15e8c0e commit feb4087

File tree

19 files changed

+317
-3
lines changed

19 files changed

+317
-3
lines changed

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,21 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore,
839839
}
840840
break;
841841
}
842+
case ALLOW_TVM_SELFDESTRUCT_RESTRICTION: {
843+
if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_8_1)) {
844+
throw new ContractValidateException(
845+
"Bad chain parameter id [ALLOW_TVM_SELFDESTRUCT_RESTRICTION]");
846+
}
847+
if (dynamicPropertiesStore.allowTvmSelfdestructRestriction()) {
848+
throw new ContractValidateException(
849+
"[ALLOW_TVM_SELFDESTRUCT_RESTRICTION] has been valid, no need to propose again");
850+
}
851+
if (value != 1) {
852+
throw new ContractValidateException(
853+
"This value[ALLOW_TVM_SELFDESTRUCT_RESTRICTION] is only allowed to be 1");
854+
}
855+
break;
856+
}
842857
default:
843858
break;
844859
}
@@ -921,7 +936,8 @@ public enum ProposalType { // current value, value range
921936
ALLOW_TVM_CANCUN(83), // 0, 1
922937
ALLOW_STRICT_MATH(87), // 0, 1
923938
CONSENSUS_LOGIC_OPTIMIZATION(88), // 0, 1
924-
ALLOW_TVM_BLOB(89); // 0, 1
939+
ALLOW_TVM_BLOB(89), // 0, 1
940+
ALLOW_TVM_SELFDESTRUCT_RESTRICTION(94); // 0, 1
925941

926942
private long code;
927943

actuator/src/main/java/org/tron/core/vm/EnergyCost.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public class EnergyCost {
5555
private static final long EXT_CODE_SIZE = 20;
5656
private static final long EXT_CODE_HASH = 400;
5757
private static final long SUICIDE = 0;
58+
private static final long SUICIDE_V2 = 5000;
5859
private static final long STOP = 0;
5960
private static final long CREATE_DATA = 200;
6061
private static final long TLOAD = 100;
@@ -289,6 +290,14 @@ public static long getSuicideCost2(Program program) {
289290
return getSuicideCost(program);
290291
}
291292

293+
public static long getSuicideCost3(Program program) {
294+
DataWord inheritorAddress = program.getStack().peek();
295+
if (isDeadAccount(program, inheritorAddress)) {
296+
return SUICIDE_V2 + NEW_ACCT_CALL;
297+
}
298+
return SUICIDE_V2;
299+
}
300+
292301
public static long getBalanceCost(Program ignored) {
293302
return BALANCE;
294303
}

actuator/src/main/java/org/tron/core/vm/OperationActions.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,4 +1072,19 @@ public static void suicideAction(Program program) {
10721072
program.stop();
10731073
}
10741074

1075+
public static void suicideAction2(Program program) {
1076+
if (program.isStaticCall()) {
1077+
throw new Program.StaticCallModificationException();
1078+
}
1079+
1080+
if (!program.canSuicide()) {
1081+
program.getResult().setRevert();
1082+
} else {
1083+
DataWord address = program.stackPop();
1084+
program.suicide2(address);
1085+
}
1086+
1087+
program.stop();
1088+
}
1089+
10751090
}

actuator/src/main/java/org/tron/core/vm/OperationRegistry.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ public static JumpTable getTable() {
7979
adjustForFairEnergy(table);
8080
}
8181

82+
if (VMConfig.allowTvmSelfdestructRestriction()) {
83+
adjustSelfdestruct(table);
84+
}
85+
8286
return table;
8387
}
8488

@@ -695,4 +699,11 @@ public static void appendCancunOperations(JumpTable table) {
695699
OperationActions::blobBaseFeeAction,
696700
tvmBlobProposal));
697701
}
702+
703+
public static void adjustSelfdestruct(JumpTable table) {
704+
table.set(new Operation(
705+
Op.SUICIDE, 1, 0,
706+
EnergyCost::getSuicideCost3,
707+
OperationActions::suicideAction2));
708+
}
698709
}

actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public static void load(StoreFactory storeFactory) {
4444
VMConfig.initAllowTvmCancun(ds.getAllowTvmCancun());
4545
VMConfig.initDisableJavaLangMath(ds.getConsensusLogicOptimization());
4646
VMConfig.initAllowTvmBlob(ds.getAllowTvmBlob());
47+
VMConfig.initAllowTvmSelfdestructRestriction(ds.getAllowTvmSelfdestructRestriction());
4748
}
4849
}
4950
}

actuator/src/main/java/org/tron/core/vm/program/ContractState.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,16 @@ public void updateContractState(byte[] address, ContractStateCapsule contractSta
121121
repository.updateContractState(address, contractStateCapsule);
122122
}
123123

124+
@Override
125+
public void putNewContract(byte[] address) {
126+
repository.putNewContract(address);
127+
}
128+
129+
@Override
130+
public boolean isNewContract(byte[] address) {
131+
return repository.isNewContract(address);
132+
}
133+
124134
@Override
125135
public void updateAccount(byte[] address, AccountCapsule accountCapsule) {
126136
repository.updateAccount(address, accountCapsule);

actuator/src/main/java/org/tron/core/vm/program/Program.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,72 @@ public void suicide(DataWord obtainerAddress) {
515515
getResult().addDeleteAccount(this.getContractAddress());
516516
}
517517

518+
public void suicide2(DataWord obtainerAddress) {
519+
520+
byte[] owner = getContextAddress();
521+
boolean isNewContract = getContractState().isNewContract(owner);
522+
if (isNewContract) {
523+
suicide(obtainerAddress);
524+
return;
525+
}
526+
527+
byte[] obtainer = obtainerAddress.toTronAddress();
528+
529+
long balance = getContractState().getBalance(owner);
530+
531+
if (logger.isDebugEnabled()) {
532+
logger.debug("Transfer to: [{}] heritage: [{}]",
533+
Hex.toHexString(obtainer),
534+
balance);
535+
}
536+
537+
increaseNonce();
538+
539+
InternalTransaction internalTx = addInternalTx(null, owner, obtainer, balance, null,
540+
"suicide", nonce, getContractState().getAccount(owner).getAssetMapV2());
541+
542+
if (FastByteComparisons.isEqual(owner, obtainer)) {
543+
return;
544+
}
545+
546+
if (VMConfig.allowTvmVote()) {
547+
withdrawRewardAndCancelVote(owner, getContractState());
548+
balance = getContractState().getBalance(owner);
549+
if (internalTx != null && balance != internalTx.getValue()) {
550+
internalTx.setValue(balance);
551+
}
552+
}
553+
554+
// transfer balance and trc10
555+
createAccountIfNotExist(getContractState(), obtainer);
556+
try {
557+
MUtil.transfer(getContractState(), owner, obtainer, balance);
558+
if (VMConfig.allowTvmTransferTrc10()) {
559+
MUtil.transferAllToken(getContractState(), owner, obtainer);
560+
}
561+
} catch (ContractValidateException e) {
562+
if (VMConfig.allowTvmConstantinople()) {
563+
throw new TransferException(
564+
"transfer all token or transfer all trx failed in suicide: %s", e.getMessage());
565+
}
566+
throw new BytecodeExecutionException("transfer failure");
567+
}
568+
569+
// transfer freeze
570+
if (VMConfig.allowTvmFreeze()) {
571+
transferDelegatedResourceToInheritor(owner, obtainer, getContractState());
572+
}
573+
574+
// transfer freezeV2
575+
if (VMConfig.allowTvmFreezeV2()) {
576+
long expireUnfrozenBalance =
577+
transferFrozenV2BalanceToInheritor(owner, obtainer, getContractState());
578+
if (expireUnfrozenBalance > 0 && internalTx != null) {
579+
internalTx.setValue(internalTx.getValue() + expireUnfrozenBalance);
580+
}
581+
}
582+
}
583+
518584
public Repository getContractState() {
519585
return this.contractState;
520586
}

actuator/src/main/java/org/tron/core/vm/repository/Repository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ public interface Repository {
5555

5656
void updateContractState(byte[] address, ContractStateCapsule contractStateCapsule);
5757

58+
void putNewContract(byte[] address);
59+
60+
boolean isNewContract(byte[] address);
61+
5862
void updateAccount(byte[] address, AccountCapsule accountCapsule);
5963

6064
void updateDynamicProperty(byte[] word, BytesCapsule bytesCapsule);

actuator/src/main/java/org/tron/core/vm/repository/RepositoryImpl.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.google.common.collect.HashBasedTable;
1010
import com.google.protobuf.ByteString;
1111
import java.util.HashMap;
12+
import java.util.HashSet;
1213
import java.util.Optional;
1314
import lombok.Getter;
1415
import lombok.extern.slf4j.Slf4j;
@@ -135,6 +136,7 @@ public class RepositoryImpl implements Repository {
135136
private final HashMap<Key, Value<byte[]>> delegationCache = new HashMap<>();
136137
private final HashMap<Key, Value<DelegatedResourceAccountIndex>> delegatedResourceAccountIndexCache = new HashMap<>();
137138
private final HashBasedTable<Key, Key, Value<byte[]>> transientStorage = HashBasedTable.create();
139+
private final HashSet<Key> newContractCache = new HashSet<>();
138140

139141
public static void removeLruCache(byte[] address) {
140142
}
@@ -479,6 +481,7 @@ public void deleteContract(byte[] address) {
479481
public void createContract(byte[] address, ContractCapsule contractCapsule) {
480482
contractCache.put(Key.create(address),
481483
Value.create(contractCapsule, Type.CREATE));
484+
putNewContract(address);
482485
}
483486

484487
@Override
@@ -533,6 +536,29 @@ public void updateContractState(byte[] address, ContractStateCapsule contractSta
533536
Value.create(contractStateCapsule, Type.DIRTY));
534537
}
535538

539+
@Override
540+
public void putNewContract(byte[] address) {
541+
newContractCache.add(Key.create(address));
542+
}
543+
544+
@Override
545+
public boolean isNewContract(byte[] address) {
546+
Key key = Key.create(address);
547+
if (newContractCache.contains(key)) {
548+
return true;
549+
}
550+
551+
if (parent != null) {
552+
boolean isNew = parent.isNewContract(address);
553+
if (isNew) {
554+
newContractCache.add(key);
555+
}
556+
return isNew;
557+
} else {
558+
return false;
559+
}
560+
}
561+
536562
@Override
537563
public void updateAccount(byte[] address, AccountCapsule accountCapsule) {
538564
accountCache.put(Key.create(address),
@@ -740,6 +766,7 @@ public void commit() {
740766
commitDelegationCache(repository);
741767
commitDelegatedResourceAccountIndexCache(repository);
742768
commitTransientStorage(repository);
769+
commitNewContractCache(repository);
743770
}
744771

745772
@Override
@@ -1060,6 +1087,12 @@ public void commitTransientStorage(Repository deposit) {
10601087
}
10611088
}
10621089

1090+
public void commitNewContractCache(Repository deposit) {
1091+
if (deposit != null) {
1092+
newContractCache.forEach(key -> deposit.putNewContract(key.getData()));
1093+
}
1094+
}
1095+
10631096
/**
10641097
* Get the block id from the number.
10651098
*/

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking<BytesCapsule>
232232

233233
private static final byte[] ALLOW_TVM_BLOB = "ALLOW_TVM_BLOB".getBytes();
234234

235+
private static final byte[] ALLOW_TVM_SELFDESTRUCT_RESTRICTION =
236+
"ALLOW_TVM_SELFDESTRUCT_RESTRICTION".getBytes();
237+
235238
@Autowired
236239
private DynamicPropertiesStore(@Value("properties") String dbName) {
237240
super(dbName);
@@ -2946,6 +2949,21 @@ public long getAllowTvmBlob() {
29462949
.orElse(CommonParameter.getInstance().getAllowTvmBlob());
29472950
}
29482951

2952+
public long getAllowTvmSelfdestructRestriction() {
2953+
return Optional.ofNullable(getUnchecked(ALLOW_TVM_SELFDESTRUCT_RESTRICTION))
2954+
.map(BytesCapsule::getData)
2955+
.map(ByteArray::toLong)
2956+
.orElse(CommonParameter.getInstance().getAllowTvmSelfdestructRestriction());
2957+
}
2958+
2959+
public void saveAllowTvmSelfdestructRestriction(long value) {
2960+
this.put(ALLOW_TVM_SELFDESTRUCT_RESTRICTION, new BytesCapsule(ByteArray.fromLong(value)));
2961+
}
2962+
2963+
public boolean allowTvmSelfdestructRestriction() {
2964+
return getAllowTvmSelfdestructRestriction() == 1L;
2965+
}
2966+
29492967
private static class DynamicResourceProperties {
29502968

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

0 commit comments

Comments
 (0)