From ecdae3a222b82ba401fcad1e8984ac84180a0a91 Mon Sep 17 00:00:00 2001 From: Liulei Date: Wed, 26 Jun 2024 15:11:30 +0800 Subject: [PATCH 1/3] feat(tvm): cancun opcodes TLOAD, TSORE, MCOPY --- .../org/tron/core/utils/ProposalUtil.java | 18 ++++++- .../java/org/tron/core/vm/EnergyCost.java | 22 +++++++++ .../src/main/java/org/tron/core/vm/Op.java | 6 +++ .../org/tron/core/vm/OperationActions.java | 31 ++++++++++++ .../org/tron/core/vm/OperationRegistry.java | 32 ++++++++++++- .../org/tron/core/vm/config/ConfigLoader.java | 1 + .../org/tron/core/vm/config/VMConfig.java | 10 ++++ .../tron/core/vm/program/ContractState.java | 15 ++++++ .../java/org/tron/core/vm/program/Memory.java | 8 ++++ .../org/tron/core/vm/program/Program.java | 4 ++ .../tron/core/vm/repository/Repository.java | 6 +++ .../core/vm/repository/RepositoryImpl.java | 45 ++++++++++++++++++ .../core/store/DynamicPropertiesStore.java | 14 ++++++ .../common/parameter/CommonParameter.java | 4 ++ .../src/main/java/org/tron/core/Constant.java | 2 + .../src/main/java/org/tron/core/Wallet.java | 5 ++ .../java/org/tron/core/config/args/Args.java | 5 ++ .../tron/core/consensus/ProposalService.java | 4 ++ .../common/runtime/vm/OperationsTest.java | 47 +++++++++++++++++++ 19 files changed, 277 insertions(+), 2 deletions(-) diff --git a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java index 8f3501442f0..f60c11fd016 100644 --- a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java @@ -779,6 +779,21 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, } break; } + case ALLOW_TVM_CANCUN: { + if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_7_5)) { + throw new ContractValidateException( + "Bad chain parameter id [ALLOW_TVM_CANCUN]"); + } + if (dynamicPropertiesStore.getAllowTvmCancun() == 1) { + throw new ContractValidateException( + "[ALLOW_TVM_CANCUN] has been valid, no need to propose again"); + } + if (value != 1) { + throw new ContractValidateException( + "This value[ALLOW_TVM_CANCUN] is only allowed to be 1"); + } + break; + } default: break; } @@ -857,7 +872,8 @@ public enum ProposalType { // current value, value range MAX_DELEGATE_LOCK_PERIOD(78), // (86400, 10512000] ALLOW_OLD_REWARD_OPT(79), // 0, 1 ALLOW_ENERGY_ADJUSTMENT(81), // 0, 1 - MAX_CREATE_ACCOUNT_TX_SIZE(82); // [500, 10000] + MAX_CREATE_ACCOUNT_TX_SIZE(82), // [500, 10000] + ALLOW_TVM_CANCUN(83); // 0, 1 private long code; diff --git a/actuator/src/main/java/org/tron/core/vm/EnergyCost.java b/actuator/src/main/java/org/tron/core/vm/EnergyCost.java index 6638b22d47f..5c78fb89ffb 100644 --- a/actuator/src/main/java/org/tron/core/vm/EnergyCost.java +++ b/actuator/src/main/java/org/tron/core/vm/EnergyCost.java @@ -57,6 +57,8 @@ public class EnergyCost { private static final long SUICIDE = 0; private static final long STOP = 0; private static final long CREATE_DATA = 200; + private static final long TLOAD = 100; + private static final long TSTORE = 100; public static long getZeroTierCost(Program ignored) { return ZERO_TIER; @@ -232,6 +234,26 @@ public static long getSstoreCost(Program program) { } + public static long getTLoadCost(Program ignored) { + return TLOAD; + } + + public static long getTStoreCost(Program ignored) { + return TSTORE; + } + + public static long getMCopyCost(Program program) { + Stack stack = program.getStack(); + long oldMemSize = program.getMemSize(); + + int dstOffset = stack.peek().intValue(); + int srcOffset = stack.get(stack.size() - 2).intValue(); + DataWord maxOffset = new DataWord(Math.max(dstOffset, srcOffset)); + return VERY_LOW_TIER + calcMemEnergy(oldMemSize, + memNeeded(maxOffset, stack.get(stack.size() - 3)), + stack.get(stack.size() - 3).longValueSafe(), Op.MCOPY); + } + public static long getLogCost(Program program) { Stack stack = program.getStack(); long oldMemSize = program.getMemSize(); diff --git a/actuator/src/main/java/org/tron/core/vm/Op.java b/actuator/src/main/java/org/tron/core/vm/Op.java index f6987c12942..4b4488ef427 100644 --- a/actuator/src/main/java/org/tron/core/vm/Op.java +++ b/actuator/src/main/java/org/tron/core/vm/Op.java @@ -145,6 +145,12 @@ public class Op { // (0x5a) Get the amount of available gas public static final int GAS = 0x5a; public static final int JUMPDEST = 0x5b; + // (0x5c) Load word from transient memory + public static final int TLOAD = 0x5c; + // (0x5d) Save word to transient memory + public static final int TSTORE = 0x5d; + // (0x5e) Copy word from memory + public static final int MCOPY = 0x5e; /* Push Operations */ // Place item on stack diff --git a/actuator/src/main/java/org/tron/core/vm/OperationActions.java b/actuator/src/main/java/org/tron/core/vm/OperationActions.java index 5ed6ead075f..5e0288c7977 100644 --- a/actuator/src/main/java/org/tron/core/vm/OperationActions.java +++ b/actuator/src/main/java/org/tron/core/vm/OperationActions.java @@ -643,6 +643,37 @@ public static void jumpDestAction(Program program) { program.step(); } + public static void tLoadAction(Program program) { + DataWord key = program.stackPop(); + DataWord address = program.getContractAddress(); + + byte[] data = + program.getContractState().getTransientStorageValue(address.getData(), key.getData()); + DataWord value = data != null ? new DataWord(data) : DataWord.ZERO; + + program.stackPush(value); + program.step(); + } + + public static void tStoreAction(Program program) { + DataWord key = program.stackPop(); + DataWord value = program.stackPop(); + DataWord address = program.getContractAddress(); + + program.getContractState() + .updateTransientStorageValue(address.getData(), key.getData(), value.getData()); + program.step(); + } + + public static void mCopyAction(Program program) { + int dstOffset = program.stackPop().intValueSafe(); + int srcOffset = program.stackPop().intValueSafe(); + int length = program.stackPop().intValueSafe(); + + program.memoryCopy(dstOffset, srcOffset, length); + program.step(); + } + public static void push0Action(Program program) { program.stackPush(DataWord.ZERO()); program.step(); diff --git a/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java b/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java index a2d3259ba89..da1c9b38e9e 100644 --- a/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java +++ b/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java @@ -12,6 +12,7 @@ public enum Version { TRON_V1_1, TRON_V1_2, TRON_V1_3, + TRON_V1_4, // add more // TRON_V2, // ETH @@ -24,6 +25,7 @@ public enum Version { tableMap.put(Version.TRON_V1_1, newTronV11OperationSet()); tableMap.put(Version.TRON_V1_2, newTronV12OperationSet()); tableMap.put(Version.TRON_V1_3, newTronV13OperationSet()); + tableMap.put(Version.TRON_V1_4, newTronV14OperationSet()); } public static JumpTable newTronV10OperationSet() { @@ -55,12 +57,18 @@ public static JumpTable newTronV13OperationSet() { return table; } + public static JumpTable newTronV14OperationSet() { + JumpTable table = newTronV13OperationSet(); + appendCancunOperations(table); + return table; + } + // Just for warming up class to avoid out_of_time public static void init() {} public static JumpTable getTable() { // always get the table which has the newest version - JumpTable table = tableMap.get(Version.TRON_V1_3); + JumpTable table = tableMap.get(Version.TRON_V1_4); // next make the corresponding changes, exclude activating opcode if (VMConfig.allowHigherLimitForMaxCpuTimeOfOneTx()) { @@ -652,4 +660,26 @@ public static void adjustForFairEnergy(JumpTable table) { EnergyCost::getSuicideCost2, OperationActions::suicideAction)); } + + public static void appendCancunOperations(JumpTable table) { + BooleanSupplier proposal = VMConfig::allowTvmCancun; + + table.set(new Operation( + Op.TLOAD, 1, 1, + EnergyCost::getTLoadCost, + OperationActions::tLoadAction, + proposal)); + + table.set(new Operation( + Op.TSTORE, 2, 0, + EnergyCost::getTStoreCost, + OperationActions::tStoreAction, + proposal)); + + table.set(new Operation( + Op.MCOPY, 3, 0, + EnergyCost::getMCopyCost, + OperationActions::mCopyAction, + proposal)); + } } diff --git a/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java b/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java index 63c3ff791d6..d90a27fae32 100644 --- a/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java +++ b/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java @@ -40,6 +40,7 @@ public static void load(StoreFactory storeFactory) { VMConfig.initDynamicEnergyMaxFactor(ds.getDynamicEnergyMaxFactor()); VMConfig.initAllowTvmShangHai(ds.getAllowTvmShangHai()); VMConfig.initAllowEnergyAdjustment(ds.getAllowEnergyAdjustment()); + VMConfig.initAllowTvmCancun(ds.getAllowTvmCancun()); } } } diff --git a/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java b/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java index 3eb1f8fd4b8..128dbe68871 100644 --- a/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java +++ b/actuator/src/main/java/org/tron/core/vm/config/VMConfig.java @@ -51,6 +51,8 @@ public class VMConfig { private static boolean ALLOW_ENERGY_ADJUSTMENT = false; + private static boolean ALLOW_TVM_CANCUN = false; + private VMConfig() { } @@ -142,6 +144,10 @@ public static void initAllowEnergyAdjustment(long allow) { ALLOW_ENERGY_ADJUSTMENT = allow == 1; } + public static void initAllowTvmCancun(long allow) { + ALLOW_TVM_CANCUN = allow == 1; + } + public static boolean getEnergyLimitHardFork() { return CommonParameter.ENERGY_LIMIT_HARD_FORK; } @@ -221,4 +227,8 @@ public static boolean allowTvmShanghai() { public static boolean allowEnergyAdjustment() { return ALLOW_ENERGY_ADJUSTMENT; } + + public static boolean allowTvmCancun() { + return ALLOW_TVM_CANCUN; + } } diff --git a/actuator/src/main/java/org/tron/core/vm/program/ContractState.java b/actuator/src/main/java/org/tron/core/vm/program/ContractState.java index 657558b3725..e095201e393 100644 --- a/actuator/src/main/java/org/tron/core/vm/program/ContractState.java +++ b/actuator/src/main/java/org/tron/core/vm/program/ContractState.java @@ -229,6 +229,11 @@ public void putDelegatedResourceAccountIndex(Key key, Value value) { repository.putDelegatedResourceAccountIndex(key, value); } + @Override + public void putTransientStorageValue(Key address, Key key, Value value) { + repository.putTransientStorageValue(address, key, value); + } + @Override public long addTokenBalance(byte[] address, byte[] tokenId, long value) { return repository.addTokenBalance(address, tokenId, value); @@ -314,6 +319,11 @@ public DelegatedResourceAccountIndexCapsule getDelegatedResourceAccountIndex(byt return repository.getDelegatedResourceAccountIndex(key); } + @Override + public byte[] getTransientStorageValue(byte[] address, byte[] key) { + return repository.getTransientStorageValue(address, key); + } + @Override public void updateDynamicProperty(byte[] word, BytesCapsule bytesCapsule) { repository.updateDynamicProperty(word, bytesCapsule); @@ -354,6 +364,11 @@ public void updateDelegatedResourceAccountIndex(byte[] word, DelegatedResourceAc repository.updateDelegatedResourceAccountIndex(word, delegatedResourceAccountIndexCapsule); } + @Override + public void updateTransientStorageValue(byte[] address, byte[] key, byte[] value) { + repository.updateTransientStorageValue(address, key, value); + } + @Override public void putDynamicProperty(Key key, Value value) { repository.putDynamicProperty(key, value); diff --git a/actuator/src/main/java/org/tron/core/vm/program/Memory.java b/actuator/src/main/java/org/tron/core/vm/program/Memory.java index e5cbebad2b9..8f263ca7344 100644 --- a/actuator/src/main/java/org/tron/core/vm/program/Memory.java +++ b/actuator/src/main/java/org/tron/core/vm/program/Memory.java @@ -181,6 +181,14 @@ public List getChunks() { return new LinkedList<>(chunks); } + public void copy(int destPos, int srcPos, int size) { + if (size <= 0) { + return; + } + byte[] data = read(srcPos, size); + write(destPos, data, size, false); + } + private int captureMax(int chunkIndex, int chunkOffset, int size, byte[] src, int srcPos) { byte[] chunk = chunks.get(chunkIndex); diff --git a/actuator/src/main/java/org/tron/core/vm/program/Program.java b/actuator/src/main/java/org/tron/core/vm/program/Program.java index 0b0ef5bc9ba..688ab8f20ff 100644 --- a/actuator/src/main/java/org/tron/core/vm/program/Program.java +++ b/actuator/src/main/java/org/tron/core/vm/program/Program.java @@ -429,6 +429,10 @@ public byte[] memoryChunk(int offset, int size) { return memory.read(offset, size); } + public void memoryCopy(int dst, int src, int size) { + memory.copy(dst, src, size); + } + /** * . Allocates extra memory in the program for a specified size, calculated from a given offset * diff --git a/actuator/src/main/java/org/tron/core/vm/repository/Repository.java b/actuator/src/main/java/org/tron/core/vm/repository/Repository.java index b4324bb8d18..664ee26ee92 100644 --- a/actuator/src/main/java/org/tron/core/vm/repository/Repository.java +++ b/actuator/src/main/java/org/tron/core/vm/repository/Repository.java @@ -41,6 +41,8 @@ public interface Repository { DelegatedResourceAccountIndexCapsule getDelegatedResourceAccountIndex(byte[] key); + byte[] getTransientStorageValue(byte[] address, byte[] key); + void deleteContract(byte[] address); void createContract(byte[] address, ContractCapsule contractCapsule); @@ -71,6 +73,8 @@ public interface Repository { void updateDelegatedResourceAccountIndex(byte[] word, DelegatedResourceAccountIndexCapsule delegatedResourceAccountIndexCapsule); + void updateTransientStorageValue(byte[] address, byte[] key, byte[] value); + void saveCode(byte[] address, byte[] code); byte[] getCode(byte[] address); @@ -113,6 +117,8 @@ public interface Repository { void putDelegatedResourceAccountIndex(Key key, Value value); + void putTransientStorageValue(Key address, Key key, Value value); + long addTokenBalance(byte[] address, byte[] tokenId, long value); long getTokenBalance(byte[] address, byte[] tokenId); diff --git a/actuator/src/main/java/org/tron/core/vm/repository/RepositoryImpl.java b/actuator/src/main/java/org/tron/core/vm/repository/RepositoryImpl.java index 50fa5385c23..7fcfbe8ef78 100644 --- a/actuator/src/main/java/org/tron/core/vm/repository/RepositoryImpl.java +++ b/actuator/src/main/java/org/tron/core/vm/repository/RepositoryImpl.java @@ -4,6 +4,7 @@ import static org.tron.core.config.Parameter.ChainConstant.BLOCK_PRODUCED_INTERVAL; import static org.tron.core.config.Parameter.ChainConstant.TRX_PRECISION; +import com.google.common.collect.HashBasedTable; import com.google.protobuf.ByteString; import java.util.HashMap; import java.util.Optional; @@ -131,6 +132,7 @@ public class RepositoryImpl implements Repository { private final HashMap> votesCache = new HashMap<>(); private final HashMap> delegationCache = new HashMap<>(); private final HashMap> delegatedResourceAccountIndexCache = new HashMap<>(); + private final HashBasedTable> transientStorage = HashBasedTable.create(); public static void removeLruCache(byte[] address) { } @@ -442,6 +444,27 @@ public DelegatedResourceAccountIndexCapsule getDelegatedResourceAccountIndex(byt return delegatedResourceAccountIndexCapsule; } + public byte[] getTransientStorageValue(byte[] address, byte[] key) { + Key cacheAddress = new Key(address); + Key cacheKey = new Key(key); + if (transientStorage.contains(cacheAddress, cacheKey)) { + return transientStorage.get(cacheAddress, cacheKey).getValue(); + } + + byte[] value; + if (parent != null) { + value = parent.getTransientStorageValue(address, key); + } else{ + value = null; + } + + if (value != null) { + transientStorage.put(cacheAddress, cacheKey, Value.create(value)); + } + + return value; + } + @Override public void deleteContract(byte[] address) { @@ -565,6 +588,11 @@ public void updateDelegatedResourceAccountIndex( Key.create(word), Value.create(delegatedResourceAccountIndexCapsule, Type.DIRTY)); } + @Override + public void updateTransientStorageValue(byte[] address, byte[] key, byte[] value) { + transientStorage.put(Key.create(address), Key.create(key), Value.create(value, Type.DIRTY)); + } + @Override public void saveCode(byte[] address, byte[] code) { codeCache.put(Key.create(address), Value.create(code, Type.CREATE)); @@ -709,6 +737,7 @@ public void commit() { commitVotesCache(repository); commitDelegationCache(repository); commitDelegatedResourceAccountIndexCache(repository); + commitTransientStorage(repository); } @Override @@ -767,6 +796,11 @@ public void putDelegatedResourceAccountIndex(Key key, Value value) { delegatedResourceAccountIndexCache.put(key, value); } + @Override + public void putTransientStorageValue(Key address, Key key, Value value) { + transientStorage.put(address, key, value); + } + @Override public long addTokenBalance(byte[] address, byte[] tokenId, long value) { byte[] tokenIdWithoutLeadingZero = ByteUtil.stripLeadingZeroes(tokenId); @@ -1013,6 +1047,17 @@ private void commitDelegatedResourceAccountIndexCache(Repository deposit) { })); } + public void commitTransientStorage(Repository deposit) { + if (deposit != null) { + transientStorage.cellSet().forEach(cell -> { + if (cell.getValue().getType().isDirty() || cell.getValue().getType().isCreate()) { + deposit.putTransientStorageValue( + cell.getRowKey(), cell.getColumnKey(), cell.getValue()); + } + }); + } + } + /** * Get the block id from the number. */ diff --git a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java index 2b50ec76af2..de8b035aa01 100644 --- a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java +++ b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java @@ -223,6 +223,8 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking private static final byte[] MAX_CREATE_ACCOUNT_TX_SIZE = "MAX_CREATE_ACCOUNT_TX_SIZE".getBytes(); + private static final byte[] ALLOW_TVM_CANCUN = "ALLOW_TVM_CANCUN".getBytes(); + @Autowired private DynamicPropertiesStore(@Value("properties") String dbName) { super(dbName); @@ -2877,6 +2879,18 @@ public long getMaxCreateAccountTxSize() { .orElse(CommonParameter.getInstance().getMaxCreateAccountTxSize()); } + public void saveAllowTvmCancun(long allowTvmCancun) { + this.put(ALLOW_TVM_CANCUN, + new BytesCapsule(ByteArray.fromLong(allowTvmCancun))); + } + + public long getAllowTvmCancun() { + return Optional.ofNullable(getUnchecked(ALLOW_TVM_CANCUN)) + .map(BytesCapsule::getData) + .map(ByteArray::toLong) + .orElse(CommonParameter.getInstance().getAllowTvmCancun()); + } + private static class DynamicResourceProperties { private static final byte[] ONE_DAY_NET_LIMIT = "ONE_DAY_NET_LIMIT".getBytes(); diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java index 22159063333..8b9f66df406 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -674,6 +674,10 @@ public class CommonParameter { @Setter public long maxCreateAccountTxSize = 1000L; + @Getter + @Setter + public long allowTvmCancun; + private static double calcMaxTimeRatio() { //return max(2.0, min(5.0, 5 * 4.0 / max(Runtime.getRuntime().availableProcessors(), 1))); return 5.0; diff --git a/common/src/main/java/org/tron/core/Constant.java b/common/src/main/java/org/tron/core/Constant.java index 0e634d3ef7d..0fbc8f376bd 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -384,4 +384,6 @@ public class Constant { public static final String COMMITTEE_ALLOW_OLD_REWARD_OPT = "committee.allowOldRewardOpt"; public static final String COMMITTEE_ALLOW_ENERGY_ADJUSTMENT = "committee.allowEnergyAdjustment"; + + public static final String COMMITTEE_ALLOW_TVM_CANCUN = "committee.allowTvmCancun"; } diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index 9d7eb75df1b..b06c2ba2adf 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -1342,6 +1342,11 @@ public Protocol.ChainParameters getChainParameters() { .setValue(dbManager.getDynamicPropertiesStore().getMaxCreateAccountTxSize()) .build()); + builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder() + .setKey("getAllowTvmCancun") + .setValue(dbManager.getDynamicPropertiesStore().getAllowTvmCancun()) + .build()); + return builder.build(); } diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index 422efefaed8..a3ca18f1d1c 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -233,6 +233,7 @@ public static void clearParam() { PARAMETER.maxUnsolidifiedBlocks = 54; PARAMETER.allowOldRewardOpt = 0; PARAMETER.allowEnergyAdjustment = 0; + PARAMETER.allowTvmCancun = 0; } /** @@ -1210,6 +1211,10 @@ public static void setParam(final String[] args, final String confFileName) { config.hasPath(Constant.COMMITTEE_ALLOW_ENERGY_ADJUSTMENT) ? config .getInt(Constant.COMMITTEE_ALLOW_ENERGY_ADJUSTMENT) : 0; + PARAMETER.allowTvmCancun = + config.hasPath(Constant.COMMITTEE_ALLOW_TVM_CANCUN) ? config + .getInt(Constant.COMMITTEE_ALLOW_TVM_CANCUN) : 0; + logConfig(); } diff --git a/framework/src/main/java/org/tron/core/consensus/ProposalService.java b/framework/src/main/java/org/tron/core/consensus/ProposalService.java index d0c106a7e57..eaa7d79c8cf 100644 --- a/framework/src/main/java/org/tron/core/consensus/ProposalService.java +++ b/framework/src/main/java/org/tron/core/consensus/ProposalService.java @@ -367,6 +367,10 @@ public static boolean process(Manager manager, ProposalCapsule proposalCapsule) manager.getDynamicPropertiesStore().saveMaxCreateAccountTxSize(entry.getValue()); break; } + case ALLOW_TVM_CANCUN: { + manager.getDynamicPropertiesStore().saveAllowTvmCancun(entry.getValue()); + break; + } default: find = false; break; diff --git a/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java b/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java index 2a70364b8d1..ed4c8c47a2c 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java @@ -934,6 +934,53 @@ public void testVoteWitnessCost() throws ContractValidateException { Assert.assertEquals(30000 + memoryExpandEnergy, EnergyCost.getVoteWitnessCost2(program)); } + @Test + public void testTransientStorageOperations() throws ContractValidateException { + VMConfig.initAllowTvmCancun(1); + + invoke = new ProgramInvokeMockImpl(); + invoke.setEnergyLimit(20000); + Protocol.Transaction trx = Protocol.Transaction.getDefaultInstance(); + InternalTransaction interTrx = + new InternalTransaction(trx, InternalTransaction.TrxType.TRX_UNKNOWN_TYPE); + + // TLOAD = 0x5c; + byte[] op = new byte[] {0x60, 0x01, 0x5c}; + program = new Program(op, op, invoke, interTrx); + testOperations(program); + Assert.assertEquals(103, program.getResult().getEnergyUsed()); + Assert.assertEquals(new DataWord(0x00), program.getStack().pop()); + + // TSTORE = 0x5d; + op = new byte[] {0x60, 0x01, 0x60, 0x01, 0x5d}; + program = new Program(op, op, invoke, interTrx); + testOperations(program); + Assert.assertEquals(106, program.getResult().getEnergyUsed()); + Assert.assertEquals("0000000000000000000000000000000000000000000000000000000000000001", + Hex.toHexString(program.getContractState().getTransientStorageValue( + program.getContractAddress().getData(), new DataWord(0x01).getData()))); + VMConfig.initAllowTvmCancun(0); + } + + @Test + public void testMCOPY() throws ContractValidateException { + VMConfig.initAllowTvmCancun(1); + + invoke = new ProgramInvokeMockImpl(); + Protocol.Transaction trx = Protocol.Transaction.getDefaultInstance(); + InternalTransaction interTrx = + new InternalTransaction(trx, InternalTransaction.TrxType.TRX_UNKNOWN_TYPE); + + // MCOPY = 0x5e + byte[] op = new byte[] {0x60, 0x20, 0x60, 0x01, 0x60, 0x20, 0x5e}; + program = new Program(op, op, invoke, interTrx); + testOperations(program); + Assert.assertEquals(21, program.getResult().getEnergyUsed()); + Assert.assertEquals(64, program.getMemSize()); + + VMConfig.initAllowTvmCancun(0); + } + private void testOperations(Program program) { try { while (!program.isStopped()) { From af5c73932e87c0771c10d11ac6bb4d781e41c0db Mon Sep 17 00:00:00 2001 From: Liulei Date: Wed, 26 Jun 2024 18:31:56 +0800 Subject: [PATCH 2/3] feat(tvm,proposal): add fork 4_8_0 --- actuator/src/main/java/org/tron/core/utils/ProposalUtil.java | 2 +- common/src/main/java/org/tron/core/config/Parameter.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java index f60c11fd016..5ae74ab8260 100644 --- a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java @@ -780,7 +780,7 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, break; } case ALLOW_TVM_CANCUN: { - if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_7_5)) { + if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_8_0)) { throw new ContractValidateException( "Bad chain parameter id [ALLOW_TVM_CANCUN]"); } diff --git a/common/src/main/java/org/tron/core/config/Parameter.java b/common/src/main/java/org/tron/core/config/Parameter.java index 027c225eb5d..92ed3177f6a 100644 --- a/common/src/main/java/org/tron/core/config/Parameter.java +++ b/common/src/main/java/org/tron/core/config/Parameter.java @@ -24,7 +24,8 @@ public enum ForkBlockVersionEnum { VERSION_4_7_1(27, 1596780000000L, 80), VERSION_4_7_2(28, 1596780000000L, 80), VERSION_4_7_4(29, 1596780000000L, 80), - VERSION_4_7_5(30, 1596780000000L, 80); + VERSION_4_7_5(30, 1596780000000L, 80), + VERSION_4_8_0(31, 1596780000000L, 80); // if add a version, modify BLOCK_VERSION simultaneously @Getter @@ -73,7 +74,7 @@ public class ChainConstant { public static final int SINGLE_REPEAT = 1; public static final int BLOCK_FILLED_SLOTS_NUMBER = 128; public static final int MAX_FROZEN_NUMBER = 1; - public static final int BLOCK_VERSION = 30; + public static final int BLOCK_VERSION = 31; public static final long FROZEN_PERIOD = 86_400_000L; public static final long DELEGATE_PERIOD = 3 * 86_400_000L; public static final long TRX_PRECISION = 1000_000L; From a04a601ed5dec36d22e64e1132077c79ff7d9d6f Mon Sep 17 00:00:00 2001 From: Liulei Date: Thu, 27 Jun 2024 17:05:50 +0800 Subject: [PATCH 3/3] feat(tvm): update comments and tests --- .../src/main/java/org/tron/core/vm/Op.java | 4 +-- .../org/tron/core/vm/OperationActions.java | 2 +- .../common/runtime/vm/OperationsTest.java | 28 ++++++++++++------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/actuator/src/main/java/org/tron/core/vm/Op.java b/actuator/src/main/java/org/tron/core/vm/Op.java index 4b4488ef427..5125f067d31 100644 --- a/actuator/src/main/java/org/tron/core/vm/Op.java +++ b/actuator/src/main/java/org/tron/core/vm/Op.java @@ -145,9 +145,9 @@ public class Op { // (0x5a) Get the amount of available gas public static final int GAS = 0x5a; public static final int JUMPDEST = 0x5b; - // (0x5c) Load word from transient memory + // (0x5c) Load word from transient storage public static final int TLOAD = 0x5c; - // (0x5d) Save word to transient memory + // (0x5d) Save word to transient storage public static final int TSTORE = 0x5d; // (0x5e) Copy word from memory public static final int MCOPY = 0x5e; diff --git a/actuator/src/main/java/org/tron/core/vm/OperationActions.java b/actuator/src/main/java/org/tron/core/vm/OperationActions.java index 5e0288c7977..9503e2d749e 100644 --- a/actuator/src/main/java/org/tron/core/vm/OperationActions.java +++ b/actuator/src/main/java/org/tron/core/vm/OperationActions.java @@ -649,7 +649,7 @@ public static void tLoadAction(Program program) { byte[] data = program.getContractState().getTransientStorageValue(address.getData(), key.getData()); - DataWord value = data != null ? new DataWord(data) : DataWord.ZERO; + DataWord value = data != null ? new DataWord(data) : DataWord.ZERO(); program.stackPush(value); program.step(); diff --git a/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java b/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java index ed4c8c47a2c..a0a6d4be85b 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/OperationsTest.java @@ -944,21 +944,22 @@ public void testTransientStorageOperations() throws ContractValidateException { InternalTransaction interTrx = new InternalTransaction(trx, InternalTransaction.TrxType.TRX_UNKNOWN_TYPE); - // TLOAD = 0x5c; - byte[] op = new byte[] {0x60, 0x01, 0x5c}; + // TSTORE = 0x5d; + byte[] op = new byte[] {0x60, 0x01, 0x60, 0x01, 0x5d}; program = new Program(op, op, invoke, interTrx); testOperations(program); - Assert.assertEquals(103, program.getResult().getEnergyUsed()); - Assert.assertEquals(new DataWord(0x00), program.getStack().pop()); + Assert.assertEquals(106, program.getResult().getEnergyUsed()); + Assert.assertArrayEquals(new DataWord(0x01).getData(), + program.getContractState().getTransientStorageValue( + program.getContractAddress().getData(), new DataWord(0x01).getData())); - // TSTORE = 0x5d; - op = new byte[] {0x60, 0x01, 0x60, 0x01, 0x5d}; + // TLOAD = 0x5c; + op = new byte[] {0x60, 0x01, 0x5c}; program = new Program(op, op, invoke, interTrx); testOperations(program); - Assert.assertEquals(106, program.getResult().getEnergyUsed()); - Assert.assertEquals("0000000000000000000000000000000000000000000000000000000000000001", - Hex.toHexString(program.getContractState().getTransientStorageValue( - program.getContractAddress().getData(), new DataWord(0x01).getData()))); + Assert.assertEquals(103, program.getResult().getEnergyUsed()); + Assert.assertEquals(new DataWord(0x01), program.getStack().pop()); + VMConfig.initAllowTvmCancun(0); } @@ -978,6 +979,13 @@ public void testMCOPY() throws ContractValidateException { Assert.assertEquals(21, program.getResult().getEnergyUsed()); Assert.assertEquals(64, program.getMemSize()); + op = + new byte[] { + 0x60, 0x01, 0x60, 0x01, 0x52, 0x60, 0x20, 0x60, 0x01, 0x60, 0x20, 0x5e, 0x60, 0x20, 0x51}; + program = new Program(op, op, invoke, interTrx); + testOperations(program); + Assert.assertEquals(new DataWord(0x01), program.getStack().pop()); + VMConfig.initAllowTvmCancun(0); }