From 0f5a8defc65f5a8d5e61820cc6a03455c994b354 Mon Sep 17 00:00:00 2001 From: lurais <107600021+lurais@users.noreply.github.com> Date: Fri, 12 Jan 2024 19:48:27 +0800 Subject: [PATCH 01/25] Merge master into develop branch (#5668) * feat(api):fix a concurrency issue for toString in BlockCapsule (#5657) * feat(db):optimize cache settings (#5659) * feat(lite):optimize DbLite tool (#5658) --- .../org/tron/core/store/WitnessStore.java | 22 +---- .../org/tron/consensus/ConsensusDelegate.java | 4 - .../consensus/dpos/MaintenanceManager.java | 4 +- .../main/java/org/tron/program/Version.java | 6 +- .../java/org/tron/core/db/ManagerTest.java | 17 +++- .../main/java/org/tron/plugins/DbLite.java | 93 ++++++++++++++++--- 6 files changed, 98 insertions(+), 48 deletions(-) diff --git a/chainbase/src/main/java/org/tron/core/store/WitnessStore.java b/chainbase/src/main/java/org/tron/core/store/WitnessStore.java index e01680cfc74..d23a73f92f9 100644 --- a/chainbase/src/main/java/org/tron/core/store/WitnessStore.java +++ b/chainbase/src/main/java/org/tron/core/store/WitnessStore.java @@ -11,10 +11,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import org.tron.common.cache.CacheManager; -import org.tron.common.cache.CacheStrategies; -import org.tron.common.cache.CacheType; -import org.tron.common.cache.TronCache; import org.tron.core.capsule.WitnessCapsule; import org.tron.core.config.Parameter; import org.tron.core.db.TronStoreWithRevoking; @@ -22,14 +18,10 @@ @Slf4j(topic = "DB") @Component public class WitnessStore extends TronStoreWithRevoking { - // cache for 127 SR - private final TronCache> witnessStandbyCache; @Autowired protected WitnessStore(@Value("witness") String dbName) { super(dbName); - String strategy = String.format(CacheStrategies.PATTERNS, 1, 1, "30s", 1); - witnessStandbyCache = CacheManager.allocate(CacheType.witnessStandby, strategy); } /** @@ -48,19 +40,8 @@ public WitnessCapsule get(byte[] key) { } public List getWitnessStandby() { - List list = - witnessStandbyCache.getIfPresent(Parameter.ChainConstant.WITNESS_STANDBY_LENGTH); - if (list != null) { - return list; - } - return updateWitnessStandby(null); - } - - public List updateWitnessStandby(List all) { List ret; - if (all == null) { - all = getAllWitnesses(); - } + List all = getAllWitnesses(); all.sort(Comparator.comparingLong(WitnessCapsule::getVoteCount) .reversed().thenComparing(Comparator.comparingInt( (WitnessCapsule w) -> w.getAddress().hashCode()).reversed())); @@ -71,7 +52,6 @@ public List updateWitnessStandby(List all) { } // trim voteCount = 0 ret.removeIf(w -> w.getVoteCount() < 1); - witnessStandbyCache.put(Parameter.ChainConstant.WITNESS_STANDBY_LENGTH, ret); return ret; } diff --git a/consensus/src/main/java/org/tron/consensus/ConsensusDelegate.java b/consensus/src/main/java/org/tron/consensus/ConsensusDelegate.java index 4a98c933bd1..767463a6a5b 100644 --- a/consensus/src/main/java/org/tron/consensus/ConsensusDelegate.java +++ b/consensus/src/main/java/org/tron/consensus/ConsensusDelegate.java @@ -108,10 +108,6 @@ public List getAllWitnesses() { return witnessStore.getAllWitnesses(); } - public List updateWitnessStandby(List all) { - return witnessStore.updateWitnessStandby(all); - } - public void saveStateFlag(int flag) { dynamicPropertiesStore.saveStateFlag(flag); } diff --git a/consensus/src/main/java/org/tron/consensus/dpos/MaintenanceManager.java b/consensus/src/main/java/org/tron/consensus/dpos/MaintenanceManager.java index fc6cdd55c15..012169bdb87 100644 --- a/consensus/src/main/java/org/tron/consensus/dpos/MaintenanceManager.java +++ b/consensus/src/main/java/org/tron/consensus/dpos/MaintenanceManager.java @@ -151,13 +151,11 @@ public void doMaintenance() { if (dynamicPropertiesStore.allowChangeDelegation()) { long nextCycle = dynamicPropertiesStore.getCurrentCycleNumber() + 1; dynamicPropertiesStore.saveCurrentCycleNumber(nextCycle); - List all = consensusDelegate.getAllWitnesses(); - all.forEach(witness -> { + consensusDelegate.getAllWitnesses().forEach(witness -> { delegationStore.setBrokerage(nextCycle, witness.createDbKey(), delegationStore.getBrokerage(witness.createDbKey())); delegationStore.setWitnessVote(nextCycle, witness.createDbKey(), witness.getVoteCount()); }); - consensusDelegate.updateWitnessStandby(all); } } diff --git a/framework/src/main/java/org/tron/program/Version.java b/framework/src/main/java/org/tron/program/Version.java index 4740daa9d5e..a01eb714297 100644 --- a/framework/src/main/java/org/tron/program/Version.java +++ b/framework/src/main/java/org/tron/program/Version.java @@ -2,9 +2,9 @@ public class Version { - public static final String VERSION_NAME = "GreatVoyage-v4.7.2-140-g9d13f9cb69"; - public static final String VERSION_CODE = "18173"; - private static final String VERSION = "4.7.3"; + public static final String VERSION_NAME = "GreatVoyage-v4.7.3-5-g788136ebe"; + public static final String VERSION_CODE = "18180"; + private static final String VERSION = "4.7.3.1"; public static String getVersion() { return VERSION; diff --git a/framework/src/test/java/org/tron/core/db/ManagerTest.java b/framework/src/test/java/org/tron/core/db/ManagerTest.java index e25faf536f7..bd79f7d9776 100755 --- a/framework/src/test/java/org/tron/core/db/ManagerTest.java +++ b/framework/src/test/java/org/tron/core/db/ManagerTest.java @@ -581,14 +581,24 @@ public void pushSwitchFork() AccountResourceInsufficientException, EventBloomException { String key = "f31db24bfbd1a2ef19beddca0a0fa37632eded9ac666a05d3bd925f01dde1f62"; + String key2 = "c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4"; byte[] privateKey = ByteArray.fromHexString(key); final ECKey ecKey = ECKey.fromPrivate(privateKey); byte[] address = ecKey.getAddress(); - + WitnessCapsule sr1 = new WitnessCapsule( + ByteString.copyFrom(address), "www.tron.net/first"); + sr1.setVoteCount(1000000000L); + byte[] privateKey2 = ByteArray.fromHexString(key2); + final ECKey ecKey2 = ECKey.fromPrivate(privateKey2); + byte[] address2 = ecKey2.getAddress(); + WitnessCapsule sr2 = new WitnessCapsule( + ByteString.copyFrom(address2), "www.tron.net/second"); + sr2.setVoteCount(100000L); + chainManager.getWitnessStore().put(address, sr1); WitnessCapsule witnessCapsule = new WitnessCapsule(ByteString.copyFrom(address)); chainManager.getWitnessScheduleStore().saveActiveWitnesses(new ArrayList<>()); chainManager.addWitness(ByteString.copyFrom(address)); - + List witnessStandby1 = chainManager.getWitnessStore().getWitnessStandby(); Block block = getSignedBlock(witnessCapsule.getAddress(), 1533529947843L, privateKey); dbManager.pushBlock(new BlockCapsule(block)); @@ -625,6 +635,9 @@ public void pushSwitchFork() } catch (Exception e) { Assert.assertTrue(e instanceof Exception); } + chainManager.getWitnessStore().put(address, sr2); + List witnessStandby2 = chainManager.getWitnessStore().getWitnessStandby(); + Assert.assertNotEquals(witnessStandby1, witnessStandby2); } diff --git a/plugins/src/main/java/org/tron/plugins/DbLite.java b/plugins/src/main/java/org/tron/plugins/DbLite.java index 8804d6210b2..732d4913021 100644 --- a/plugins/src/main/java/org/tron/plugins/DbLite.java +++ b/plugins/src/main/java/org/tron/plugins/DbLite.java @@ -3,6 +3,8 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.primitives.Bytes; +import com.google.common.primitives.Ints; import com.google.common.primitives.Longs; import java.io.File; import java.io.FileNotFoundException; @@ -153,10 +155,10 @@ public void generateSnapshot(String sourceDir, String snapshotDir) { long start = System.currentTimeMillis(); snapshotDir = Paths.get(snapshotDir, SNAPSHOT_DIR_NAME).toString(); try { - mergeCheckpoint(sourceDir); hasEnoughBlock(sourceDir); List snapshotDbs = getSnapshotDbs(sourceDir); split(sourceDir, snapshotDir, snapshotDbs); + mergeCheckpoint2Snapshot(sourceDir, snapshotDir); // write genesisBlock , latest recent blocks and trans fillSnapshotBlockAndTransDb(sourceDir, snapshotDir); // save min block to info @@ -190,9 +192,9 @@ public void generateHistory(String sourceDir, String historyDir) { throw new IllegalStateException( String.format("Unavailable sourceDir: %s is not fullNode data.", sourceDir)); } - mergeCheckpoint(sourceDir); hasEnoughBlock(sourceDir); split(sourceDir, historyDir, archiveDbs); + mergeCheckpoint2History(sourceDir, historyDir); // save max block to info generateInfoProperties(Paths.get(historyDir, INFO_FILE_NAME).toString(), getLatestBlockHeaderNum(sourceDir)); @@ -261,6 +263,15 @@ private List getSnapshotDbs(String sourceDir) { return snapshotDbs; } + private void mergeCheckpoint2Snapshot(String sourceDir, String historyDir) { + List snapshotDbs = getSnapshotDbs(sourceDir); + mergeCheckpoint(sourceDir, historyDir, snapshotDbs); + } + + private void mergeCheckpoint2History(String sourceDir, String destDir) { + mergeCheckpoint(sourceDir, destDir, archiveDbs); + } + private void split(String sourceDir, String destDir, List dbs) throws IOException { logger.info("Begin to split the dbs."); spec.commandLine().getOut().println("Begin to split the dbs."); @@ -278,7 +289,7 @@ private void split(String sourceDir, String destDir, List dbs) throws IO FileUtils.copyDatabases(Paths.get(sourceDir), Paths.get(destDir), dbs); } - private void mergeCheckpoint(String sourceDir) { + private void mergeCheckpoint(String sourceDir, String destDir, List destDbs) { logger.info("Begin to merge checkpoint to dataset."); spec.commandLine().getOut().println("Begin to merge checkpoint to dataset."); try { @@ -287,18 +298,18 @@ private void mergeCheckpoint(String sourceDir) { for (String cp : cpList) { DBInterface checkpointDb = DbTool.getDB( sourceDir + "/" + DBUtils.CHECKPOINT_DB_V2, cp); - recover(checkpointDb, sourceDir); + recover(checkpointDb, destDir, destDbs); } } else if (Paths.get(sourceDir, CHECKPOINT_DB).toFile().exists()) { DBInterface tmpDb = DbTool.getDB(sourceDir, CHECKPOINT_DB); - recover(tmpDb, sourceDir); + recover(tmpDb, destDir, destDbs); } } catch (IOException | RocksDBException e) { throw new RuntimeException(e); } } - private void recover(DBInterface db, String destDir) + private void recover(DBInterface db, String destDir, List destDbs) throws IOException, RocksDBException { try (DBIterator iterator = db.iterator()) { for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) { @@ -312,15 +323,17 @@ private void recover(DBInterface db, String destDir) byte[] realKey = Arrays.copyOfRange(key, dbName.getBytes().length + 4, key.length); byte[] realValue = value.length == 1 ? null : Arrays.copyOfRange(value, 1, value.length); - DBInterface destDb = DbTool.getDB(destDir, dbName); - if (realValue != null) { - destDb.put(realKey, realValue); - } else { - byte op = value[0]; - if (DBUtils.Operator.DELETE.getValue() == op) { - destDb.delete(realKey); + if (destDbs != null && destDbs.contains(dbName)) { + DBInterface destDb = DbTool.getDB(destDir, dbName); + if (realValue != null) { + destDb.put(realKey, realValue); } else { - destDb.put(realKey, new byte[0]); + byte op = value[0]; + if (DBUtils.Operator.DELETE.getValue() == op) { + destDb.delete(realKey); + } else { + destDb.put(realKey, new byte[0]); + } } } } @@ -340,7 +353,15 @@ private void generateInfoProperties(String propertyfile, long num) } private long getLatestBlockHeaderNum(String databaseDir) throws IOException, RocksDBException { + // query latest_block_header_number from checkpoint first final String latestBlockHeaderNumber = "latest_block_header_number"; + DBInterface checkpointDb = getCheckpointDb(databaseDir); + Long blockNumber = getLatestBlockHeaderNumFromCP(checkpointDb, + latestBlockHeaderNumber.getBytes()); + if (blockNumber != null) { + return blockNumber; + } + // query from propertiesDb if checkpoint not contains latest_block_header_number DBInterface propertiesDb = DbTool.getDB(databaseDir, PROPERTIES_DB_NAME); return Optional.ofNullable(propertiesDb.get(ByteArray.fromString(latestBlockHeaderNumber))) .map(ByteArray::toLong) @@ -348,6 +369,14 @@ private long getLatestBlockHeaderNum(String databaseDir) throws IOException, Roc () -> new IllegalArgumentException("not found latest block header number")); } + private Long getLatestBlockHeaderNumFromCP(DBInterface db, byte[] key) { + byte[] value = db.get(Bytes.concat(simpleEncode(PROPERTIES_DB_NAME), key)); + if (value != null && value.length > 1) { + return ByteArray.toLong(Arrays.copyOfRange(value, 1, value.length)); + } + return null; + } + /** * recent blocks, trans and genesis block. */ @@ -414,6 +443,15 @@ private byte[] getGenesisBlockHash(String parentDir) throws IOException, RocksDB return result; } + private static byte[] simpleEncode(String s) { + byte[] bytes = s.getBytes(); + byte[] length = Ints.toByteArray(bytes.length); + byte[] r = new byte[4 + bytes.length]; + System.arraycopy(length, 0, r, 0, 4); + System.arraycopy(bytes, 0, r, 4, bytes.length); + return r; + } + private BlockNumInfo checkAndGetBlockNumInfo(String historyDir, String liteDir) throws IOException, RocksDBException { logger.info("Check the compatibility of this history."); @@ -485,6 +523,7 @@ private void trimExtraHistory(String liteDir, BlockNumInfo blockNumInfo) DBInterface transDb = DbTool.getDB(liteDir, TRANS_DB_NAME); DBInterface tranRetDb = DbTool.getDB(liteDir, TRANSACTION_RET_DB_NAME); + ProgressBar.wrap(LongStream.rangeClosed(start, end) .boxed() .sorted((a, b) -> Long.compare(b, a)), "trimHistory").forEach(n -> { @@ -519,6 +558,7 @@ private void mergeBak2Database(String liteDir, BlockNumInfo blockNumInfo) throws return; } + Path bakDir = Paths.get(liteDir, BACKUP_DIR_PREFIX + START_TIME); logger.info("Begin to merge {} to database, start {} end {}.", bakDir, start, end); spec.commandLine().getOut() @@ -545,7 +585,17 @@ private void mergeBak2Database(String liteDir, BlockNumInfo blockNumInfo) throws private byte[] getDataFromSourceDB(String sourceDir, String dbName, byte[] key) throws IOException, RocksDBException { - byte[] value = DbTool.getDB(sourceDir, dbName).get(key); + DBInterface sourceDb = DbTool.getDB(sourceDir, dbName); + DBInterface checkpointDb = getCheckpointDb(sourceDir); + // get data from tmp first. + byte[] valueFromTmp = checkpointDb.get(Bytes.concat(simpleEncode(dbName), key)); + byte[] value; + if (isEmptyBytes(valueFromTmp)) { + value = sourceDb.get(key); + } else { + value = valueFromTmp.length == 1 + ? null : Arrays.copyOfRange(valueFromTmp, 1, valueFromTmp.length); + } if (isEmptyBytes(value)) { throw new RuntimeException(String.format("data not found in store, dbName: %s, key: %s", dbName, Arrays.toString(key))); @@ -614,6 +664,19 @@ private long getSecondBlock(String databaseDir) throws RocksDBException, IOExcep return num; } + private DBInterface getCheckpointDb(String sourceDir) throws IOException, RocksDBException { + List cpList = getCheckpointV2List(sourceDir); + DBInterface checkpointDb; + if (cpList.size() > 0) { + String latestCp = cpList.get(cpList.size() - 1); + checkpointDb = DbTool.getDB( + sourceDir + "/" + DBUtils.CHECKPOINT_DB_V2, latestCp); + } else { + checkpointDb = DbTool.getDB(sourceDir, CHECKPOINT_DB); + } + return checkpointDb; + } + @VisibleForTesting public static void setRecentBlks(long recentBlks) { RECENT_BLKS = recentBlks; From 9d00aef081018584ca9fdb6c5c9e46b6c849eeca Mon Sep 17 00:00:00 2001 From: wubin01 Date: Wed, 21 Feb 2024 11:52:40 +0800 Subject: [PATCH 02/25] feat(net): use the correct clearing function --- .../main/java/org/tron/core/net/peer/PeerConnection.java | 6 +++--- .../java/org/tron/core/net/peer/PeerConnectionTest.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/framework/src/main/java/org/tron/core/net/peer/PeerConnection.java b/framework/src/main/java/org/tron/core/net/peer/PeerConnection.java index 6743f00421d..4fac50b82c7 100644 --- a/framework/src/main/java/org/tron/core/net/peer/PeerConnection.java +++ b/framework/src/main/java/org/tron/core/net/peer/PeerConnection.java @@ -197,10 +197,10 @@ public void onConnect() { public void onDisconnect() { syncService.onDisconnect(this); advService.onDisconnect(this); - advInvReceive.cleanUp(); - advInvSpread.cleanUp(); + advInvReceive.invalidateAll(); + advInvSpread.invalidateAll(); advInvRequest.clear(); - syncBlockIdCache.cleanUp(); + syncBlockIdCache.invalidateAll(); syncBlockToFetch.clear(); syncBlockRequested.clear(); syncBlockInProcess.clear(); diff --git a/framework/src/test/java/org/tron/core/net/peer/PeerConnectionTest.java b/framework/src/test/java/org/tron/core/net/peer/PeerConnectionTest.java index c0d81ca2763..9db5230ed45 100644 --- a/framework/src/test/java/org/tron/core/net/peer/PeerConnectionTest.java +++ b/framework/src/test/java/org/tron/core/net/peer/PeerConnectionTest.java @@ -60,9 +60,9 @@ public void testOnDisconnect() { peerConnection.onDisconnect(); - //Assert.assertEquals(0, peerConnection.getAdvInvReceive().size()); - //Assert.assertEquals(0, peerConnection.getAdvInvSpread().size()); - //Assert.assertEquals(0, peerConnection.getSyncBlockIdCache().size()); + Assert.assertEquals(0, peerConnection.getAdvInvReceive().size()); + Assert.assertEquals(0, peerConnection.getAdvInvSpread().size()); + Assert.assertEquals(0, peerConnection.getSyncBlockIdCache().size()); Assert.assertEquals(0, peerConnection.getSyncBlockToFetch().size()); Assert.assertEquals(0, peerConnection.getSyncBlockRequested().size()); Assert.assertEquals(0, peerConnection.getSyncBlockInProcess().size()); From e81a5aa6894cb990ffed5f05c9a384b23a2db759 Mon Sep 17 00:00:00 2001 From: adir852 <59093315+adir852@users.noreply.github.com> Date: Fri, 23 Feb 2024 09:37:39 +0200 Subject: [PATCH 03/25] docs(README):fix code typos (#5730) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 89101bbc4d1..bdb0877d70b 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ TRON enables large-scale development and engagement. With over 2000 transactions # Building the source -Building java-tron requires `git` and 64-bit version of `Oracle JDK 1.8` to be installed, other JDK versions are not supported yet. Make sure you operate on `Linux` and `MacOS` operating systems. +Building java-tron requires `git` package and 64-bit version of `Oracle JDK 1.8` to be installed, other JDK versions are not supported yet. Make sure you operate on `Linux` and `MacOS` operating systems. Clone the repo and switch to the `master` branch @@ -73,7 +73,7 @@ $ cd java-tron $ git checkout -t origin/master ``` -then run the following command to build java-tron, the `FullNode.jar` file can be found in `java-tron/build/libs/` after build successful. +then run the following command to build java-tron, the `FullNode.jar` file can be found in `java-tron/build/libs/` after build successfully. ```bash $ ./gradlew clean build -x test @@ -120,7 +120,7 @@ $ nohup java -Xms9G -Xmx9G -XX:ReservedCodeCacheSize=256m \ Adding the `--witness` parameter to the startup command, full node will run as a super representative node. The super representative node supports all the functions of the full node and also supports block production. Before running, make sure you have a super representative account and get votes from others. Once the number of obtained votes ranks in the top 27, your super representative node will participate in block production. -Fill in the private key of super representative address into the `localwitness` list in the `main_net_config.conf`. Here is an example: +Fill in the private key of a super representative address into the `localwitness` list in the `main_net_config.conf`. Here is an example: ``` localwitness = [ From 88bd6341a85274112ab7968b0eec29126e754bff Mon Sep 17 00:00:00 2001 From: halibobo1205 <82020050+halibobo1205@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:20:45 +0800 Subject: [PATCH 04/25] docs(issue/template): update issue template for feature (#5774) add background,specification,test specification and scope of impact --- .github/ISSUE_TEMPLATE/request-a-feature.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/request-a-feature.md b/.github/ISSUE_TEMPLATE/request-a-feature.md index 5099a72008b..261f1088ded 100644 --- a/.github/ISSUE_TEMPLATE/request-a-feature.md +++ b/.github/ISSUE_TEMPLATE/request-a-feature.md @@ -6,13 +6,23 @@ labels: 'type:feature' assignees: '' --- +# Background # Rationale Why should this feature exist? + What are the use-cases? +# Specification + +# Test Specification + +# Scope Of Impact + + # Implementation Do you have ideas regarding the implementation of this feature? + Are you willing to implement this feature? From a126f2e40f207e0076811a6a821aa446447d0821 Mon Sep 17 00:00:00 2001 From: Casper Date: Mon, 18 Mar 2024 19:06:49 +0800 Subject: [PATCH 05/25] feat(docs): Update quickstart.md (#5773) --- quickstart.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickstart.md b/quickstart.md index 7dc2d1009fb..6eda855f1e9 100644 --- a/quickstart.md +++ b/quickstart.md @@ -28,8 +28,9 @@ cd java-tron #### Build the docker image -Use below command to start the build: +Use the command below to navigate to the docker directory and start the build: ``` +cd docker docker build -t tronprotocol/java-tron . ``` From 40d7f2695c754ce6ae8c1191dfcbc0027c90bc34 Mon Sep 17 00:00:00 2001 From: halibobo1205 <82020050+halibobo1205@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:48:28 +0800 Subject: [PATCH 06/25] docs(issue/template): update issue template for bug (#5785) --- .github/ISSUE_TEMPLATE/report-a-bug.md | 36 +++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/report-a-bug.md b/.github/ISSUE_TEMPLATE/report-a-bug.md index cfadd364c21..d3cd98beeef 100644 --- a/.github/ISSUE_TEMPLATE/report-a-bug.md +++ b/.github/ISSUE_TEMPLATE/report-a-bug.md @@ -7,20 +7,50 @@ assignees: '' --- + + + + #### System information -java-tron version: `java -jar FullNode.jar -v` -OS & Version: Windows/Linux/OSX -Commit hash : (if `develop`) + +**Versions** +* Software version: [`java -jar FullNode.jar -v`] +* Java version: [`java -version`] +* OS Name & Version: [`cat /etc/*release`] +* Kernel Version: [`uname -a`] +* Virtual Machine software & version: [`vmware -v`] +* Docker Version: [`docker version`] +* Cloud VM, type, size: [Amazon Web Services I3-large] +* Node Type: [e.g. fullNode, liteFullNode] +* Blockchain Net: [e.g. main, test or private ] +* Commit hash : [if `develop`] + +**Smart contract information (If you're reporting an issue arising from deploying or calling a smart contract, please supply related information)** +* Solidity version [`solc --version`] +* Repo with minimal set of deployable/reproducible contract code - please provide a link +* Please include specifics on how you are deploying/calling the contract + +**Additional Information (Add any of the following or anything else that may be relevant)** +* setup info - startup script, config options +* System info - memory、 CPU、network bandwidth, disk type- #### Expected behaviour + #### Actual behaviour + + +#### Frequency + #### Steps to reproduce the behaviour +1. [Step 1] +2. [Step 2] +3. [Step ...] #### Backtrace From 20f02116146972912d0171209c3730f33351c7d2 Mon Sep 17 00:00:00 2001 From: halibobo1205 Date: Fri, 19 Apr 2024 14:14:06 +0800 Subject: [PATCH 07/25] docs(issue/template): simplify issue template for bug --- .github/ISSUE_TEMPLATE/report-a-bug.md | 35 +++++++++----------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/report-a-bug.md b/.github/ISSUE_TEMPLATE/report-a-bug.md index d3cd98beeef..a0d68121565 100644 --- a/.github/ISSUE_TEMPLATE/report-a-bug.md +++ b/.github/ISSUE_TEMPLATE/report-a-bug.md @@ -11,29 +11,18 @@ assignees: '' -#### System information - - -**Versions** -* Software version: [`java -jar FullNode.jar -v`] -* Java version: [`java -version`] -* OS Name & Version: [`cat /etc/*release`] -* Kernel Version: [`uname -a`] -* Virtual Machine software & version: [`vmware -v`] -* Docker Version: [`docker version`] -* Cloud VM, type, size: [Amazon Web Services I3-large] -* Node Type: [e.g. fullNode, liteFullNode] -* Blockchain Net: [e.g. main, test or private ] -* Commit hash : [if `develop`] - -**Smart contract information (If you're reporting an issue arising from deploying or calling a smart contract, please supply related information)** -* Solidity version [`solc --version`] -* Repo with minimal set of deployable/reproducible contract code - please provide a link -* Please include specifics on how you are deploying/calling the contract - -**Additional Information (Add any of the following or anything else that may be relevant)** -* setup info - startup script, config options -* System info - memory、 CPU、network bandwidth, disk type- +#### Software Versions + + + #### Expected behaviour From 963868e44655737235106b6258f6f06b4413a956 Mon Sep 17 00:00:00 2001 From: Asuka Date: Mon, 22 Apr 2024 11:34:42 +0800 Subject: [PATCH 08/25] docs(params): fix parameter descriptions for minTimeRatio and maxTimeRatio --- .../main/java/org/tron/common/parameter/CommonParameter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 95a1eb2d0ae..f9562e580e3 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -68,12 +68,12 @@ public class CommonParameter { @Getter @Setter @Parameter(names = {"--min-time-ratio"}, description = "Maximum CPU tolerance when executing " - + "non-timeout transactions while synchronizing blocks. (default: 5.0)") + + "timeout transactions while synchronizing blocks. (default: 0.0)") public double minTimeRatio = 0.0; @Getter @Setter @Parameter(names = {"--max-time-ratio"}, description = "Maximum CPU tolerance when executing " - + "timeout transactions while synchronizing blocks. (default: 0.0)") + + "non-timeout transactions while synchronizing blocks. (default: 5.0)") public double maxTimeRatio = calcMaxTimeRatio(); @Getter @Setter From 428ede2e5d3351167608634a972258c36061e601 Mon Sep 17 00:00:00 2001 From: zeusoo001 Date: Sun, 28 Apr 2024 16:52:07 +0800 Subject: [PATCH 09/25] feat(consensus): optimize block production logic --- .../src/main/java/org/tron/consensus/dpos/DposTask.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/consensus/src/main/java/org/tron/consensus/dpos/DposTask.java b/consensus/src/main/java/org/tron/consensus/dpos/DposTask.java index 537fe49ae65..8d5697cdc89 100644 --- a/consensus/src/main/java/org/tron/consensus/dpos/DposTask.java +++ b/consensus/src/main/java/org/tron/consensus/dpos/DposTask.java @@ -91,6 +91,11 @@ private State produceBlock() { try { synchronized (dposService.getBlockHandle().getLock()) { + state = stateManager.getState(); + if (!State.OK.equals(state)) { + return state; + } + long slot = dposSlot.getSlot(System.currentTimeMillis() + 50); if (slot == 0) { return State.NOT_TIME_YET; From 8b4a5dddf31e49b7c86777b2a6efe609702fb825 Mon Sep 17 00:00:00 2001 From: zeusoo001 Date: Sun, 28 Apr 2024 17:01:40 +0800 Subject: [PATCH 10/25] fix(net): solve the problem of concurrent access to syncBlockToFetch object --- .../java/org/tron/core/net/service/sync/SyncService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/framework/src/main/java/org/tron/core/net/service/sync/SyncService.java b/framework/src/main/java/org/tron/core/net/service/sync/SyncService.java index 1e3e18441b9..9453700df0d 100644 --- a/framework/src/main/java/org/tron/core/net/service/sync/SyncService.java +++ b/framework/src/main/java/org/tron/core/net/service/sync/SyncService.java @@ -321,8 +321,9 @@ private void processSyncBlock(BlockCapsule block, PeerConnection peerConnection) } for (PeerConnection peer : tronNetDelegate.getActivePeer()) { - if (blockId.equals(peer.getSyncBlockToFetch().peek())) { - peer.getSyncBlockToFetch().pop(); + BlockId bid = peer.getSyncBlockToFetch().peek(); + if (blockId.equals(bid)) { + peer.getSyncBlockToFetch().remove(bid); if (flag) { peer.setBlockBothHave(blockId); if (peer.getSyncBlockToFetch().isEmpty() && peer.isFetchAble()) { From 934e04bc8ec840431a82791ba12d6b765eb018c8 Mon Sep 17 00:00:00 2001 From: zeusoo001 Date: Sun, 28 Apr 2024 16:48:42 +0800 Subject: [PATCH 11/25] feat(net): optimize block message processing logic --- .../net/messagehandler/BlockMsgHandler.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java b/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java index 14523df86a5..623b0140701 100644 --- a/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java +++ b/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java @@ -61,6 +61,18 @@ public void processMessage(PeerConnection peer, TronMessage msg) throws P2pExcep BlockMessage blockMessage = (BlockMessage) msg; BlockId blockId = blockMessage.getBlockId(); + BlockCapsule blockCapsule = blockMessage.getBlockCapsule(); + if (blockCapsule.getInstance().getSerializedSize() > maxBlockSize) { + logger.error("Receive bad block {} from peer {}, block size over limit", + blockMessage.getBlockId(), peer.getInetSocketAddress()); + throw new P2pException(TypeEnum.BAD_MESSAGE, "block size over limit"); + } + long gap = blockCapsule.getTimeStamp() - System.currentTimeMillis(); + if (gap >= BLOCK_PRODUCED_INTERVAL) { + logger.error("Receive bad block {} from peer {}, block time error", + blockMessage.getBlockId(), peer.getInetSocketAddress()); + throw new P2pException(TypeEnum.BAD_MESSAGE, "block time error"); + } if (!fastForward && !peer.isRelayPeer()) { check(peer, blockMessage); } @@ -109,18 +121,6 @@ private void check(PeerConnection peer, BlockMessage msg) throws P2pException { msg.getBlockId(), peer.getInetSocketAddress()); throw new P2pException(TypeEnum.BAD_MESSAGE, "no request"); } - BlockCapsule blockCapsule = msg.getBlockCapsule(); - if (blockCapsule.getInstance().getSerializedSize() > maxBlockSize) { - logger.error("Receive bad block {} from peer {}, block size over limit", - msg.getBlockId(), peer.getInetSocketAddress()); - throw new P2pException(TypeEnum.BAD_MESSAGE, "block size over limit"); - } - long gap = blockCapsule.getTimeStamp() - System.currentTimeMillis(); - if (gap >= BLOCK_PRODUCED_INTERVAL) { - logger.error("Receive bad block {} from peer {}, block time error", - msg.getBlockId(), peer.getInetSocketAddress()); - throw new P2pException(TypeEnum.BAD_MESSAGE, "block time error"); - } } private void processBlock(PeerConnection peer, BlockCapsule block) throws P2pException { From 089fa8a76a8dac38413318b2efe31770933649c0 Mon Sep 17 00:00:00 2001 From: zeusoo001 Date: Sun, 28 Apr 2024 16:59:27 +0800 Subject: [PATCH 12/25] fix(net): solve the problem of concurrent access to fetchBlockInfo object --- .../tron/core/net/service/fetchblock/FetchBlockService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/framework/src/main/java/org/tron/core/net/service/fetchblock/FetchBlockService.java b/framework/src/main/java/org/tron/core/net/service/fetchblock/FetchBlockService.java index 889f6f6e132..bda2646abbc 100644 --- a/framework/src/main/java/org/tron/core/net/service/fetchblock/FetchBlockService.java +++ b/framework/src/main/java/org/tron/core/net/service/fetchblock/FetchBlockService.java @@ -71,9 +71,10 @@ public void fetchBlock(List sha256HashList, PeerConnection peer) { sha256HashList.stream().filter(sha256Hash -> new BlockCapsule.BlockId(sha256Hash).getNum() == chainBaseManager.getHeadBlockNum() + 1) .findFirst().ifPresent(sha256Hash -> { - fetchBlockInfo = new FetchBlockInfo(sha256Hash, peer, System.currentTimeMillis()); + long now = System.currentTimeMillis(); + fetchBlockInfo = new FetchBlockInfo(sha256Hash, peer, now); logger.info("Set fetchBlockInfo, block: {}, peer: {}, time: {}", sha256Hash, - fetchBlockInfo.getPeer().getInetAddress(), fetchBlockInfo.getTime()); + peer.getInetAddress(), now); }); } From 9cc15de61a8db733852549de351d2ace645dbdcc Mon Sep 17 00:00:00 2001 From: zeusoo001 Date: Thu, 30 May 2024 10:23:53 +0800 Subject: [PATCH 13/25] feat(consensus): add unit test for DposTask --- .../org/tron/core/consensus/DposTaskTest.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 framework/src/test/java/org/tron/core/consensus/DposTaskTest.java diff --git a/framework/src/test/java/org/tron/core/consensus/DposTaskTest.java b/framework/src/test/java/org/tron/core/consensus/DposTaskTest.java new file mode 100644 index 00000000000..89d887d5fe9 --- /dev/null +++ b/framework/src/test/java/org/tron/core/consensus/DposTaskTest.java @@ -0,0 +1,64 @@ +package org.tron.core.consensus; + +import static org.mockito.Mockito.mock; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; +import org.tron.consensus.base.BlockHandle; +import org.tron.consensus.base.State; +import org.tron.consensus.dpos.DposService; +import org.tron.consensus.dpos.DposSlot; +import org.tron.consensus.dpos.DposTask; +import org.tron.consensus.dpos.StateManager; + +public class DposTaskTest { + private DposTask dposTask = new DposTask(); + + @Test + public void tet() throws Exception { + StateManager stateManager = mock(StateManager.class); + Mockito.when(stateManager.getState()).thenReturn(State.BACKUP_IS_NOT_MASTER); + + Field field = dposTask.getClass().getDeclaredField("stateManager"); + field.setAccessible(true); + field.set(dposTask, stateManager); + + Method method = dposTask.getClass().getDeclaredMethod("produceBlock"); + method.setAccessible(true); + State state = (State) method.invoke(dposTask); + + Assert.assertEquals(State.BACKUP_IS_NOT_MASTER, state); + + + Mockito.when(stateManager.getState()).thenReturn(State.OK); + + DposSlot dposSlot = mock(DposSlot.class); + Mockito.when(dposSlot.getTime(1)).thenReturn(Long.MAX_VALUE); + + field = dposTask.getClass().getDeclaredField("dposSlot"); + field.setAccessible(true); + field.set(dposTask, dposSlot); + + + Mockito.when(stateManager.getState()).thenReturn(State.OK); + + BlockHandle blockHandle = mock(BlockHandle.class); + Mockito.when(blockHandle.getLock()).thenReturn(new Object()); + + + DposService dposService = mock(DposService.class); + Mockito.when(dposService.getBlockHandle()).thenReturn(blockHandle); + + field = dposTask.getClass().getDeclaredField("dposService"); + field.setAccessible(true); + field.set(dposTask, dposService); + + state = (State) method.invoke(dposTask); + + Assert.assertEquals(State.NOT_TIME_YET, state); + } + +} From b311f9a6d0c4faf84eec61451c12b66432e684f2 Mon Sep 17 00:00:00 2001 From: zeusoo001 Date: Thu, 30 May 2024 10:32:54 +0800 Subject: [PATCH 14/25] feat(net): remove redundant code --- .../org/tron/core/net/messagehandler/BlockMsgHandler.java | 7 ------- .../java/org/tron/core/net/service/adv/AdvService.java | 1 - 2 files changed, 8 deletions(-) diff --git a/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java b/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java index 14523df86a5..66ebeaa641a 100644 --- a/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java +++ b/framework/src/main/java/org/tron/core/net/messagehandler/BlockMsgHandler.java @@ -150,14 +150,7 @@ private void processBlock(PeerConnection peer, BlockCapsule block) throws P2pExc try { tronNetDelegate.processBlock(block, false); - witnessProductBlockService.validWitnessProductTwoBlock(block); - - tronNetDelegate.getActivePeer().forEach(p -> { - if (p.getAdvInvReceive().getIfPresent(blockId) != null) { - p.setBlockBothHave(blockId); - } - }); } catch (Exception e) { logger.warn("Process adv block {} from peer {} failed. reason: {}", blockId, peer.getInetAddress(), e.getMessage()); diff --git a/framework/src/main/java/org/tron/core/net/service/adv/AdvService.java b/framework/src/main/java/org/tron/core/net/service/adv/AdvService.java index ea608c1ea86..505b53358c8 100644 --- a/framework/src/main/java/org/tron/core/net/service/adv/AdvService.java +++ b/framework/src/main/java/org/tron/core/net/service/adv/AdvService.java @@ -200,7 +200,6 @@ public void broadcast(Message msg) { logger.info("Ready to broadcast block {}", blockMsg.getBlockId().getString()); blockMsg.getBlockCapsule().getTransactions().forEach(transactionCapsule -> { Sha256Hash tid = transactionCapsule.getTransactionId(); - invToSpread.remove(tid); trxCache.put(new Item(tid, InventoryType.TRX), new TransactionMessage(transactionCapsule.getInstance())); }); From 9378787b8b8e2139ab3644d9bf335ec262a73836 Mon Sep 17 00:00:00 2001 From: halibobo1205 Date: Thu, 30 May 2024 11:42:11 +0800 Subject: [PATCH 15/25] feat(version): update version to 4.7.5 --- framework/src/main/java/org/tron/program/Version.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/main/java/org/tron/program/Version.java b/framework/src/main/java/org/tron/program/Version.java index 483f5be713f..ee624f6078a 100644 --- a/framework/src/main/java/org/tron/program/Version.java +++ b/framework/src/main/java/org/tron/program/Version.java @@ -4,7 +4,7 @@ public class Version { public static final String VERSION_NAME = "GreatVoyage-v4.7.3.1-78-ge84a9e778"; public static final String VERSION_CODE = "18260"; - private static final String VERSION = "4.7.4"; + private static final String VERSION = "4.7.5"; public static String getVersion() { return VERSION; From e434b28444934c7d39e1dd1f0d5b734b92f33cdc Mon Sep 17 00:00:00 2001 From: liuxincheng Date: Wed, 29 May 2024 22:53:27 +0800 Subject: [PATCH 16/25] feat(validate): validate account creation transaction size --- .../org/tron/core/utils/ProposalUtil.java | 19 ++++++- .../tron/core/capsule/TransactionCapsule.java | 3 ++ .../org/tron/core/db/BandwidthProcessor.java | 18 +++++-- .../org/tron/core/db/ResourceProcessor.java | 3 +- .../core/store/DynamicPropertiesStore.java | 14 ++++++ .../common/parameter/CommonParameter.java | 4 ++ .../src/main/java/org/tron/core/Constant.java | 3 ++ .../java/org/tron/core/config/Parameter.java | 5 +- .../src/main/java/org/tron/core/Wallet.java | 5 ++ .../tron/core/consensus/ProposalService.java | 4 ++ .../main/java/org/tron/core/db/Manager.java | 3 +- .../vm/BandWidthRuntimeOutOfTimeTest.java | 4 +- ...andWidthRuntimeOutOfTimeWithCheckTest.java | 4 +- .../runtime/vm/BandWidthRuntimeTest.java | 4 +- .../vm/BandWidthRuntimeWithCheckTest.java | 3 +- .../org/tron/core/BandwidthProcessorTest.java | 7 +++ .../actuator/ProposalCreateActuatorTest.java | 50 +++++++++++++++++++ .../org/tron/core/config/args/ArgsTest.java | 1 + 18 files changed, 142 insertions(+), 12 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 cfec5b09d96..c82ed0a8302 100644 --- a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java @@ -1,5 +1,7 @@ package org.tron.core.utils; +import static org.tron.core.Constant.CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE; +import static org.tron.core.Constant.CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE; import static org.tron.core.Constant.DYNAMIC_ENERGY_INCREASE_FACTOR_RANGE; import static org.tron.core.Constant.DYNAMIC_ENERGY_MAX_FACTOR_RANGE; import static org.tron.core.config.Parameter.ChainConstant.ONE_YEAR_BLOCK_NUMBERS; @@ -748,6 +750,20 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, } break; } + case MAX_CREATE_ACCOUNT_TX_SIZE: { + if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_7_5)) { + throw new ContractValidateException( + "Bad chain parameter id [MAX_CREATE_ACCOUNT_TX_SIZE]"); + } + if (value < CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE + || value > CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE) { + throw new ContractValidateException( + "This value[MAX_CREATE_ACCOUNT_TX_SIZE] is only allowed to be greater than or equal " + + "to " + CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE + " and less than or equal to " + + CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE + "!"); + } + break; + } default: break; } @@ -824,7 +840,8 @@ public enum ProposalType { // current value, value range ALLOW_TVM_SHANGHAI(76), // 0, 1 ALLOW_CANCEL_ALL_UNFREEZE_V2(77), // 0, 1 MAX_DELEGATE_LOCK_PERIOD(78), // (86400, 10512000] - ALLOW_OLD_REWARD_OPT(79); // 0, 1 + ALLOW_OLD_REWARD_OPT(79), // 0, 1 + MAX_CREATE_ACCOUNT_TX_SIZE(82); // [500, 10000] private long code; diff --git a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java index a588b28c748..f897e5d848a 100755 --- a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java @@ -114,6 +114,9 @@ public class TransactionCapsule implements ProtoCapsule { @Getter @Setter private boolean isTransactionCreate = false; + @Getter + @Setter + private boolean isInBlock = false; public byte[] getOwnerAddress() { if (this.ownerAddress == null) { diff --git a/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java b/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java index f13002f2dfa..d6da5904aa3 100644 --- a/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java +++ b/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java @@ -1,8 +1,10 @@ package org.tron.core.db; +import static org.tron.core.Constant.PER_SIGN_LENGTH; import static org.tron.core.config.Parameter.ChainConstant.TRX_PRECISION; import static org.tron.protos.Protocol.Transaction.Contract.ContractType.ShieldedTransferContract; import static org.tron.protos.Protocol.Transaction.Contract.ContractType.TransferAssetContract; +import static org.tron.protos.contract.Common.ResourceCode.BANDWIDTH; import com.google.protobuf.ByteString; import java.util.HashMap; @@ -19,13 +21,12 @@ import org.tron.core.capsule.TransactionCapsule; import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.protos.Protocol.Transaction.Contract; import org.tron.protos.contract.AssetIssueContractOuterClass.TransferAssetContract; import org.tron.protos.contract.BalanceContract.TransferContract; -import static org.tron.protos.contract.Common.ResourceCode.BANDWIDTH; - @Slf4j(topic = "DB") public class BandwidthProcessor extends ResourceProcessor { @@ -95,7 +96,7 @@ public void updateUsage(AssetIssueCapsule assetIssueCapsule, long now) { @Override public void consume(TransactionCapsule trx, TransactionTrace trace) throws ContractValidateException, AccountResourceInsufficientException, - TooBigTransactionResultException { + TooBigTransactionResultException, TooBigTransactionException { List contracts = trx.getInstance().getRawData().getContractList(); if (trx.getResultSerializedSize() > Constant.MAX_RESULT_SIZE_IN_TX * contracts.size()) { throw new TooBigTransactionResultException(); @@ -127,6 +128,17 @@ public void consume(TransactionCapsule trx, TransactionTrace trace) } long now = chainBaseManager.getHeadSlot(); if (contractCreateNewAccount(contract)) { + if (!trx.isInBlock()) { + long maxCreateAccountTxSize = dynamicPropertiesStore.getMaxCreateAccountTxSize(); + int signatureCount = trx.getInstance().getSignatureCount(); + long createAccountBytesSize = trx.getInstance().toBuilder().clearRet() + .build().getSerializedSize() - (signatureCount * PER_SIGN_LENGTH); + if (createAccountBytesSize > maxCreateAccountTxSize) { + throw new TooBigTransactionException(String.format( + "Too big new account transaction, TxId %s, the size is %d bytes, maxTxSize %d", + trx.getTransactionId(), createAccountBytesSize, maxCreateAccountTxSize)); + } + } consumeForCreateNewAccount(accountCapsule, bytesSize, now, trace); continue; } diff --git a/chainbase/src/main/java/org/tron/core/db/ResourceProcessor.java b/chainbase/src/main/java/org/tron/core/db/ResourceProcessor.java index a7a22390958..c1875408850 100644 --- a/chainbase/src/main/java/org/tron/core/db/ResourceProcessor.java +++ b/chainbase/src/main/java/org/tron/core/db/ResourceProcessor.java @@ -11,6 +11,7 @@ import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.BalanceInsufficientException; import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.core.store.AccountStore; import org.tron.core.store.DynamicPropertiesStore; @@ -35,7 +36,7 @@ protected ResourceProcessor(DynamicPropertiesStore dynamicPropertiesStore, } abstract void consume(TransactionCapsule trx, TransactionTrace trace) - throws ContractValidateException, AccountResourceInsufficientException, TooBigTransactionResultException; + throws ContractValidateException, AccountResourceInsufficientException, TooBigTransactionResultException, TooBigTransactionException; protected long increase(long lastUsage, long usage, long lastTime, long now) { return increase(lastUsage, usage, lastTime, now, windowSize); 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 bf788232640..57a21753b9a 100644 --- a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java +++ b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java @@ -219,6 +219,8 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking private static final byte[] ALLOW_OLD_REWARD_OPT = "ALLOW_OLD_REWARD_OPT".getBytes(); + private static final byte[] MAX_CREATE_ACCOUNT_TX_SIZE = "MAX_CREATE_ACCOUNT_TX_SIZE".getBytes(); + @Autowired private DynamicPropertiesStore(@Value("properties") String dbName) { super(dbName); @@ -2850,6 +2852,18 @@ public long getAllowOldRewardOpt() { .orElse(CommonParameter.getInstance().getAllowOldRewardOpt()); } + public void saveMaxCreateAccountTxSize(long maxCreateAccountTxSize) { + this.put(MAX_CREATE_ACCOUNT_TX_SIZE, + new BytesCapsule(ByteArray.fromLong(maxCreateAccountTxSize))); + } + + public long getMaxCreateAccountTxSize() { + return Optional.ofNullable(getUnchecked(MAX_CREATE_ACCOUNT_TX_SIZE)) + .map(BytesCapsule::getData) + .map(ByteArray::toLong) + .orElse(CommonParameter.getInstance().getMaxCreateAccountTxSize()); + } + 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 f9562e580e3..d511f6b0d49 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -666,6 +666,10 @@ public class CommonParameter { @Setter public long allowOldRewardOpt; + @Getter + @Setter + public long maxCreateAccountTxSize = 1000L; + 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 2cd9ea95f15..729f59c8317 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -24,6 +24,8 @@ public class Constant { // config for transaction public static final long TRANSACTION_MAX_BYTE_SIZE = 500 * 1_024L; + public static final int CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE = 500; + public static final int CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE = 10000; public static final long MAXIMUM_TIME_UNTIL_EXPIRATION = 24 * 60 * 60 * 1_000L; //one day public static final long TRANSACTION_DEFAULT_EXPIRATION_TIME = 60 * 1_000L; //60 seconds public static final long TRANSACTION_FEE_POOL_PERIOD = 1; //1 blocks @@ -31,6 +33,7 @@ public class Constant { public static final long SUN_PER_ENERGY = 100; // 1 us = 100 SUN = 100 * 10^-6 TRX public static final long ENERGY_LIMIT_IN_CONSTANT_TX = 3_000_000L; // ref: 1 us = 1 energy public static final long MAX_RESULT_SIZE_IN_TX = 64; // max 8 * 8 items in result + public static final long PER_SIGN_LENGTH = 65L; public static final long PB_DEFAULT_ENERGY_LIMIT = 0L; public static final long CREATOR_DEFAULT_ENERGY_LIMIT = 1000 * 10_000L; 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 247826af77a..027c225eb5d 100644 --- a/common/src/main/java/org/tron/core/config/Parameter.java +++ b/common/src/main/java/org/tron/core/config/Parameter.java @@ -23,7 +23,8 @@ public enum ForkBlockVersionEnum { VERSION_4_7(26, 1596780000000L, 80), VERSION_4_7_1(27, 1596780000000L, 80), VERSION_4_7_2(28, 1596780000000L, 80), - VERSION_4_7_4(29, 1596780000000L, 80); + VERSION_4_7_4(29, 1596780000000L, 80), + VERSION_4_7_5(30, 1596780000000L, 80); // if add a version, modify BLOCK_VERSION simultaneously @Getter @@ -72,7 +73,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 = 29; + public static final int BLOCK_VERSION = 30; 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; diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index 96af6fc7476..50dffcf3c83 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -1334,6 +1334,11 @@ public Protocol.ChainParameters getChainParameters() { .setValue(dbManager.getDynamicPropertiesStore().getAllowOldRewardOpt()) .build()); + builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder() + .setKey("getMaxCreateAccountTxSize") + .setValue(dbManager.getDynamicPropertiesStore().getMaxCreateAccountTxSize()) + .build()); + return builder.build(); } 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 58da117cfc6..73628c6e2b9 100644 --- a/framework/src/main/java/org/tron/core/consensus/ProposalService.java +++ b/framework/src/main/java/org/tron/core/consensus/ProposalService.java @@ -359,6 +359,10 @@ public static boolean process(Manager manager, ProposalCapsule proposalCapsule) manager.getDynamicPropertiesStore().saveAllowOldRewardOpt(entry.getValue()); break; } + case MAX_CREATE_ACCOUNT_TX_SIZE: { + manager.getDynamicPropertiesStore().saveMaxCreateAccountTxSize(entry.getValue()); + break; + } default: find = false; break; diff --git a/framework/src/main/java/org/tron/core/db/Manager.java b/framework/src/main/java/org/tron/core/db/Manager.java index 63bbef9ff7f..69265951ea8 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -966,7 +966,7 @@ public void consumeMemoFee(TransactionCapsule trx, TransactionTrace trace) public void consumeBandwidth(TransactionCapsule trx, TransactionTrace trace) throws ContractValidateException, AccountResourceInsufficientException, - TooBigTransactionResultException { + TooBigTransactionResultException, TooBigTransactionException { BandwidthProcessor processor = new BandwidthProcessor(chainBaseManager); processor.consume(trx, trace); } @@ -1422,6 +1422,7 @@ public TransactionInfo processTransaction(final TransactionCapsule trxCap, Block if (Objects.nonNull(blockCap)) { chainBaseManager.getBalanceTraceStore().initCurrentTransactionBalanceTrace(trxCap); + trxCap.setInBlock(true); } validateTapos(trxCap); diff --git a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeTest.java b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeTest.java index afac8cd7d22..30bba35b43c 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeTest.java @@ -33,6 +33,7 @@ import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.core.exception.TronException; import org.tron.core.exception.VMIllegalException; @@ -154,7 +155,8 @@ public void testSuccess() { private byte[] createContract() throws ContractValidateException, AccountResourceInsufficientException, - TooBigTransactionResultException, ContractExeException, VMIllegalException { + TooBigTransactionResultException, ContractExeException, VMIllegalException, + TooBigTransactionException { AccountCapsule owner = dbManager.getAccountStore() .get(Commons.decodeFromBase58Check(OwnerAddress)); long energy = owner.getEnergyUsage(); diff --git a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeWithCheckTest.java b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeWithCheckTest.java index 7203388f815..0eef2266f9d 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeWithCheckTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeOutOfTimeWithCheckTest.java @@ -34,6 +34,7 @@ import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; import org.tron.core.exception.ReceiptCheckErrException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.core.exception.TronException; import org.tron.core.exception.VMIllegalException; @@ -156,7 +157,8 @@ public void testSuccess() { private byte[] createContract() throws ContractValidateException, AccountResourceInsufficientException, - TooBigTransactionResultException, ContractExeException, VMIllegalException { + TooBigTransactionResultException, ContractExeException, VMIllegalException, + TooBigTransactionException { AccountCapsule owner = dbManager.getAccountStore() .get(Commons.decodeFromBase58Check(OwnerAddress)); long energy = owner.getEnergyUsage(); diff --git a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java index 40c5908c2dd..8b8e3a3c1eb 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java @@ -35,6 +35,7 @@ import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.core.exception.TronException; import org.tron.core.exception.VMIllegalException; @@ -186,7 +187,8 @@ public void testSuccessNoBandd() { private byte[] createContract() throws ContractValidateException, AccountResourceInsufficientException, - TooBigTransactionResultException, ContractExeException, VMIllegalException { + TooBigTransactionResultException, ContractExeException, VMIllegalException, + TooBigTransactionException { AccountCapsule owner = dbManager.getAccountStore() .get(Commons.decodeFromBase58Check(OwnerAddress)); long energy = owner.getEnergyUsage(); diff --git a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeWithCheckTest.java b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeWithCheckTest.java index e359e7eab1a..4b3331187e2 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeWithCheckTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeWithCheckTest.java @@ -34,6 +34,7 @@ import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; import org.tron.core.exception.ReceiptCheckErrException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.core.exception.TronException; import org.tron.core.exception.VMIllegalException; @@ -198,7 +199,7 @@ public void testSuccessNoBandWidth() { private byte[] createContract() throws ContractValidateException, AccountResourceInsufficientException, TooBigTransactionResultException, ContractExeException, ReceiptCheckErrException, - VMIllegalException { + VMIllegalException, TooBigTransactionException { AccountCapsule owner = dbManager.getAccountStore() .get(Commons.decodeFromBase58Check(OwnerAddress)); long energy = owner.getEnergyUsage(); diff --git a/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java b/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java index 300c202e11a..7d13892c635 100755 --- a/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java +++ b/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java @@ -19,6 +19,7 @@ import org.tron.core.db.TransactionTrace; import org.tron.core.exception.AccountResourceInsufficientException; import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.TooBigTransactionException; import org.tron.core.exception.TooBigTransactionResultException; import org.tron.core.store.StoreFactory; import org.tron.protos.Protocol; @@ -646,6 +647,8 @@ public void sameTokenNameCloseConsumeSuccess() { Assert.assertFalse(e instanceof TooBigTransactionResultException); } catch (AccountResourceInsufficientException e) { Assert.assertFalse(e instanceof AccountResourceInsufficientException); + } catch (TooBigTransactionException e) { + Assert.fail(); } finally { chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(OWNER_ADDRESS)); chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(TO_ADDRESS)); @@ -752,6 +755,8 @@ public void sameTokenNameOpenConsumeSuccess() { Assert.assertFalse(e instanceof TooBigTransactionResultException); } catch (AccountResourceInsufficientException e) { Assert.assertFalse(e instanceof AccountResourceInsufficientException); + } catch (TooBigTransactionException e) { + Assert.fail(); } finally { chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(OWNER_ADDRESS)); chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(TO_ADDRESS)); @@ -821,6 +826,8 @@ public void sameTokenNameCloseTransferToAccountNotExist() { Assert.assertFalse(e instanceof TooBigTransactionResultException); } catch (AccountResourceInsufficientException e) { Assert.assertFalse(e instanceof AccountResourceInsufficientException); + } catch (TooBigTransactionException e) { + Assert.fail(); } finally { chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(OWNER_ADDRESS)); chainBaseManager.getAccountStore().delete(ByteArray.fromHexString(TO_ADDRESS)); diff --git a/framework/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java b/framework/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java index a42a4ffbe5a..7210fe8d074 100644 --- a/framework/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java +++ b/framework/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java @@ -1,6 +1,10 @@ package org.tron.core.actuator; import static junit.framework.TestCase.fail; +import static org.junit.Assert.assertThrows; +import static org.tron.core.Constant.CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE; +import static org.tron.core.Constant.CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE; +import static org.tron.core.config.Parameter.ChainConstant.ONE_YEAR_BLOCK_NUMBERS; import com.google.protobuf.Any; import com.google.protobuf.ByteString; @@ -9,8 +13,10 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; import org.tron.common.BaseTest; import org.tron.common.utils.ByteArray; +import org.tron.common.utils.ForkController; import org.tron.core.Constant; import org.tron.core.Wallet; import org.tron.core.capsule.AccountCapsule; @@ -279,6 +285,50 @@ public void invalidPara() { Assert.assertEquals("This value[REMOVE_THE_POWER_OF_THE_GR] is only allowed to be 1", e.getMessage()); } + // verify Proposal No. 78 + paras = new HashMap<>(); + paras.put(78L, 10L); + actuator = new ProposalCreateActuator(); + actuator.setChainBaseManager(dbManager.getChainBaseManager()) + .setForkUtils(dbManager.getChainBaseManager().getForkController()) + .setAny(getContract(OWNER_ADDRESS_FIRST, paras)); + assertThrows( + "Bad chain parameter id [MAX_DELEGATE_LOCK_PERIOD]", + ContractValidateException.class, actuator::validate); + + actuator = new ProposalCreateActuator(); + ForkController forkController = Mockito.mock(ForkController.class); + Mockito.when(forkController.pass(Mockito.any())).thenReturn(true); + actuator.setChainBaseManager(dbManager.getChainBaseManager()) + .setForkUtils(forkController) + .setAny(getContract(OWNER_ADDRESS_FIRST, paras)); + dbManager.getDynamicPropertiesStore().saveMaxDelegateLockPeriod(86400L); + long maxDelegateLockPeriod = dbManager.getDynamicPropertiesStore().getMaxDelegateLockPeriod(); + assertThrows( + "This value[MAX_DELEGATE_LOCK_PERIOD] is only allowed to be greater than " + + maxDelegateLockPeriod + " and less than or equal to " + ONE_YEAR_BLOCK_NUMBERS + "!", + ContractValidateException.class, actuator::validate); + + // verify Proposal No. 82 + paras = new HashMap<>(); + paras.put(82L, 0L); + actuator = new ProposalCreateActuator(); + actuator.setChainBaseManager(dbManager.getChainBaseManager()) + .setForkUtils(dbManager.getChainBaseManager().getForkController()) + .setAny(getContract(OWNER_ADDRESS_FIRST, paras)); + assertThrows( + "Bad chain parameter id [ALLOW_ENERGY_ADJUSTMENT]", + ContractValidateException.class, actuator::validate); + + actuator = new ProposalCreateActuator(); + actuator.setChainBaseManager(dbManager.getChainBaseManager()) + .setForkUtils(forkController) + .setAny(getContract(OWNER_ADDRESS_FIRST, paras)); + assertThrows( + "This value[MAX_CREATE_ACCOUNT_TX_SIZE] is only allowed to be greater than or equal " + + "to " + CREATE_ACCOUNT_TRANSACTION_MIN_BYTE_SIZE + " and less than or equal to " + + CREATE_ACCOUNT_TRANSACTION_MAX_BYTE_SIZE + "!", + ContractValidateException.class, actuator::validate); } /** diff --git a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java index 52307d9d294..5bbf08fd96e 100644 --- a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java +++ b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java @@ -101,6 +101,7 @@ public void get() { Assert.assertEquals(43, parameter.getNodeP2pVersion()); Assert.assertEquals(54, parameter.getMaxUnsolidifiedBlocks()); Assert.assertEquals(false, parameter.isUnsolidifiedBlockCheck()); + Assert.assertEquals(1000, parameter.getMaxCreateAccountTxSize()); //Assert.assertEquals(30, args.getSyncNodeCount()); // gRPC network configs checking From d1f851193b06f22e1a760c5f654d491384f1392f Mon Sep 17 00:00:00 2001 From: Asuka Date: Tue, 30 Apr 2024 16:44:17 +0800 Subject: [PATCH 17/25] func(proposal,tvm): add energy adjustment proposal and implement --- .../org/tron/core/actuator/VMActuator.java | 7 +++++ .../org/tron/core/utils/ProposalUtil.java | 13 +++++++- .../java/org/tron/core/vm/EnergyCost.java | 31 ++++++++++++++++++- .../org/tron/core/vm/OperationRegistry.java | 17 ++++++++++ .../main/java/org/tron/core/vm/VMUtils.java | 7 ++++- .../org/tron/core/vm/config/ConfigLoader.java | 1 + .../org/tron/core/vm/config/VMConfig.java | 10 ++++++ .../org/tron/core/vm/program/Program.java | 3 +- .../core/store/DynamicPropertiesStore.java | 13 ++++++++ .../common/parameter/CommonParameter.java | 4 +++ .../src/main/java/org/tron/core/Constant.java | 4 +++ .../java/org/tron/core/config/Parameter.java | 5 +-- .../src/main/java/org/tron/core/Wallet.java | 5 +++ .../java/org/tron/core/config/args/Args.java | 5 +++ .../tron/core/consensus/ProposalService.java | 4 +++ 15 files changed, 123 insertions(+), 6 deletions(-) diff --git a/actuator/src/main/java/org/tron/core/actuator/VMActuator.java b/actuator/src/main/java/org/tron/core/actuator/VMActuator.java index 326e2472757..31db5d799e2 100644 --- a/actuator/src/main/java/org/tron/core/actuator/VMActuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/VMActuator.java @@ -189,6 +189,13 @@ public void execute(Object object) throws ContractExeException { VM.play(program, OperationRegistry.getTable()); result = program.getResult(); + if (VMConfig.allowEnergyAdjustment()) { + // If the last op consumed too much execution time, the CPU time limit for the whole tx can be exceeded. + // This is not fair for other txs in the same block. + // So when allowFairEnergyAdjustment is on, the CPU time limit will be checked at the end of tx execution. + program.checkCPUTimeLimit("TX_LAST_OP"); + } + if (TrxType.TRX_CONTRACT_CREATION_TYPE == trxType && !result.isRevert()) { byte[] code = program.getResult().getHReturn(); if (code.length != 0 && VMConfig.allowTvmLondon() && code[0] == (byte) 0xEF) { 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 cfec5b09d96..3521bacfa35 100644 --- a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java @@ -748,6 +748,16 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, } break; } + case ALLOW_ENERGY_ADJUSTMENT: { + if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_7_5)) { + throw new ContractValidateException( + "Bad chain parameter id [ALLOW_ENERGY_ADJUSTMENT]"); + } + if (value != 1) { + throw new ContractValidateException( + "This value[ALLOW_ENERGY_ADJUSTMENT] is only allowed to be 1"); + } + } default: break; } @@ -824,7 +834,8 @@ public enum ProposalType { // current value, value range ALLOW_TVM_SHANGHAI(76), // 0, 1 ALLOW_CANCEL_ALL_UNFREEZE_V2(77), // 0, 1 MAX_DELEGATE_LOCK_PERIOD(78), // (86400, 10512000] - ALLOW_OLD_REWARD_OPT(79); // 0, 1 + ALLOW_OLD_REWARD_OPT(79), // 0, 1 + ALLOW_ENERGY_ADJUSTMENT(80); // 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 3b62b2f549a..6638b22d47f 100644 --- a/actuator/src/main/java/org/tron/core/vm/EnergyCost.java +++ b/actuator/src/main/java/org/tron/core/vm/EnergyCost.java @@ -259,12 +259,19 @@ public static long getSuicideCost(Program ignored) { return SUICIDE; } + public static long getSuicideCost2(Program program) { + DataWord inheritorAddress = program.getStack().peek(); + if (isDeadAccount(program, inheritorAddress)) { + return getSuicideCost(program) + NEW_ACCT_CALL; + } + return getSuicideCost(program); + } + public static long getBalanceCost(Program ignored) { return BALANCE; } public static long getFreezeCost(Program program) { - Stack stack = program.getStack(); DataWord receiverAddressWord = stack.get(stack.size() - 3); if (isDeadAccount(program, receiverAddressWord)) { @@ -306,7 +313,27 @@ public static long getUnDelegateResourceCost(Program ignored) { } public static long getVoteWitnessCost(Program program) { + Stack stack = program.getStack(); + long oldMemSize = program.getMemSize(); + DataWord amountArrayLength = stack.get(stack.size() - 1).clone(); + DataWord amountArrayOffset = stack.get(stack.size() - 2); + DataWord witnessArrayLength = stack.get(stack.size() - 3).clone(); + DataWord witnessArrayOffset = stack.get(stack.size() - 4); + + DataWord wordSize = new DataWord(DataWord.WORD_SIZE); + + amountArrayLength.mul(wordSize); + BigInteger amountArrayMemoryNeeded = memNeeded(amountArrayOffset, amountArrayLength); + + witnessArrayLength.mul(wordSize); + BigInteger witnessArrayMemoryNeeded = memNeeded(witnessArrayOffset, witnessArrayLength); + + return VOTE_WITNESS + calcMemEnergy(oldMemSize, + (amountArrayMemoryNeeded.compareTo(witnessArrayMemoryNeeded) > 0 + ? amountArrayMemoryNeeded : witnessArrayMemoryNeeded), 0, Op.VOTEWITNESS); + } + public static long getVoteWitnessCost2(Program program) { Stack stack = program.getStack(); long oldMemSize = program.getMemSize(); DataWord amountArrayLength = stack.get(stack.size() - 1).clone(); @@ -317,9 +344,11 @@ public static long getVoteWitnessCost(Program program) { DataWord wordSize = new DataWord(DataWord.WORD_SIZE); amountArrayLength.mul(wordSize); + amountArrayLength.add(wordSize); // dynamic array length is at least 32 bytes BigInteger amountArrayMemoryNeeded = memNeeded(amountArrayOffset, amountArrayLength); witnessArrayLength.mul(wordSize); + witnessArrayLength.add(wordSize); // dynamic array length is at least 32 bytes BigInteger witnessArrayMemoryNeeded = memNeeded(witnessArrayOffset, witnessArrayLength); return VOTE_WITNESS + calcMemEnergy(oldMemSize, 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 e4b1e174702..8cf0ea7242a 100644 --- a/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java +++ b/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java @@ -67,6 +67,10 @@ public static JumpTable getTable() { adjustMemOperations(table); } + if (VMConfig.allowEnergyAdjustment()) { + ajustForFairEnergy(table); + } + return table; } @@ -635,4 +639,17 @@ public static void appendShangHaiOperations(JumpTable table) { OperationActions::push0Action, proposal)); } + + public static void ajustForFairEnergy(JumpTable table) { + table.set(new Operation( + Op.VOTEWITNESS, 4, 1, + EnergyCost::getVoteWitnessCost2, + OperationActions::voteWitnessAction, + VMConfig::allowTvmVote)); + + table.set(new Operation( + Op.SUICIDE, 1, 0, + EnergyCost::getSuicideCost2, + OperationActions::suicideAction)); + } } diff --git a/actuator/src/main/java/org/tron/core/vm/VMUtils.java b/actuator/src/main/java/org/tron/core/vm/VMUtils.java index abdf6c7fe4c..1df0e0e22f1 100644 --- a/actuator/src/main/java/org/tron/core/vm/VMUtils.java +++ b/actuator/src/main/java/org/tron/core/vm/VMUtils.java @@ -12,7 +12,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; -import java.util.Map; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; import lombok.extern.slf4j.Slf4j; @@ -20,6 +19,7 @@ import org.tron.common.utils.ByteUtil; import org.tron.common.utils.Commons; import org.tron.common.utils.DecodeUtil; +import org.tron.core.Constant; import org.tron.core.capsule.AccountCapsule; import org.tron.core.exception.ContractValidateException; import org.tron.core.vm.config.VMConfig; @@ -33,6 +33,11 @@ public final class VMUtils { private VMUtils() { } + public static int getAddressSize() { + return VMConfig.allowEnergyAdjustment() ? + Constant.TRON_ADDRESS_SIZE : Constant.STANDARD_ADDRESS_SIZE; + } + public static void closeQuietly(Closeable closeable) { try { if (closeable != null) { 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 463d8c8995a..63c3ff791d6 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 @@ -39,6 +39,7 @@ public static void load(StoreFactory storeFactory) { VMConfig.initDynamicEnergyIncreaseFactor(ds.getDynamicEnergyIncreaseFactor()); VMConfig.initDynamicEnergyMaxFactor(ds.getDynamicEnergyMaxFactor()); VMConfig.initAllowTvmShangHai(ds.getAllowTvmShangHai()); + VMConfig.initAllowEnergyAdjustment(ds.getAllowEnergyAdjustment()); } } } 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 97202432598..3eb1f8fd4b8 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 @@ -49,6 +49,8 @@ public class VMConfig { private static boolean ALLOW_TVM_SHANGHAI = false; + private static boolean ALLOW_ENERGY_ADJUSTMENT = false; + private VMConfig() { } @@ -136,6 +138,10 @@ public static void initAllowTvmShangHai(long allow) { ALLOW_TVM_SHANGHAI = allow == 1; } + public static void initAllowEnergyAdjustment(long allow) { + ALLOW_ENERGY_ADJUSTMENT = allow == 1; + } + public static boolean getEnergyLimitHardFork() { return CommonParameter.ENERGY_LIMIT_HARD_FORK; } @@ -211,4 +217,8 @@ public static long getDynamicEnergyMaxFactor() { public static boolean allowTvmShanghai() { return ALLOW_TVM_SHANGHAI; } + + public static boolean allowEnergyAdjustment() { + return ALLOW_ENERGY_ADJUSTMENT; + } } 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 e02ba225c6b..2e547dc86f2 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 @@ -457,7 +457,8 @@ public void suicide(DataWord obtainerAddress) { InternalTransaction internalTx = addInternalTx(null, owner, obtainer, balance, null, "suicide", nonce, getContractState().getAccount(owner).getAssetMapV2()); - if (FastByteComparisons.compareTo(owner, 0, 20, obtainer, 0, 20) == 0) { + int ADDRESS_SIZE = VMUtils.getAddressSize(); + if (FastByteComparisons.compareTo(owner, 0, ADDRESS_SIZE, obtainer, 0, ADDRESS_SIZE) == 0) { // if owner == obtainer just zeroing account according to Yellow Paper getContractState().addBalance(owner, -balance); byte[] blackHoleAddress = getContractState().getBlackHoleAddress(); 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 bf788232640..5c1a3d7b460 100644 --- a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java +++ b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java @@ -219,6 +219,8 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking private static final byte[] ALLOW_OLD_REWARD_OPT = "ALLOW_OLD_REWARD_OPT".getBytes(); + private static final byte[] ALLOW_ENERGY_ADJUSTMENT = "ALLOW_FAIR_ENERGY_ADJUSTMENT".getBytes(); + @Autowired private DynamicPropertiesStore(@Value("properties") String dbName) { super(dbName); @@ -2850,6 +2852,17 @@ public long getAllowOldRewardOpt() { .orElse(CommonParameter.getInstance().getAllowOldRewardOpt()); } + public void saveAllowEnergyAdjustment(long allowEnergyAdjustment) { + this.put(ALLOW_ENERGY_ADJUSTMENT, new BytesCapsule(ByteArray.fromLong(allowEnergyAdjustment))); + } + + public long getAllowEnergyAdjustment() { + return Optional.ofNullable(getUnchecked(ALLOW_ENERGY_ADJUSTMENT)) + .map(BytesCapsule::getData) + .map(ByteArray::toLong) + .orElse(CommonParameter.getInstance().getAllowEnergyAdjustment()); + } + 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 f9562e580e3..eb6398d631b 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -666,6 +666,10 @@ public class CommonParameter { @Setter public long allowOldRewardOpt; + @Getter + @Setter + public long allowEnergyAdjustment; + 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 2cd9ea95f15..d91506d71fa 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -18,6 +18,8 @@ public class Constant { public static final String ADD_PRE_FIX_STRING_MAINNET = "41"; public static final byte ADD_PRE_FIX_BYTE_TESTNET = (byte) 0xa0; //a0 + address public static final String ADD_PRE_FIX_STRING_TESTNET = "a0"; + public static final int STANDARD_ADDRESS_SIZE = 20; + public static final int TRON_ADDRESS_SIZE = 21; public static final int NODE_TYPE_FULL_NODE = 0; public static final int NODE_TYPE_LIGHT_NODE = 1; @@ -376,4 +378,6 @@ public class Constant { public static final String MAX_UNSOLIDIFIED_BLOCKS = "node.maxUnsolidifiedBlocks"; public static final String COMMITTEE_ALLOW_OLD_REWARD_OPT = "committee.allowOldRewardOpt"; + + public static final String COMMITTEE_ALLOW_ENERGY_ADJUSTMENT = "committee.allowEnergyAdjustment"; } 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 247826af77a..027c225eb5d 100644 --- a/common/src/main/java/org/tron/core/config/Parameter.java +++ b/common/src/main/java/org/tron/core/config/Parameter.java @@ -23,7 +23,8 @@ public enum ForkBlockVersionEnum { VERSION_4_7(26, 1596780000000L, 80), VERSION_4_7_1(27, 1596780000000L, 80), VERSION_4_7_2(28, 1596780000000L, 80), - VERSION_4_7_4(29, 1596780000000L, 80); + VERSION_4_7_4(29, 1596780000000L, 80), + VERSION_4_7_5(30, 1596780000000L, 80); // if add a version, modify BLOCK_VERSION simultaneously @Getter @@ -72,7 +73,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 = 29; + public static final int BLOCK_VERSION = 30; 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; diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index 96af6fc7476..d192fa020e0 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -1334,6 +1334,11 @@ public Protocol.ChainParameters getChainParameters() { .setValue(dbManager.getDynamicPropertiesStore().getAllowOldRewardOpt()) .build()); + builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder() + .setKey("getAllowEnergyAdjustment") + .setValue(dbManager.getDynamicPropertiesStore().getAllowEnergyAdjustment()) + .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 a8547b73948..422efefaed8 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 @@ -232,6 +232,7 @@ public static void clearParam() { PARAMETER.unsolidifiedBlockCheck = false; PARAMETER.maxUnsolidifiedBlocks = 54; PARAMETER.allowOldRewardOpt = 0; + PARAMETER.allowEnergyAdjustment = 0; } /** @@ -1205,6 +1206,10 @@ public static void setParam(final String[] args, final String confFileName) { } PARAMETER.allowOldRewardOpt = allowOldRewardOpt; + PARAMETER.allowEnergyAdjustment = + config.hasPath(Constant.COMMITTEE_ALLOW_ENERGY_ADJUSTMENT) ? config + .getInt(Constant.COMMITTEE_ALLOW_ENERGY_ADJUSTMENT) : 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 58da117cfc6..bd157a2592f 100644 --- a/framework/src/main/java/org/tron/core/consensus/ProposalService.java +++ b/framework/src/main/java/org/tron/core/consensus/ProposalService.java @@ -359,6 +359,10 @@ public static boolean process(Manager manager, ProposalCapsule proposalCapsule) manager.getDynamicPropertiesStore().saveAllowOldRewardOpt(entry.getValue()); break; } + case ALLOW_ENERGY_ADJUSTMENT: { + manager.getDynamicPropertiesStore().saveAllowEnergyAdjustment(entry.getValue()); + break; + } default: find = false; break; From 2fbb853d3d60006c494e5d11a8a52a6478c6c715 Mon Sep 17 00:00:00 2001 From: Asuka Date: Mon, 6 May 2024 14:40:49 +0800 Subject: [PATCH 18/25] func(proposal): adjust proposal id --- actuator/src/main/java/org/tron/core/utils/ProposalUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3521bacfa35..12d85901b30 100644 --- a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java @@ -835,7 +835,7 @@ public enum ProposalType { // current value, value range ALLOW_CANCEL_ALL_UNFREEZE_V2(77), // 0, 1 MAX_DELEGATE_LOCK_PERIOD(78), // (86400, 10512000] ALLOW_OLD_REWARD_OPT(79), // 0, 1 - ALLOW_ENERGY_ADJUSTMENT(80); // 0, 1 + ALLOW_ENERGY_ADJUSTMENT(81); // 0, 1 private long code; From 7491af6d4724e1c451e9ca6a7de9bc9baaf9b2b2 Mon Sep 17 00:00:00 2001 From: Asuka Date: Thu, 9 May 2024 14:33:30 +0800 Subject: [PATCH 19/25] fix(proposal): should break for each proposal case --- actuator/src/main/java/org/tron/core/utils/ProposalUtil.java | 1 + 1 file changed, 1 insertion(+) 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 12d85901b30..6501b40ac79 100644 --- a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java @@ -757,6 +757,7 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, throw new ContractValidateException( "This value[ALLOW_ENERGY_ADJUSTMENT] is only allowed to be 1"); } + break; } default: break; From 9da13ac1213813a2fbc62a8d2e5423ebdc9c0001 Mon Sep 17 00:00:00 2001 From: Asuka Date: Sat, 11 May 2024 12:20:20 +0800 Subject: [PATCH 20/25] func(test): add unit test for energy adjustment proposal --- .../org/tron/core/actuator/VMActuator.java | 3 +- .../org/tron/core/vm/OperationRegistry.java | 4 +- .../org/tron/core/vm/program/Program.java | 4 ++ .../common/runtime/vm/OperationsTest.java | 53 +++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/actuator/src/main/java/org/tron/core/actuator/VMActuator.java b/actuator/src/main/java/org/tron/core/actuator/VMActuator.java index 31db5d799e2..08d0f5a8da5 100644 --- a/actuator/src/main/java/org/tron/core/actuator/VMActuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/VMActuator.java @@ -38,6 +38,7 @@ import org.tron.core.utils.TransactionUtil; import org.tron.core.vm.EnergyCost; import org.tron.core.vm.LogInfoTriggerParser; +import org.tron.core.vm.Op; import org.tron.core.vm.OperationRegistry; import org.tron.core.vm.VM; import org.tron.core.vm.VMConstant; @@ -193,7 +194,7 @@ public void execute(Object object) throws ContractExeException { // If the last op consumed too much execution time, the CPU time limit for the whole tx can be exceeded. // This is not fair for other txs in the same block. // So when allowFairEnergyAdjustment is on, the CPU time limit will be checked at the end of tx execution. - program.checkCPUTimeLimit("TX_LAST_OP"); + program.checkCPUTimeLimit(Op.getNameOf(program.getLastOp()) + "(TX_LAST_OP)"); } if (TrxType.TRX_CONTRACT_CREATION_TYPE == trxType && !result.isRevert()) { 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 8cf0ea7242a..a2d3259ba89 100644 --- a/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java +++ b/actuator/src/main/java/org/tron/core/vm/OperationRegistry.java @@ -68,7 +68,7 @@ public static JumpTable getTable() { } if (VMConfig.allowEnergyAdjustment()) { - ajustForFairEnergy(table); + adjustForFairEnergy(table); } return table; @@ -640,7 +640,7 @@ public static void appendShangHaiOperations(JumpTable table) { proposal)); } - public static void ajustForFairEnergy(JumpTable table) { + public static void adjustForFairEnergy(JumpTable table) { table.set(new Operation( Op.VOTEWITNESS, 4, 1, EnergyCost::getVoteWitnessCost2, 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 2e547dc86f2..0b0ef5bc9ba 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 @@ -275,6 +275,10 @@ public void setLastOp(byte op) { this.lastOp = op; } + public byte getLastOp() { + return this.lastOp; + } + /** * Returns the last fully executed OP. */ 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 be031d7c00b..68104794384 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 @@ -3,6 +3,8 @@ import static org.junit.Assert.assertEquals; import java.util.List; +import java.util.Random; + import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Hex; @@ -15,6 +17,7 @@ import org.tron.common.BaseTest; import org.tron.common.parameter.CommonParameter; import org.tron.common.runtime.InternalTransaction; +import org.tron.common.utils.DecodeUtil; import org.tron.core.Constant; import org.tron.core.config.args.Args; import org.tron.core.exception.ContractValidateException; @@ -864,6 +867,50 @@ public void testPush0() throws ContractValidateException { VMConfig.initAllowTvmShangHai(0); } + @Test + public void testSuicideCost() throws ContractValidateException { + invoke = new ProgramInvokeMockImpl(StoreFactory.getInstance(), new byte[0], new byte[21]); + program = new Program(null, null, invoke, + new InternalTransaction( + Protocol.Transaction.getDefaultInstance(), + InternalTransaction.TrxType.TRX_UNKNOWN_TYPE)); + + byte[] receiver1 = generateRandomAddress(); + program.stackPush(new DataWord(receiver1)); + Assert.assertEquals(0, EnergyCost.getSuicideCost(program)); + invoke.getDeposit().createAccount(receiver1, Protocol.AccountType.Normal); + Assert.assertEquals(0, EnergyCost.getSuicideCost(program)); + + byte[] receiver2 = generateRandomAddress(); + program.stackPush(new DataWord(receiver2)); + Assert.assertEquals(25000, EnergyCost.getSuicideCost2(program)); + invoke.getDeposit().createAccount(receiver2, Protocol.AccountType.Normal); + Assert.assertEquals(0, EnergyCost.getSuicideCost2(program)); + } + + @Test + public void testVoteWitnessCost() throws ContractValidateException { + // Build stack environment, the stack from top to bottom is 0x00, 0x80, 0x00, 0x80 + program = new Program(null, null, new ProgramInvokeMockImpl(), + new InternalTransaction( + Protocol.Transaction.getDefaultInstance(), + InternalTransaction.TrxType.TRX_UNKNOWN_TYPE)); + program.stackPush(DataWord.of((byte) 0x80)); + program.stackPush(DataWord.of((byte) 0x00)); + program.stackPush(DataWord.of((byte) 0x80)); + program.stackPush(DataWord.of((byte) 0x00)); + + // Test VoteWitness before EnergyAdjustment, should not have memory expand energy + Assert.assertEquals(30000, EnergyCost.getVoteWitnessCost(program)); + + // Test VoteWitness after EnergyAdjustment, should have memory expand energy + VMConfig.initAllowEnergyAdjustment(1); + + long memWords = (0x80 + 32) / 32; + long memoryExpandEnergy = 3 * memWords + memWords * memWords / 512; + Assert.assertEquals(30000 + memoryExpandEnergy, EnergyCost.getVoteWitnessCost2(program)); + } + private void testOperations(Program program) { try { while (!program.isStopped()) { @@ -954,4 +1001,10 @@ private byte[] compile(String code) { return new BytecodeCompiler().compile(code); } + private byte[] generateRandomAddress() { + byte[] address = new byte[21]; + new Random().nextBytes(address); + address[0] = DecodeUtil.addressPreFixByte; + return address; + } } From eb2b88095c94d155bfc700552fa7b927dea14969 Mon Sep 17 00:00:00 2001 From: Asuka Date: Mon, 13 May 2024 09:35:09 +0800 Subject: [PATCH 21/25] func(proposal): proposal 81th will not be able to be reopened in the state in which it was opened. --- actuator/src/main/java/org/tron/core/utils/ProposalUtil.java | 4 ++++ .../main/java/org/tron/core/store/DynamicPropertiesStore.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) 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 6501b40ac79..7c12c07f059 100644 --- a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java @@ -753,6 +753,10 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, throw new ContractValidateException( "Bad chain parameter id [ALLOW_ENERGY_ADJUSTMENT]"); } + if (dynamicPropertiesStore.getAllowEnergyAdjustment() == 1) { + throw new ContractValidateException( + "[ALLOW_ENERGY_ADJUSTMENT] has been valid, no need to propose again"); + } if (value != 1) { throw new ContractValidateException( "This value[ALLOW_ENERGY_ADJUSTMENT] is only allowed to be 1"); 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 5c1a3d7b460..9cadf1fdab9 100644 --- a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java +++ b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java @@ -219,7 +219,7 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking private static final byte[] ALLOW_OLD_REWARD_OPT = "ALLOW_OLD_REWARD_OPT".getBytes(); - private static final byte[] ALLOW_ENERGY_ADJUSTMENT = "ALLOW_FAIR_ENERGY_ADJUSTMENT".getBytes(); + private static final byte[] ALLOW_ENERGY_ADJUSTMENT = "ALLOW_ENERGY_ADJUSTMENT".getBytes(); @Autowired private DynamicPropertiesStore(@Value("properties") String dbName) { From 40587026e8ae69ba9a0b1e17a16ccb6e145282ec Mon Sep 17 00:00:00 2001 From: Asuka Date: Thu, 30 May 2024 14:33:48 +0800 Subject: [PATCH 22/25] func(test): add unit test for getAllowEnergyAdjustment proposal --- .../core/actuator/utils/ProposalUtilTest.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java b/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java index 8e2b7647967..0bb303cafa0 100644 --- a/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java +++ b/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java @@ -3,6 +3,7 @@ import com.google.protobuf.ByteString; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import javax.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -12,13 +13,18 @@ import org.tron.common.BaseTest; import org.tron.common.utils.ByteArray; import org.tron.common.utils.ForkController; +import org.tron.core.ChainBaseManager; import org.tron.core.Constant; import org.tron.core.capsule.BytesCapsule; +import org.tron.core.capsule.ProposalCapsule; import org.tron.core.config.Parameter; import org.tron.core.config.Parameter.ForkBlockVersionEnum; import org.tron.core.config.args.Args; +import org.tron.core.consensus.ProposalService; +import org.tron.core.db.Manager; import org.tron.core.exception.ContractValidateException; import org.tron.core.store.DynamicPropertiesStore; +import org.tron.core.store.StoreFactory; import org.tron.core.utils.ProposalUtil; import org.tron.core.utils.ProposalUtil.ProposalType; @@ -381,11 +387,76 @@ public void validateCheck() { e.getMessage()); } + testEnergyAdjustmentProposal(); + forkUtils.getManager().getDynamicPropertiesStore() .statsByVersion(ForkBlockVersionEnum.ENERGY_LIMIT.getValue(), stats); forkUtils.reset(); } + private void testEnergyAdjustmentProposal() { + // Should fail because cannot pass the fork controller check + try { + ProposalUtil.validator(dynamicPropertiesStore, forkUtils, + ProposalType.ALLOW_ENERGY_ADJUSTMENT.getCode(), 1); + Assert.fail(); + } catch (ContractValidateException e) { + Assert.assertEquals( + "Bad chain parameter id [ALLOW_ENERGY_ADJUSTMENT]", + e.getMessage()); + } + + long maintenanceTimeInterval = forkUtils.getManager().getDynamicPropertiesStore() + .getMaintenanceTimeInterval(); + + long hardForkTime = + ((ForkBlockVersionEnum.VERSION_4_7_5.getHardForkTime() - 1) / maintenanceTimeInterval + 1) + * maintenanceTimeInterval; + forkUtils.getManager().getDynamicPropertiesStore() + .saveLatestBlockHeaderTimestamp(hardForkTime + 1); + + byte[] stats = new byte[27]; + Arrays.fill(stats, (byte) 1); + forkUtils.getManager().getDynamicPropertiesStore() + .statsByVersion(ForkBlockVersionEnum.VERSION_4_7_5.getValue(), stats); + + // Should fail because the proposal value is invalid + try { + ProposalUtil.validator(dynamicPropertiesStore, forkUtils, + ProposalType.ALLOW_ENERGY_ADJUSTMENT.getCode(), 2); + Assert.fail(); + } catch (ContractValidateException e) { + Assert.assertEquals( + "This value[ALLOW_ENERGY_ADJUSTMENT] is only allowed to be 1", + e.getMessage()); + } + + // Should succeed + try { + ProposalUtil.validator(dynamicPropertiesStore, forkUtils, + ProposalType.ALLOW_ENERGY_ADJUSTMENT.getCode(), 1); + } catch (Throwable t) { + Assert.fail(); + } + + ProposalCapsule proposalCapsule = new ProposalCapsule(ByteString.empty(), 0); + proposalCapsule.setParameters(new HashMap(){{ + put(81L, 1L); + }}); + + ProposalService.process(dbManager, proposalCapsule); + + try { + ProposalUtil.validator(dynamicPropertiesStore, forkUtils, + ProposalType.ALLOW_ENERGY_ADJUSTMENT.getCode(), 1); + Assert.fail(); + } catch (ContractValidateException e) { + Assert.assertEquals( + "[ALLOW_ENERGY_ADJUSTMENT] has been valid, no need to propose again", + e.getMessage()); + } + } + @Test public void blockVersionCheck() { for (ForkBlockVersionEnum forkVersion : ForkBlockVersionEnum.values()) { From 4ddd640bb7c25a29086e060cc0ede1b54691ca78 Mon Sep 17 00:00:00 2001 From: liuxincheng Date: Wed, 29 May 2024 23:04:07 +0800 Subject: [PATCH 23/25] feat(validate): limit big transaction size --- .../main/java/org/tron/core/db/Manager.java | 16 +++++++- .../java/org/tron/core/db/ManagerTest.java | 37 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/framework/src/main/java/org/tron/core/db/Manager.java b/framework/src/main/java/org/tron/core/db/Manager.java index 63bbef9ff7f..e190620d3e2 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -1,6 +1,7 @@ package org.tron.core.db; import static org.tron.common.utils.Commons.adjustBalance; +import static org.tron.core.Constant.TRANSACTION_MAX_BYTE_SIZE; import static org.tron.core.exception.BadBlockException.TypeEnum.CALC_MERKLE_ROOT_FAILED; import static org.tron.protos.Protocol.Transaction.Contract.ContractType.TransferContract; import static org.tron.protos.Protocol.Transaction.Result.contractResult.SUCCESS; @@ -793,9 +794,22 @@ void validateTapos(TransactionCapsule transactionCapsule) throws TaposException void validateCommon(TransactionCapsule transactionCapsule) throws TransactionExpirationException, TooBigTransactionException { + if (!transactionCapsule.isInBlock()) { + long generalBytesSize = + transactionCapsule.getInstance().toBuilder().clearRet().build().getSerializedSize() + + Constant.MAX_RESULT_SIZE_IN_TX + Constant.MAX_RESULT_SIZE_IN_TX; + if (generalBytesSize > TRANSACTION_MAX_BYTE_SIZE) { + throw new TooBigTransactionException(String.format( + "Too big transaction with result, TxId %s, the size is %d bytes, maxTxSize %d", + transactionCapsule.getTransactionId(), generalBytesSize, TRANSACTION_MAX_BYTE_SIZE)); + } + } + if (transactionCapsule.getData().length > Constant.TRANSACTION_MAX_BYTE_SIZE) { throw new TooBigTransactionException(String.format( - "Too big transaction, the size is %d bytes", transactionCapsule.getData().length)); + "Too big transaction, TxId %s, the size is %d bytes, maxTxSize %d", + transactionCapsule.getTransactionId(), transactionCapsule.getData().length, + TRANSACTION_MAX_BYTE_SIZE)); } long transactionExpiration = transactionCapsule.getExpiration(); long headBlockTime = chainBaseManager.getHeadBlockTimeStamp(); diff --git a/framework/src/test/java/org/tron/core/db/ManagerTest.java b/framework/src/test/java/org/tron/core/db/ManagerTest.java index 053647cc25a..a2a0718abaf 100755 --- a/framework/src/test/java/org/tron/core/db/ManagerTest.java +++ b/framework/src/test/java/org/tron/core/db/ManagerTest.java @@ -1,5 +1,6 @@ package org.tron.core.db; +import static org.junit.Assert.assertThrows; import static org.tron.common.utils.Commons.adjustAssetBalanceV2; import static org.tron.common.utils.Commons.adjustBalance; import static org.tron.common.utils.Commons.adjustTotalShieldedPoolValue; @@ -8,8 +9,10 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.google.protobuf.Any; import com.google.protobuf.ByteString; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -85,6 +88,7 @@ import org.tron.protos.Protocol.Block; import org.tron.protos.Protocol.Transaction; import org.tron.protos.Protocol.Transaction.Contract.ContractType; +import org.tron.protos.Protocol.Transaction.raw; import org.tron.protos.contract.AccountContract; import org.tron.protos.contract.AssetIssueContractOuterClass; import org.tron.protos.contract.BalanceContract.TransferContract; @@ -1114,4 +1118,37 @@ public void testExpireTransaction() { Assert.fail(); } } + + @Test + public void testTooBigTransaction() { + TransferContract transferContract = + TransferContract.newBuilder() + .setAmount(10) + .setOwnerAddress(ByteString.copyFromUtf8("aaa")) + .setToAddress(ByteString.copyFromUtf8("bbb")) + .build(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 6666; i++) { + sb.append("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + } + Transaction transaction = Transaction.newBuilder().setRawData(raw.newBuilder() + .setData(ByteString.copyFrom(sb.toString().getBytes(StandardCharsets.UTF_8))) + .addContract(Transaction.Contract.newBuilder().setParameter(Any.pack(transferContract)) + .setType(ContractType.TransferContract))).build(); + TransactionCapsule trx = new TransactionCapsule(transaction); + trx.setInBlock(false); + assertThrows( + "Too big transaction with result, " + + "TxId 1c05e9fca6a2d0c366ed4430456527eb40198e70c8b20f5ceca4739c68a79af8, " + + "the size is 533483 bytes, maxTxSize 512000", + TooBigTransactionException.class, ()-> dbManager.validateCommon(trx)); + + trx.setInBlock(true); + assertThrows( + "Too big transaction, " + + "TxId 1c05e9fca6a2d0c366ed4430456527eb40198e70c8b20f5ceca4739c68a79af8, " + + "the size is 1066643 bytes, maxTxSize 512000", + TooBigTransactionException.class, ()-> dbManager.validateCommon(trx)); + + } } From 3aa94e029ecb78334ddc9a1261ee0c30a434256e Mon Sep 17 00:00:00 2001 From: Asuka Date: Thu, 30 May 2024 15:36:28 +0800 Subject: [PATCH 24/25] test(tvm): add unit test for suicide action --- .../common/runtime/vm/OperationsTest.java | 23 +++++++++++++++++++ .../core/actuator/utils/ProposalUtilTest.java | 11 ++++----- 2 files changed, 27 insertions(+), 7 deletions(-) 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 68104794384..2a70364b8d1 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 @@ -888,6 +888,29 @@ public void testSuicideCost() throws ContractValidateException { Assert.assertEquals(0, EnergyCost.getSuicideCost2(program)); } + @Test + public void testSuicideAction() throws ContractValidateException { + invoke = new ProgramInvokeMockImpl( + StoreFactory.getInstance(), + new byte[0], + Hex.decode("41471fd3ad3e9eeadeec4608b92d16ce6b500704cc")); + + program = new Program(null, null, invoke, + new InternalTransaction( + Protocol.Transaction.getDefaultInstance(), + InternalTransaction.TrxType.TRX_UNKNOWN_TYPE)); + + VMConfig.initAllowEnergyAdjustment(1); + byte prePrefixByte = DecodeUtil.addressPreFixByte; + DecodeUtil.addressPreFixByte = Constant.ADD_PRE_FIX_BYTE_MAINNET; + + program.suicide(new DataWord( + dbManager.getAccountStore().getBlackhole().getAddress().toByteArray())); + + DecodeUtil.addressPreFixByte = prePrefixByte; + VMConfig.initAllowEnergyAdjustment(0); + } + @Test public void testVoteWitnessCost() throws ContractValidateException { // Build stack environment, the stack from top to bottom is 0x00, 0x80, 0x00, 0x80 diff --git a/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java b/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java index 0bb303cafa0..db122f90c4f 100644 --- a/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java +++ b/framework/src/test/java/org/tron/core/actuator/utils/ProposalUtilTest.java @@ -5,6 +5,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; @@ -13,7 +14,6 @@ import org.tron.common.BaseTest; import org.tron.common.utils.ByteArray; import org.tron.common.utils.ForkController; -import org.tron.core.ChainBaseManager; import org.tron.core.Constant; import org.tron.core.capsule.BytesCapsule; import org.tron.core.capsule.ProposalCapsule; @@ -21,10 +21,8 @@ import org.tron.core.config.Parameter.ForkBlockVersionEnum; import org.tron.core.config.args.Args; import org.tron.core.consensus.ProposalService; -import org.tron.core.db.Manager; import org.tron.core.exception.ContractValidateException; import org.tron.core.store.DynamicPropertiesStore; -import org.tron.core.store.StoreFactory; import org.tron.core.utils.ProposalUtil; import org.tron.core.utils.ProposalUtil.ProposalType; @@ -440,10 +438,9 @@ private void testEnergyAdjustmentProposal() { } ProposalCapsule proposalCapsule = new ProposalCapsule(ByteString.empty(), 0); - proposalCapsule.setParameters(new HashMap(){{ - put(81L, 1L); - }}); - + Map parameter = new HashMap<>(); + parameter.put(81L, 1L); + proposalCapsule.setParameters(parameter); ProposalService.process(dbManager, proposalCapsule); try { From 271e3d01c400fd3aaeff1626ea4924f40297ddd0 Mon Sep 17 00:00:00 2001 From: liuxincheng Date: Wed, 29 May 2024 23:21:29 +0800 Subject: [PATCH 25/25] feat(*): remove redundant ret for transaction --- .../tron/core/capsule/TransactionCapsule.java | 24 +++++++++++++ .../org/tron/core/db/BandwidthProcessor.java | 7 ++++ .../src/main/java/org/tron/core/Constant.java | 1 + .../src/main/java/org/tron/core/Wallet.java | 6 ++-- .../main/java/org/tron/core/db/Manager.java | 27 +++++++++----- .../runtime/vm/BandWidthRuntimeTest.java | 15 ++++++++ .../org/tron/core/BandwidthProcessorTest.java | 34 ++++++++++++++++++ .../core/capsule/TransactionCapsuleTest.java | 20 +++++++++++ .../java/org/tron/core/db/ManagerTest.java | 36 +++++++++++++++++++ protocol/src/main/protos/core/Tron.proto | 1 + 10 files changed, 159 insertions(+), 12 deletions(-) diff --git a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java index a588b28c748..11bd3a8a0cf 100755 --- a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java @@ -17,6 +17,7 @@ import static org.tron.common.utils.StringUtil.encode58Check; import static org.tron.common.utils.WalletUtil.checkPermissionOperations; +import static org.tron.core.Constant.MAX_CONTRACT_RESULT_SIZE; import static org.tron.core.exception.P2pException.TypeEnum.PROTOBUF_ERROR; import com.google.common.primitives.Bytes; @@ -730,6 +731,15 @@ public long getResultSerializedSize() { return size; } + public long getResultSizeWithMaxContractRet() { + long size = 0; + for (Result result : this.transaction.getRetList()) { + size += result.toBuilder().clearContractRet().build().getSerializedSize() + + MAX_CONTRACT_RESULT_SIZE; + } + return size; + } + @Override public Transaction getInstance() { return this.transaction; @@ -842,4 +852,18 @@ public BalanceContract.TransferContract getTransferContract() { return null; } } + + public void removeRedundantRet() { + Transaction tx = this.getInstance(); + List tmpList = new ArrayList<>(tx.getRetList()); + int contractCount = tx.getRawData().getContractCount(); + if (tx.getRetCount() > contractCount && contractCount > 0) { + Transaction.Builder transactionBuilder = tx.toBuilder().clearRet(); + for (int i = 0; i < contractCount; i++) { + Result result = tmpList.get(i); + transactionBuilder.addRet(result); + } + this.transaction = transactionBuilder.build(); + } + } } diff --git a/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java b/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java index f13002f2dfa..0ae6b431217 100644 --- a/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java +++ b/chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java @@ -97,6 +97,13 @@ public void consume(TransactionCapsule trx, TransactionTrace trace) throws ContractValidateException, AccountResourceInsufficientException, TooBigTransactionResultException { List contracts = trx.getInstance().getRawData().getContractList(); + long resultSizeWithMaxContractRet = trx.getResultSizeWithMaxContractRet(); + if (!trx.isInBlock() && resultSizeWithMaxContractRet > + Constant.MAX_RESULT_SIZE_IN_TX * contracts.size()) { + throw new TooBigTransactionResultException(String.format( + "Too big transaction result, TxId %s, the result size is %d bytes, maxResultSize %d", + trx.getTransactionId(), resultSizeWithMaxContractRet, Constant.MAX_RESULT_SIZE_IN_TX)); + } if (trx.getResultSerializedSize() > Constant.MAX_RESULT_SIZE_IN_TX * contracts.size()) { throw new TooBigTransactionResultException(); } diff --git a/common/src/main/java/org/tron/core/Constant.java b/common/src/main/java/org/tron/core/Constant.java index 2cd9ea95f15..f0f275593c9 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -31,6 +31,7 @@ public class Constant { public static final long SUN_PER_ENERGY = 100; // 1 us = 100 SUN = 100 * 10^-6 TRX public static final long ENERGY_LIMIT_IN_CONSTANT_TX = 3_000_000L; // ref: 1 us = 1 energy public static final long MAX_RESULT_SIZE_IN_TX = 64; // max 8 * 8 items in result + public static final long MAX_CONTRACT_RESULT_SIZE = 2L; public static final long PB_DEFAULT_ENERGY_LIMIT = 0L; public static final long CREATOR_DEFAULT_ENERGY_LIMIT = 1000 * 10_000L; diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index 96af6fc7476..cdc9a589667 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -497,8 +497,6 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) { trx.setTime(System.currentTimeMillis()); Sha256Hash txID = trx.getTransactionId(); try { - TransactionMessage message = new TransactionMessage(signedTransaction.toByteArray()); - if (tronNetDelegate.isBlockUnsolidified()) { logger.warn("Broadcast transaction {} has failed, block unsolidified.", txID); return builder.setResult(false).setCode(response_code.BLOCK_UNSOLIDIFIED) @@ -550,6 +548,7 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) { if (trx.getInstance().getRawData().getContractCount() == 0) { throw new ContractValidateException(ActuatorConstant.CONTRACT_NOT_EXIST); } + TransactionMessage message = new TransactionMessage(trx.getInstance().toByteArray()); dbManager.pushTransaction(trx); int num = tronNetService.fastBroadcastTransaction(message); if (num == 0 && minEffectiveConnection != 0) { @@ -592,8 +591,7 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) { } catch (TooBigTransactionException e) { logger.warn(BROADCAST_TRANS_FAILED, txID, e.getMessage()); return builder.setResult(false).setCode(response_code.TOO_BIG_TRANSACTION_ERROR) - .setMessage(ByteString.copyFromUtf8("Transaction size is too big.")) - .build(); + .setMessage(ByteString.copyFromUtf8(e.getMessage())).build(); } catch (TransactionExpirationException e) { logger.warn(BROADCAST_TRANS_FAILED, txID, e.getMessage()); return builder.setResult(false).setCode(response_code.TRANSACTION_EXPIRATION_ERROR) diff --git a/framework/src/main/java/org/tron/core/db/Manager.java b/framework/src/main/java/org/tron/core/db/Manager.java index 63bbef9ff7f..664d0cf4159 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -1,6 +1,7 @@ package org.tron.core.db; import static org.tron.common.utils.Commons.adjustBalance; +import static org.tron.core.Constant.TRANSACTION_MAX_BYTE_SIZE; import static org.tron.core.exception.BadBlockException.TypeEnum.CALC_MERKLE_ROOT_FAILED; import static org.tron.protos.Protocol.Transaction.Contract.ContractType.TransferContract; import static org.tron.protos.Protocol.Transaction.Result.contractResult.SUCCESS; @@ -793,6 +794,17 @@ void validateTapos(TransactionCapsule transactionCapsule) throws TaposException void validateCommon(TransactionCapsule transactionCapsule) throws TransactionExpirationException, TooBigTransactionException { + if (!transactionCapsule.isInBlock()) { + transactionCapsule.removeRedundantRet(); + long generalBytesSize = + transactionCapsule.getInstance().toBuilder().clearRet().build().getSerializedSize() + + Constant.MAX_RESULT_SIZE_IN_TX + Constant.MAX_RESULT_SIZE_IN_TX; + if (generalBytesSize > TRANSACTION_MAX_BYTE_SIZE) { + throw new TooBigTransactionException(String.format( + "Too big transaction with result, TxId %s, the size is %d bytes, maxTxSize %d", + transactionCapsule.getTransactionId(), generalBytesSize, TRANSACTION_MAX_BYTE_SIZE)); + } + } if (transactionCapsule.getData().length > Constant.TRANSACTION_MAX_BYTE_SIZE) { throw new TooBigTransactionException(String.format( "Too big transaction, the size is %d bytes", transactionCapsule.getData().length)); @@ -1411,8 +1423,14 @@ public TransactionInfo processTransaction(final TransactionCapsule trxCap, Block if (trxCap == null) { return null; } - Contract contract = trxCap.getInstance().getRawData().getContract(0); Sha256Hash txId = trxCap.getTransactionId(); + if (trxCap.getInstance().getRawData().getContractList().size() != 1) { + throw new ContractSizeNotEqualToOneException( + String.format( + "tx %s contract size should be exactly 1, this is extend feature ,actual :%d", + txId, trxCap.getInstance().getRawData().getContractList().size())); + } + Contract contract = trxCap.getInstance().getRawData().getContract(0); final Histogram.Timer requestTimer = Metrics.histogramStartTimer( MetricKeys.Histogram.PROCESS_TRANSACTION_LATENCY, Objects.nonNull(blockCap) ? MetricLabels.BLOCK : MetricLabels.TRX, @@ -1427,13 +1445,6 @@ public TransactionInfo processTransaction(final TransactionCapsule trxCap, Block validateTapos(trxCap); validateCommon(trxCap); - if (trxCap.getInstance().getRawData().getContractList().size() != 1) { - throw new ContractSizeNotEqualToOneException( - String.format( - "tx %s contract size should be exactly 1, this is extend feature ,actual :%d", - txId, trxCap.getInstance().getRawData().getContractList().size())); - } - validateDup(trxCap); if (!trxCap.validateSignature(chainBaseManager.getAccountStore(), diff --git a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java index 40c5908c2dd..82de20dc359 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/BandWidthRuntimeTest.java @@ -43,6 +43,8 @@ import org.tron.protos.Protocol.Transaction; import org.tron.protos.Protocol.Transaction.Contract; import org.tron.protos.Protocol.Transaction.Contract.ContractType; +import org.tron.protos.Protocol.Transaction.Result; +import org.tron.protos.Protocol.Transaction.Result.contractResult; import org.tron.protos.Protocol.Transaction.raw; import org.tron.protos.contract.SmartContractOuterClass.CreateSmartContract; import org.tron.protos.contract.SmartContractOuterClass.TriggerSmartContract; @@ -235,4 +237,17 @@ private byte[] createContract() Assert.assertNull(trace.getRuntimeError()); return trace.getRuntimeResult().getContractAddress(); } + + @Test + public void testMaxContractResultSize() { + int maxSize = 0; + for (contractResult cr : contractResult.values()) { + if (cr.name().equals("UNRECOGNIZED")) { + continue; + } + Result result = Result.newBuilder().setContractRet(cr).build(); + maxSize = Math.max(maxSize, result.getSerializedSize()); + } + Assert.assertEquals(2, maxSize); + } } \ No newline at end of file diff --git a/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java b/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java index 300c202e11a..b17e9615b5a 100755 --- a/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java +++ b/framework/src/test/java/org/tron/core/BandwidthProcessorTest.java @@ -1,7 +1,10 @@ package org.tron.core; +import static org.junit.Assert.assertThrows; + import com.google.protobuf.Any; import com.google.protobuf.ByteString; +import java.nio.charset.StandardCharsets; import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; import org.junit.Assert; @@ -23,6 +26,11 @@ import org.tron.core.store.StoreFactory; import org.tron.protos.Protocol; import org.tron.protos.Protocol.AccountType; +import org.tron.protos.Protocol.Transaction; +import org.tron.protos.Protocol.Transaction.Contract; +import org.tron.protos.Protocol.Transaction.Contract.ContractType; +import org.tron.protos.Protocol.Transaction.Result; +import org.tron.protos.Protocol.Transaction.raw; import org.tron.protos.contract.AssetIssueContractOuterClass.AssetIssueContract; import org.tron.protos.contract.AssetIssueContractOuterClass.TransferAssetContract; import org.tron.protos.contract.BalanceContract.TransferContract; @@ -539,6 +547,32 @@ public void testUsingFee() throws Exception { dbManager.consumeBandwidth(trx, trace); } + @Test + public void testConsumeBandwidthTooBigTransactionResultException() { + TransferContract transferContract = + TransferContract.newBuilder() + .setAmount(10) + .setOwnerAddress(ByteString.copyFromUtf8("aaa")) + .setToAddress(ByteString.copyFromUtf8("bbb")) + .build(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 6666; i++) { + sb.append("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + } + Transaction transaction = Transaction.newBuilder().setRawData(raw.newBuilder() + .setData(ByteString.copyFrom(sb.toString().getBytes(StandardCharsets.UTF_8))) + .addContract(Contract.newBuilder().setParameter(Any.pack(transferContract)) + .setType(ContractType.TransferContract))) + .addRet(Result.newBuilder().setAssetIssueID(sb.toString()).build()).build(); + TransactionCapsule trx = new TransactionCapsule(transaction); + trx.setInBlock(false); + TransactionTrace trace = new TransactionTrace(trx, StoreFactory + .getInstance(), new RuntimeImpl()); + assertThrows( + "Too big transaction result, TxId %s, the result size is %d bytes, maxResultSize %d", + TooBigTransactionResultException.class, () -> dbManager.consumeBandwidth(trx, trace)); + } + /** * sameTokenName close, consume success assetIssueCapsule.getOwnerAddress() != * fromAccount.getAddress()) contract.getType() = TransferAssetContract diff --git a/framework/src/test/java/org/tron/core/capsule/TransactionCapsuleTest.java b/framework/src/test/java/org/tron/core/capsule/TransactionCapsuleTest.java index fcb2a4fbfd5..17e9d3ac887 100644 --- a/framework/src/test/java/org/tron/core/capsule/TransactionCapsuleTest.java +++ b/framework/src/test/java/org/tron/core/capsule/TransactionCapsuleTest.java @@ -1,5 +1,9 @@ package org.tron.core.capsule; +import static org.tron.protos.Protocol.Transaction.Result.contractResult.BAD_JUMP_DESTINATION; +import static org.tron.protos.Protocol.Transaction.Result.contractResult.PRECOMPILED_CONTRACT; +import static org.tron.protos.Protocol.Transaction.Result.contractResult.SUCCESS; + import com.google.protobuf.ByteString; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; @@ -13,8 +17,10 @@ import org.tron.core.config.args.Args; import org.tron.protos.Protocol.AccountType; import org.tron.protos.Protocol.Transaction; +import org.tron.protos.Protocol.Transaction.Contract.ContractType; import org.tron.protos.Protocol.Transaction.Result; import org.tron.protos.Protocol.Transaction.Result.contractResult; +import org.tron.protos.Protocol.Transaction.raw; @Slf4j public class TransactionCapsuleTest extends BaseTest { @@ -1064,4 +1070,18 @@ public void trxCapsuleClearTest() { Assert.assertEquals(trxCap.getInstance() .getRet(0).getContractRet(), Result.contractResult.OUT_OF_TIME); } + + @Test + public void testRemoveRedundantRet() { + Transaction.Builder transaction = Transaction.newBuilder().setRawData(raw.newBuilder() + .addContract(Transaction.Contract.newBuilder().setType(ContractType.TriggerSmartContract)) + .setFeeLimit(1000000000)).build().toBuilder(); + transaction.addRet(Result.newBuilder().setContractRet(SUCCESS).build()); + transaction.addRet(Result.newBuilder().setContractRet(PRECOMPILED_CONTRACT).build()); + transaction.addRet(Result.newBuilder().setContractRet(BAD_JUMP_DESTINATION).build()); + TransactionCapsule transactionCapsule = new TransactionCapsule(transaction.build()); + transactionCapsule.removeRedundantRet(); + Assert.assertEquals(1, transactionCapsule.getInstance().getRetCount()); + Assert.assertEquals(SUCCESS, transactionCapsule.getInstance().getRet(0).getContractRet()); + } } \ No newline at end of file diff --git a/framework/src/test/java/org/tron/core/db/ManagerTest.java b/framework/src/test/java/org/tron/core/db/ManagerTest.java index 053647cc25a..de68af58c50 100755 --- a/framework/src/test/java/org/tron/core/db/ManagerTest.java +++ b/framework/src/test/java/org/tron/core/db/ManagerTest.java @@ -1,5 +1,6 @@ package org.tron.core.db; +import static org.junit.Assert.assertThrows; import static org.tron.common.utils.Commons.adjustAssetBalanceV2; import static org.tron.common.utils.Commons.adjustBalance; import static org.tron.common.utils.Commons.adjustTotalShieldedPoolValue; @@ -8,8 +9,10 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.google.protobuf.Any; import com.google.protobuf.ByteString; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -1114,4 +1117,37 @@ public void testExpireTransaction() { Assert.fail(); } } + + @Test + public void testTooBigTransaction() { + TransferContract transferContract = + TransferContract.newBuilder() + .setAmount(10) + .setOwnerAddress(ByteString.copyFromUtf8("aaa")) + .setToAddress(ByteString.copyFromUtf8("bbb")) + .build(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 6666; i++) { + sb.append("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + } + Transaction transaction = Transaction.newBuilder().setRawData(Transaction.raw.newBuilder() + .setData(ByteString.copyFrom(sb.toString().getBytes(StandardCharsets.UTF_8))) + .addContract(Transaction.Contract.newBuilder().setParameter(Any.pack(transferContract)) + .setType(ContractType.TransferContract))).build(); + TransactionCapsule trx = new TransactionCapsule(transaction); + trx.setInBlock(false); + assertThrows( + "Too big transaction with result, " + + "TxId 1c05e9fca6a2d0c366ed4430456527eb40198e70c8b20f5ceca4739c68a79af8, " + + "the size is 533483 bytes, maxTxSize 512000", + TooBigTransactionException.class, () -> dbManager.validateCommon(trx)); + + trx.setInBlock(true); + assertThrows( + "Too big transaction, " + + "TxId 1c05e9fca6a2d0c366ed4430456527eb40198e70c8b20f5ceca4739c68a79af8, " + + "the size is 1066643 bytes, maxTxSize 512000", + TooBigTransactionException.class, () -> dbManager.validateCommon(trx)); + + } } diff --git a/protocol/src/main/protos/core/Tron.proto b/protocol/src/main/protos/core/Tron.proto index 41ef968d907..2ffefbf9f3e 100644 --- a/protocol/src/main/protos/core/Tron.proto +++ b/protocol/src/main/protos/core/Tron.proto @@ -407,6 +407,7 @@ message Transaction { UNKNOWN = 13; TRANSFER_FAILED = 14; INVALID_CODE = 15; + // please fill in the order according to the serial number } int64 fee = 1; code ret = 2;