diff --git a/README.md b/README.md index 0d0eeb6ef71..3a21f3d63f4 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,7 @@

- - - - - + @@ -63,8 +59,20 @@ TRON enables large-scale development and engagement. With over 2000 transactions # Building the Source Code -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. +Building java-tron requires `git` package + +## Operating systems +Make sure you operate on `Linux` or `MacOS` operating systems, other operating systems are not supported yet. + +## Architecture + +### x86_64 +64-bit version of `Oracle JDK 1.8` to be installed, other JDK versions are not supported yet. + +### ARM64 +64-bit version of `JDK 17` to be installed, other JDK versions are not supported yet. +### build Clone the repo and switch to the `master` branch ```bash @@ -81,8 +89,19 @@ $ ./gradlew clean build -x test # Running java-tron -Running java-tron requires 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. +## Operating systems +Make sure you operate on `Linux` or `MacOS` operating systems, other operating systems are not supported yet. +## Architecture + +### X86_64 +Requires 64-bit version of `Oracle JDK 1.8` to be installed, other JDK versions are not supported yet. + +### ARM64 +Requires 64-bit version of `JDK 17` to be installed, other JDK versions are not supported yet. + + +## Configuration flile Get the mainnet configuration file: [main_net_config.conf](https://github.com/tronprotocol/tron-deployment/blob/master/main_net_config.conf), other network configuration files can be found [here](https://github.com/tronprotocol/tron-deployment). ## Hardware Requirements @@ -104,6 +123,7 @@ Recommended: Full node has full historical data, it is the entry point into the TRON network, it can be used by other processes as a gateway into the TRON network via HTTP and GRPC endpoints. You can interact with the TRON network through full node:transfer assets, deploy contracts, interact with contracts and so on. `-c` parameter specifies a configuration file to run a full node: +### x86_64 JDK 1.8 ```bash $ nohup java -Xms9G -Xmx9G -XX:ReservedCodeCacheSize=256m \ -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m \ @@ -115,6 +135,19 @@ $ nohup java -Xms9G -Xmx9G -XX:ReservedCodeCacheSize=256m \ -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 \ -jar FullNode.jar -c main_net_config.conf >> start.log 2>&1 & ``` +### ARM64 JDK 17 +```bash +$ nohup java -Xms9G -Xmx9G -XX:+UseZGC \ + -Xlog:gc*:file=gc.log:time,uptime,level,tags:filecount=50,filesize=100M \ + -XX:ReservedCodeCacheSize=256m \ + -XX:+UseCodeCacheFlushing \ + -XX:MetaspaceSize=256m \ + -XX:MaxMetaspaceSize=512m \ + -XX:MaxDirectMemorySize=1g \ + -XX:+HeapDumpOnOutOfMemoryError \ + -jar FullNode.jar -c main_net_config.conf >> start.log 2>&1 & +``` + ## Running a super representative node for mainnet @@ -130,6 +163,7 @@ Fill in the private key of a super representative address into the `localwitness then run the following command to start the node: +### x86_64 JDK 1.8 ```bash $ nohup java -Xms9G -Xmx9G -XX:ReservedCodeCacheSize=256m \ -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m \ @@ -141,9 +175,22 @@ $ nohup java -Xms9G -Xmx9G -XX:ReservedCodeCacheSize=256m \ -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 \ -jar FullNode.jar --witness -c main_net_config.conf >> start.log 2>&1 & ``` +### ARM64 JDK 17 +```bash +$ nohup java -Xms9G -Xmx9G -XX:+UseZGC \ + -Xlog:gc*:file=gc.log:time,uptime,level,tags:filecount=50,filesize=100M \ + -XX:ReservedCodeCacheSize=256m \ + -XX:+UseCodeCacheFlushing \ + -XX:MetaspaceSize=256m \ + -XX:MaxMetaspaceSize=512m \ + -XX:MaxDirectMemorySize=1g \ + -XX:+HeapDumpOnOutOfMemoryError \ + -jar FullNode.jar --witness -c main_net_config.conf >> start.log 2>&1 & +``` ## Quick Start Tool +### x86_64 JDK 1.8 An easier way to build and run java-tron is to use `start.sh`. `start.sh` is a quick start script written in the Shell language. You can use it to build and run java-tron quickly and easily. Here are some common use cases of the scripting tool @@ -154,6 +201,18 @@ Here are some common use cases of the scripting tool For more details, please refer to the tool [guide](./shell.md). +### ARM64 JDK 17 +You can refer to the [start.sh.simple](start.sh.simple). + +```bash +# cp start.sh.simple start.sh +# Usage: +# sh start.sh # Start the java-tron FullNode +# sh start.sh -s # Stop the java-tron FullNode +# sh start.sh [options] # Start with additional java-tron options,such as: -c config.conf -d /path_to_data, etc. +# +``` + ## Run inside Docker container One of the quickest ways to get `java-tron` up and running on your machine is by using Docker: @@ -173,7 +232,7 @@ This will mount the `output-directory` and `logs` directories on the host, the d [Tron Developers & SRs](https://discord.gg/hqKvyAM) is Tron's official Discord channel. Feel free to join this channel if you have any questions. -[Core Devs Community](https://t.me/troncoredevscommunity) is the Telegram channel for java-tron community developers. If you want to contribute to java-tron, please join this channel. +The [Core Devs Community](https://t.me/troncoredevscommunity) and [Tron Official Developer Group](https://t.me/TronOfficialDevelopersGroupEn) are Telegram channels specifically designed for java-tron community developers to engage in technical discussions. [tronprotocol/allcoredev](https://gitter.im/tronprotocol/allcoredev) is the official Gitter channel for developers. @@ -184,7 +243,7 @@ Thank you for considering to help out with the source code! If you'd like to con # Resources - [Medium](https://medium.com/@coredevs) java-tron's official technical articles are published there. -- [Documentation](https://tronprotocol.github.io/documentation-en/introduction/) java-tron's official technical documentation website. +- [Documentation](https://tronprotocol.github.io/documentation-en/) and [TRON Developer Hub](https://developers.tron.network/) serve as java-tron’s primary documentation websites. - [Test network](http://nileex.io/) A stable test network of TRON contributed by TRON community. - [Tronscan](https://tronscan.org/#/) TRON network blockchain browser. - [Wallet-cli](https://github.com/tronprotocol/wallet-cli) TRON network wallet using command line. diff --git a/actuator/src/main/java/org/tron/core/actuator/ProposalCreateActuator.java b/actuator/src/main/java/org/tron/core/actuator/ProposalCreateActuator.java index a3639cca07f..e0044c4958d 100755 --- a/actuator/src/main/java/org/tron/core/actuator/ProposalCreateActuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/ProposalCreateActuator.java @@ -9,7 +9,6 @@ import java.util.Map; import java.util.Objects; import lombok.extern.slf4j.Slf4j; -import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.DecodeUtil; import org.tron.common.utils.StringUtil; import org.tron.core.capsule.ProposalCapsule; @@ -53,7 +52,7 @@ public boolean execute(Object result) throws ContractExeException { long currentMaintenanceTime = chainBaseManager.getDynamicPropertiesStore().getNextMaintenanceTime(); - long now3 = now + CommonParameter.getInstance().getProposalExpireTime(); + long now3 = now + chainBaseManager.getDynamicPropertiesStore().getProposalExpireTime(); long round = (now3 - currentMaintenanceTime) / maintenanceTimeInterval; long expirationTime = currentMaintenanceTime + (round + 1) * maintenanceTimeInterval; diff --git a/actuator/src/main/java/org/tron/core/actuator/ShieldedTransferActuator.java b/actuator/src/main/java/org/tron/core/actuator/ShieldedTransferActuator.java index 2773dc07d26..338e948f304 100644 --- a/actuator/src/main/java/org/tron/core/actuator/ShieldedTransferActuator.java +++ b/actuator/src/main/java/org/tron/core/actuator/ShieldedTransferActuator.java @@ -170,28 +170,27 @@ private void executeShielded(List spends, List= MAX_PROPOSAL_EXPIRE_TIME) { + throw new ContractValidateException( + "This value[PROPOSAL_EXPIRE_TIME] is only allowed to be greater than " + + MIN_PROPOSAL_EXPIRE_TIME + " and less than " + + MAX_PROPOSAL_EXPIRE_TIME + "!"); + } + break; + } default: break; } @@ -921,7 +937,8 @@ public enum ProposalType { // current value, value range ALLOW_TVM_CANCUN(83), // 0, 1 ALLOW_STRICT_MATH(87), // 0, 1 CONSENSUS_LOGIC_OPTIMIZATION(88), // 0, 1 - ALLOW_TVM_BLOB(89); // 0, 1 + ALLOW_TVM_BLOB(89), // 0, 1 + PROPOSAL_EXPIRE_TIME(92); // (0, 31536003000) private long code; diff --git a/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java b/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java index 7913d7928fa..db6b22fb339 100644 --- a/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java +++ b/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java @@ -41,6 +41,7 @@ import org.apache.commons.lang3.tuple.Triple; import org.tron.common.crypto.Blake2bfMessageDigest; import org.tron.common.crypto.Hash; +import org.tron.common.crypto.Rsv; import org.tron.common.crypto.SignUtils; import org.tron.common.crypto.SignatureInterface; import org.tron.common.crypto.zksnark.BN128; @@ -352,22 +353,13 @@ private static byte[] encodeMultiRes(byte[]... words) { } private static byte[] recoverAddrBySign(byte[] sign, byte[] hash) { - byte v; - byte[] r; - byte[] s; byte[] out = null; if (ArrayUtils.isEmpty(sign) || sign.length < 65) { return new byte[0]; } try { - r = Arrays.copyOfRange(sign, 0, 32); - s = Arrays.copyOfRange(sign, 32, 64); - v = sign[64]; - if (v < 27) { - v += 27; - } - - SignatureInterface signature = SignUtils.fromComponents(r, s, v, + Rsv rsv = Rsv.fromSignature(sign); + SignatureInterface signature = SignUtils.fromComponents(rsv.getR(), rsv.getS(), rsv.getV(), CommonParameter.getInstance().isECKeyCryptoEngine()); if (signature.validateComponents()) { out = SignUtils.signatureToAddress(hash, signature, diff --git a/actuator/src/main/java/org/tron/core/vm/VM.java b/actuator/src/main/java/org/tron/core/vm/VM.java index 2150df04c64..b1d7b027601 100644 --- a/actuator/src/main/java/org/tron/core/vm/VM.java +++ b/actuator/src/main/java/org/tron/core/vm/VM.java @@ -108,7 +108,10 @@ public static void play(Program program, JumpTable jumpTable) { } catch (JVMStackOverFlowException | OutOfTimeException e) { throw e; } catch (RuntimeException e) { - if (StringUtils.isEmpty(e.getMessage())) { + // https://openjdk.org/jeps/358 + // https://bugs.openjdk.org/browse/JDK-8220715 + // since jdk 14, the NullPointerExceptions message is not empty + if (e instanceof NullPointerException || StringUtils.isEmpty(e.getMessage())) { logger.warn("Unknown Exception occurred, tx id: {}", Hex.toHexString(program.getRootTransactionId()), e); program.setRuntimeFailure(new RuntimeException("Unknown Exception")); diff --git a/actuator/src/main/java/org/tron/core/vm/program/invoke/ProgramInvokeImpl.java b/actuator/src/main/java/org/tron/core/vm/program/invoke/ProgramInvokeImpl.java index 7997aaedcd5..ede20103609 100644 --- a/actuator/src/main/java/org/tron/core/vm/program/invoke/ProgramInvokeImpl.java +++ b/actuator/src/main/java/org/tron/core/vm/program/invoke/ProgramInvokeImpl.java @@ -314,7 +314,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return new Integer(Boolean.valueOf(byTestingSuite).hashCode() + return Boolean.valueOf(byTestingSuite).hashCode() + Boolean.valueOf(byTransaction).hashCode() + address.hashCode() + balance.hashCode() @@ -326,8 +326,7 @@ public int hashCode() { + origin.hashCode() + prevHash.hashCode() + deposit.hashCode() - + timestamp.hashCode() - ).hashCode(); + + timestamp.hashCode(); } @Override diff --git a/actuator/src/main/java/org/tron/core/vm/repository/Type.java b/actuator/src/main/java/org/tron/core/vm/repository/Type.java index e0842e6a593..9dfbd69f9ae 100644 --- a/actuator/src/main/java/org/tron/core/vm/repository/Type.java +++ b/actuator/src/main/java/org/tron/core/vm/repository/Type.java @@ -73,7 +73,7 @@ public boolean equals(Object obj) { @Override public int hashCode() { - return new Integer(type).hashCode(); + return type; } @Override diff --git a/actuator/src/main/java/org/tron/core/vm/repository/Value.java b/actuator/src/main/java/org/tron/core/vm/repository/Value.java index bf5d99c9c94..1df758f0b3e 100644 --- a/actuator/src/main/java/org/tron/core/vm/repository/Value.java +++ b/actuator/src/main/java/org/tron/core/vm/repository/Value.java @@ -58,6 +58,6 @@ public boolean equals(Object obj) { @Override public int hashCode() { - return new Integer(type.hashCode() + Objects.hashCode(value)).hashCode(); + return type.hashCode() + Objects.hashCode(value); } } diff --git a/build.gradle b/build.gradle index 14b095b1795..e66ee616807 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,52 @@ +import org.gradle.nativeplatform.platform.internal.Architectures allprojects { version = "1.0.0" apply plugin: "java-library" + ext { + springVersion = "5.3.39" + } +} +def arch = System.getProperty("os.arch").toLowerCase() +def javaVersion = JavaVersion.current() +def isArm64 = Architectures.AARCH64.isAlias(arch) +def archSource = isArm64 ? "arm" : "x86" + +ext.archInfo = [ + name : arch, + java : javaVersion, + isArm64 : isArm64, + sourceSets: [ + main: [ + java: [ + srcDirs: ["src/main/java/common", "src/main/java/${archSource}"] + ] + ], + test: [ + java: [ + srcDirs: ["src/test/java"] + ] + ] + ], + requires: [ + JavaVersion: isArm64 ? JavaVersion.VERSION_17 : JavaVersion.VERSION_1_8, + RocksdbVersion: isArm64 ? '7.7.3' : '5.15.10' + ], + VMOptions: isArm64 ? "${rootDir}/gradle/jdk17/java-tron.vmoptions" : "${rootDir}/gradle/java-tron.vmoptions" +] + +if (!archInfo.java.is(archInfo.requires.JavaVersion)) { + throw new GradleException("Java ${archInfo.requires.JavaVersion} is required for ${archInfo.name}. Detected version ${archInfo.java}") } +println "Building for architecture: ${archInfo.name}, Java version: ${archInfo.java}" + + subprojects { apply plugin: "jacoco" apply plugin: "maven-publish" sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.current() [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' jacoco { @@ -41,18 +79,23 @@ subprojects { implementation group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.25' implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.13' implementation "com.google.code.findbugs:jsr305:3.0.0" - implementation group: 'org.springframework', name: 'spring-context', version: '5.3.18' - implementation group: 'org.springframework', name: 'spring-tx', version: '5.3.18' + implementation group: 'org.springframework', name: 'spring-context', version: "${springVersion}" implementation "org.apache.commons:commons-lang3:3.4" implementation group: 'org.apache.commons', name: 'commons-math', version: '2.2' implementation "org.apache.commons:commons-collections4:4.1" implementation group: 'joda-time', name: 'joda-time', version: '2.3' implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.69' - compileOnly 'org.projectlombok:lombok:1.18.12' - annotationProcessor 'org.projectlombok:lombok:1.18.12' - testCompileOnly 'org.projectlombok:lombok:1.18.12' - testAnnotationProcessor 'org.projectlombok:lombok:1.18.12' + compileOnly 'org.projectlombok:lombok:1.18.34' + annotationProcessor 'org.projectlombok:lombok:1.18.34' + testCompileOnly 'org.projectlombok:lombok:1.18.34' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.34' + + // https://www.oracle.com/java/technologies/javase/11-relnote-issues.html#JDK-8190378 + implementation group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2' + // for json-rpc, see https://github.com/briandilley/jsonrpc4j/issues/278 + implementation group: 'javax.jws', name: 'javax.jws-api', version: '1.1' + annotationProcessor group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2' testImplementation group: 'junit', name: 'junit', version: '4.13.2' testImplementation "org.mockito:mockito-core:4.11.0" @@ -71,6 +114,10 @@ subprojects { reproducibleFileOrder = true duplicatesStrategy = DuplicatesStrategy.INCLUDE // allow duplicates } + tasks.withType(Test).configureEach { + // https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html#org.gradle.api.tasks.testing.Test:environment + environment 'CI', 'true' + } } task copyToParent(type: Copy) { diff --git a/chainbase/build.gradle b/chainbase/build.gradle index bc82d9496c3..1a07ff95fa5 100644 --- a/chainbase/build.gradle +++ b/chainbase/build.gradle @@ -10,7 +10,6 @@ dependencies { api project(":common") api project(":crypto") api "org.fusesource.jansi:jansi:$jansiVersion" - api 'io.github.tronprotocol:zksnark-java-sdk:1.0.0' api 'org.reflections:reflections:0.9.11' } diff --git a/chainbase/src/main/java/org/tron/common/storage/OptionsPicker.java b/chainbase/src/main/java/org/tron/common/storage/OptionsPicker.java new file mode 100644 index 00000000000..acace12b39d --- /dev/null +++ b/chainbase/src/main/java/org/tron/common/storage/OptionsPicker.java @@ -0,0 +1,15 @@ +package org.tron.common.storage; + +import org.tron.common.setting.RocksDbSettings; +import org.tron.common.utils.StorageUtils; + +public class OptionsPicker { + + protected org.iq80.leveldb.Options getOptionsByDbNameForLevelDB(String dbName) { + return StorageUtils.getOptionsByDbName(dbName); + } + + protected org.rocksdb.Options getOptionsByDbNameForRocksDB(String dbName) { + return RocksDbSettings.getOptionsByDbName(dbName); + } +} diff --git a/chainbase/src/main/java/org/tron/common/storage/leveldb/LevelDbDataSourceImpl.java b/chainbase/src/main/java/org/tron/common/storage/leveldb/LevelDbDataSourceImpl.java index 506ecdcb6c7..72bdd80d64e 100644 --- a/chainbase/src/main/java/org/tron/common/storage/leveldb/LevelDbDataSourceImpl.java +++ b/chainbase/src/main/java/org/tron/common/storage/leveldb/LevelDbDataSourceImpl.java @@ -17,7 +17,10 @@ import static org.fusesource.leveldbjni.JniDBFactory.factory; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Strings; import com.google.common.collect.Sets; +import com.google.common.primitives.Bytes; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -30,18 +33,14 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Objects; import java.util.Set; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; - -import com.google.common.primitives.Bytes; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.iq80.leveldb.CompressionType; import org.iq80.leveldb.DB; import org.iq80.leveldb.DBIterator; import org.iq80.leveldb.Logger; @@ -54,6 +53,7 @@ import org.tron.common.storage.WriteOptionsWrapper; import org.tron.common.storage.metric.DbStat; import org.tron.common.utils.FileUtil; +import org.tron.common.utils.PropUtil; import org.tron.common.utils.StorageUtils; import org.tron.core.db.common.DbSourceInter; import org.tron.core.db.common.iterator.StoreIterator; @@ -75,6 +75,7 @@ public class LevelDbDataSourceImpl extends DbStat implements DbSourceInter allKeys() { resetDbLock.readLock().lock(); @@ -243,6 +272,7 @@ public Set allKeys() { } @Deprecated + @VisibleForTesting @Override public Set allValues() { resetDbLock.readLock().lock(); @@ -362,6 +392,8 @@ public Map prefixQuery(byte[] key) { } } + @Deprecated + @VisibleForTesting @Override public long getTotal() throws RuntimeException { resetDbLock.readLock().lock(); @@ -378,13 +410,6 @@ public long getTotal() throws RuntimeException { } } - private void updateByBatchInner(Map rows) throws Exception { - try (WriteBatch batch = database.createWriteBatch()) { - innerBatchUpdate(rows,batch); - database.write(batch, writeOptions); - } - } - private void updateByBatchInner(Map rows, WriteOptions options) throws Exception { try (WriteBatch batch = database.createWriteBatch()) { innerBatchUpdate(rows,batch); @@ -404,30 +429,23 @@ private void innerBatchUpdate(Map rows, WriteBatch batch) { @Override public void updateByBatch(Map rows, WriteOptionsWrapper options) { - resetDbLock.readLock().lock(); - try { - updateByBatchInner(rows, options.level); - } catch (Exception e) { - try { - updateByBatchInner(rows, options.level); - } catch (Exception e1) { - throw new RuntimeException(e); - } - } finally { - resetDbLock.readLock().unlock(); - } + this.updateByBatch(rows, options.level); } @Override public void updateByBatch(Map rows) { + this.updateByBatch(rows, writeOptions); + } + + private void updateByBatch(Map rows, WriteOptions options) { resetDbLock.readLock().lock(); try { - updateByBatchInner(rows); + updateByBatchInner(rows, options); } catch (Exception e) { try { - updateByBatchInner(rows); + updateByBatchInner(rows, options); } catch (Exception e1) { - throw new RuntimeException(e); + throw new RuntimeException(e1); } } finally { resetDbLock.readLock().unlock(); diff --git a/chainbase/src/main/java/org/tron/common/storage/rocksdb/RocksDbDataSourceImpl.java b/chainbase/src/main/java/org/tron/common/storage/rocksdb/RocksDbDataSourceImpl.java index 5c051bdc101..af34dff670c 100644 --- a/chainbase/src/main/java/org/tron/common/storage/rocksdb/RocksDbDataSourceImpl.java +++ b/chainbase/src/main/java/org/tron/common/storage/rocksdb/RocksDbDataSourceImpl.java @@ -1,5 +1,7 @@ package org.tron.common.storage.rocksdb; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Strings; import com.google.common.collect.Sets; import com.google.common.primitives.Bytes; import java.io.File; @@ -20,10 +22,7 @@ import java.util.stream.Collectors; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.rocksdb.BlockBasedTableConfig; -import org.rocksdb.BloomFilter; import org.rocksdb.Checkpoint; -import org.rocksdb.DirectComparator; import org.rocksdb.InfoLogLevel; import org.rocksdb.Logger; import org.rocksdb.Options; @@ -31,11 +30,11 @@ import org.rocksdb.RocksDB; import org.rocksdb.RocksDBException; import org.rocksdb.RocksIterator; -import org.rocksdb.Statistics; import org.rocksdb.Status; import org.rocksdb.WriteBatch; import org.rocksdb.WriteOptions; import org.slf4j.LoggerFactory; +import org.tron.common.error.TronDBException; import org.tron.common.setting.RocksDbSettings; import org.tron.common.storage.WriteOptionsWrapper; import org.tron.common.storage.metric.DbStat; @@ -53,36 +52,28 @@ public class RocksDbDataSourceImpl extends DbStat implements DbSourceInter, Iterable>, Instance { - ReadOptions readOpts; private String dataBaseName; private RocksDB database; + private Options options; private volatile boolean alive; private String parentPath; private ReadWriteLock resetDbLock = new ReentrantReadWriteLock(); private static final String KEY_ENGINE = "ENGINE"; private static final String ROCKSDB = "ROCKSDB"; - private DirectComparator comparator; private static final org.slf4j.Logger rocksDbLogger = LoggerFactory.getLogger(ROCKSDB); - public RocksDbDataSourceImpl(String parentPath, String name, RocksDbSettings settings, - DirectComparator comparator) { + public RocksDbDataSourceImpl(String parentPath, String name, Options options) { this.dataBaseName = name; this.parentPath = parentPath; - this.comparator = comparator; - RocksDbSettings.setRocksDbSettings(settings); - initDB(); - } - - public RocksDbDataSourceImpl(String parentPath, String name, RocksDbSettings settings) { - this.dataBaseName = name; - this.parentPath = parentPath; - RocksDbSettings.setRocksDbSettings(settings); + this.options = options; initDB(); } + @VisibleForTesting public RocksDbDataSourceImpl(String parentPath, String name) { this.parentPath = parentPath; this.dataBaseName = name; + this.options = RocksDbSettings.getOptionsByDbName(name); } public Path getDbPath() { @@ -125,40 +116,65 @@ public void resetDb() { } } - private boolean quitIfNotAlive() { + private void throwIfNotAlive() { if (!isAlive()) { - logger.warn("DB {} is not alive.", dataBaseName); + throw new TronDBException("DB " + this.getDBName() + " is closed."); } - return !isAlive(); } + /** copy from {@link org.fusesource.leveldbjni.internal#checkArgNotNull} */ + private static void checkArgNotNull(Object value, String name) { + if (value == null) { + throw new IllegalArgumentException("The " + name + " argument cannot be null"); + } + } + + @Deprecated + @VisibleForTesting @Override public Set allKeys() throws RuntimeException { resetDbLock.readLock().lock(); - try { - if (quitIfNotAlive()) { - return null; - } + try (final RocksIterator iter = getRocksIterator()) { Set result = Sets.newHashSet(); - try (final RocksIterator iter = getRocksIterator()) { - for (iter.seekToFirst(); iter.isValid(); iter.next()) { - result.add(iter.key()); - } - return result; + for (iter.seekToFirst(); iter.isValid(); iter.next()) { + result.add(iter.key()); } + return result; } finally { resetDbLock.readLock().unlock(); } } + @Deprecated + @VisibleForTesting @Override public Set allValues() throws RuntimeException { - return null; + resetDbLock.readLock().lock(); + try (final RocksIterator iter = getRocksIterator()) { + Set result = Sets.newHashSet(); + for (iter.seekToFirst(); iter.isValid(); iter.next()) { + result.add(iter.value()); + } + return result; + } finally { + resetDbLock.readLock().unlock(); + } } + @Deprecated + @VisibleForTesting @Override public long getTotal() throws RuntimeException { - return 0; + resetDbLock.readLock().lock(); + try (final RocksIterator iter = getRocksIterator()) { + long total = 0; + for (iter.seekToFirst(); iter.isValid(); iter.next()) { + total++; + } + return total; + } finally { + resetDbLock.readLock().unlock(); + } } @Override @@ -168,12 +184,18 @@ public String getDBName() { @Override public void setDBName(String name) { + this.dataBaseName = name; } public boolean checkOrInitEngine() { String dir = getDbPath().toString(); String enginePath = dir + File.separator + "engine.properties"; - + File currentFile = new File(dir, "CURRENT"); + if (currentFile.exists() && !Paths.get(enginePath).toFile().exists()) { + // if the CURRENT file exists, but the engine.properties file does not exist, it is LevelDB + logger.error(" You are trying to open a LevelDB database with RocksDB engine."); + return false; + } if (FileUtil.createDirIfNotExists(dir)) { if (!FileUtil.createFileIfNotExists(enginePath)) { return false; @@ -184,7 +206,7 @@ public boolean checkOrInitEngine() { // for the first init engine String engine = PropUtil.readProperty(enginePath, KEY_ENGINE); - if (engine.isEmpty() && !PropUtil.writeProperty(enginePath, KEY_ENGINE, ROCKSDB)) { + if (Strings.isNullOrEmpty(engine) && !PropUtil.writeProperty(enginePath, KEY_ENGINE, ROCKSDB)) { return false; } engine = PropUtil.readProperty(enginePath, KEY_ENGINE); @@ -194,13 +216,10 @@ public boolean checkOrInitEngine() { public void initDB() { if (!checkOrInitEngine()) { - throw new RuntimeException( - String.format("failed to check database: %s, engine do not match", dataBaseName)); + throw new RuntimeException(String.format( + "Cannot open LevelDB database '%s' with RocksDB engine." + + " Set db.engine=LEVELDB or use RocksDB database. ", dataBaseName)); } - initDB(RocksDbSettings.getSettings()); - } - - public void initDB(RocksDbSettings settings) { resetDbLock.writeLock().lock(); try { if (isAlive()) { @@ -209,81 +228,40 @@ public void initDB(RocksDbSettings settings) { if (dataBaseName == null) { throw new IllegalArgumentException("No name set to the dbStore"); } + options.setLogger(new Logger(options) { + @Override + protected void log(InfoLogLevel infoLogLevel, String logMsg) { + rocksDbLogger.info("{} {}", dataBaseName, logMsg); + } + }); - try (Options options = new Options()) { - - // most of these options are suggested by https://github.com/facebook/rocksdb/wiki/Set-Up-Options + try { + logger.debug("Opening database {}.", dataBaseName); + final Path dbPath = getDbPath(); - // general options - if (settings.isEnableStatistics()) { - options.setStatistics(new Statistics()); - options.setStatsDumpPeriodSec(60); - } - options.setCreateIfMissing(true); - options.setIncreaseParallelism(1); - options.setLevelCompactionDynamicLevelBytes(true); - options.setMaxOpenFiles(settings.getMaxOpenFiles()); - - // general options supported user config - options.setNumLevels(settings.getLevelNumber()); - options.setMaxBytesForLevelMultiplier(settings.getMaxBytesForLevelMultiplier()); - options.setMaxBytesForLevelBase(settings.getMaxBytesForLevelBase()); - options.setMaxBackgroundCompactions(settings.getCompactThreads()); - options.setLevel0FileNumCompactionTrigger(settings.getLevel0FileNumCompactionTrigger()); - options.setTargetFileSizeMultiplier(settings.getTargetFileSizeMultiplier()); - options.setTargetFileSizeBase(settings.getTargetFileSizeBase()); - if (comparator != null) { - options.setComparator(comparator); + if (!Files.isSymbolicLink(dbPath.getParent())) { + Files.createDirectories(dbPath.getParent()); } - options.setLogger(new Logger(options) { - @Override - protected void log(InfoLogLevel infoLogLevel, String logMsg) { - rocksDbLogger.info("{} {}", dataBaseName, logMsg); - } - }); - - // table options - final BlockBasedTableConfig tableCfg; - options.setTableFormatConfig(tableCfg = new BlockBasedTableConfig()); - tableCfg.setBlockSize(settings.getBlockSize()); - tableCfg.setBlockCache(RocksDbSettings.getCache()); - tableCfg.setCacheIndexAndFilterBlocks(true); - tableCfg.setPinL0FilterAndIndexBlocksInCache(true); - tableCfg.setFilter(new BloomFilter(10, false)); - - // read options - readOpts = new ReadOptions(); - readOpts = readOpts.setPrefixSameAsStart(true) - .setVerifyChecksums(false); try { - logger.debug("Opening database {}.", dataBaseName); - final Path dbPath = getDbPath(); - - if (!Files.isSymbolicLink(dbPath.getParent())) { - Files.createDirectories(dbPath.getParent()); - } - - try { - database = RocksDB.open(options, dbPath.toString()); - } catch (RocksDBException e) { - if (Objects.equals(e.getStatus().getCode(), Status.Code.Corruption)) { - logger.error("Database {} corrupted, please delete database directory({}) " + - "and restart.", dataBaseName, parentPath, e); - } else { - logger.error("Open Database {} failed", dataBaseName, e); - } - throw new TronError(e, TronError.ErrCode.ROCKSDB_INIT); + database = RocksDB.open(options, dbPath.toString()); + } catch (RocksDBException e) { + if (Objects.equals(e.getStatus().getCode(), Status.Code.Corruption)) { + logger.error("Database {} corrupted, please delete database directory({}) " + + "and restart.", dataBaseName, parentPath, e); + } else { + logger.error("Open Database {} failed", dataBaseName, e); } - - alive = true; - } catch (IOException ioe) { - throw new RuntimeException( - String.format("failed to init database: %s", dataBaseName), ioe); + throw new TronError(e, TronError.ErrCode.ROCKSDB_INIT); } - logger.debug("Init DB {} done.", dataBaseName); + alive = true; + } catch (IOException ioe) { + throw new RuntimeException( + String.format("failed to init database: %s", dataBaseName), ioe); } + + logger.debug("Init DB {} done.", dataBaseName); } finally { resetDbLock.writeLock().unlock(); } @@ -293,9 +271,9 @@ protected void log(InfoLogLevel infoLogLevel, String logMsg) { public void putData(byte[] key, byte[] value) { resetDbLock.readLock().lock(); try { - if (quitIfNotAlive()) { - return; - } + throwIfNotAlive(); + checkArgNotNull(key, "key"); + checkArgNotNull(value, "value"); database.put(key, value); } catch (RocksDBException e) { throw new RuntimeException(dataBaseName, e); @@ -308,9 +286,8 @@ public void putData(byte[] key, byte[] value) { public byte[] getData(byte[] key) { resetDbLock.readLock().lock(); try { - if (quitIfNotAlive()) { - return null; - } + throwIfNotAlive(); + checkArgNotNull(key, "key"); return database.get(key); } catch (RocksDBException e) { throw new RuntimeException(dataBaseName, e); @@ -323,9 +300,8 @@ public byte[] getData(byte[] key) { public void deleteData(byte[] key) { resetDbLock.readLock().lock(); try { - if (quitIfNotAlive()) { - return; - } + throwIfNotAlive(); + checkArgNotNull(key, "key"); database.delete(key); } catch (RocksDBException e) { throw new RuntimeException(dataBaseName, e); @@ -344,69 +320,39 @@ public org.tron.core.db.common.iterator.DBIterator iterator() { return new RockStoreIterator(getRocksIterator()); } - private void updateByBatchInner(Map rows) throws Exception { - if (quitIfNotAlive()) { - return; - } - try (WriteBatch batch = new WriteBatch()) { - for (Map.Entry entry : rows.entrySet()) { - if (entry.getValue() == null) { - batch.delete(entry.getKey()); - } else { - batch.put(entry.getKey(), entry.getValue()); - } - } - database.write(new WriteOptions(), batch); - } - } - private void updateByBatchInner(Map rows, WriteOptions options) throws Exception { - if (quitIfNotAlive()) { - return; - } try (WriteBatch batch = new WriteBatch()) { for (Map.Entry entry : rows.entrySet()) { + checkArgNotNull(entry.getKey(), "key"); if (entry.getValue() == null) { batch.delete(entry.getKey()); } else { batch.put(entry.getKey(), entry.getValue()); } } + throwIfNotAlive(); database.write(options, batch); } } @Override public void updateByBatch(Map rows, WriteOptionsWrapper optionsWrapper) { - resetDbLock.readLock().lock(); - try { - if (quitIfNotAlive()) { - return; - } - updateByBatchInner(rows, optionsWrapper.rocks); - } catch (Exception e) { - try { - updateByBatchInner(rows); - } catch (Exception e1) { - throw new RuntimeException(dataBaseName, e1); - } - } finally { - resetDbLock.readLock().unlock(); - } + this.updateByBatch(rows, optionsWrapper.rocks); } @Override public void updateByBatch(Map rows) { + this.updateByBatch(rows, new WriteOptions()); + } + + private void updateByBatch(Map rows, WriteOptions options) { resetDbLock.readLock().lock(); try { - if (quitIfNotAlive()) { - return; - } - updateByBatchInner(rows); + updateByBatchInner(rows, options); } catch (Exception e) { try { - updateByBatchInner(rows); + updateByBatchInner(rows, options); } catch (Exception e1) { throw new RuntimeException(dataBaseName, e1); } @@ -416,45 +362,34 @@ public void updateByBatch(Map rows) { } public List getKeysNext(byte[] key, long limit) { + if (limit <= 0) { + return new ArrayList<>(); + } resetDbLock.readLock().lock(); - try { - if (quitIfNotAlive()) { - return new ArrayList<>(); - } - if (limit <= 0) { - return new ArrayList<>(); - } - - try (RocksIterator iter = getRocksIterator()) { - List result = new ArrayList<>(); - long i = 0; - for (iter.seek(key); iter.isValid() && i < limit; iter.next(), i++) { - result.add(iter.key()); - } - return result; + try (RocksIterator iter = getRocksIterator()) { + List result = new ArrayList<>(); + long i = 0; + for (iter.seek(key); iter.isValid() && i < limit; iter.next(), i++) { + result.add(iter.key()); } + return result; } finally { resetDbLock.readLock().unlock(); } } public Map getNext(byte[] key, long limit) { + if (limit <= 0) { + return Collections.emptyMap(); + } resetDbLock.readLock().lock(); - try { - if (quitIfNotAlive()) { - return null; - } - if (limit <= 0) { - return Collections.emptyMap(); - } - try (RocksIterator iter = getRocksIterator()) { - Map result = new HashMap<>(); - long i = 0; - for (iter.seek(key); iter.isValid() && i < limit; iter.next(), i++) { - result.put(iter.key(), iter.value()); - } - return result; + try (RocksIterator iter = getRocksIterator()) { + Map result = new HashMap<>(); + long i = 0; + for (iter.seek(key); iter.isValid() && i < limit; iter.next(), i++) { + result.put(iter.key(), iter.value()); } + return result; } finally { resetDbLock.readLock().unlock(); } @@ -463,78 +398,64 @@ public Map getNext(byte[] key, long limit) { @Override public Map prefixQuery(byte[] key) { resetDbLock.readLock().lock(); - try { - if (quitIfNotAlive()) { - return null; - } - try (RocksIterator iterator = getRocksIterator()) { - Map result = new HashMap<>(); - for (iterator.seek(key); iterator.isValid(); iterator.next()) { - if (Bytes.indexOf(iterator.key(), key) == 0) { - result.put(WrappedByteArray.of(iterator.key()), iterator.value()); - } else { - return result; - } + try (RocksIterator iterator = getRocksIterator()) { + Map result = new HashMap<>(); + for (iterator.seek(key); iterator.isValid(); iterator.next()) { + if (Bytes.indexOf(iterator.key(), key) == 0) { + result.put(WrappedByteArray.of(iterator.key()), iterator.value()); + } else { + return result; } - return result; } + return result; } finally { resetDbLock.readLock().unlock(); } } public Set getlatestValues(long limit) { + if (limit <= 0) { + return Sets.newHashSet(); + } resetDbLock.readLock().lock(); - try { - if (quitIfNotAlive()) { - return null; - } - if (limit <= 0) { - return Sets.newHashSet(); - } - try (RocksIterator iter = getRocksIterator()) { - Set result = Sets.newHashSet(); - long i = 0; - for (iter.seekToLast(); iter.isValid() && i < limit; iter.prev(), i++) { - result.add(iter.value()); - } - return result; + try (RocksIterator iter = getRocksIterator()) { + Set result = Sets.newHashSet(); + long i = 0; + for (iter.seekToLast(); iter.isValid() && i < limit; iter.prev(), i++) { + result.add(iter.value()); } + return result; } finally { resetDbLock.readLock().unlock(); } } - public Set getValuesNext(byte[] key, long limit) { + if (limit <= 0) { + return Sets.newHashSet(); + } resetDbLock.readLock().lock(); - try { - if (quitIfNotAlive()) { - return null; - } - if (limit <= 0) { - return Sets.newHashSet(); - } - try (RocksIterator iter = getRocksIterator()) { - Set result = Sets.newHashSet(); - long i = 0; - for (iter.seek(key); iter.isValid() && i < limit; iter.next(), i++) { - result.add(iter.value()); - } - return result; + try (RocksIterator iter = getRocksIterator()) { + Set result = Sets.newHashSet(); + long i = 0; + for (iter.seek(key); iter.isValid() && i < limit; iter.next(), i++) { + result.add(iter.value()); } + return result; } finally { resetDbLock.readLock().unlock(); } } public void backup(String dir) throws RocksDBException { + throwIfNotAlive(); Checkpoint cp = Checkpoint.create(database); cp.createCheckpoint(dir + this.getDBName()); } private RocksIterator getRocksIterator() { try ( ReadOptions readOptions = new ReadOptions().setFillCache(false)) { + throwIfNotAlive(); return database.newIterator(readOptions); } } @@ -545,7 +466,8 @@ public boolean deleteDbBakPath(String dir) { @Override public RocksDbDataSourceImpl newInstance() { - return new RocksDbDataSourceImpl(parentPath, dataBaseName, RocksDbSettings.getSettings()); + return new RocksDbDataSourceImpl(parentPath, dataBaseName, + this.options); } diff --git a/chainbase/src/main/java/org/tron/common/utils/StorageUtils.java b/chainbase/src/main/java/org/tron/common/utils/StorageUtils.java index 16df43f1534..375f0ba92fb 100644 --- a/chainbase/src/main/java/org/tron/common/utils/StorageUtils.java +++ b/chainbase/src/main/java/org/tron/common/utils/StorageUtils.java @@ -6,6 +6,7 @@ import org.apache.commons.lang3.StringUtils; import org.iq80.leveldb.Options; import org.tron.common.parameter.CommonParameter; +import org.tron.core.Constant; public class StorageUtils { @@ -52,9 +53,15 @@ public static String getOutputDirectory() { } public static Options getOptionsByDbName(String dbName) { + Options options; if (hasProperty(dbName)) { - return getProperty(dbName).getDbOptions(); + options = getProperty(dbName).getDbOptions(); + } else { + options = CommonParameter.getInstance().getStorage().newDefaultDbOptions(dbName); } - return CommonParameter.getInstance().getStorage().newDefaultDbOptions(dbName); + if (Constant.MARKET_PAIR_PRICE_TO_ORDER.equals(dbName)) { + options.comparator(new MarketOrderPriceComparatorForLevelDB()); + } + return options; } } diff --git a/chainbase/src/main/java/org/tron/common/zksnark/JLibrustzcash.java b/chainbase/src/main/java/org/tron/common/zksnark/JLibrustzcash.java index f7b8c17b57f..3700d300411 100644 --- a/chainbase/src/main/java/org/tron/common/zksnark/JLibrustzcash.java +++ b/chainbase/src/main/java/org/tron/common/zksnark/JLibrustzcash.java @@ -29,65 +29,42 @@ @Slf4j public class JLibrustzcash { - private static Librustzcash INSTANCE; + private static Librustzcash INSTANCE = LibrustzcashWrapper.getInstance(); public static void librustzcashZip32XskMaster(Zip32XskMasterParams params) { - if (!isOpenZen()) { - return; - } INSTANCE.librustzcashZip32XskMaster(params.getData(), params.getSize(), params.getM_bytes()); } public static void librustzcashInitZksnarkParams(InitZksnarkParams params) { - if (!isOpenZen()) { - return; - } INSTANCE.librustzcashInitZksnarkParams(params.getSpend_path(), params.getSpend_hash(), params.getOutput_path(), params.getOutput_hash()); } public static void librustzcashZip32XskDerive(Zip32XskDeriveParams params) { - if (!isOpenZen()) { - return; - } INSTANCE.librustzcashZip32XskDerive(params.getData(), params.getSize(), params.getM_bytes()); } public static boolean librustzcashZip32XfvkAddress(Zip32XfvkAddressParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashZip32XfvkAddress(params.getXfvk(), params.getJ(), params.getJ_ret(), params.getAddr_ret()); } public static void librustzcashCrhIvk(CrhIvkParams params) { - if (!isOpenZen()) { - return; - } INSTANCE.librustzcashCrhIvk(params.getAk(), params.getNk(), params.getIvk()); } public static boolean librustzcashKaAgree(KaAgreeParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingKaAgree(params.getP(), params.getSk(), params.getResult()); } public static boolean librustzcashComputeCm(ComputeCmParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingComputeCm(params.getD(), params.getPkD(), params.getValue(), params.getR(), params.getCm()); } public static boolean librustzcashComputeNf(ComputeNfParams params) { - if (isOpenZen()) { - INSTANCE.librustzcashSaplingComputeNf(params.getD(), params.getPkD(), params.getValue(), - params.getR(), params.getAk(), params.getNk(), params.getPosition(), params.getResult()); - } + INSTANCE.librustzcashSaplingComputeNf(params.getD(), params.getPkD(), params.getValue(), + params.getR(), params.getAk(), params.getNk(), params.getPosition(), params.getResult()); return true; } @@ -96,9 +73,6 @@ public static boolean librustzcashComputeNf(ComputeNfParams params) { * @return ak 32 bytes */ public static byte[] librustzcashAskToAk(byte[] ask) throws ZksnarkException { - if (!isOpenZen()) { - return ByteUtil.EMPTY_BYTE_ARRAY; - } LibrustzcashParam.valid32Params(ask); byte[] ak = new byte[32]; INSTANCE.librustzcashAskToAk(ask, ak); @@ -110,9 +84,6 @@ public static byte[] librustzcashAskToAk(byte[] ask) throws ZksnarkException { * @return 32 bytes */ public static byte[] librustzcashNskToNk(byte[] nsk) throws ZksnarkException { - if (!isOpenZen()) { - return ByteUtil.EMPTY_BYTE_ARRAY; - } LibrustzcashParam.valid32Params(nsk); byte[] nk = new byte[32]; INSTANCE.librustzcashNskToNk(nsk, nk); @@ -125,26 +96,17 @@ public static byte[] librustzcashNskToNk(byte[] nsk) throws ZksnarkException { * @return r: random number, less than r_J, 32 bytes */ public static byte[] librustzcashSaplingGenerateR(byte[] r) throws ZksnarkException { - if (!isOpenZen()) { - return ByteUtil.EMPTY_BYTE_ARRAY; - } LibrustzcashParam.valid32Params(r); INSTANCE.librustzcashSaplingGenerateR(r); return r; } public static boolean librustzcashSaplingKaDerivepublic(KaDerivepublicParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingKaDerivepublic(params.getDiversifier(), params.getEsk(), params.getResult()); } public static long librustzcashSaplingProvingCtxInit() { - if (!isOpenZen()) { - return 0; - } return INSTANCE.librustzcashSaplingProvingCtxInit(); } @@ -154,17 +116,11 @@ public static long librustzcashSaplingProvingCtxInit() { * @param d 11 bytes */ public static boolean librustzcashCheckDiversifier(byte[] d) throws ZksnarkException { - if (!isOpenZen()) { - return true; - } LibrustzcashParam.valid11Params(d); return INSTANCE.librustzcashCheckDiversifier(d); } public static boolean librustzcashSaplingSpendProof(SpendProofParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingSpendProof(params.getCtx(), params.getAk(), params.getNsk(), params.getD(), params.getR(), params.getAlpha(), params.getValue(), params.getAnchor(), params.getVoucherPath(), params.getCv(), params.getRk(), @@ -172,26 +128,17 @@ public static boolean librustzcashSaplingSpendProof(SpendProofParams params) { } public static boolean librustzcashSaplingOutputProof(OutputProofParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingOutputProof(params.getCtx(), params.getEsk(), params.getD(), params.getPkD(), params.getR(), params.getValue(), params.getCv(), params.getZkproof()); } public static boolean librustzcashSaplingSpendSig(SpendSigParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingSpendSig(params.getAsk(), params.getAlpha(), params.getSigHash(), params.getResult()); } public static boolean librustzcashSaplingBindingSig(BindingSigParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingBindingSig(params.getCtx(), params.getValueBalance(), params.getSighash(), params.getResult()); } @@ -203,74 +150,47 @@ public static boolean librustzcashSaplingBindingSig(BindingSigParams params) { * @param data 32 bytes */ public static void librustzcashToScalar(byte[] value, byte[] data) throws ZksnarkException { - if (!isOpenZen()) { - return; - } LibrustzcashParam.validParamLength(value, 64); LibrustzcashParam.valid32Params(data); INSTANCE.librustzcashToScalar(value, data); } public static void librustzcashSaplingProvingCtxFree(long ctx) { - if (!isOpenZen()) { - return; - } INSTANCE.librustzcashSaplingProvingCtxFree(ctx); } public static long librustzcashSaplingVerificationCtxInit() { - if (!isOpenZen()) { - return 0; - } return INSTANCE.librustzcashSaplingVerificationCtxInit(); } public static boolean librustzcashSaplingCheckSpend(CheckSpendParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingCheckSpend(params.getCtx(), params.getCv(), params.getAnchor(), params.getNullifier(), params.getRk(), params.getZkproof(), params.getSpendAuthSig(), params.getSighashValue()); } public static boolean librustzcashSaplingCheckOutput(CheckOutputParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingCheckOutput(params.getCtx(), params.getCv(), params.getCm(), params.getEphemeralKey(), params.getZkproof()); } public static boolean librustzcashSaplingFinalCheck(FinalCheckParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingFinalCheck(params.getCtx(), params.getValueBalance(), params.getBindingSig(), params.getSighashValue()); } public static boolean librustzcashSaplingCheckSpendNew(CheckSpendNewParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingCheckSpendNew(params.getCv(), params.getAnchor(), params.getNullifier(), params.getRk(), params.getZkproof(), params.getSpendAuthSig(), params.getSighashValue()); } public static boolean librustzcashSaplingCheckOutputNew(CheckOutputNewParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashSaplingCheckOutputNew(params.getCv(), params.getCm(), params.getEphemeralKey(), params.getZkproof()); } public static boolean librustzcashSaplingFinalCheckNew(FinalCheckNewParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE .librustzcashSaplingFinalCheckNew(params.getValueBalance(), params.getBindingSig(), params.getSighashValue(), params.getSpendCv(), params.getSpendCvLen(), @@ -278,23 +198,14 @@ public static boolean librustzcashSaplingFinalCheckNew(FinalCheckNewParams param } public static void librustzcashSaplingVerificationCtxFree(long ctx) { - if (!isOpenZen()) { - return; - } INSTANCE.librustzcashSaplingVerificationCtxFree(ctx); } public static boolean librustzcashIvkToPkd(IvkToPkdParams params) { - if (!isOpenZen()) { - return true; - } return INSTANCE.librustzcashIvkToPkd(params.getIvk(), params.getD(), params.getPkD()); } public static void librustzcashMerkleHash(MerkleHashParams params) { - if (!isOpenZen()) { - return; - } INSTANCE.librustzcashMerkleHash(params.getDepth(), params.getA(), params.getB(), params.getResult()); } @@ -303,19 +214,7 @@ public static void librustzcashMerkleHash(MerkleHashParams params) { * @param result uncommitted value, 32 bytes */ public static void librustzcashTreeUncommitted(byte[] result) throws ZksnarkException { - if (!isOpenZen()) { - return; - } LibrustzcashParam.valid32Params(result); INSTANCE.librustzcashTreeUncommitted(result); } - - public static boolean isOpenZen() { - boolean res = CommonParameter.getInstance().isFullNodeAllowShieldedTransactionArgs(); - if (res) { - INSTANCE = LibrustzcashWrapper.getInstance(); - } - return res; - } - } diff --git a/chainbase/src/main/java/org/tron/common/zksnark/JLibsodium.java b/chainbase/src/main/java/org/tron/common/zksnark/JLibsodium.java index 0159ba0bf6b..0713d74b7bd 100644 --- a/chainbase/src/main/java/org/tron/common/zksnark/JLibsodium.java +++ b/chainbase/src/main/java/org/tron/common/zksnark/JLibsodium.java @@ -12,37 +12,25 @@ public class JLibsodium { public static final int CRYPTO_GENERICHASH_BLAKE2B_PERSONALBYTES = 16; public static final int CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12; - private static Libsodium INSTANCE; + private static Libsodium INSTANCE = LibsodiumWrapper.getInstance(); public static int cryptoGenerichashBlake2bInitSaltPersonal(Blake2bInitSaltPersonalParams params) { - if (!isOpenZen()) { - return 0; - } return INSTANCE .cryptoGenerichashBlake2BInitSaltPersonal(params.getState(), params.getKey(), params.getKeyLen(), params.getOutLen(), params.getSalt(), params.getPersonal()); } public static int cryptoGenerichashBlake2bUpdate(Blake2bUpdateParams params) { - if (!isOpenZen()) { - return 0; - } return INSTANCE .cryptoGenerichashBlake2BUpdate(params.getState(), params.getIn(), params.getInLen()); } public static int cryptoGenerichashBlake2bFinal(Blake2bFinalParams params) { - if (!isOpenZen()) { - return 0; - } return INSTANCE.cryptoGenerichashBlake2BFinal(params.getState(), params.getOut(), params.getOutLen()); } public static int cryptoGenerichashBlack2bSaltPersonal(Black2bSaltPersonalParams params) { - if (!isOpenZen()) { - return 0; - } return INSTANCE.cryptoGenerichashBlake2BSaltPersonal(params.getOut(), params.getOutLen(), params.getIn(), params.getInLen(), params.getKey(), params.getKeyLen(), params.getSalt(), @@ -51,9 +39,6 @@ public static int cryptoGenerichashBlack2bSaltPersonal(Black2bSaltPersonalParams public static int cryptoAeadChacha20poly1305IetfDecrypt( Chacha20poly1305IetfDecryptParams params) { - if (!isOpenZen()) { - return 0; - } return INSTANCE .cryptoAeadChacha20Poly1305IetfDecrypt(params.getM(), params.getMLenP(), params.getNSec(), @@ -63,9 +48,6 @@ public static int cryptoAeadChacha20poly1305IetfDecrypt( public static int cryptoAeadChacha20Poly1305IetfEncrypt( Chacha20Poly1305IetfEncryptParams params) { - if (!isOpenZen()) { - return 0; - } return INSTANCE .cryptoAeadChacha20Poly1305IetfEncrypt(params.getC(), params.getCLenP(), params.getM(), params.getMLen(), params.getAd(), params.getAdLen(), @@ -73,25 +55,10 @@ public static int cryptoAeadChacha20Poly1305IetfEncrypt( } public static long initState() { - if (!isOpenZen()) { - return 0; - } return INSTANCE.cryptoGenerichashBlake2BStateInit(); } public static void freeState(long state) { - if (!isOpenZen()) { - return; - } INSTANCE.cryptoGenerichashBlake2BStateFree(state); } - - private static boolean isOpenZen() { - boolean res = CommonParameter.getInstance() - .isFullNodeAllowShieldedTransactionArgs(); - if (res) { - INSTANCE = LibsodiumWrapper.getInstance(); - } - return res; - } } 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 95f436b19f0..b11c6b1e0a4 100755 --- a/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java +++ b/chainbase/src/main/java/org/tron/core/capsule/TransactionCapsule.java @@ -41,6 +41,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ArrayUtils; import org.tron.common.crypto.ECKey.ECDSASignature; +import org.tron.common.crypto.Rsv; import org.tron.common.crypto.SignInterface; import org.tron.common.crypto.SignUtils; import org.tron.common.es.ExecutorServiceManager; @@ -456,14 +457,8 @@ public static long getCallValue(Transaction.Contract contract) { } public static String getBase64FromByteString(ByteString sign) { - byte[] r = sign.substring(0, 32).toByteArray(); - byte[] s = sign.substring(32, 64).toByteArray(); - byte v = sign.byteAt(64); - if (v < 27) { - v += 27; //revId -> v - } - ECDSASignature signature = ECDSASignature.fromComponents(r, s, v); - return signature.toBase64(); + Rsv rsv = Rsv.fromSignature(sign.toByteArray()); + return ECDSASignature.fromComponents(rsv.getR(), rsv.getS(), rsv.getV()).toBase64(); } public static boolean validateSignature(Transaction transaction, diff --git a/chainbase/src/main/java/org/tron/core/capsule/utils/MarketUtils.java b/chainbase/src/main/java/org/tron/core/capsule/utils/MarketUtils.java index d711ac0d63b..e98bba9db08 100644 --- a/chainbase/src/main/java/org/tron/core/capsule/utils/MarketUtils.java +++ b/chainbase/src/main/java/org/tron/core/capsule/utils/MarketUtils.java @@ -25,6 +25,7 @@ import org.tron.common.crypto.Hash; import org.tron.common.utils.ByteArray; import org.tron.common.utils.ByteUtil; +import org.tron.common.utils.MarketComparator; import org.tron.core.capsule.AccountCapsule; import org.tron.core.capsule.MarketAccountOrderCapsule; import org.tron.core.capsule.MarketOrderCapsule; @@ -227,29 +228,6 @@ public static byte[] createPairKey(byte[] sellTokenId, byte[] buyTokenId) { return result; } - /** - * Note: the params should be the same token pair, or you should change the order. - * All the quantity should be bigger than 0. - * */ - public static int comparePrice(long price1SellQuantity, long price1BuyQuantity, - long price2SellQuantity, long price2BuyQuantity) { - try { - return Long.compare(multiplyExact(price1BuyQuantity, price2SellQuantity, true), - multiplyExact(price2BuyQuantity, price1SellQuantity, true)); - - } catch (ArithmeticException ex) { - // do nothing here, because we will use BigInteger to compute again - } - - BigInteger price1BuyQuantityBI = BigInteger.valueOf(price1BuyQuantity); - BigInteger price1SellQuantityBI = BigInteger.valueOf(price1SellQuantity); - BigInteger price2BuyQuantityBI = BigInteger.valueOf(price2BuyQuantity); - BigInteger price2SellQuantityBI = BigInteger.valueOf(price2SellQuantity); - - return price1BuyQuantityBI.multiply(price2SellQuantityBI) - .compareTo(price2BuyQuantityBI.multiply(price1SellQuantityBI)); - } - /** * if takerPrice >= makerPrice, return True * note: here are two different token pairs @@ -265,7 +243,8 @@ public static boolean priceMatch(MarketPrice takerPrice, MarketPrice makerPrice) // ==> Price_TRX * sellQuantity_taker/buyQuantity_taker >= Price_TRX * buyQuantity_maker/sellQuantity_maker // ==> sellQuantity_taker * sellQuantity_maker > buyQuantity_taker * buyQuantity_maker - return comparePrice(takerPrice.getBuyTokenQuantity(), takerPrice.getSellTokenQuantity(), + return MarketComparator.comparePrice(takerPrice.getBuyTokenQuantity(), + takerPrice.getSellTokenQuantity(), makerPrice.getSellTokenQuantity(), makerPrice.getBuyTokenQuantity()) >= 0; } @@ -316,57 +295,7 @@ public static void returnSellTokenRemain(MarketOrderCapsule orderCapsule, } public static int comparePriceKey(byte[] o1, byte[] o2) { - //compare pair - byte[] pair1 = new byte[TOKEN_ID_LENGTH * 2]; - byte[] pair2 = new byte[TOKEN_ID_LENGTH * 2]; - - System.arraycopy(o1, 0, pair1, 0, TOKEN_ID_LENGTH * 2); - System.arraycopy(o2, 0, pair2, 0, TOKEN_ID_LENGTH * 2); - - int pairResult = org.bouncycastle.util.Arrays.compareUnsigned(pair1, pair2); - if (pairResult != 0) { - return pairResult; - } - - //compare price - byte[] getSellTokenQuantity1 = new byte[8]; - byte[] getBuyTokenQuantity1 = new byte[8]; - - byte[] getSellTokenQuantity2 = new byte[8]; - byte[] getBuyTokenQuantity2 = new byte[8]; - - int longByteNum = 8; - - System.arraycopy(o1, TOKEN_ID_LENGTH + TOKEN_ID_LENGTH, - getSellTokenQuantity1, 0, longByteNum); - System.arraycopy(o1, TOKEN_ID_LENGTH + TOKEN_ID_LENGTH + longByteNum, - getBuyTokenQuantity1, 0, longByteNum); - - System.arraycopy(o2, TOKEN_ID_LENGTH + TOKEN_ID_LENGTH, - getSellTokenQuantity2, 0, longByteNum); - System.arraycopy(o2, TOKEN_ID_LENGTH + TOKEN_ID_LENGTH + longByteNum, - getBuyTokenQuantity2, 0, longByteNum); - - long sellTokenQuantity1 = ByteArray.toLong(getSellTokenQuantity1); - long buyTokenQuantity1 = ByteArray.toLong(getBuyTokenQuantity1); - long sellTokenQuantity2 = ByteArray.toLong(getSellTokenQuantity2); - long buyTokenQuantity2 = ByteArray.toLong(getBuyTokenQuantity2); - - if ((sellTokenQuantity1 == 0 || buyTokenQuantity1 == 0) - && (sellTokenQuantity2 == 0 || buyTokenQuantity2 == 0)) { - return 0; - } - - if (sellTokenQuantity1 == 0 || buyTokenQuantity1 == 0) { - return -1; - } - - if (sellTokenQuantity2 == 0 || buyTokenQuantity2 == 0) { - return 1; - } - - return comparePrice(sellTokenQuantity1, buyTokenQuantity1, - sellTokenQuantity2, buyTokenQuantity2); + return MarketComparator.comparePriceKey(o1, o2); } diff --git a/chainbase/src/main/java/org/tron/core/db/TronDatabase.java b/chainbase/src/main/java/org/tron/core/db/TronDatabase.java index d791e189eb4..8630fbdcdff 100644 --- a/chainbase/src/main/java/org/tron/core/db/TronDatabase.java +++ b/chainbase/src/main/java/org/tron/core/db/TronDatabase.java @@ -9,9 +9,9 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.iq80.leveldb.WriteOptions; -import org.rocksdb.DirectComparator; import org.springframework.beans.factory.annotation.Autowired; import org.tron.common.parameter.CommonParameter; +import org.tron.common.storage.OptionsPicker; import org.tron.common.storage.WriteOptionsWrapper; import org.tron.common.storage.leveldb.LevelDbDataSourceImpl; import org.tron.common.storage.metric.DbStatService; @@ -24,7 +24,7 @@ import org.tron.core.exception.ItemNotFoundException; @Slf4j(topic = "DB") -public abstract class TronDatabase implements ITronChainBase { +public abstract class TronDatabase extends OptionsPicker implements ITronChainBase { protected DbSourceInter dbSource; @Getter @@ -51,8 +51,7 @@ protected TronDatabase(String dbName) { String parentName = Paths.get(StorageUtils.getOutputDirectoryByDbName(dbName), CommonParameter.getInstance().getStorage().getDbDirectory()).toString(); dbSource = - new RocksDbDataSourceImpl(parentName, dbName, CommonParameter.getInstance() - .getRocksDBCustomSettings(), getDirectComparator()); + new RocksDbDataSourceImpl(parentName, dbName, getOptionsByDbNameForRocksDB(dbName)); } dbSource.initDB(); @@ -66,14 +65,6 @@ protected void init() { protected TronDatabase() { } - protected org.iq80.leveldb.Options getOptionsByDbNameForLevelDB(String dbName) { - return StorageUtils.getOptionsByDbName(dbName); - } - - protected DirectComparator getDirectComparator() { - return null; - } - public DbSourceInter getDbSource() { return dbSource; } diff --git a/chainbase/src/main/java/org/tron/core/db/TronStoreWithRevoking.java b/chainbase/src/main/java/org/tron/core/db/TronStoreWithRevoking.java index 4b75ddee3a4..4952b70478d 100644 --- a/chainbase/src/main/java/org/tron/core/db/TronStoreWithRevoking.java +++ b/chainbase/src/main/java/org/tron/core/db/TronStoreWithRevoking.java @@ -16,9 +16,9 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.iq80.leveldb.WriteOptions; -import org.rocksdb.DirectComparator; import org.springframework.beans.factory.annotation.Autowired; import org.tron.common.parameter.CommonParameter; +import org.tron.common.storage.OptionsPicker; import org.tron.common.storage.leveldb.LevelDbDataSourceImpl; import org.tron.common.storage.metric.DbStatService; import org.tron.common.storage.rocksdb.RocksDbDataSourceImpl; @@ -38,7 +38,7 @@ @Slf4j(topic = "DB") -public abstract class TronStoreWithRevoking implements ITronChainBase { +public abstract class TronStoreWithRevoking extends OptionsPicker implements ITronChainBase { @Getter // only for unit test protected IRevokingDB revokingDB; @@ -69,22 +69,13 @@ protected TronStoreWithRevoking(String dbName) { .getInstance().getStorage().getDbDirectory()).toString(); this.db = new RocksDB( new RocksDbDataSourceImpl(parentPath, - dbName, CommonParameter.getInstance() - .getRocksDBCustomSettings(), getDirectComparator())); + dbName, getOptionsByDbNameForRocksDB(dbName))); } else { throw new RuntimeException(String.format("db engine %s is error", dbEngine)); } this.revokingDB = new Chainbase(new SnapshotRoot(this.db)); } - protected org.iq80.leveldb.Options getOptionsByDbNameForLevelDB(String dbName) { - return StorageUtils.getOptionsByDbName(dbName); - } - - protected DirectComparator getDirectComparator() { - return null; - } - protected TronStoreWithRevoking(DB db) { this.db = db; this.revokingDB = new Chainbase(new SnapshotRoot(db)); diff --git a/chainbase/src/main/java/org/tron/core/db/common/DbSourceInter.java b/chainbase/src/main/java/org/tron/core/db/common/DbSourceInter.java index 0823b7a7cf4..18461860fc2 100755 --- a/chainbase/src/main/java/org/tron/core/db/common/DbSourceInter.java +++ b/chainbase/src/main/java/org/tron/core/db/common/DbSourceInter.java @@ -17,11 +17,10 @@ */ package org.tron.core.db.common; -import org.tron.core.db2.common.WrappedByteArray; - +import com.google.common.annotations.VisibleForTesting; import java.util.Map; import java.util.Set; - +import org.tron.core.db2.common.WrappedByteArray; public interface DbSourceInter extends BatchSourceInter, Iterable> { @@ -38,10 +37,16 @@ public interface DbSourceInter extends BatchSourceInter, void resetDb(); + @VisibleForTesting + @Deprecated Set allKeys() throws RuntimeException; + @VisibleForTesting + @Deprecated Set allValues() throws RuntimeException; + @VisibleForTesting + @Deprecated long getTotal() throws RuntimeException; void stat(); diff --git a/chainbase/src/main/java/org/tron/core/db/common/iterator/RockStoreIterator.java b/chainbase/src/main/java/org/tron/core/db/common/iterator/RockStoreIterator.java index 541f71348af..105d845dc64 100644 --- a/chainbase/src/main/java/org/tron/core/db/common/iterator/RockStoreIterator.java +++ b/chainbase/src/main/java/org/tron/core/db/common/iterator/RockStoreIterator.java @@ -47,7 +47,7 @@ public boolean hasNext() { try { close(); } catch (Exception e1) { - logger.error(e.getMessage(), e); + logger.error(e1.getMessage(), e1); } } return hasNext; @@ -79,6 +79,11 @@ public byte[] setValue(byte[] value) { }; } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + @Override public void seek(byte[] key) { checkState(); diff --git a/chainbase/src/main/java/org/tron/core/db/common/iterator/StoreIterator.java b/chainbase/src/main/java/org/tron/core/db/common/iterator/StoreIterator.java index d771716a7e8..c2803f99637 100755 --- a/chainbase/src/main/java/org/tron/core/db/common/iterator/StoreIterator.java +++ b/chainbase/src/main/java/org/tron/core/db/common/iterator/StoreIterator.java @@ -46,6 +46,11 @@ public boolean hasNext() { } } catch (Exception e) { logger.error(e.getMessage(), e); + try { + close(); + } catch (Exception e1) { + logger.error(e1.getMessage(), e1); + } } return hasNext; diff --git a/chainbase/src/main/java/org/tron/core/db2/common/TxCacheDB.java b/chainbase/src/main/java/org/tron/core/db2/common/TxCacheDB.java index 9d2409685c9..db9516d6203 100644 --- a/chainbase/src/main/java/org/tron/core/db2/common/TxCacheDB.java +++ b/chainbase/src/main/java/org/tron/core/db2/common/TxCacheDB.java @@ -35,6 +35,7 @@ import org.tron.common.parameter.CommonParameter; import org.tron.common.prometheus.MetricKeys; import org.tron.common.prometheus.Metrics; +import org.tron.common.storage.OptionsPicker; import org.tron.common.storage.leveldb.LevelDbDataSourceImpl; import org.tron.common.storage.rocksdb.RocksDbDataSourceImpl; import org.tron.common.utils.ByteArray; @@ -48,7 +49,7 @@ import org.tron.core.store.DynamicPropertiesStore; @Slf4j(topic = "DB") -public class TxCacheDB implements DB, Flusher { +public class TxCacheDB extends OptionsPicker implements DB, Flusher { // > 65_536(= 2^16) blocks, that is the number of the reference block private static final long MAX_BLOCK_SIZE = 65536; @@ -106,7 +107,7 @@ public TxCacheDB(String name, RecentTransactionStore recentTransactionStore, if ("LEVELDB".equals(dbEngine.toUpperCase())) { this.persistentStore = new LevelDB( new LevelDbDataSourceImpl(StorageUtils.getOutputDirectoryByDbName(name), - name, StorageUtils.getOptionsByDbName(name), + name, getOptionsByDbNameForLevelDB(name), new WriteOptions().sync(CommonParameter.getInstance() .getStorage().isDbSync()))); } else if ("ROCKSDB".equals(dbEngine.toUpperCase())) { @@ -115,9 +116,7 @@ public TxCacheDB(String name, RecentTransactionStore recentTransactionStore, .getInstance().getStorage().getDbDirectory()).toString(); this.persistentStore = new RocksDB( - new RocksDbDataSourceImpl(parentPath, - name, CommonParameter.getInstance() - .getRocksDBCustomSettings())); + new RocksDbDataSourceImpl(parentPath, name, getOptionsByDbNameForRocksDB(name))); } else { throw new RuntimeException(String.format("db type: %s is not supported", dbEngine)); } diff --git a/chainbase/src/main/java/org/tron/core/service/MortgageService.java b/chainbase/src/main/java/org/tron/core/service/MortgageService.java index b1fd279c2db..f0182503ae8 100644 --- a/chainbase/src/main/java/org/tron/core/service/MortgageService.java +++ b/chainbase/src/main/java/org/tron/core/service/MortgageService.java @@ -182,7 +182,7 @@ private long computeReward(long cycle, List> votes) { } long userVote = vote.getValue(); double voteRate = (double) userVote / totalVote; - reward += voteRate * totalReward; + reward += (long) (voteRate * totalReward); } return reward; } diff --git a/chainbase/src/main/java/org/tron/core/store/AccountStore.java b/chainbase/src/main/java/org/tron/core/store/AccountStore.java index 4d39049ee79..5aec5958729 100644 --- a/chainbase/src/main/java/org/tron/core/store/AccountStore.java +++ b/chainbase/src/main/java/org/tron/core/store/AccountStore.java @@ -12,6 +12,7 @@ import org.tron.core.capsule.BlockCapsule; import org.tron.core.db.TronStoreWithRevoking; import org.tron.core.db.accountstate.AccountStateCallBackUtils; +import org.tron.core.exception.TronError; import org.tron.protos.contract.BalanceContract.TransactionBalanceTrace; import org.tron.protos.contract.BalanceContract.TransactionBalanceTrace.Operation; @@ -23,6 +24,8 @@ @Component public class AccountStore extends TronStoreWithRevoking { + private static String ACCOUNT_BLACKHOLE = "Blackhole"; + private static Map assertsAddress = new HashMap<>(); // key = name , value = address @Autowired @@ -50,6 +53,9 @@ public static void setAccount(com.typesafe.config.Config config) { byte[] address = Commons.decodeFromBase58Check(obj.get("address").unwrapped().toString()); assertsAddress.put(accountName, address); } + if (assertsAddress.get(ACCOUNT_BLACKHOLE) == null) { + throw new TronError("Account[Blackhole] is not configured.", TronError.ErrCode.GENESIS_BLOCK_INIT); + } } @Override @@ -109,12 +115,12 @@ public AccountCapsule getSun() { * Min TRX account. */ public AccountCapsule getBlackhole() { - return getUnchecked(assertsAddress.get("Blackhole")); + return getUnchecked(assertsAddress.get(ACCOUNT_BLACKHOLE)); } public byte[] getBlackholeAddress() { - return assertsAddress.get("Blackhole"); + return assertsAddress.get(ACCOUNT_BLACKHOLE); } /** 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 91b0cff68a0..bee13782e53 100644 --- a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java +++ b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java @@ -1,6 +1,8 @@ package org.tron.core.store; import static org.tron.common.math.Maths.max; +import static org.tron.core.Constant.MAX_PROPOSAL_EXPIRE_TIME; +import static org.tron.core.Constant.MIN_PROPOSAL_EXPIRE_TIME; import static org.tron.core.config.Parameter.ChainConstant.BLOCK_PRODUCED_INTERVAL; import static org.tron.core.config.Parameter.ChainConstant.DELEGATE_PERIOD; @@ -231,6 +233,7 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking private static final byte[] ALLOW_TVM_CANCUN = "ALLOW_TVM_CANCUN".getBytes(); private static final byte[] ALLOW_TVM_BLOB = "ALLOW_TVM_BLOB".getBytes(); + private static final byte[] PROPOSAL_EXPIRE_TIME = "PROPOSAL_EXPIRE_TIME".getBytes(); @Autowired private DynamicPropertiesStore(@Value("properties") String dbName) { @@ -2946,6 +2949,18 @@ public long getAllowTvmBlob() { .orElse(CommonParameter.getInstance().getAllowTvmBlob()); } + public void saveProposalExpireTime(long proposalExpireTime) { + this.put(PROPOSAL_EXPIRE_TIME, new BytesCapsule(ByteArray.fromLong(proposalExpireTime))); + } + + public long getProposalExpireTime() { + return Optional.ofNullable(getUnchecked(PROPOSAL_EXPIRE_TIME)) + .map(BytesCapsule::getData) + .map(ByteArray::toLong) + .filter(time -> time > MIN_PROPOSAL_EXPIRE_TIME && time < MAX_PROPOSAL_EXPIRE_TIME) + .orElse(CommonParameter.getInstance().getProposalExpireTime()); + } + private static class DynamicResourceProperties { private static final byte[] ONE_DAY_NET_LIMIT = "ONE_DAY_NET_LIMIT".getBytes(); diff --git a/chainbase/src/main/java/org/tron/core/store/MarketPairPriceToOrderStore.java b/chainbase/src/main/java/org/tron/core/store/MarketPairPriceToOrderStore.java index 605952328ed..391fb4249c8 100644 --- a/chainbase/src/main/java/org/tron/core/store/MarketPairPriceToOrderStore.java +++ b/chainbase/src/main/java/org/tron/core/store/MarketPairPriceToOrderStore.java @@ -3,16 +3,11 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.iq80.leveldb.Options; -import org.rocksdb.ComparatorOptions; -import org.rocksdb.DirectComparator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.tron.common.utils.ByteUtil; -import org.tron.common.utils.MarketOrderPriceComparatorForLevelDB; -import org.tron.common.utils.MarketOrderPriceComparatorForRockDB; -import org.tron.common.utils.StorageUtils; +import org.tron.core.Constant; import org.tron.core.capsule.MarketOrderIdListCapsule; import org.tron.core.capsule.utils.MarketUtils; import org.tron.core.db.TronStoreWithRevoking; @@ -22,24 +17,10 @@ public class MarketPairPriceToOrderStore extends TronStoreWithRevoking { @Autowired - protected MarketPairPriceToOrderStore(@Value("market_pair_price_to_order") String dbName) { + protected MarketPairPriceToOrderStore(@Value(Constant.MARKET_PAIR_PRICE_TO_ORDER) String dbName) { super(dbName); } - @Override - protected Options getOptionsByDbNameForLevelDB(String dbName) { - Options options = StorageUtils.getOptionsByDbName(dbName); - options.comparator(new MarketOrderPriceComparatorForLevelDB()); - return options; - } - - //todo: to test later - @Override - protected DirectComparator getDirectComparator() { - ComparatorOptions comparatorOptions = new ComparatorOptions(); - return new MarketOrderPriceComparatorForRockDB(comparatorOptions); - } - @Override public MarketOrderIdListCapsule get(byte[] key) throws ItemNotFoundException { byte[] value = revokingDB.get(key); diff --git a/common/build.gradle b/common/build.gradle index c6ce8cf44f9..83fe638ae50 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -6,45 +6,23 @@ version '1.0.0' sourceCompatibility = 1.8 -// Dependency versions -// --------------------------------------- -def leveldbVersion = "1.8" -// -------------------------------------- - -static def isWindows() { - return org.gradle.internal.os.OperatingSystem.current().isWindows() -} - -if (isWindows()) { - ext { - leveldbGroup = "org.ethereum" - leveldbName = "leveldbjni-all" - leveldbVersion = "1.18.3" - } -} else { - ext { - leveldbGroup = "org.fusesource.leveldbjni" - leveldbName = "leveldbjni-all" - leveldbVersion = "1.8" - } -} dependencies { - api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.4.2' // https://github.com/FasterXML/jackson-databind/issues/3627 - api "com.cedarsoftware:java-util:1.8.0" + api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.3' // https://github.com/FasterXML/jackson-databind/issues/3627 + api "com.cedarsoftware:java-util:3.2.0" api group: 'org.apache.httpcomponents', name: 'httpasyncclient', version: '4.1.1' api group: 'commons-codec', name: 'commons-codec', version: '1.11' api group: 'com.beust', name: 'jcommander', version: '1.78' api group: 'com.typesafe', name: 'config', version: '1.3.2' - api group: leveldbGroup, name: leveldbName, version: leveldbVersion - api group: 'org.rocksdb', name: 'rocksdbjni', version: '5.15.10' api group: 'io.prometheus', name: 'simpleclient', version: '0.15.0' api group: 'io.prometheus', name: 'simpleclient_httpserver', version: '0.15.0' api group: 'io.prometheus', name: 'simpleclient_hotspot', version: '0.15.0' - api 'org.aspectj:aspectjrt:1.8.13' - api 'org.aspectj:aspectjweaver:1.8.13' - api 'org.aspectj:aspectjtools:1.8.13' - api group: 'io.github.tronprotocol', name: 'libp2p', version: '2.2.5',{ + // https://openjdk.org/jeps/396, JEP 396: Strongly Encapsulate JDK Internals by Default + // https://eclipse.dev/aspectj/doc/latest/release/JavaVersionCompatibility.html + api 'org.aspectj:aspectjrt:1.9.8' + api 'org.aspectj:aspectjweaver:1.9.8' + api 'org.aspectj:aspectjtools:1.9.8' + api group: 'io.github.tronprotocol', name: 'libp2p', version: '2.2.6',{ exclude group: 'io.grpc', module: 'grpc-context' exclude group: 'io.grpc', module: 'grpc-core' exclude group: 'io.grpc', module: 'grpc-netty' @@ -62,6 +40,7 @@ dependencies { exclude group: 'org.bouncycastle', module: 'bcutil-jdk18on' } api project(":protocol") + api project(":platform") } jacocoTestReport { diff --git a/common/src/main/java/org/tron/common/exit/ExitManager.java b/common/src/main/java/org/tron/common/exit/ExitManager.java index d80b7838c08..1a1cc9ed3fc 100644 --- a/common/src/main/java/org/tron/common/exit/ExitManager.java +++ b/common/src/main/java/org/tron/common/exit/ExitManager.java @@ -46,7 +46,7 @@ public static Optional findTronError(Throwable e) { public static void logAndExit(TronError exit) { final int code = exit.getErrCode().getCode(); - logger.error("Shutting down with code: {}.", exit.getErrCode(), exit); + logger.error("Shutting down with code: {}, reason: {}", exit.getErrCode(), exit.getMessage()); Thread exitThread = exitThreadFactory.newThread(() -> System.exit(code)); exitThread.start(); } 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 45893970fb0..e32708a77e6 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -205,7 +205,15 @@ public class CommonParameter { //If you are running a solidity node for java tron, this flag is set to true @Getter @Setter + @Parameter(names = {"--solidity"}, description = "running a solidity node for java tron") public boolean solidityNode = false; + + //If you are running KeystoreFactory, this flag is set to true + @Getter + @Setter + @Parameter(names = {"--keystore"}, description = "running KeystoreFactory") + public boolean keystore = false; + @Getter @Setter public int rpcPort; @@ -383,7 +391,7 @@ public class CommonParameter { // full node used this parameter to close shielded transaction @Getter @Setter - public boolean fullNodeAllowShieldedTransactionArgs; + public boolean allowShieldedTransactionApi; @Getter @Setter public long blockNumForEnergyLimit; @@ -429,6 +437,15 @@ public class CommonParameter { @Getter public int rateLimiterGlobalApiQps; @Getter + @Setter + public double rateLimiterSyncBlockChain; + @Getter + @Setter + public double rateLimiterFetchInvData; + @Getter + @Setter + public double rateLimiterDisconnect; + @Getter public DbBackupConfig dbBackupConfig; @Getter public RocksDbSettings rocksDBCustomSettings; diff --git a/common/src/main/java/org/tron/common/setting/RocksDbSettings.java b/common/src/main/java/org/tron/common/setting/RocksDbSettings.java index 7436150cae2..5c2e5eacddf 100644 --- a/common/src/main/java/org/tron/common/setting/RocksDbSettings.java +++ b/common/src/main/java/org/tron/common/setting/RocksDbSettings.java @@ -1,16 +1,21 @@ package org.tron.common.setting; +import java.util.Arrays; import lombok.Getter; -import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.rocksdb.BlockBasedTableConfig; +import org.rocksdb.BloomFilter; +import org.rocksdb.ComparatorOptions; import org.rocksdb.LRUCache; +import org.rocksdb.Options; import org.rocksdb.RocksDB; +import org.rocksdb.Statistics; +import org.tron.common.utils.MarketOrderPriceComparatorForRocksDB; +import org.tron.core.Constant; @Slf4j public class RocksDbSettings { - @Setter - @Getter private static RocksDbSettings rocksDbSettings; @Getter @@ -40,6 +45,15 @@ public class RocksDbSettings { private static final LRUCache cache = new LRUCache(1 * 1024 * 1024 * 1024L); + private static final String[] CI_ENVIRONMENT_VARIABLES = { + "CI", + "JENKINS_URL", + "TRAVIS", + "CIRCLECI", + "GITHUB_ACTIONS", + "GITLAB_CI" + }; + private RocksDbSettings() { } @@ -60,9 +74,9 @@ public static RocksDbSettings initCustomSettings(int levelNumber, int compactThr int blockSize, long maxBytesForLevelBase, double maxBytesForLevelMultiplier, int level0FileNumCompactionTrigger, long targetFileSizeBase, - int targetFileSizeMultiplier) { + int targetFileSizeMultiplier, int maxOpenFiles) { rocksDbSettings = new RocksDbSettings() - .withMaxOpenFiles(5000) + .withMaxOpenFiles(maxOpenFiles) .withEnableStatistics(false) .withLevelNumber(levelNumber) .withCompactThreads(compactThreads) @@ -76,16 +90,17 @@ public static RocksDbSettings initCustomSettings(int levelNumber, int compactThr } public static void loggingSettings() { - logger.info(String.format( - "level number: %d, CompactThreads: %d, Blocksize: %d, maxBytesForLevelBase: %d," - + " withMaxBytesForLevelMultiplier: %f, level0FileNumCompactionTrigger: %d, " - + "withTargetFileSizeBase: %d, withTargetFileSizeMultiplier: %d", + logger.info( + "level number: {}, CompactThreads: {}, Blocksize:{}, maxBytesForLevelBase: {}," + + " withMaxBytesForLevelMultiplier: {}, level0FileNumCompactionTrigger: {}, " + + "withTargetFileSizeBase: {}, withTargetFileSizeMultiplier: {}, maxOpenFiles: {}", rocksDbSettings.getLevelNumber(), rocksDbSettings.getCompactThreads(), rocksDbSettings.getBlockSize(), rocksDbSettings.getMaxBytesForLevelBase(), rocksDbSettings.getMaxBytesForLevelMultiplier(), rocksDbSettings.getLevel0FileNumCompactionTrigger(), - rocksDbSettings.getTargetFileSizeBase(), rocksDbSettings.getTargetFileSizeMultiplier())); + rocksDbSettings.getTargetFileSizeBase(), rocksDbSettings.getTargetFileSizeMultiplier(), + rocksDbSettings.getMaxOpenFiles()); } public RocksDbSettings withMaxOpenFiles(int maxOpenFiles) { @@ -140,4 +155,63 @@ public RocksDbSettings withTargetFileSizeMultiplier(int targetFileSizeMultiplier public static LRUCache getCache() { return cache; } + + public static Options getOptionsByDbName(String dbName) { + RocksDbSettings settings = getSettings(); + + Options options = new Options(); + + // most of these options are suggested by https://github.com/facebook/rocksdb/wiki/Set-Up-Options + + // general options + if (settings.isEnableStatistics()) { + options.setStatistics(new Statistics()); + options.setStatsDumpPeriodSec(60); + } + options.setCreateIfMissing(true); + options.setIncreaseParallelism(1); + options.setLevelCompactionDynamicLevelBytes(true); + options.setMaxOpenFiles(settings.getMaxOpenFiles()); + + // general options supported user config + options.setNumLevels(settings.getLevelNumber()); + options.setMaxBytesForLevelMultiplier(settings.getMaxBytesForLevelMultiplier()); + options.setMaxBytesForLevelBase(settings.getMaxBytesForLevelBase()); + options.setMaxBackgroundCompactions(settings.getCompactThreads()); + options.setLevel0FileNumCompactionTrigger(settings.getLevel0FileNumCompactionTrigger()); + options.setTargetFileSizeMultiplier(settings.getTargetFileSizeMultiplier()); + options.setTargetFileSizeBase(settings.getTargetFileSizeBase()); + + // table options + final BlockBasedTableConfig tableCfg; + options.setTableFormatConfig(tableCfg = new BlockBasedTableConfig()); + tableCfg.setBlockSize(settings.getBlockSize()); + tableCfg.setBlockCache(RocksDbSettings.getCache()); + tableCfg.setCacheIndexAndFilterBlocks(true); + tableCfg.setPinL0FilterAndIndexBlocksInCache(true); + tableCfg.setFilter(new BloomFilter(10, false)); + if (Constant.MARKET_PAIR_PRICE_TO_ORDER.equals(dbName)) { + ComparatorOptions comparatorOptions = new ComparatorOptions(); + options.setComparator(new MarketOrderPriceComparatorForRocksDB(comparatorOptions)); + } + + if (isRunningInCI()) { + // Disable fallocate calls to avoid issues with disk space + options.setAllowFAllocate(false); + // Set WAL size limits to avoid excessive disk + options.setMaxTotalWalSize(2 * 1024 * 1024); + // Set recycle log file + options.setRecycleLogFileNum(1); + // Enable creation of missing column families + options.setCreateMissingColumnFamilies(true); + // Set max background flushes to 1 to reduce resource usage + options.setMaxBackgroundFlushes(1); + } + + return options; + } + + private static boolean isRunningInCI() { + return Arrays.stream(CI_ENVIRONMENT_VARIABLES).anyMatch(System.getenv()::containsKey); + } } diff --git a/common/src/main/java/org/tron/common/utils/ByteArray.java b/common/src/main/java/org/tron/common/utils/ByteArray.java index b77dd310380..d0ac4cbaddf 100644 --- a/common/src/main/java/org/tron/common/utils/ByteArray.java +++ b/common/src/main/java/org/tron/common/utils/ByteArray.java @@ -14,7 +14,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.bouncycastle.util.encoders.Hex; -import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; /* * Copyright (c) [2016] [ ] diff --git a/common/src/main/java/org/tron/core/Constant.java b/common/src/main/java/org/tron/core/Constant.java index c5a8a02fb4e..824373b1328 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -24,6 +24,10 @@ public class Constant { public static final int NODE_TYPE_FULL_NODE = 0; public static final int NODE_TYPE_LIGHT_NODE = 1; + // DB NAME + public static final String MARKET_PAIR_PRICE_TO_ORDER = "market_pair_price_to_order"; + // DB NAME + // 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; @@ -39,6 +43,9 @@ public class Constant { 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; + public static final long MIN_PROPOSAL_EXPIRE_TIME = 0L; // 0 ms + public static final long MAX_PROPOSAL_EXPIRE_TIME = 31536003000L; // ms of 365 days + 3000 ms + public static final long DEFAULT_PROPOSAL_EXPIRE_TIME = 259200000L; // ms of 3 days // Numbers @@ -251,6 +258,9 @@ public class Constant { public static final String NODE_FULLNODE_ALLOW_SHIELDED_TRANSACTION = "node" + ".fullNodeAllowShieldedTransaction"; + public static final String ALLOW_SHIELDED_TRANSACTION_API = "node" + + ".allowShieldedTransactionApi"; + public static final String NODE_ZEN_TOKENID = "node.zenTokenId"; public static final String COMMITTEE_ALLOW_PROTO_FILTER_NUM = "committee.allowProtoFilterNum"; @@ -318,6 +328,9 @@ public class Constant { public static final String RATE_LIMITER_HTTP = "rate.limiter.http"; public static final String RATE_LIMITER_RPC = "rate.limiter.rpc"; + public static final String RATE_LIMITER_P2P_SYNC_BLOCK_CHAIN = "rate.limiter.p2p.syncBlockChain"; + public static final String RATE_LIMITER_P2P_FETCH_INV_DATA = "rate.limiter.p2p.fetchInvData"; + public static final String RATE_LIMITER_P2P_DISCONNECT = "rate.limiter.p2p.disconnect"; public static final String SEED_NODE_IP_LIST = "seed.node.ip.list"; public static final String NODE_METRICS_ENABLE = "node.metricsEnable"; @@ -405,4 +418,5 @@ public class Constant { public static final String COMMITTEE_ALLOW_TVM_CANCUN = "committee.allowTvmCancun"; public static final String COMMITTEE_ALLOW_TVM_BLOB = "committee.allowTvmBlob"; + public static final String COMMITTEE_PROPOSAL_EXPIRE_TIME = "committee.proposalExpireTime"; } diff --git a/common/src/main/java/org/tron/core/config/CommonConfig.java b/common/src/main/java/org/tron/core/config/CommonConfig.java index 4d17a0faedd..b258a4cf3f5 100644 --- a/common/src/main/java/org/tron/core/config/CommonConfig.java +++ b/common/src/main/java/org/tron/core/config/CommonConfig.java @@ -21,10 +21,8 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; -import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration -@EnableTransactionManagement @EnableAspectJAutoProxy @ComponentScan(basePackages = "org.tron") public class CommonConfig { 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 a71dc58e8bd..7d0681a9f91 100644 --- a/common/src/main/java/org/tron/core/config/Parameter.java +++ b/common/src/main/java/org/tron/core/config/Parameter.java @@ -26,7 +26,8 @@ public enum ForkBlockVersionEnum { VERSION_4_7_4(29, 1596780000000L, 80), VERSION_4_7_5(30, 1596780000000L, 80), VERSION_4_7_7(31, 1596780000000L, 80), - VERSION_4_8_0(32, 1596780000000L, 80); + VERSION_4_8_0(32, 1596780000000L, 80), + VERSION_4_8_1(33, 1596780000000L, 80); // if add a version, modify BLOCK_VERSION simultaneously @Getter @@ -75,7 +76,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 = 32; + public static final int BLOCK_VERSION = 33; 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/common/src/main/java/org/tron/core/config/args/Storage.java b/common/src/main/java/org/tron/core/config/args/Storage.java index 9cf6eb6bab1..655b6b779fe 100644 --- a/common/src/main/java/org/tron/core/config/args/Storage.java +++ b/common/src/main/java/org/tron/core/config/args/Storage.java @@ -25,9 +25,11 @@ import java.util.stream.Collectors; import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.iq80.leveldb.CompressionType; import org.iq80.leveldb.Options; +import org.tron.common.arch.Arch; import org.tron.common.cache.CacheStrategies; import org.tron.common.cache.CacheType; import org.tron.common.utils.DbOptionalsUtils; @@ -42,6 +44,7 @@ * @version 1.0 * @since 2018/5/25 */ +@Slf4j(topic = "db") public class Storage { /** @@ -87,6 +90,7 @@ public class Storage { * Default values of directory */ private static final String DEFAULT_DB_ENGINE = "LEVELDB"; + private static final String ROCKS_DB_ENGINE = "ROCKSDB"; private static final boolean DEFAULT_DB_SYNC = false; private static final boolean DEFAULT_EVENT_SUBSCRIBE_CONTRACT_PARSE = true; private static final String DEFAULT_DB_DIRECTORY = "database"; @@ -171,6 +175,11 @@ public class Storage { private final Map dbRoots = Maps.newConcurrentMap(); public static String getDbEngineFromConfig(final Config config) { + if (Arch.isArm64()) { + // if is arm64 but config is leveldb, should throw exception? + logger.warn("Arm64 architecture detected, using RocksDB as db engine, ignore config."); + return ROCKS_DB_ENGINE; + } return config.hasPath(DB_ENGINE_CONFIG_KEY) ? config.getString(DB_ENGINE_CONFIG_KEY) : DEFAULT_DB_ENGINE; } diff --git a/common/src/main/java/org/tron/core/exception/P2pException.java b/common/src/main/java/org/tron/core/exception/P2pException.java index 00d82e9fbf7..eae830627c2 100644 --- a/common/src/main/java/org/tron/core/exception/P2pException.java +++ b/common/src/main/java/org/tron/core/exception/P2pException.java @@ -52,6 +52,7 @@ public enum TypeEnum { PROTOBUF_ERROR(14, "protobuf inconsistent"), BLOCK_SIGN_ERROR(15, "block sign error"), BLOCK_MERKLE_ERROR(16, "block merkle error"), + RATE_LIMIT_EXCEEDED(17, "rate limit exceeded"), DEFAULT(100, "default exception"); diff --git a/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcException.java b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcException.java new file mode 100644 index 00000000000..7ed42d101d5 --- /dev/null +++ b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcException.java @@ -0,0 +1,32 @@ +package org.tron.core.exception.jsonrpc; + +import lombok.Getter; +import org.tron.core.exception.TronException; + +@Getter +public class JsonRpcException extends TronException { + private Object data = null; + + public JsonRpcException() { + super(); + report(); + } + + public JsonRpcException(String message, Object data) { + super(message); + this.data = data; + report(); + } + + public JsonRpcException(String message) { + super(message); + report(); + } + + public JsonRpcException(String message, Throwable cause) { + super(message, cause); + report(); + } + + +} diff --git a/common/src/main/java/org/tron/core/exception/JsonRpcInternalException.java b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcInternalException.java similarity index 53% rename from common/src/main/java/org/tron/core/exception/JsonRpcInternalException.java rename to common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcInternalException.java index 12310e67747..904449866ae 100644 --- a/common/src/main/java/org/tron/core/exception/JsonRpcInternalException.java +++ b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcInternalException.java @@ -1,6 +1,6 @@ -package org.tron.core.exception; +package org.tron.core.exception.jsonrpc; -public class JsonRpcInternalException extends TronException { +public class JsonRpcInternalException extends JsonRpcException { public JsonRpcInternalException() { super(); @@ -13,4 +13,8 @@ public JsonRpcInternalException(String message) { public JsonRpcInternalException(String message, Throwable cause) { super(message, cause); } + + public JsonRpcInternalException(String message, Object data) { + super(message, data); + } } \ No newline at end of file diff --git a/common/src/main/java/org/tron/core/exception/JsonRpcInvalidParamsException.java b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcInvalidParamsException.java similarity index 68% rename from common/src/main/java/org/tron/core/exception/JsonRpcInvalidParamsException.java rename to common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcInvalidParamsException.java index adf205a309a..55ee15521e1 100644 --- a/common/src/main/java/org/tron/core/exception/JsonRpcInvalidParamsException.java +++ b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcInvalidParamsException.java @@ -1,6 +1,6 @@ -package org.tron.core.exception; +package org.tron.core.exception.jsonrpc; -public class JsonRpcInvalidParamsException extends TronException { +public class JsonRpcInvalidParamsException extends JsonRpcException { public JsonRpcInvalidParamsException() { super(); diff --git a/common/src/main/java/org/tron/core/exception/JsonRpcInvalidRequestException.java b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcInvalidRequestException.java similarity index 69% rename from common/src/main/java/org/tron/core/exception/JsonRpcInvalidRequestException.java rename to common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcInvalidRequestException.java index 2689bff0cd2..32bd11a3ed9 100644 --- a/common/src/main/java/org/tron/core/exception/JsonRpcInvalidRequestException.java +++ b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcInvalidRequestException.java @@ -1,6 +1,6 @@ -package org.tron.core.exception; +package org.tron.core.exception.jsonrpc; -public class JsonRpcInvalidRequestException extends TronException { +public class JsonRpcInvalidRequestException extends JsonRpcException { public JsonRpcInvalidRequestException() { super(); diff --git a/common/src/main/java/org/tron/core/exception/JsonRpcMethodNotFoundException.java b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcMethodNotFoundException.java similarity index 68% rename from common/src/main/java/org/tron/core/exception/JsonRpcMethodNotFoundException.java rename to common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcMethodNotFoundException.java index d8e18168d9d..406a51f45bd 100644 --- a/common/src/main/java/org/tron/core/exception/JsonRpcMethodNotFoundException.java +++ b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcMethodNotFoundException.java @@ -1,6 +1,6 @@ -package org.tron.core.exception; +package org.tron.core.exception.jsonrpc; -public class JsonRpcMethodNotFoundException extends TronException { +public class JsonRpcMethodNotFoundException extends JsonRpcException { public JsonRpcMethodNotFoundException() { super(); diff --git a/common/src/main/java/org/tron/core/exception/JsonRpcTooManyResultException.java b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcTooManyResultException.java similarity index 69% rename from common/src/main/java/org/tron/core/exception/JsonRpcTooManyResultException.java rename to common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcTooManyResultException.java index e8e183d49c1..03bc089b1c7 100644 --- a/common/src/main/java/org/tron/core/exception/JsonRpcTooManyResultException.java +++ b/common/src/main/java/org/tron/core/exception/jsonrpc/JsonRpcTooManyResultException.java @@ -1,6 +1,6 @@ -package org.tron.core.exception; +package org.tron.core.exception.jsonrpc; -public class JsonRpcTooManyResultException extends TronException { +public class JsonRpcTooManyResultException extends JsonRpcException { public JsonRpcTooManyResultException() { super(); diff --git a/crypto/src/main/java/org/tron/common/crypto/Rsv.java b/crypto/src/main/java/org/tron/common/crypto/Rsv.java new file mode 100644 index 00000000000..136a77a4592 --- /dev/null +++ b/crypto/src/main/java/org/tron/common/crypto/Rsv.java @@ -0,0 +1,26 @@ +package org.tron.common.crypto; + + +import java.util.Arrays; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class Rsv { + + private final byte[] r; + private final byte[] s; + private final byte v; + + + public static Rsv fromSignature(byte[] sign) { + byte[] r = Arrays.copyOfRange(sign, 0, 32); + byte[] s = Arrays.copyOfRange(sign, 32, 64); + byte v = sign[64]; + if (v < 27) { + v += (byte) 27; //revId -> v + } + return new Rsv(r, s, v); + } +} diff --git a/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp12.java b/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp12.java index 26ea708fbe4..f144656b0ba 100644 --- a/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp12.java +++ b/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp12.java @@ -356,7 +356,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return new Integer(a.hashCode() + b.hashCode()).hashCode(); + return a.hashCode() + b.hashCode(); } @Override diff --git a/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp2.java b/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp2.java index ba2a1ceb477..162a5b13b30 100644 --- a/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp2.java +++ b/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp2.java @@ -164,7 +164,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return new Integer(a.hashCode() + b.hashCode()).hashCode(); + return a.hashCode() + b.hashCode(); } Fp2 frobeniusMap(int power) { diff --git a/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp6.java b/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp6.java index 0636cc334f1..fb863bb6b34 100644 --- a/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp6.java +++ b/crypto/src/main/java/org/tron/common/crypto/zksnark/Fp6.java @@ -246,6 +246,6 @@ public boolean equals(Object o) { @Override public int hashCode() { - return new Integer(a.hashCode() + b.hashCode() + c.hashCode()).hashCode(); + return a.hashCode() + b.hashCode() + c.hashCode(); } } diff --git a/docker/arm64/Dockerfile b/docker/arm64/Dockerfile new file mode 100644 index 00000000000..6435faf7ead --- /dev/null +++ b/docker/arm64/Dockerfile @@ -0,0 +1,33 @@ +FROM arm64v8/eclipse-temurin:17 + +ENV TMP_DIR="/tron-build" +ENV BASE_DIR="/java-tron" + +RUN set -o errexit -o nounset \ + && apt-get update \ + && apt-get -y install git p7zip-full wget libtcmalloc-minimal4 \ + && echo "git clone" \ + && mkdir -p $TMP_DIR \ + && cd $TMP_DIR \ + && git clone https://github.com/tronprotocol/java-tron.git \ + && cd java-tron \ + && git checkout master \ + && ./gradlew clean build -x test -x check --no-daemon \ + && cd build/distributions \ + && 7za x -y java-tron-1.0.0.zip \ + && mv java-tron-1.0.0 $BASE_DIR \ + && rm -rf $TMP_DIR \ + && rm -rf ~/.gradle \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +ENV LD_PRELOAD="/usr/lib/aarch64-linux-gnu/libtcmalloc_minimal.so.4" +ENV TCMALLOC_RELEASE_RATE=10 + +RUN wget -P $BASE_DIR/config https://raw.githubusercontent.com/tronprotocol/tron-deployment/master/main_net_config.conf + +COPY docker-entrypoint.sh $BASE_DIR/bin + +WORKDIR $BASE_DIR + +ENTRYPOINT ["./bin/docker-entrypoint.sh"] \ No newline at end of file diff --git a/framework/build.gradle b/framework/build.gradle index 0f04685f2d8..59d070e066d 100644 --- a/framework/build.gradle +++ b/framework/build.gradle @@ -38,15 +38,11 @@ dependencies { //local libraries implementation fileTree(dir: 'libs', include: '*.jar') // end local libraries - testImplementation group: 'org.hamcrest', name: 'hamcrest-junit', version: '1.0.0.1' - - implementation group: 'com.google.inject', name: 'guice', version: '4.1.0' implementation group: 'io.dropwizard.metrics', name: 'metrics-core', version: '3.1.2' implementation group: 'com.github.davidb', name: 'metrics-influxdb', version: '0.8.2' - implementation group: 'com.carrotsearch', name: 'java-sizeof', version: '0.0.5' // http - implementation 'org.eclipse.jetty:jetty-server:9.4.53.v20231009' - implementation 'org.eclipse.jetty:jetty-servlet:9.4.53.v20231009' + implementation 'org.eclipse.jetty:jetty-server:9.4.57.v20241219' + implementation 'org.eclipse.jetty:jetty-servlet:9.4.57.v20241219' implementation 'com.alibaba:fastjson:1.2.83' // end http @@ -56,14 +52,11 @@ dependencies { // https://mvnrepository.com/artifact/javax.portlet/portlet-api compileOnly group: 'javax.portlet', name: 'portlet-api', version: '3.0.1' - implementation "io.vavr:vavr:0.9.2" implementation (group: 'org.pf4j', name: 'pf4j', version: '3.10.0') { exclude group: "org.slf4j", module: "slf4j-api" } - testImplementation group: 'org.springframework', name: 'spring-test', version: '5.2.0.RELEASE' - testImplementation group: 'org.springframework', name: 'spring-web', version: '5.2.0.RELEASE' - + testImplementation group: 'org.springframework', name: 'spring-test', version: "${springVersion}" implementation group: 'org.zeromq', name: 'jeromq', version: '0.5.3' api project(":chainbase") api project(":protocol") @@ -123,6 +116,17 @@ test { destinationFile = file("$buildDir/jacoco/jacocoTest.exec") classDumpDir = file("$buildDir/jacoco/classpathdumps") } + if (rootProject.archInfo.isArm64) { + exclude { element -> + element.file.name.toLowerCase().contains('leveldb') + } + filter { + excludeTestsMatching '*.*leveldb*' + excludeTestsMatching '*.*Leveldb*' + excludeTestsMatching '*.*LevelDB*' + excludeTestsMatching '*.*LevelDb*' + } + } if (isWindows()) { exclude '**/ShieldedTransferActuatorTest.class' exclude '**/BackupDbUtilTest.class' @@ -134,6 +138,7 @@ test { } maxHeapSize = "1024m" doFirst { + // Restart the JVM after every 100 tests to avoid memory leaks and ensure test isolation forkEvery = 100 jvmArgs "-XX:MetaspaceSize=128m","-XX:MaxMetaspaceSize=256m", "-XX:+UseG1GC" } @@ -158,7 +163,7 @@ def binaryRelease(taskName, jarName, mainClass) { // explicit_dependency dependsOn (project(':actuator').jar, project(':consensus').jar, project(':chainbase').jar, - project(':crypto').jar, project(':common').jar, project(':protocol').jar) + project(':crypto').jar, project(':common').jar, project(':protocol').jar, project(':platform').jar) from { configurations.runtimeClasspath.collect { @@ -204,8 +209,7 @@ def createScript(project, mainClass, name) { } } } - -applicationDistribution.from("../gradle/java-tron.vmoptions") { +applicationDistribution.from(rootProject.archInfo.VMOptions) { into "bin" } //distZip { @@ -219,35 +223,12 @@ startScripts.enabled = false run.enabled = false tasks.distTar.enabled = false -createScript(project, 'org.tron.program.SolidityNode', 'SolidityNode') createScript(project, 'org.tron.program.FullNode', 'FullNode') -createScript(project, 'org.tron.program.KeystoreFactory', 'KeystoreFactory') -createScript(project, 'org.tron.program.DBConvert', 'DBConvert') - def releaseBinary = hasProperty('binaryRelease') ? getProperty('binaryRelease') : 'true' -def skipSolidity = hasProperty('skipSolidity') ? true : false -def skipKeystore = hasProperty('skipKeystore') ? true : false -def skipConvert = hasProperty('skipConvert') ? true : false -def skipAll = hasProperty('skipAll') ? true : false if (releaseBinary == 'true') { artifacts { archives(binaryRelease('buildFullNodeJar', 'FullNode', 'org.tron.program.FullNode')) } - if (!skipAll) { - if (!skipSolidity) { - artifacts { - archives(binaryRelease('buildSolidityNodeJar', 'SolidityNode', 'org.tron.program.SolidityNode'))} - } - if (!skipKeystore) { - artifacts { - archives(binaryRelease('buildKeystoreFactoryJar', 'KeystoreFactory', 'org.tron.program.KeystoreFactory'))} - } - if (!skipConvert) { - artifacts { - archives(binaryRelease('buildDBConvertJar', 'DBConvert', 'org.tron.program.DBConvert'))} - } - } - } task copyToParent(type: Copy) { diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index 8dfb18331ff..125443d59dd 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -177,7 +177,6 @@ import org.tron.core.exception.DupTransactionException; import org.tron.core.exception.HeaderNotFound; import org.tron.core.exception.ItemNotFoundException; -import org.tron.core.exception.JsonRpcInvalidParamsException; import org.tron.core.exception.NonUniqueObjectException; import org.tron.core.exception.PermissionException; import org.tron.core.exception.SignatureFormatException; @@ -188,6 +187,7 @@ import org.tron.core.exception.VMIllegalException; import org.tron.core.exception.ValidateSignatureException; import org.tron.core.exception.ZksnarkException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; import org.tron.core.net.TronNetDelegate; import org.tron.core.net.TronNetService; import org.tron.core.net.message.adv.TransactionMessage; @@ -1387,6 +1387,11 @@ public Protocol.ChainParameters getChainParameters() { .setValue(dbManager.getDynamicPropertiesStore().getAllowTvmBlob()) .build()); + builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder() + .setKey("getProposalExpireTime") + .setValue(dbManager.getDynamicPropertiesStore().getProposalExpireTime()) + .build()); + return builder.build(); } @@ -1806,12 +1811,8 @@ public Exchange getExchangeById(ByteString exchangeId) { return null; } - private boolean getFullNodeAllowShieldedTransaction() { - return Args.getInstance().isFullNodeAllowShieldedTransactionArgs(); - } - - private void checkFullNodeAllowShieldedTransaction() throws ZksnarkException { - if (!getFullNodeAllowShieldedTransaction()) { + private void checkAllowShieldedTransactionApi() throws ZksnarkException { + if (!Args.getInstance().isAllowShieldedTransactionApi()) { throw new ZksnarkException(SHIELDED_ID_NOT_ALLOWED); } } @@ -1830,10 +1831,7 @@ public BytesMessage getNullifier(ByteString id) { } private long getBlockNumber(OutputPoint outPoint) - throws BadItemException, ZksnarkException { - if (!getFullNodeAllowShieldedTransaction()) { - throw new ZksnarkException(SHIELDED_ID_NOT_ALLOWED); - } + throws BadItemException { ByteString txId = outPoint.getHash(); long blockNum = chainBaseManager.getTransactionStore().getBlockNumber(txId.toByteArray()); @@ -1848,9 +1846,6 @@ private long getBlockNumber(OutputPoint outPoint) private IncrementalMerkleVoucherContainer createWitness(OutputPoint outPoint, Long blockNumber) throws ItemNotFoundException, BadItemException, InvalidProtocolBufferException, ZksnarkException { - if (!getFullNodeAllowShieldedTransaction()) { - throw new ZksnarkException(SHIELDED_ID_NOT_ALLOWED); - } ByteString txId = outPoint.getHash(); //Get the tree in blockNum-1 position @@ -1946,9 +1941,6 @@ private IncrementalMerkleVoucherContainer createWitness(OutputPoint outPoint, Lo private void updateWitnesses(List witnessList, long large, int synBlockNum) throws ItemNotFoundException, BadItemException, InvalidProtocolBufferException, ZksnarkException { - if (!getFullNodeAllowShieldedTransaction()) { - throw new ZksnarkException(SHIELDED_ID_NOT_ALLOWED); - } long start = large; long end = large + synBlockNum - 1; @@ -2022,10 +2014,7 @@ private void updateLowWitness(IncrementalMerkleVoucherContainer witness, long bl } } - private void validateInput(OutputPointInfo request) throws BadItemException, ZksnarkException { - if (!getFullNodeAllowShieldedTransaction()) { - throw new ZksnarkException(SHIELDED_ID_NOT_ALLOWED); - } + private void validateInput(OutputPointInfo request) throws BadItemException { if (request.getBlockNum() < 0 || request.getBlockNum() > 1000) { throw new BadItemException("request.BlockNum must be specified with range in [0, 1000]"); } @@ -2051,7 +2040,7 @@ private void validateInput(OutputPointInfo request) throws BadItemException, Zks public IncrementalMerkleVoucherInfo getMerkleTreeVoucherInfo(OutputPointInfo request) throws ItemNotFoundException, BadItemException, InvalidProtocolBufferException, ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); validateInput(request); IncrementalMerkleVoucherInfo.Builder result = IncrementalMerkleVoucherInfo.newBuilder(); @@ -2097,9 +2086,7 @@ public IncrementalMerkleVoucherInfo getMerkleTreeVoucherInfo(OutputPointInfo req } public IncrementalMerkleTree getMerkleTreeOfBlock(long blockNum) throws ZksnarkException { - if (!getFullNodeAllowShieldedTransaction()) { - throw new ZksnarkException(SHIELDED_ID_NOT_ALLOWED); - } + checkAllowShieldedTransactionApi(); if (blockNum < 0) { return null; } @@ -2166,7 +2153,7 @@ public ReceiveNote createReceiveNoteRandom(long value) throws ZksnarkException, public TransactionCapsule createShieldedTransaction(PrivateParameters request) throws ContractValidateException, RuntimeException, ZksnarkException, BadItemException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); ZenTransactionBuilder builder = new ZenTransactionBuilder(this); @@ -2268,7 +2255,7 @@ public TransactionCapsule createShieldedTransaction(PrivateParameters request) public TransactionCapsule createShieldedTransactionWithoutSpendAuthSig( PrivateParametersWithoutAsk request) throws ContractValidateException, ZksnarkException, BadItemException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); ZenTransactionBuilder builder = new ZenTransactionBuilder(this); @@ -2385,7 +2372,7 @@ private void shieldedOutput(List shieldedReceives, public ShieldedAddressInfo getNewShieldedAddress() throws BadItemException, ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); ShieldedAddressInfo.Builder addressInfo = ShieldedAddressInfo.newBuilder(); @@ -2418,7 +2405,7 @@ public ShieldedAddressInfo getNewShieldedAddress() throws BadItemException, Zksn } public BytesMessage getSpendingKey() throws ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); byte[] sk = SpendingKey.random().getValue(); return BytesMessage.newBuilder().setValue(ByteString.copyFrom(sk)).build(); @@ -2426,7 +2413,7 @@ public BytesMessage getSpendingKey() throws ZksnarkException { public ExpandedSpendingKeyMessage getExpandedSpendingKey(ByteString spendingKey) throws BadItemException, ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); if (Objects.isNull(spendingKey)) { throw new BadItemException("spendingKey is null"); @@ -2452,7 +2439,7 @@ public ExpandedSpendingKeyMessage getExpandedSpendingKey(ByteString spendingKey) public BytesMessage getAkFromAsk(ByteString ask) throws BadItemException, ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); if (Objects.isNull(ask)) { throw new BadItemException("ask is null"); @@ -2468,7 +2455,7 @@ public BytesMessage getAkFromAsk(ByteString ask) throws public BytesMessage getNkFromNsk(ByteString nsk) throws BadItemException, ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); if (Objects.isNull(nsk)) { throw new BadItemException("nsk is null"); @@ -2484,7 +2471,7 @@ public BytesMessage getNkFromNsk(ByteString nsk) throws public IncomingViewingKeyMessage getIncomingViewingKey(byte[] ak, byte[] nk) throws ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); byte[] ivk = new byte[32]; // the incoming viewing key JLibrustzcash.librustzcashCrhIvk(new CrhIvkParams(ak, nk, ivk)); @@ -2495,7 +2482,7 @@ public IncomingViewingKeyMessage getIncomingViewingKey(byte[] ak, byte[] nk) } public DiversifierMessage getDiversifier() throws ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); byte[] d; while (true) { @@ -2511,7 +2498,7 @@ public DiversifierMessage getDiversifier() throws ZksnarkException { } public BytesMessage getRcm() throws ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); byte[] rcm = Note.generateR(); return BytesMessage.newBuilder().setValue(ByteString.copyFrom(rcm)).build(); @@ -2519,7 +2506,7 @@ public BytesMessage getRcm() throws ZksnarkException { public PaymentAddressMessage getPaymentAddress(IncomingViewingKey ivk, DiversifierT d) throws BadItemException, ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); if (!JLibrustzcash.librustzcashCheckDiversifier(d.getData())) { throw new BadItemException("d is not valid"); @@ -2543,7 +2530,7 @@ public PaymentAddressMessage getPaymentAddress(IncomingViewingKey ivk, public SpendResult isSpend(NoteParameters noteParameters) throws ZksnarkException, InvalidProtocolBufferException, BadItemException, ItemNotFoundException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); GrpcAPI.Note note = noteParameters.getNote(); byte[] ak = noteParameters.getAk().toByteArray(); @@ -2599,7 +2586,7 @@ public SpendResult isSpend(NoteParameters noteParameters) throws public BytesMessage createSpendAuthSig(SpendAuthSigParameters spendAuthSigParameters) throws ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); byte[] result = new byte[64]; SpendSigParams spendSigParams = new SpendSigParams( @@ -2613,7 +2600,7 @@ public BytesMessage createSpendAuthSig(SpendAuthSigParameters spendAuthSigParame } public BytesMessage createShieldNullifier(NfParameters nfParameters) throws ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); byte[] ak = nfParameters.getAk().toByteArray(); byte[] nk = nfParameters.getNk().toByteArray(); @@ -2649,7 +2636,7 @@ public BytesMessage createShieldNullifier(NfParameters nfParameters) throws Zksn public BytesMessage getShieldTransactionHash(Transaction transaction) throws ContractValidateException, ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); List contract = transaction.getRawData().getContractList(); if (contract == null || contract.isEmpty()) { @@ -3354,7 +3341,7 @@ private GrpcAPI.DecryptNotes queryNoteByIvk(long startNum, long endNum, byte[] i */ public GrpcAPI.DecryptNotes scanNoteByIvk(long startNum, long endNum, byte[] ivk) throws BadItemException, ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); return queryNoteByIvk(startNum, endNum, ivk); } @@ -3365,7 +3352,7 @@ public GrpcAPI.DecryptNotes scanNoteByIvk(long startNum, long endNum, public GrpcAPI.DecryptNotesMarked scanAndMarkNoteByIvk(long startNum, long endNum, byte[] ivk, byte[] ak, byte[] nk) throws BadItemException, ZksnarkException, InvalidProtocolBufferException, ItemNotFoundException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); GrpcAPI.DecryptNotes srcNotes = queryNoteByIvk(startNum, endNum, ivk); GrpcAPI.DecryptNotesMarked.Builder builder = GrpcAPI.DecryptNotesMarked.newBuilder(); @@ -3398,7 +3385,7 @@ public GrpcAPI.DecryptNotesMarked scanAndMarkNoteByIvk(long startNum, long endNu */ public GrpcAPI.DecryptNotes scanNoteByOvk(long startNum, long endNum, byte[] ovk) throws BadItemException, ZksnarkException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); GrpcAPI.DecryptNotes.Builder builder = GrpcAPI.DecryptNotes.newBuilder(); if (!(startNum >= 0 && endNum > startNum && endNum - startNum <= 1000)) { @@ -3538,7 +3525,7 @@ private void buildShieldedTRC20Output(ShieldedTRC20ParametersBuilder builder, public ShieldedTRC20Parameters createShieldedContractParameters( PrivateShieldedTRC20Parameters request) throws ContractValidateException, ZksnarkException, ContractExeException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); ShieldedTRC20ParametersBuilder builder = new ShieldedTRC20ParametersBuilder(); @@ -3675,7 +3662,7 @@ private void buildShieldedTRC20InputWithAK( public ShieldedTRC20Parameters createShieldedContractParametersWithoutAsk( PrivateShieldedTRC20ParametersWithoutAsk request) throws ZksnarkException, ContractValidateException, ContractExeException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); ShieldedTRC20ParametersBuilder builder = new ShieldedTRC20ParametersBuilder(); byte[] shieldedTRC20ContractAddress = request.getShieldedTRC20ContractAddress().toByteArray(); @@ -3971,7 +3958,7 @@ public DecryptNotesTRC20 scanShieldedTRC20NotesByIvk( long startNum, long endNum, byte[] shieldedTRC20ContractAddress, byte[] ivk, byte[] ak, byte[] nk, ProtocolStringList topicsList) throws BadItemException, ZksnarkException, ContractExeException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); return queryTRC20NoteByIvk(startNum, endNum, shieldedTRC20ContractAddress, ivk, ak, nk, topicsList); @@ -4050,7 +4037,7 @@ private Optional getNoteTxFromLogListByOvk( public DecryptNotesTRC20 scanShieldedTRC20NotesByOvk(long startNum, long endNum, byte[] ovk, byte[] shieldedTRC20ContractAddress, ProtocolStringList topicsList) throws ZksnarkException, BadItemException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); DecryptNotesTRC20.Builder builder = DecryptNotesTRC20.newBuilder(); if (!(startNum >= 0 && endNum > startNum && endNum - startNum <= 1000)) { @@ -4113,7 +4100,7 @@ private byte[] getShieldedTRC20Nullifier(GrpcAPI.Note note, long pos, byte[] ak, public GrpcAPI.NullifierResult isShieldedTRC20ContractNoteSpent(NfTRC20Parameters request) throws ZksnarkException, ContractExeException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); return GrpcAPI.NullifierResult.newBuilder() .setIsSpent(isShieldedTRC20NoteSpent(request.getNote(), @@ -4236,7 +4223,7 @@ public byte[] getShieldedContractScalingFactor(byte[] contractAddress) public BytesMessage getTriggerInputForShieldedTRC20Contract( ShieldedTRC20TriggerContractParameters request) throws ZksnarkException, ContractValidateException { - checkFullNodeAllowShieldedTransaction(); + checkAllowShieldedTransactionApi(); ShieldedTRC20Parameters shieldedTRC20Parameters = request.getShieldedTRC20Parameters(); List spendAuthoritySignature = request.getSpendAuthoritySignatureList(); diff --git a/framework/src/main/java/org/tron/core/capsule/utils/RLP.java b/framework/src/main/java/org/tron/core/capsule/utils/RLP.java index 24b5c502a1c..e5ace11206d 100644 --- a/framework/src/main/java/org/tron/core/capsule/utils/RLP.java +++ b/framework/src/main/java/org/tron/core/capsule/utils/RLP.java @@ -165,7 +165,7 @@ static short decodeShort(byte[] data, int index) { byte pow = (byte) (length - 1); for (int i = 1; i <= length; ++i) { // << (8 * pow) == bit shift to 0 (*1), 8 (*256) , 16 (*65..) - value += (data[index + i] & 0xFF) << (8 * pow); + value += (short) ((data[index + i] & 0xFF) << (8 * pow)); pow--; } } else { 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 277b3e7bc79..3c162e03549 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 @@ -4,8 +4,11 @@ import static org.tron.common.math.Maths.max; import static org.tron.common.math.Maths.min; import static org.tron.core.Constant.ADD_PRE_FIX_BYTE_MAINNET; +import static org.tron.core.Constant.DEFAULT_PROPOSAL_EXPIRE_TIME; 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.Constant.MAX_PROPOSAL_EXPIRE_TIME; +import static org.tron.core.Constant.MIN_PROPOSAL_EXPIRE_TIME; import static org.tron.core.config.Parameter.ChainConstant.BLOCK_PRODUCE_TIMEOUT_PERCENT; import static org.tron.core.config.Parameter.ChainConstant.MAX_ACTIVE_WITNESS_NUM; @@ -44,6 +47,7 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.tron.common.arch.Arch; import org.tron.common.args.Account; import org.tron.common.args.GenesisBlock; import org.tron.common.args.Witness; @@ -169,6 +173,7 @@ public static void clearParam() { PARAMETER.tcpNettyWorkThreadNum = 0; PARAMETER.udpNettyWorkThreadNum = 0; PARAMETER.solidityNode = false; + PARAMETER.keystore = false; PARAMETER.trustNodeAddr = ""; PARAMETER.walletExtensionApi = false; PARAMETER.estimateEnergy = false; @@ -186,7 +191,7 @@ public static void clearParam() { PARAMETER.maxHttpConnectNumber = 50; PARAMETER.allowMultiSign = 0; PARAMETER.trxExpirationTimeInMilliseconds = 0; - PARAMETER.fullNodeAllowShieldedTransactionArgs = true; + PARAMETER.allowShieldedTransactionApi = true; PARAMETER.zenTokenId = "000000"; PARAMETER.allowProtoFilterNum = 0; PARAMETER.allowAccountStateRoot = 0; @@ -235,6 +240,9 @@ public static void clearParam() { PARAMETER.rateLimiterGlobalQps = 50000; PARAMETER.rateLimiterGlobalIpQps = 10000; PARAMETER.rateLimiterGlobalApiQps = 1000; + PARAMETER.rateLimiterSyncBlockChain = 3.0; + PARAMETER.rateLimiterFetchInvData = 3.0; + PARAMETER.rateLimiterDisconnect = 1.0; PARAMETER.p2pDisable = false; PARAMETER.dynamicConfigEnable = false; PARAMETER.dynamicConfigCheckInterval = 600; @@ -342,7 +350,7 @@ private static String getCommitIdAbbrev() { private static Map getOptionGroup() { String[] tronOption = new String[] {"version", "help", "shellConfFileName", "logbackPath", - "eventSubscribe"}; + "eventSubscribe", "solidityNode", "keystore"}; String[] dbOption = new String[] {"outputDirectory"}; String[] witnessOption = new String[] {"witness", "privateKey"}; String[] vmOption = new String[] {"debug"}; @@ -369,6 +377,7 @@ private static Map getOptionGroup() { * set parameters. */ public static void setParam(final String[] args, final String confFileName) { + Arch.throwUnsupportedJavaException(); JCommander.newBuilder().addObject(PARAMETER).build().parse(args); if (PARAMETER.version) { printVersion(); @@ -815,9 +824,7 @@ public static void setParam(final Config config) { config.hasPath(Constant.BLOCK_MAINTENANCE_TIME_INTERVAL) ? config .getInt(Constant.BLOCK_MAINTENANCE_TIME_INTERVAL) : 21600000L; - PARAMETER.proposalExpireTime = - config.hasPath(Constant.BLOCK_PROPOSAL_EXPIRE_TIME) ? config - .getInt(Constant.BLOCK_PROPOSAL_EXPIRE_TIME) : 259200000L; + PARAMETER.proposalExpireTime = getProposalExpirationTime(config); PARAMETER.checkFrozenTime = config.hasPath(Constant.BLOCK_CHECK_FROZEN_TIME) ? config @@ -991,9 +998,18 @@ public static void setParam(final Config config) { PARAMETER.eventFilter = config.hasPath(Constant.EVENT_SUBSCRIBE_FILTER) ? getEventFilter(config) : null; - PARAMETER.fullNodeAllowShieldedTransactionArgs = - !config.hasPath(Constant.NODE_FULLNODE_ALLOW_SHIELDED_TRANSACTION) - || config.getBoolean(Constant.NODE_FULLNODE_ALLOW_SHIELDED_TRANSACTION); + if (config.hasPath(Constant.ALLOW_SHIELDED_TRANSACTION_API)) { + PARAMETER.allowShieldedTransactionApi = + config.getBoolean(Constant.ALLOW_SHIELDED_TRANSACTION_API); + } else if (config.hasPath(Constant.NODE_FULLNODE_ALLOW_SHIELDED_TRANSACTION)) { + // for compatibility with previous configuration + PARAMETER.allowShieldedTransactionApi = + config.getBoolean(Constant.NODE_FULLNODE_ALLOW_SHIELDED_TRANSACTION); + logger.warn("Configuring [node.fullNodeAllowShieldedTransaction] will be deprecated. " + + "Please use [node.allowShieldedTransactionApi] instead."); + } else { + PARAMETER.allowShieldedTransactionApi = true; + } PARAMETER.zenTokenId = config.hasPath(Constant.NODE_ZEN_TOKENID) ? config.getString(Constant.NODE_ZEN_TOKENID) : "000000"; @@ -1030,10 +1046,6 @@ public static void setParam(final Config config) { config.hasPath(Constant.NODE_SHIELDED_TRANS_IN_PENDING_MAX_COUNTS) ? config .getInt(Constant.NODE_SHIELDED_TRANS_IN_PENDING_MAX_COUNTS) : 10; - if (PARAMETER.isWitness()) { - PARAMETER.fullNodeAllowShieldedTransactionArgs = true; - } - PARAMETER.rateLimiterGlobalQps = config.hasPath(Constant.RATE_LIMITER_GLOBAL_QPS) ? config .getInt(Constant.RATE_LIMITER_GLOBAL_QPS) : 50000; @@ -1048,6 +1060,18 @@ public static void setParam(final Config config) { PARAMETER.rateLimiterInitialization = getRateLimiterFromConfig(config); + PARAMETER.rateLimiterSyncBlockChain = + config.hasPath(Constant.RATE_LIMITER_P2P_SYNC_BLOCK_CHAIN) ? config + .getDouble(Constant.RATE_LIMITER_P2P_SYNC_BLOCK_CHAIN) : 3.0; + + PARAMETER.rateLimiterFetchInvData = + config.hasPath(Constant.RATE_LIMITER_P2P_FETCH_INV_DATA) ? config + .getDouble(Constant.RATE_LIMITER_P2P_FETCH_INV_DATA) : 3.0; + + PARAMETER.rateLimiterDisconnect = + config.hasPath(Constant.RATE_LIMITER_P2P_DISCONNECT) ? config + .getDouble(Constant.RATE_LIMITER_P2P_DISCONNECT) : 1.0; + PARAMETER.changedDelegation = config.hasPath(Constant.COMMITTEE_CHANGED_DELEGATION) ? config .getInt(Constant.COMMITTEE_CHANGED_DELEGATION) : 0; @@ -1300,6 +1324,26 @@ public static void setParam(final Config config) { logConfig(); } + private static long getProposalExpirationTime(final Config config) { + if (config.hasPath(Constant.COMMITTEE_PROPOSAL_EXPIRE_TIME)) { + throw new IllegalArgumentException("It is not allowed to configure " + + "commit.proposalExpireTime in config.conf, please set the value in " + + "block.proposalExpireTime."); + } + if (config.hasPath(Constant.BLOCK_PROPOSAL_EXPIRE_TIME)) { + long proposalExpireTime = config.getLong(Constant.BLOCK_PROPOSAL_EXPIRE_TIME); + if (proposalExpireTime <= MIN_PROPOSAL_EXPIRE_TIME + || proposalExpireTime >= MAX_PROPOSAL_EXPIRE_TIME) { + throw new IllegalArgumentException("The value[block.proposalExpireTime] is only allowed to " + + "be greater than " + MIN_PROPOSAL_EXPIRE_TIME + " and less than " + + MAX_PROPOSAL_EXPIRE_TIME + "!"); + } + return proposalExpireTime; + } else { + return DEFAULT_PROPOSAL_EXPIRE_TIME; + } + } + private static List getWitnessesFromConfig(final com.typesafe.config.Config config) { return config.getObjectList(Constant.GENESIS_BLOCK_WITNESSES).stream() .map(Args::createWitness) @@ -1684,11 +1728,13 @@ private static void initRocksDbSettings(Config config) { .getLong(prefix + "targetFileSizeBase") : 64; int targetFileSizeMultiplier = config.hasPath(prefix + "targetFileSizeMultiplier") ? config .getInt(prefix + "targetFileSizeMultiplier") : 1; + int maxOpenFiles = config.hasPath(prefix + "maxOpenFiles") + ? config.getInt(prefix + "maxOpenFiles") : 5000; PARAMETER.rocksDBCustomSettings = RocksDbSettings .initCustomSettings(levelNumber, compactThreads, blocksize, maxBytesForLevelBase, maxBytesForLevelMultiplier, level0FileNumCompactionTrigger, - targetFileSizeBase, targetFileSizeMultiplier); + targetFileSizeBase, targetFileSizeMultiplier, maxOpenFiles); RocksDbSettings.loggingSettings(); } @@ -1725,6 +1771,8 @@ private static void initBackupProperty(Config config) { public static void logConfig() { CommonParameter parameter = CommonParameter.getInstance(); logger.info("\n"); + logger.info("************************ System info ************************"); + logger.info("{}", Arch.withAll()); logger.info("************************ Net config ************************"); logger.info("P2P version: {}", parameter.getNodeP2pVersion()); logger.info("LAN IP: {}", parameter.getNodeLanIp()); @@ -1769,10 +1817,6 @@ public static void logConfig() { logger.info("\n"); } - public static void setFullNodeAllowShieldedTransaction(boolean fullNodeAllowShieldedTransaction) { - PARAMETER.fullNodeAllowShieldedTransactionArgs = fullNodeAllowShieldedTransaction; - } - private static void witnessAddressCheck(Config config) { if (config.hasPath(Constant.LOCAL_WITNESS_ACCOUNT_ADDRESS)) { byte[] bytes = Commons 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 b25f0d6fa8d..d6cf0e5fe67 100644 --- a/framework/src/main/java/org/tron/core/consensus/ProposalService.java +++ b/framework/src/main/java/org/tron/core/consensus/ProposalService.java @@ -384,6 +384,10 @@ public static boolean process(Manager manager, ProposalCapsule proposalCapsule) manager.getDynamicPropertiesStore().saveAllowTvmBlob(entry.getValue()); break; } + case PROPOSAL_EXPIRE_TIME: { + manager.getDynamicPropertiesStore().saveProposalExpireTime(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 1eecc103874..17e2687e98b 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -868,9 +868,9 @@ public boolean pushTransaction(final TransactionCapsule trx) TooBigTransactionException, TransactionExpirationException, ReceiptCheckErrException, VMIllegalException, TooBigTransactionResultException { - if (isShieldedTransaction(trx.getInstance()) && !Args.getInstance() - .isFullNodeAllowShieldedTransactionArgs()) { - return true; + if (isShieldedTransaction(trx.getInstance()) && !chainBaseManager.getDynamicPropertiesStore() + .supportShieldedTransaction()) { + return false; } pushTransactionQueue.add(trx); @@ -1857,12 +1857,10 @@ private void processBlock(BlockCapsule block, List txs) chainBaseManager.getBalanceTraceStore().resetCurrentBlockTrace(); - if (CommonParameter.getInstance().isJsonRpcFilterEnabled()) { - Bloom blockBloom = chainBaseManager.getSectionBloomStore() - .initBlockSection(transactionRetCapsule); - chainBaseManager.getSectionBloomStore().write(block.getNum()); - block.setBloom(blockBloom); - } + Bloom blockBloom = chainBaseManager.getSectionBloomStore() + .initBlockSection(transactionRetCapsule); + chainBaseManager.getSectionBloomStore().write(block.getNum()); + block.setBloom(blockBloom); } private void payReward(BlockCapsule block) { diff --git a/framework/src/main/java/org/tron/core/net/P2pEventHandlerImpl.java b/framework/src/main/java/org/tron/core/net/P2pEventHandlerImpl.java index 795c90b4edd..9cfa5058e8c 100644 --- a/framework/src/main/java/org/tron/core/net/P2pEventHandlerImpl.java +++ b/framework/src/main/java/org/tron/core/net/P2pEventHandlerImpl.java @@ -178,9 +178,11 @@ private void processMessage(PeerConnection peer, byte[] data) { handshakeService.processHelloMessage(peer, (HelloMessage) msg); break; case P2P_DISCONNECT: - peer.getChannel().close(); - peer.getNodeStatistics() - .nodeDisconnectedRemote(((DisconnectMessage)msg).getReason()); + if (peer.getP2pRateLimiter().tryAcquire(type.asByte())) { + peer.getChannel().close(); + peer.getNodeStatistics() + .nodeDisconnectedRemote(((DisconnectMessage)msg).getReason()); + } break; case SYNC_BLOCK_CHAIN: syncBlockChainMsgHandler.processMessage(peer, msg); @@ -253,12 +255,14 @@ private void processException(PeerConnection peer, TronMessage msg, Exception ex code = Protocol.ReasonCode.BAD_TX; break; case BAD_BLOCK: + case BLOCK_SIGN_ERROR: code = Protocol.ReasonCode.BAD_BLOCK; break; case NO_SUCH_MESSAGE: code = Protocol.ReasonCode.NO_SUCH_MESSAGE; break; case BAD_MESSAGE: + case RATE_LIMIT_EXCEEDED: code = Protocol.ReasonCode.BAD_PROTOCOL; break; case SYNC_FAILED: diff --git a/framework/src/main/java/org/tron/core/net/P2pRateLimiter.java b/framework/src/main/java/org/tron/core/net/P2pRateLimiter.java new file mode 100644 index 00000000000..9b36e1e5df3 --- /dev/null +++ b/framework/src/main/java/org/tron/core/net/P2pRateLimiter.java @@ -0,0 +1,32 @@ +package org.tron.core.net; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.util.concurrent.RateLimiter; + +public class P2pRateLimiter { + private final Cache rateLimiters = CacheBuilder.newBuilder() + .maximumSize(32).build(); + + public void register(Byte type, double rate) { + RateLimiter rateLimiter = RateLimiter.create(Double.POSITIVE_INFINITY); + rateLimiter.setRate(rate); + rateLimiters.put(type, rateLimiter); + } + + public void acquire(Byte type) { + RateLimiter rateLimiter = rateLimiters.getIfPresent(type); + if (rateLimiter == null) { + return; + } + rateLimiter.acquire(); + } + + public boolean tryAcquire(Byte type) { + RateLimiter rateLimiter = rateLimiters.getIfPresent(type); + if (rateLimiter == null) { + return true; + } + return rateLimiter.tryAcquire(); + } +} diff --git a/framework/src/main/java/org/tron/core/net/message/handshake/HelloMessage.java b/framework/src/main/java/org/tron/core/net/message/handshake/HelloMessage.java index 867ced5dbff..68123c93db6 100755 --- a/framework/src/main/java/org/tron/core/net/message/handshake/HelloMessage.java +++ b/framework/src/main/java/org/tron/core/net/message/handshake/HelloMessage.java @@ -5,6 +5,7 @@ import org.apache.commons.lang3.StringUtils; import org.tron.common.utils.ByteArray; import org.tron.common.utils.DecodeUtil; +import org.tron.common.utils.Sha256Hash; import org.tron.common.utils.StringUtil; import org.tron.core.ChainBaseManager; import org.tron.core.capsule.BlockCapsule; @@ -156,17 +157,17 @@ public Protocol.HelloMessage getInstance() { public boolean valid() { byte[] genesisBlockByte = this.helloMessage.getGenesisBlockId().getHash().toByteArray(); - if (genesisBlockByte.length == 0) { + if (genesisBlockByte.length != Sha256Hash.LENGTH) { return false; } byte[] solidBlockId = this.helloMessage.getSolidBlockId().getHash().toByteArray(); - if (solidBlockId.length == 0) { + if (solidBlockId.length != Sha256Hash.LENGTH) { return false; } byte[] headBlockId = this.helloMessage.getHeadBlockId().getHash().toByteArray(); - if (headBlockId.length == 0) { + if (headBlockId.length != Sha256Hash.LENGTH) { return false; } diff --git a/framework/src/main/java/org/tron/core/net/messagehandler/FetchInvDataMsgHandler.java b/framework/src/main/java/org/tron/core/net/messagehandler/FetchInvDataMsgHandler.java index 5415ea435e3..38cf3f2a0e2 100644 --- a/framework/src/main/java/org/tron/core/net/messagehandler/FetchInvDataMsgHandler.java +++ b/framework/src/main/java/org/tron/core/net/messagehandler/FetchInvDataMsgHandler.java @@ -156,6 +156,14 @@ private void check(PeerConnection peer, FetchInvDataMessage fetchInvDataMsg) thr if (!peer.isNeedSyncFromUs()) { throw new P2pException(TypeEnum.BAD_MESSAGE, "no need sync"); } + if (!peer.getP2pRateLimiter().tryAcquire(fetchInvDataMsg.getType().asByte())) { + throw new P2pException(TypeEnum.RATE_LIMIT_EXCEEDED, fetchInvDataMsg.getType() + + " message exceeds the rate limit"); + } + if (fetchInvDataMsg.getHashList().size() > NetConstants.MAX_BLOCK_FETCH_PER_PEER) { + throw new P2pException(TypeEnum.BAD_MESSAGE, "fetch too many blocks, size:" + + fetchInvDataMsg.getHashList().size()); + } for (Sha256Hash hash : fetchInvDataMsg.getHashList()) { long blockNum = new BlockId(hash).getNum(); long minBlockNum = diff --git a/framework/src/main/java/org/tron/core/net/messagehandler/SyncBlockChainMsgHandler.java b/framework/src/main/java/org/tron/core/net/messagehandler/SyncBlockChainMsgHandler.java index 55446593bd0..71d268b22bc 100644 --- a/framework/src/main/java/org/tron/core/net/messagehandler/SyncBlockChainMsgHandler.java +++ b/framework/src/main/java/org/tron/core/net/messagehandler/SyncBlockChainMsgHandler.java @@ -58,6 +58,14 @@ public void processMessage(PeerConnection peer, TronMessage msg) throws P2pExcep } private boolean check(PeerConnection peer, SyncBlockChainMessage msg) throws P2pException { + if (peer.getRemainNum() > 0 + && !peer.getP2pRateLimiter().tryAcquire(msg.getType().asByte())) { + // Discard messages that exceed the rate limit + logger.warn("{} message from peer {} exceeds the rate limit", + msg.getType(), peer.getInetSocketAddress()); + return false; + } + List blockIds = msg.getBlockIds(); if (CollectionUtils.isEmpty(blockIds)) { throw new P2pException(TypeEnum.BAD_MESSAGE, "SyncBlockChain blockIds is empty"); 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 2e08e105bed..253502bc3a1 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 @@ -1,5 +1,9 @@ package org.tron.core.net.peer; +import static org.tron.core.net.message.MessageTypes.FETCH_INV_DATA; +import static org.tron.core.net.message.MessageTypes.P2P_DISCONNECT; +import static org.tron.core.net.message.MessageTypes.SYNC_BLOCK_CHAIN; + import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.protobuf.ByteString; @@ -32,6 +36,7 @@ import org.tron.core.config.args.Args; import org.tron.core.metrics.MetricsKey; import org.tron.core.metrics.MetricsUtil; +import org.tron.core.net.P2pRateLimiter; import org.tron.core.net.TronNetDelegate; import org.tron.core.net.message.adv.InventoryMessage; import org.tron.core.net.message.adv.TransactionsMessage; @@ -85,7 +90,7 @@ public class PeerConnection { @Getter @Setter - private TronState tronState = TronState.INIT; + private volatile TronState tronState = TronState.INIT; @Autowired private TronNetDelegate tronNetDelegate; @@ -123,15 +128,15 @@ public class PeerConnection { private Map advInvRequest = new ConcurrentHashMap<>(); @Setter - private BlockId fastForwardBlock; + private volatile BlockId fastForwardBlock; @Getter - private BlockId blockBothHave = new BlockId(); + private volatile BlockId blockBothHave = new BlockId(); @Getter private volatile long blockBothHaveUpdateTime = System.currentTimeMillis(); @Setter @Getter - private BlockId lastSyncBlockId; + private volatile BlockId lastSyncBlockId; @Setter @Getter private volatile long remainNum; @@ -146,7 +151,7 @@ public class PeerConnection { private Map syncBlockRequested = new ConcurrentHashMap<>(); @Setter @Getter - private Pair, Long> syncChainRequested = null; + private volatile Pair, Long> syncChainRequested = null; @Setter @Getter private Set syncBlockInProcess = new HashSet<>(); @@ -156,6 +161,8 @@ public class PeerConnection { @Setter @Getter private volatile boolean needSyncFromUs = true; + @Getter + private P2pRateLimiter p2pRateLimiter = new P2pRateLimiter(); public void setChannel(Channel channel) { this.channel = channel; @@ -164,6 +171,12 @@ public void setChannel(Channel channel) { } this.nodeStatistics = TronStatsManager.getNodeStatistics(channel.getInetAddress()); lastInteractiveTime = System.currentTimeMillis(); + p2pRateLimiter.register(SYNC_BLOCK_CHAIN.asByte(), + Args.getInstance().getRateLimiterSyncBlockChain()); + p2pRateLimiter.register(FETCH_INV_DATA.asByte(), + Args.getInstance().getRateLimiterFetchInvData()); + p2pRateLimiter.register(P2P_DISCONNECT.asByte(), + Args.getInstance().getRateLimiterDisconnect()); } public void setBlockBothHave(BlockId blockId) { diff --git a/framework/src/main/java/org/tron/core/net/service/handshake/HandshakeService.java b/framework/src/main/java/org/tron/core/net/service/handshake/HandshakeService.java index 6cd117c83dd..070a9f56406 100644 --- a/framework/src/main/java/org/tron/core/net/service/handshake/HandshakeService.java +++ b/framework/src/main/java/org/tron/core/net/service/handshake/HandshakeService.java @@ -6,6 +6,7 @@ import org.springframework.stereotype.Component; import org.tron.common.utils.ByteArray; import org.tron.core.ChainBaseManager; +import org.tron.core.ChainBaseManager.NodeType; import org.tron.core.config.args.Args; import org.tron.core.net.TronNetService; import org.tron.core.net.message.handshake.HelloMessage; @@ -57,7 +58,7 @@ public void processHelloMessage(PeerConnection peer, HelloMessage msg) { msg.getInstance().getAddress().toByteArray().length, msg.getInstance().getSignature().toByteArray().length, msg.getInstance().getCodeVersion().toByteArray().length); - peer.disconnect(ReasonCode.UNEXPECTED_IDENTITY); + peer.disconnect(ReasonCode.INCOMPATIBLE_PROTOCOL); return; } @@ -96,12 +97,17 @@ public void processHelloMessage(PeerConnection peer, HelloMessage msg) { } if (chainBaseManager.getSolidBlockId().getNum() >= msg.getSolidBlockId().getNum() - && !chainBaseManager.containBlockInMainChain(msg.getSolidBlockId())) { - logger.info("Peer {} different solid block, peer->{}, me->{}", - peer.getInetSocketAddress(), - msg.getSolidBlockId().getString(), - chainBaseManager.getSolidBlockId().getString()); - peer.disconnect(ReasonCode.FORKED); + && !chainBaseManager.containBlockInMainChain(msg.getSolidBlockId())) { + if (chainBaseManager.getLowestBlockNum() <= msg.getSolidBlockId().getNum()) { + logger.info("Peer {} different solid block, fork with me, peer->{}, me->{}", + peer.getInetSocketAddress(), + msg.getSolidBlockId().getString(), + chainBaseManager.getSolidBlockId().getString()); + peer.disconnect(ReasonCode.FORKED); + } else { + logger.info("Peer {} solid block is below than my lowest", peer.getInetSocketAddress()); + peer.disconnect(ReasonCode.LIGHT_NODE_SYNC_FAIL); + } return; } 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 e387329c467..75349bd4c19 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 @@ -124,7 +124,11 @@ public void syncNext(PeerConnection peer) { peer.setSyncChainRequested(new Pair<>(chainSummary, System.currentTimeMillis())); peer.sendMessage(new SyncBlockChainMessage(chainSummary)); } catch (Exception e) { - logger.error("Peer {} sync failed, reason: {}", peer.getInetAddress(), e); + if (e instanceof P2pException) { + logger.warn("Peer {} sync failed, reason: {}", peer.getInetAddress(), e.getMessage()); + } else { + logger.error("Peer {} sync failed.", peer.getInetAddress(), e); + } peer.disconnect(ReasonCode.SYNC_FAIL); } } @@ -159,9 +163,8 @@ private void invalid(BlockId blockId, PeerConnection peerConnection) { } private LinkedList getBlockChainSummary(PeerConnection peer) throws P2pException { - - BlockId beginBlockId = peer.getBlockBothHave(); List blockIds = new ArrayList<>(peer.getSyncBlockToFetch()); + BlockId beginBlockId = peer.getBlockBothHave(); List forkList = new LinkedList<>(); LinkedList summary = new LinkedList<>(); long syncBeginNumber = tronNetDelegate.getSyncBeginNumber(); @@ -323,9 +326,9 @@ private void processSyncBlock(BlockCapsule block, PeerConnection peerConnection) for (PeerConnection peer : tronNetDelegate.getActivePeer()) { BlockId bid = peer.getSyncBlockToFetch().peek(); if (blockId.equals(bid)) { + peer.setBlockBothHave(blockId); peer.getSyncBlockToFetch().remove(bid); if (flag) { - peer.setBlockBothHave(blockId); if (peer.getSyncBlockToFetch().isEmpty() && peer.isFetchAble()) { syncNext(peer); } diff --git a/framework/src/main/java/org/tron/core/services/RpcApiService.java b/framework/src/main/java/org/tron/core/services/RpcApiService.java index 8f9c6b15bb7..b443d470b0a 100755 --- a/framework/src/main/java/org/tron/core/services/RpcApiService.java +++ b/framework/src/main/java/org/tron/core/services/RpcApiService.java @@ -291,20 +291,6 @@ private StatusRuntimeException getRunTimeException(Exception e) { } } - private void checkSupportShieldedTransaction() throws ZksnarkException { - String msg = "Not support Shielded Transaction, need to be opened by the committee"; - if (!dbManager.getDynamicPropertiesStore().supportShieldedTransaction()) { - throw new ZksnarkException(msg); - } - } - - private void checkSupportShieldedTRC20Transaction() throws ZksnarkException { - String msg = "Not support Shielded TRC20 Transaction, need to be opened by the committee"; - if (!dbManager.getDynamicPropertiesStore().supportShieldedTRC20Transaction()) { - throw new ZksnarkException(msg); - } - } - /** * DatabaseApi. */ @@ -651,8 +637,6 @@ public void getMerkleTreeVoucherInfo(OutputPointInfo request, StreamObserver responseObserver) { try { - checkSupportShieldedTransaction(); - IncrementalMerkleVoucherInfo witnessInfo = wallet .getMerkleTreeVoucherInfo(request); responseObserver.onNext(witnessInfo); @@ -669,8 +653,6 @@ public void scanNoteByIvk(GrpcAPI.IvkDecryptParameters request, long endNum = request.getEndBlockIndex(); try { - checkSupportShieldedTransaction(); - DecryptNotes decryptNotes = wallet .scanNoteByIvk(startNum, endNum, request.getIvk().toByteArray()); responseObserver.onNext(decryptNotes); @@ -687,8 +669,6 @@ public void scanAndMarkNoteByIvk(GrpcAPI.IvkDecryptAndMarkParameters request, long endNum = request.getEndBlockIndex(); try { - checkSupportShieldedTransaction(); - DecryptNotesMarked decryptNotes = wallet.scanAndMarkNoteByIvk(startNum, endNum, request.getIvk().toByteArray(), request.getAk().toByteArray(), @@ -707,8 +687,6 @@ public void scanNoteByOvk(GrpcAPI.OvkDecryptParameters request, long startNum = request.getStartBlockIndex(); long endNum = request.getEndBlockIndex(); try { - checkSupportShieldedTransaction(); - DecryptNotes decryptNotes = wallet .scanNoteByOvk(startNum, endNum, request.getOvk().toByteArray()); responseObserver.onNext(decryptNotes); @@ -721,8 +699,6 @@ public void scanNoteByOvk(GrpcAPI.OvkDecryptParameters request, @Override public void isSpend(NoteParameters request, StreamObserver responseObserver) { try { - checkSupportShieldedTransaction(); - responseObserver.onNext(wallet.isSpend(request)); } catch (Exception e) { responseObserver.onError(getRunTimeException(e)); @@ -742,7 +718,6 @@ public void scanShieldedTRC20NotesByIvk(IvkDecryptTRC20Parameters request, ProtocolStringList topicsList = request.getEventsList(); try { - checkSupportShieldedTRC20Transaction(); responseObserver.onNext( wallet.scanShieldedTRC20NotesByIvk(startNum, endNum, contractAddress, ivk, ak, nk, topicsList)); @@ -762,7 +737,6 @@ public void scanShieldedTRC20NotesByOvk(OvkDecryptTRC20Parameters request, byte[] ovk = request.getOvk().toByteArray(); ProtocolStringList topicList = request.getEventsList(); try { - checkSupportShieldedTRC20Transaction(); responseObserver .onNext(wallet .scanShieldedTRC20NotesByOvk(startNum, endNum, ovk, contractAddress, topicList)); @@ -776,7 +750,6 @@ public void scanShieldedTRC20NotesByOvk(OvkDecryptTRC20Parameters request, public void isShieldedTRC20ContractNoteSpent(NfTRC20Parameters request, StreamObserver responseObserver) { try { - checkSupportShieldedTRC20Transaction(); responseObserver.onNext(wallet.isShieldedTRC20ContractNoteSpent(request)); } catch (Exception e) { responseObserver.onError(getRunTimeException(e)); @@ -2066,8 +2039,6 @@ public void getMerkleTreeVoucherInfo(OutputPointInfo request, StreamObserver responseObserver) { try { - checkSupportShieldedTransaction(); - IncrementalMerkleVoucherInfo witnessInfo = wallet .getMerkleTreeVoucherInfo(request); responseObserver.onNext(witnessInfo); @@ -2087,8 +2058,6 @@ public void createShieldedTransaction(PrivateParameters request, Return.Builder retBuilder = Return.newBuilder(); try { - checkSupportShieldedTransaction(); - TransactionCapsule trx = wallet.createShieldedTransaction(request); trxExtBuilder.setTransaction(trx.getInstance()); trxExtBuilder.setTxid(trx.getTransactionId().getByteString()); @@ -2118,8 +2087,6 @@ public void createShieldedTransactionWithoutSpendAuthSig(PrivateParametersWithou Return.Builder retBuilder = Return.newBuilder(); try { - checkSupportShieldedTransaction(); - TransactionCapsule trx = wallet.createShieldedTransactionWithoutSpendAuthSig(request); trxExtBuilder.setTransaction(trx.getInstance()); trxExtBuilder.setTxid(trx.getTransactionId().getByteString()); @@ -2147,8 +2114,6 @@ public void getNewShieldedAddress(EmptyMessage request, StreamObserver responseObserver) { try { - checkSupportShieldedTRC20Transaction(); - responseObserver.onNext(wallet.getNewShieldedAddress()); } catch (Exception e) { responseObserver.onError(getRunTimeException(e)); @@ -2161,8 +2126,6 @@ public void getNewShieldedAddress(EmptyMessage request, public void getSpendingKey(EmptyMessage request, StreamObserver responseObserver) { try { - checkSupportShieldedTRC20Transaction(); - responseObserver.onNext(wallet.getSpendingKey()); } catch (Exception e) { responseObserver.onError(getRunTimeException(e)); @@ -2175,8 +2138,6 @@ public void getSpendingKey(EmptyMessage request, public void getRcm(EmptyMessage request, StreamObserver responseObserver) { try { - checkSupportShieldedTRC20Transaction(); - responseObserver.onNext(wallet.getRcm()); } catch (Exception e) { responseObserver.onError(getRunTimeException(e)); @@ -2191,8 +2152,6 @@ public void getExpandedSpendingKey(BytesMessage request, ByteString spendingKey = request.getValue(); try { - checkSupportShieldedTRC20Transaction(); - ExpandedSpendingKeyMessage response = wallet.getExpandedSpendingKey(spendingKey); responseObserver.onNext(response); } catch (BadItemException | ZksnarkException e) { @@ -2208,8 +2167,6 @@ public void getAkFromAsk(BytesMessage request, StreamObserver resp ByteString ak = request.getValue(); try { - checkSupportShieldedTRC20Transaction(); - responseObserver.onNext(wallet.getAkFromAsk(ak)); } catch (BadItemException | ZksnarkException e) { responseObserver.onError(getRunTimeException(e)); @@ -2224,8 +2181,6 @@ public void getNkFromNsk(BytesMessage request, StreamObserver resp ByteString nk = request.getValue(); try { - checkSupportShieldedTRC20Transaction(); - responseObserver.onNext(wallet.getNkFromNsk(nk)); } catch (BadItemException | ZksnarkException e) { responseObserver.onError(getRunTimeException(e)); @@ -2242,8 +2197,6 @@ public void getIncomingViewingKey(ViewingKeyMessage request, ByteString nk = request.getNk(); try { - checkSupportShieldedTRC20Transaction(); - responseObserver.onNext(wallet.getIncomingViewingKey(ak.toByteArray(), nk.toByteArray())); } catch (ZksnarkException e) { responseObserver.onError(getRunTimeException(e)); @@ -2257,8 +2210,6 @@ public void getIncomingViewingKey(ViewingKeyMessage request, public void getDiversifier(EmptyMessage request, StreamObserver responseObserver) { try { - checkSupportShieldedTRC20Transaction(); - DiversifierMessage d = wallet.getDiversifier(); responseObserver.onNext(d); } catch (ZksnarkException e) { @@ -2276,8 +2227,6 @@ public void getZenPaymentAddress(IncomingViewingKeyDiversifierMessage request, DiversifierMessage d = request.getD(); try { - checkSupportShieldedTRC20Transaction(); - PaymentAddressMessage saplingPaymentAddressMessage = wallet.getPaymentAddress(new IncomingViewingKey(ivk.getIvk().toByteArray()), new DiversifierT(d.getD().toByteArray())); @@ -2298,8 +2247,6 @@ public void scanNoteByIvk(GrpcAPI.IvkDecryptParameters request, long endNum = request.getEndBlockIndex(); try { - checkSupportShieldedTransaction(); - DecryptNotes decryptNotes = wallet .scanNoteByIvk(startNum, endNum, request.getIvk().toByteArray()); responseObserver.onNext(decryptNotes); @@ -2318,8 +2265,6 @@ public void scanAndMarkNoteByIvk(GrpcAPI.IvkDecryptAndMarkParameters request, long endNum = request.getEndBlockIndex(); try { - checkSupportShieldedTransaction(); - DecryptNotesMarked decryptNotes = wallet.scanAndMarkNoteByIvk(startNum, endNum, request.getIvk().toByteArray(), request.getAk().toByteArray(), @@ -2340,8 +2285,6 @@ public void scanNoteByOvk(GrpcAPI.OvkDecryptParameters request, long endNum = request.getEndBlockIndex(); try { - checkSupportShieldedTransaction(); - DecryptNotes decryptNotes = wallet .scanNoteByOvk(startNum, endNum, request.getOvk().toByteArray()); responseObserver.onNext(decryptNotes); @@ -2355,8 +2298,6 @@ public void scanNoteByOvk(GrpcAPI.OvkDecryptParameters request, @Override public void isSpend(NoteParameters request, StreamObserver responseObserver) { try { - checkSupportShieldedTransaction(); - responseObserver.onNext(wallet.isSpend(request)); } catch (Exception e) { responseObserver.onError(getRunTimeException(e)); @@ -2369,8 +2310,6 @@ public void isSpend(NoteParameters request, StreamObserver response public void createShieldNullifier(GrpcAPI.NfParameters request, StreamObserver responseObserver) { try { - checkSupportShieldedTransaction(); - BytesMessage nf = wallet .createShieldNullifier(request); responseObserver.onNext(nf); @@ -2385,8 +2324,6 @@ public void createShieldNullifier(GrpcAPI.NfParameters request, public void createSpendAuthSig(SpendAuthSigParameters request, StreamObserver responseObserver) { try { - checkSupportShieldedTRC20Transaction(); - BytesMessage spendAuthSig = wallet.createSpendAuthSig(request); responseObserver.onNext(spendAuthSig); } catch (Exception e) { @@ -2400,8 +2337,6 @@ public void createSpendAuthSig(SpendAuthSigParameters request, public void getShieldTransactionHash(Transaction request, StreamObserver responseObserver) { try { - checkSupportShieldedTransaction(); - BytesMessage transactionHash = wallet.getShieldTransactionHash(request); responseObserver.onNext(transactionHash); } catch (Exception e) { @@ -2416,8 +2351,6 @@ public void createShieldedContractParameters( PrivateShieldedTRC20Parameters request, StreamObserver responseObserver) { try { - checkSupportShieldedTRC20Transaction(); - ShieldedTRC20Parameters shieldedTRC20Parameters = wallet .createShieldedContractParameters(request); responseObserver.onNext(shieldedTRC20Parameters); @@ -2438,8 +2371,6 @@ public void createShieldedContractParametersWithoutAsk( PrivateShieldedTRC20ParametersWithoutAsk request, StreamObserver responseObserver) { try { - checkSupportShieldedTRC20Transaction(); - ShieldedTRC20Parameters shieldedTRC20Parameters = wallet .createShieldedContractParametersWithoutAsk(request); responseObserver.onNext(shieldedTRC20Parameters); @@ -2459,8 +2390,6 @@ public void scanShieldedTRC20NotesByIvk( long startNum = request.getStartBlockIndex(); long endNum = request.getEndBlockIndex(); try { - checkSupportShieldedTRC20Transaction(); - DecryptNotesTRC20 decryptNotes = wallet.scanShieldedTRC20NotesByIvk(startNum, endNum, request.getShieldedTRC20ContractAddress().toByteArray(), request.getIvk().toByteArray(), @@ -2487,8 +2416,6 @@ public void scanShieldedTRC20NotesByOvk( long startNum = request.getStartBlockIndex(); long endNum = request.getEndBlockIndex(); try { - checkSupportShieldedTRC20Transaction(); - DecryptNotesTRC20 decryptNotes = wallet.scanShieldedTRC20NotesByOvk(startNum, endNum, request.getOvk().toByteArray(), request.getShieldedTRC20ContractAddress().toByteArray(), @@ -2506,8 +2433,6 @@ public void scanShieldedTRC20NotesByOvk( public void isShieldedTRC20ContractNoteSpent(NfTRC20Parameters request, StreamObserver responseObserver) { try { - checkSupportShieldedTRC20Transaction(); - GrpcAPI.NullifierResult nf = wallet .isShieldedTRC20ContractNoteSpent(request); responseObserver.onNext(nf); @@ -2523,8 +2448,6 @@ public void getTriggerInputForShieldedTRC20Contract( ShieldedTRC20TriggerContractParameters request, StreamObserver responseObserver) { try { - checkSupportShieldedTRC20Transaction(); - responseObserver.onNext(wallet.getTriggerInputForShieldedTRC20Contract(request)); } catch (Exception e) { responseObserver.onError(e); diff --git a/framework/src/main/java/org/tron/core/services/http/GetBrokerageServlet.java b/framework/src/main/java/org/tron/core/services/http/GetBrokerageServlet.java index 1fbd94fe690..6ef22e198f9 100644 --- a/framework/src/main/java/org/tron/core/services/http/GetBrokerageServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/GetBrokerageServlet.java @@ -28,8 +28,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) { response.getWriter().println("{\"brokerage\": " + value + "}"); } catch (DecoderException | IllegalArgumentException e) { try { - response.getWriter() - .println("{\"Error\": " + "\"INVALID address, " + e.getMessage() + "\"}"); + response.getWriter().println("{\"Error\": " + "\"INVALID address\"}"); } catch (IOException ioe) { logger.debug("IOException: {}", ioe.getMessage()); } diff --git a/framework/src/main/java/org/tron/core/services/http/GetProposalByIdServlet.java b/framework/src/main/java/org/tron/core/services/http/GetProposalByIdServlet.java index a903a5b4920..9d7805d4f98 100644 --- a/framework/src/main/java/org/tron/core/services/http/GetProposalByIdServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/GetProposalByIdServlet.java @@ -26,7 +26,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) { try { boolean visible = Util.getVisible(request); String input = request.getParameter("id"); - long id = new Long(input); + long id = Long.parseLong(input); fillResponse(ByteString.copyFrom(ByteArray.fromLong(id)), visible, response); } catch (Exception e) { Util.processError(e, response); diff --git a/framework/src/main/java/org/tron/core/services/http/GetRewardServlet.java b/framework/src/main/java/org/tron/core/services/http/GetRewardServlet.java index c4d97f46c57..78042072df8 100644 --- a/framework/src/main/java/org/tron/core/services/http/GetRewardServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/GetRewardServlet.java @@ -27,8 +27,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) { response.getWriter().println("{\"reward\": " + value + "}"); } catch (DecoderException | IllegalArgumentException e) { try { - response.getWriter() - .println("{\"Error\": " + "\"INVALID address, " + e.getMessage() + "\"}"); + response.getWriter().println("{\"Error\": " + "\"INVALID address\"}"); } catch (IOException ioe) { logger.debug("IOException: {}", ioe.getMessage()); } diff --git a/framework/src/main/java/org/tron/core/services/http/solidity/GetTransactionByIdSolidityServlet.java b/framework/src/main/java/org/tron/core/services/http/solidity/GetTransactionByIdSolidityServlet.java index f98c7450afc..5998bc0850f 100644 --- a/framework/src/main/java/org/tron/core/services/http/solidity/GetTransactionByIdSolidityServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/solidity/GetTransactionByIdSolidityServlet.java @@ -30,12 +30,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) { String input = request.getParameter("value"); fillResponse(ByteString.copyFrom(ByteArray.fromHexString(input)), visible, response); } catch (Exception e) { - logger.debug("Exception: {}", e.getMessage()); - try { - response.getWriter().println(e.getMessage()); - } catch (IOException ioe) { - logger.debug("IOException: {}", ioe.getMessage()); - } + Util.processError(e, response); } } @@ -46,12 +41,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) JsonFormat.merge(params.getParams(), build, params.isVisible()); fillResponse(build.build().getValue(), params.isVisible(), response); } catch (Exception e) { - logger.debug("Exception: {}", e.getMessage()); - try { - response.getWriter().println(e.getMessage()); - } catch (IOException ioe) { - logger.debug("IOException: {}", ioe.getMessage()); - } + Util.processError(e, response); } } diff --git a/framework/src/main/java/org/tron/core/services/http/solidity/GetTransactionInfoByIdSolidityServlet.java b/framework/src/main/java/org/tron/core/services/http/solidity/GetTransactionInfoByIdSolidityServlet.java index 0408215f09d..197f5aaec0d 100644 --- a/framework/src/main/java/org/tron/core/services/http/solidity/GetTransactionInfoByIdSolidityServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/solidity/GetTransactionInfoByIdSolidityServlet.java @@ -1,7 +1,6 @@ package org.tron.core.services.http.solidity; import com.google.protobuf.ByteString; -import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; @@ -37,12 +36,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) { response.getWriter().println(JsonFormat.printToString(transInfo, visible)); } } catch (Exception e) { - logger.debug("Exception: {}", e.getMessage()); - try { - response.getWriter().println(e.getMessage()); - } catch (IOException ioe) { - logger.debug("IOException: {}", ioe.getMessage()); - } + Util.processError(e, response); } } @@ -60,12 +54,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) response.getWriter().println(JsonFormat.printToString(transInfo, params.isVisible())); } } catch (Exception e) { - logger.debug("Exception: {}", e.getMessage()); - try { - response.getWriter().println(e.getMessage()); - } catch (IOException ioe) { - logger.debug("IOException: {}", ioe.getMessage()); - } + Util.processError(e, response); } } diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcApiUtil.java b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcApiUtil.java index 955ba55060f..4a60f14b534 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcApiUtil.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcApiUtil.java @@ -26,7 +26,7 @@ import org.tron.common.utils.Sha256Hash; import org.tron.common.utils.StringUtil; import org.tron.core.Wallet; -import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; import org.tron.protos.Protocol.Block; import org.tron.protos.Protocol.Transaction; import org.tron.protos.Protocol.Transaction.Contract.ContractType; diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcErrorResolver.java b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcErrorResolver.java new file mode 100644 index 00000000000..b92b3cf1af6 --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcErrorResolver.java @@ -0,0 +1,81 @@ +package org.tron.core.services.jsonrpc; + +import com.fasterxml.jackson.databind.JsonNode; +import com.googlecode.jsonrpc4j.ErrorData; +import com.googlecode.jsonrpc4j.ErrorResolver; +import com.googlecode.jsonrpc4j.JsonRpcError; +import com.googlecode.jsonrpc4j.JsonRpcErrors; +import com.googlecode.jsonrpc4j.ReflectionUtil; +import java.lang.reflect.Method; +import java.util.List; +import org.tron.core.exception.jsonrpc.JsonRpcException; + +/** + * {@link ErrorResolver} that uses annotations. + */ +public enum JsonRpcErrorResolver implements ErrorResolver { + INSTANCE; + + /** + * {@inheritDoc} + */ + @Override + public JsonError resolveError( + Throwable thrownException, Method method, List arguments) { + JsonRpcError resolver = getResolverForException(thrownException, method); + if (notFoundResolver(resolver)) { + return null; + } + + String message = hasErrorMessage(resolver) ? resolver.message() : thrownException.getMessage(); + + // data priority: exception > annotation > default ErrorData + Object data = null; + if (thrownException instanceof JsonRpcException) { + JsonRpcException jsonRpcException = (JsonRpcException) thrownException; + data = jsonRpcException.getData(); + } + + if (data == null) { + data = hasErrorData(resolver) + ? resolver.data() + : new ErrorData(resolver.exception().getName(), message); + } + + return new JsonError(resolver.code(), message, data); + } + + private JsonRpcError getResolverForException(Throwable thrownException, Method method) { + JsonRpcErrors errors = ReflectionUtil.getAnnotation(method, JsonRpcErrors.class); + if (hasAnnotations(errors)) { + for (JsonRpcError errorDefined : errors.value()) { + if (isExceptionInstanceOfError(thrownException, errorDefined)) { + return errorDefined; + } + } + } + return null; + } + + private boolean notFoundResolver(JsonRpcError resolver) { + return resolver == null; + } + + private boolean hasErrorMessage(JsonRpcError em) { + // noinspection ConstantConditions + return em.message() != null && !em.message().trim().isEmpty(); + } + + private boolean hasErrorData(JsonRpcError em) { + // noinspection ConstantConditions + return em.data() != null && !em.data().trim().isEmpty(); + } + + private boolean hasAnnotations(JsonRpcErrors errors) { + return errors != null; + } + + private boolean isExceptionInstanceOfError(Throwable target, JsonRpcError em) { + return em.exception().isInstance(target); + } +} \ No newline at end of file diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java index 878b71d86b5..104a0e9e470 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java @@ -43,6 +43,7 @@ public void init(ServletConfig config) throws ServletException { true); rpcServer = new JsonRpcServer(compositeService); + rpcServer.setErrorResolver(JsonRpcErrorResolver.INSTANCE); HttpStatusCodeProvider httpStatusCodeProvider = new HttpStatusCodeProvider() { @Override diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java index 52a3a2380d1..5e6fc771c80 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java @@ -18,11 +18,11 @@ import org.tron.common.utils.ByteArray; import org.tron.core.exception.BadItemException; import org.tron.core.exception.ItemNotFoundException; -import org.tron.core.exception.JsonRpcInternalException; -import org.tron.core.exception.JsonRpcInvalidParamsException; -import org.tron.core.exception.JsonRpcInvalidRequestException; -import org.tron.core.exception.JsonRpcMethodNotFoundException; -import org.tron.core.exception.JsonRpcTooManyResultException; +import org.tron.core.exception.jsonrpc.JsonRpcInternalException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidRequestException; +import org.tron.core.exception.jsonrpc.JsonRpcMethodNotFoundException; +import org.tron.core.exception.jsonrpc.JsonRpcTooManyResultException; import org.tron.core.services.jsonrpc.types.BlockResult; import org.tron.core.services.jsonrpc.types.BuildArguments; import org.tron.core.services.jsonrpc.types.CallArguments; @@ -146,6 +146,14 @@ TransactionResult getTransactionByBlockNumberAndIndex(String blockNumOrTag, Stri }) TransactionReceipt getTransactionReceipt(String txid) throws JsonRpcInvalidParamsException; + @JsonRpcMethod("eth_getBlockReceipts") + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + @JsonRpcError(exception = JsonRpcInternalException.class, code = -32000, data = "{}") + }) + List getBlockReceipts(String blockNumOrTag) + throws JsonRpcInvalidParamsException, JsonRpcInternalException; + @JsonRpcMethod("eth_call") @JsonRpcErrors({ @JsonRpcError(exception = JsonRpcInvalidRequestException.class, code = -32600, data = "{}"), diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java index eb432432a1c..f681a94fe9f 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java @@ -15,6 +15,7 @@ import com.google.protobuf.GeneratedMessageV3; import java.io.Closeable; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; @@ -24,7 +25,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.regex.Matcher; import java.util.regex.Pattern; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -38,6 +38,7 @@ import org.tron.api.GrpcAPI.Return; import org.tron.api.GrpcAPI.Return.response_code; import org.tron.api.GrpcAPI.TransactionExtention; +import org.tron.api.GrpcAPI.TransactionInfoList; import org.tron.common.crypto.Hash; import org.tron.common.es.ExecutorServiceManager; import org.tron.common.logsfilter.ContractEventParser; @@ -57,12 +58,12 @@ import org.tron.core.exception.ContractValidateException; import org.tron.core.exception.HeaderNotFound; import org.tron.core.exception.ItemNotFoundException; -import org.tron.core.exception.JsonRpcInternalException; -import org.tron.core.exception.JsonRpcInvalidParamsException; -import org.tron.core.exception.JsonRpcInvalidRequestException; -import org.tron.core.exception.JsonRpcMethodNotFoundException; -import org.tron.core.exception.JsonRpcTooManyResultException; import org.tron.core.exception.VMIllegalException; +import org.tron.core.exception.jsonrpc.JsonRpcInternalException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidRequestException; +import org.tron.core.exception.jsonrpc.JsonRpcMethodNotFoundException; +import org.tron.core.exception.jsonrpc.JsonRpcTooManyResultException; import org.tron.core.services.NodeInfoService; import org.tron.core.services.http.JsonFormat; import org.tron.core.services.http.Util; @@ -76,12 +77,14 @@ import org.tron.core.services.jsonrpc.types.BuildArguments; import org.tron.core.services.jsonrpc.types.CallArguments; import org.tron.core.services.jsonrpc.types.TransactionReceipt; +import org.tron.core.services.jsonrpc.types.TransactionReceipt.TransactionContext; import org.tron.core.services.jsonrpc.types.TransactionResult; import org.tron.core.store.StorageRowStore; import org.tron.core.vm.program.Storage; import org.tron.program.Version; import org.tron.protos.Protocol.Account; import org.tron.protos.Protocol.Block; +import org.tron.protos.Protocol.ResourceReceipt; import org.tron.protos.Protocol.Transaction; import org.tron.protos.Protocol.Transaction.Contract.ContractType; import org.tron.protos.Protocol.Transaction.Result.code; @@ -94,6 +97,7 @@ import org.tron.protos.contract.SmartContractOuterClass.SmartContractDataWrapper; import org.tron.protos.contract.SmartContractOuterClass.TriggerSmartContract; + @Slf4j(topic = "API") @Component public class TronJsonRpcImpl implements TronJsonRpc, Closeable { @@ -230,15 +234,11 @@ public static void handleLogsFilter(LogsFilterCapsule logsFilterCapsule) { @Override public String web3ClientVersion() { - Pattern shortVersion = Pattern.compile("(\\d\\.\\d).*"); - Matcher matcher = shortVersion.matcher(System.getProperty("java.version")); - matcher.matches(); - return String.join("/", Arrays.asList( "TRON", "v" + Version.getVersion(), System.getProperty("os.name"), - "Java" + matcher.group(1))); + "Java" + System.getProperty("java.specification.version"))); } @Override @@ -473,7 +473,6 @@ private String call(byte[] ownerAddressByte, byte[] contractAddressByte, long va } result = ByteArray.toJsonHex(listBytes); } else { - logger.error("trigger contract failed."); String errMsg = retBuilder.getMessage().toStringUtf8(); byte[] resData = trxExtBuilder.getConstantResult(0).toByteArray(); if (resData.length > 4 && Hex.toHexString(resData).startsWith(ERROR_SELECTOR)) { @@ -483,7 +482,12 @@ private String call(byte[] ownerAddressByte, byte[] contractAddressByte, long va errMsg += ": " + msg; } - throw new JsonRpcInternalException(errMsg); + if (resData.length > 0) { + throw new JsonRpcInternalException(errMsg, ByteArray.toJsonHex(resData)); + } else { + throw new JsonRpcInternalException(errMsg); + } + } return result; @@ -644,7 +648,12 @@ public String estimateGas(CallArguments args) throws JsonRpcInvalidRequestExcept errMsg += ": " + msg; } - throw new JsonRpcInternalException(errMsg); + if (data.length > 0) { + throw new JsonRpcInternalException(errMsg, ByteArray.toJsonHex(data)); + } else { + throw new JsonRpcInternalException(errMsg); + } + } else { if (supportEstimateEnergy) { @@ -763,6 +772,13 @@ public TransactionResult getTransactionByBlockNumberAndIndex(String blockNumOrTa return getTransactionByBlockAndIndex(block, index); } + /** + * Get a transaction receipt by transaction hash + * + * @param txId the transaction hash in hex format (with or without 0x prefix) + * @return TransactionReceipt object for the specified transaction, or null if not found + * @throws JsonRpcInvalidParamsException if the transaction hash format is invalid + */ @Override public TransactionReceipt getTransactionReceipt(String txId) throws JsonRpcInvalidParamsException { @@ -777,7 +793,116 @@ public TransactionReceipt getTransactionReceipt(String txId) return null; } - return new TransactionReceipt(block, transactionInfo, wallet); + BlockCapsule blockCapsule = new BlockCapsule(block); + long blockNum = blockCapsule.getNum(); + TransactionInfoList transactionInfoList = wallet.getTransactionInfoByBlockNum(blockNum); + long energyFee = wallet.getEnergyFee(blockCapsule.getTimeStamp()); + + // Find transaction context + TransactionReceipt.TransactionContext context + = findTransactionContext(transactionInfoList, + transactionInfo.getId()); + + if (context == null) { + return null; // Transaction not found in block + } + + return new TransactionReceipt(blockCapsule, transactionInfo, context, energyFee); + } + + /** + * Finds transaction context for a specific transaction ID within the block + * Calculates cumulative gas and log count up to the target transaction + * @param infoList the transactionInfo list for the block + * @param txId the transaction ID + * @return TransactionContext containing index and cumulative values, or null if not found + */ + private TransactionContext findTransactionContext(TransactionInfoList infoList, + ByteString txId) { + + long cumulativeGas = 0; + long cumulativeLogCount = 0; + + for (int index = 0; index < infoList.getTransactionInfoCount(); index++) { + TransactionInfo info = infoList.getTransactionInfo(index); + ResourceReceipt resourceReceipt = info.getReceipt(); + + if (info.getId().equals(txId)) { + return new TransactionContext(index, cumulativeGas, cumulativeLogCount); + } else { + cumulativeGas += resourceReceipt.getEnergyUsageTotal(); + cumulativeLogCount += info.getLogCount(); + } + } + return null; + } + + /** + * Get all transaction receipts for a specific block + * @param blockNumOrTag the block number or tag (latest, earliest, pending, finalized) + * @return List of TransactionReceipt objects for all transactions in the block, + * null if block not found + * @throws JsonRpcInvalidParamsException if the parameter format is invalid + * @throws JsonRpcInternalException if there's an internal error + */ + @Override + public List getBlockReceipts(String blockNumOrTag) + throws JsonRpcInvalidParamsException, JsonRpcInternalException { + Block block = wallet.getByJsonBlockId(blockNumOrTag); + if (block == null) { + return null; + } + + BlockCapsule blockCapsule = new BlockCapsule(block); + long blockNum = blockCapsule.getNum(); + TransactionInfoList transactionInfoList = wallet.getTransactionInfoByBlockNum(blockNum); + + //energy price at the block timestamp + long energyFee = wallet.getEnergyFee(blockCapsule.getTimeStamp()); + + // Validate transaction list size consistency + int transactionSizeInBlock = blockCapsule.getTransactions().size(); + if (transactionSizeInBlock != transactionInfoList.getTransactionInfoCount()) { + throw new JsonRpcInternalException( + String.format("TransactionList size mismatch: " + + "block has %d transactions, but transactionInfoList has %d", + transactionSizeInBlock, transactionInfoList.getTransactionInfoCount())); + } + + return getTransactionReceiptsFromBlock(blockCapsule, transactionInfoList, energyFee); + } + + /** + * Get all TransactionReceipts from a block + * This method processes all transactions in the block + * and creates receipts with cumulative gas calculations + * @param blockCapsule the block containing transactions + * @param transactionInfoList the transaction info list for the block + * @param energyFee the energy price at the block timestamp + * @return List of TransactionReceipt objects for all transactions in the block + */ + private List getTransactionReceiptsFromBlock(BlockCapsule blockCapsule, + TransactionInfoList transactionInfoList, long energyFee) { + + List receipts = new ArrayList<>(); + long cumulativeGas = 0; + long cumulativeLogCount = 0; + + for (int index = 0; index < transactionInfoList.getTransactionInfoCount(); index++) { + TransactionInfo info = transactionInfoList.getTransactionInfo(index); + ResourceReceipt resourceReceipt = info.getReceipt(); + + TransactionReceipt.TransactionContext context = new TransactionContext( + index, cumulativeGas, cumulativeLogCount); + + // Use the constructor with pre-calculated context + TransactionReceipt receipt = new TransactionReceipt(blockCapsule, info, context, energyFee); + receipts.add(receipt); + + cumulativeGas += resourceReceipt.getEnergyUsageTotal(); + cumulativeLogCount += info.getLogCount(); + } + return receipts; } @Override diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogBlockQuery.java b/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogBlockQuery.java index 7665c51106f..2daf2ca3271 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogBlockQuery.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogBlockQuery.java @@ -2,7 +2,11 @@ import java.util.ArrayList; import java.util.BitSet; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -10,7 +14,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.tron.common.bloom.Bloom; import org.tron.common.crypto.Hash; -import org.tron.core.exception.JsonRpcTooManyResultException; +import org.tron.core.exception.jsonrpc.JsonRpcTooManyResultException; import org.tron.core.store.SectionBloomStore; /** @@ -121,44 +125,76 @@ private BitSet subMatch(int[][] bitIndexes) throws ExecutionException, Interrupt } /** - * every section has a compound query of sectionBloomStore, works parallel - * "and" condition in second dimension of query, "or" condition in first dimension - * return a BitSet whose capacity is blockPerSection + * Match blocks using optimized bloom filter operations. This method reduces database queries + * and BitSet operations by handling duplicate bit indexes and skipping invalid groups. + * + * @param bitIndexes A 2D array where: + * - First dimension represents different topic/address (OR) + * - Second dimension contains bit indexes within each topic/address (AND) + * Example: [[1,2,3], [4,5,6]] means (1 AND 2 AND 3) OR (4 AND 5 AND 6) + * @param section The section number in the bloom filter store to query + * @return A BitSet representing the matching blocks in this section + * @throws ExecutionException If there's an error in concurrent execution + * @throws InterruptedException If the concurrent execution is interrupted */ private BitSet partialMatch(final int[][] bitIndexes, int section) throws ExecutionException, InterruptedException { - List>> bitSetList = new ArrayList<>(); - + // 1. Collect all unique bitIndexes + Set uniqueBitIndexes = new HashSet<>(); for (int[] index : bitIndexes) { - List> futureList = new ArrayList<>(); - for (final int bitIndex : index) { //must be 3 - Future bitSetFuture = - sectionExecutor.submit(() -> sectionBloomStore.get(section, bitIndex)); - futureList.add(bitSetFuture); + for (int bitIndex : index) { //normally 3, but could be less due to hash collisions + uniqueBitIndexes.add(bitIndex); + } + } + + // 2. Submit concurrent requests for all unique bitIndexes + Map> bitIndexResults = new HashMap<>(); + for (int bitIndex : uniqueBitIndexes) { + Future future + = sectionExecutor.submit(() -> sectionBloomStore.get(section, bitIndex)); + bitIndexResults.put(bitIndex, future); + } + + // 3. Wait for all results and cache them + Map resultCache = new HashMap<>(); + for (Map.Entry> entry : bitIndexResults.entrySet()) { + BitSet result = entry.getValue().get(); + if (result != null) { + resultCache.put(entry.getKey(), result); } - bitSetList.add(futureList); } - BitSet bitSet = new BitSet(SectionBloomStore.BLOCK_PER_SECTION); - for (List> futureList : bitSetList) { - // initial a BitSet with all 1 - BitSet subBitSet = new BitSet(SectionBloomStore.BLOCK_PER_SECTION); - subBitSet.set(0, SectionBloomStore.BLOCK_PER_SECTION); + // 4. Process valid groups with reused BitSet objects + BitSet finalResult = new BitSet(SectionBloomStore.BLOCK_PER_SECTION); + BitSet tempBitSet = new BitSet(SectionBloomStore.BLOCK_PER_SECTION); + + for (int[] index : bitIndexes) { + + // init tempBitSet with all 1 + tempBitSet.set(0, SectionBloomStore.BLOCK_PER_SECTION); + // and condition in second dimension - for (Future future : futureList) { - BitSet one = future.get(); - if (one == null) { //match nothing - subBitSet.clear(); + for (int bitIndex : index) { + BitSet cached = resultCache.get(bitIndex); + if (cached == null) { //match nothing + tempBitSet.clear(); break; } // "and" condition in second dimension - subBitSet.and(one); + tempBitSet.and(cached); + if (tempBitSet.isEmpty()) { + break; + } } + // "or" condition in first dimension - bitSet.or(subBitSet); + if (!tempBitSet.isEmpty()) { + finalResult.or(tempBitSet); + } } - return bitSet; + + return finalResult; } /** diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilter.java b/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilter.java index ce315e506d2..42bc123d4bc 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilter.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilter.java @@ -14,7 +14,7 @@ import org.tron.common.crypto.Hash; import org.tron.common.runtime.vm.DataWord; import org.tron.core.config.args.Args; -import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; import org.tron.core.services.jsonrpc.TronJsonRpc.FilterRequest; import org.tron.protos.Protocol.TransactionInfo.Log; diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilterAndResult.java b/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilterAndResult.java index 3b893aec4cf..57739819d1e 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilterAndResult.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilterAndResult.java @@ -5,7 +5,7 @@ import java.util.concurrent.LinkedBlockingQueue; import lombok.Getter; import org.tron.core.Wallet; -import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; import org.tron.core.services.jsonrpc.TronJsonRpc.FilterRequest; import org.tron.core.services.jsonrpc.TronJsonRpc.LogFilterElement; diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilterWrapper.java b/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilterWrapper.java index c0cd1ff12df..97a012b7f9a 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilterWrapper.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilterWrapper.java @@ -8,7 +8,7 @@ import org.tron.common.utils.ByteArray; import org.tron.core.Wallet; import org.tron.core.config.args.Args; -import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; import org.tron.core.services.jsonrpc.JsonRpcApiUtil; import org.tron.core.services.jsonrpc.TronJsonRpc.FilterRequest; import org.tron.protos.Protocol.Block; diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogMatch.java b/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogMatch.java index d96aa07f9a4..2c3d3c2a52e 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogMatch.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogMatch.java @@ -10,7 +10,7 @@ import org.tron.core.db.Manager; import org.tron.core.exception.BadItemException; import org.tron.core.exception.ItemNotFoundException; -import org.tron.core.exception.JsonRpcTooManyResultException; +import org.tron.core.exception.jsonrpc.JsonRpcTooManyResultException; import org.tron.core.services.jsonrpc.TronJsonRpc.LogFilterElement; import org.tron.protos.Protocol.TransactionInfo; import org.tron.protos.Protocol.TransactionInfo.Log; diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/types/BuildArguments.java b/framework/src/main/java/org/tron/core/services/jsonrpc/types/BuildArguments.java index 223e807e622..490219a13d9 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/types/BuildArguments.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/types/BuildArguments.java @@ -14,8 +14,8 @@ import org.apache.commons.lang3.StringUtils; import org.tron.api.GrpcAPI.BytesMessage; import org.tron.core.Wallet; -import org.tron.core.exception.JsonRpcInvalidParamsException; -import org.tron.core.exception.JsonRpcInvalidRequestException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidRequestException; import org.tron.protos.Protocol.Transaction.Contract.ContractType; import org.tron.protos.contract.SmartContractOuterClass.SmartContract; diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/types/CallArguments.java b/framework/src/main/java/org/tron/core/services/jsonrpc/types/CallArguments.java index 1485448c4b6..70edd1ad94f 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/types/CallArguments.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/types/CallArguments.java @@ -13,8 +13,8 @@ import org.apache.commons.lang3.StringUtils; import org.tron.api.GrpcAPI.BytesMessage; import org.tron.core.Wallet; -import org.tron.core.exception.JsonRpcInvalidParamsException; -import org.tron.core.exception.JsonRpcInvalidRequestException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidRequestException; import org.tron.protos.Protocol.Transaction.Contract.ContractType; import org.tron.protos.contract.SmartContractOuterClass.SmartContract; diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionReceipt.java b/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionReceipt.java index 81b7c763cca..fd57ec0d9ad 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionReceipt.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionReceipt.java @@ -9,179 +9,151 @@ import java.util.List; import lombok.Getter; import lombok.Setter; -import org.tron.api.GrpcAPI.TransactionInfoList; import org.tron.common.utils.ByteArray; -import org.tron.core.Wallet; import org.tron.core.capsule.BlockCapsule; import org.tron.core.capsule.TransactionCapsule; import org.tron.protos.Protocol; -import org.tron.protos.Protocol.ResourceReceipt; import org.tron.protos.Protocol.Transaction.Contract; import org.tron.protos.Protocol.Transaction.Contract.ContractType; import org.tron.protos.Protocol.TransactionInfo; +@Getter +@Setter @JsonPropertyOrder(alphabetic = true) public class TransactionReceipt { - @JsonPropertyOrder(alphabetic = true) + @Getter + @Setter public static class TransactionLog { - @Getter - @Setter private String logIndex; - @Getter - @Setter private String blockHash; - @Getter - @Setter private String blockNumber; - @Getter - @Setter private String transactionIndex; - @Getter - @Setter private String transactionHash; - @Getter - @Setter private String address; - @Getter - @Setter private String data; - @Getter - @Setter private String[] topics; - @Getter - @Setter private boolean removed = false; - public TransactionLog() { - } + public TransactionLog() {} } - @Getter - @Setter private String blockHash; - @Getter - @Setter private String blockNumber; - @Getter - @Setter private String transactionIndex; - @Getter - @Setter private String transactionHash; - @Getter - @Setter private String from; - @Getter - @Setter private String to; - @Getter - @Setter private String cumulativeGasUsed; - @Getter - @Setter private String effectiveGasPrice; - @Getter - @Setter private String gasUsed; - @Getter - @Setter private String contractAddress; - @Getter - @Setter private TransactionLog[] logs; - @Getter - @Setter - private String logsBloom; - @JsonInclude(JsonInclude.Include.NON_NULL) - public String root; // 32 bytes of post-transaction stateroot (pre Byzantium) - @JsonInclude(JsonInclude.Include.NON_NULL) - public String status; // either 1 (success) or 0 (failure) (post Byzantium) + private String logsBloom = ByteArray.toJsonHex(new byte[256]); // default no value; - @Getter - @Setter - private String type = "0x0"; - - public TransactionReceipt(Protocol.Block block, TransactionInfo txInfo, Wallet wallet) { - BlockCapsule blockCapsule = new BlockCapsule(block); - String txid = ByteArray.toHexString(txInfo.getId().toByteArray()); - long blockNum = blockCapsule.getNum(); - - Protocol.Transaction transaction = null; - long cumulativeGas = 0; - long cumulativeLogCount = 0; - - TransactionInfoList infoList = wallet.getTransactionInfoByBlockNum(blockNum); - for (int index = 0; index < infoList.getTransactionInfoCount(); index++) { - TransactionInfo info = infoList.getTransactionInfo(index); - ResourceReceipt resourceReceipt = info.getReceipt(); - - long energyUsage = resourceReceipt.getEnergyUsageTotal(); - cumulativeGas += energyUsage; - - if (ByteArray.toHexString(info.getId().toByteArray()).equals(txid)) { - transactionIndex = ByteArray.toJsonHex(index); - cumulativeGasUsed = ByteArray.toJsonHex(cumulativeGas); - gasUsed = ByteArray.toJsonHex(energyUsage); - status = resourceReceipt.getResultValue() <= 1 ? "0x1" : "0x0"; - - transaction = block.getTransactions(index); - break; - } else { - cumulativeLogCount += info.getLogCount(); - } - } - - blockHash = ByteArray.toJsonHex(blockCapsule.getBlockId().getBytes()); - blockNumber = ByteArray.toJsonHex(blockCapsule.getNum()); - transactionHash = ByteArray.toJsonHex(txInfo.getId().toByteArray()); - effectiveGasPrice = ByteArray.toJsonHex(wallet.getEnergyFee(blockCapsule.getTimeStamp())); - - from = null; - to = null; - contractAddress = null; + @JsonInclude(JsonInclude.Include.NON_NULL) + private String root = null; // 32 bytes of post-transaction stateroot (pre Byzantium) - if (transaction != null && !transaction.getRawData().getContractList().isEmpty()) { + @JsonInclude(JsonInclude.Include.NON_NULL) + private String status; // either 1 (success) or 0 (failure) (post Byzantium) + + private String type = "0x0"; // legacy transaction, set 0 in java-tron + + /** + * Constructor for creating a TransactionReceipt + * + * @param blockCapsule the block containing the transaction + * @param txInfo the transaction info containing execution details + * @param context the pre-calculated transaction context + * @param energyFee the energy price at the block timestamp + */ + public TransactionReceipt( + BlockCapsule blockCapsule, + TransactionInfo txInfo, + TransactionContext context, + long energyFee) { + // Set basic fields + this.blockHash = ByteArray.toJsonHex(blockCapsule.getBlockId().getBytes()); + this.blockNumber = ByteArray.toJsonHex(blockCapsule.getNum()); + this.transactionHash = ByteArray.toJsonHex(txInfo.getId().toByteArray()); + this.transactionIndex = ByteArray.toJsonHex(context.index); + // Compute cumulative gas until this transaction + this.cumulativeGasUsed = + ByteArray.toJsonHex(context.cumulativeGas + txInfo.getReceipt().getEnergyUsageTotal()); + this.gasUsed = ByteArray.toJsonHex(txInfo.getReceipt().getEnergyUsageTotal()); + this.status = txInfo.getReceipt().getResultValue() <= 1 ? "0x1" : "0x0"; + this.effectiveGasPrice = ByteArray.toJsonHex(energyFee); + + // Set contract fields + this.from = null; + this.to = null; + this.contractAddress = null; + + TransactionCapsule txCapsule = blockCapsule.getTransactions().get(context.index); + Protocol.Transaction transaction = txCapsule.getInstance(); + if (!transaction.getRawData().getContractList().isEmpty()) { Contract contract = transaction.getRawData().getContract(0); byte[] fromByte = TransactionCapsule.getOwner(contract); byte[] toByte = getToAddress(transaction); - from = ByteArray.toJsonHexAddress(fromByte); - to = ByteArray.toJsonHexAddress(toByte); + this.from = ByteArray.toJsonHexAddress(fromByte); + this.to = ByteArray.toJsonHexAddress(toByte); if (contract.getType() == ContractType.CreateSmartContract) { - contractAddress = ByteArray.toJsonHexAddress(txInfo.getContractAddress().toByteArray()); + this.contractAddress = + ByteArray.toJsonHexAddress(txInfo.getContractAddress().toByteArray()); } } - // logs + // Set logs List logList = new ArrayList<>(); - for (int index = 0; index < txInfo.getLogCount(); index++) { - TransactionInfo.Log log = txInfo.getLogList().get(index); - - TransactionReceipt.TransactionLog transactionLog = new TransactionReceipt.TransactionLog(); - // index is the index in the block - transactionLog.logIndex = ByteArray.toJsonHex(index + cumulativeLogCount); - transactionLog.transactionHash = transactionHash; - transactionLog.transactionIndex = transactionIndex; - transactionLog.blockHash = blockHash; - transactionLog.blockNumber = blockNumber; + for (int logIndex = 0; logIndex < txInfo.getLogCount(); logIndex++) { + TransactionInfo.Log log = txInfo.getLogList().get(logIndex); + TransactionLog transactionLog = new TransactionLog(); + transactionLog.setLogIndex(ByteArray.toJsonHex(logIndex + context.cumulativeLogCount)); + transactionLog.setTransactionHash(this.transactionHash); + transactionLog.setTransactionIndex(this.transactionIndex); + transactionLog.setBlockHash(this.blockHash); + transactionLog.setBlockNumber(this.blockNumber); + byte[] addressByte = convertToTronAddress(log.getAddress().toByteArray()); - transactionLog.address = ByteArray.toJsonHexAddress(addressByte); - transactionLog.data = ByteArray.toJsonHex(log.getData().toByteArray()); + transactionLog.setAddress(ByteArray.toJsonHexAddress(addressByte)); + transactionLog.setData(ByteArray.toJsonHex(log.getData().toByteArray())); String[] topics = new String[log.getTopicsCount()]; for (int i = 0; i < log.getTopicsCount(); i++) { topics[i] = ByteArray.toJsonHex(log.getTopics(i).toByteArray()); } - transactionLog.topics = topics; + transactionLog.setTopics(topics); logList.add(transactionLog); } + this.logs = logList.toArray(new TransactionLog[0]); + + } - logs = logList.toArray(new TransactionReceipt.TransactionLog[logList.size()]); - logsBloom = ByteArray.toJsonHex(new byte[256]); // no value - root = null; + /** + * Context class to hold transaction creation parameters Contains index and cumulative values + * needed for receipt creation + */ + @Getter + public static class TransactionContext { + private final int index; + private final long cumulativeGas; + private final long cumulativeLogCount; + + /** + * Creates a transaction context with the given parameters + * + * @param index the transaction index within the block + * @param cumulativeGas the cumulative gas used up to this transaction + * @param cumulativeLogCount the cumulative log count up to this transaction + */ + public TransactionContext(int index, long cumulativeGas, long cumulativeLogCount) { + this.index = index; + this.cumulativeGas = cumulativeGas; + this.cumulativeLogCount = cumulativeLogCount; + } } -} \ No newline at end of file +} diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionResult.java b/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionResult.java index 389c58505cd..57650355d46 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionResult.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionResult.java @@ -5,9 +5,9 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.google.protobuf.ByteString; -import java.util.Arrays; import lombok.Getter; import lombok.ToString; +import org.tron.common.crypto.Rsv; import org.tron.common.utils.ByteArray; import org.tron.core.Wallet; import org.tron.core.capsule.BlockCapsule; @@ -65,16 +65,10 @@ private void parseSignature(Transaction tx) { } ByteString signature = tx.getSignature(0); // r[32] + s[32] + v[1] - byte[] signData = signature.toByteArray(); - byte[] rByte = Arrays.copyOfRange(signData, 0, 32); - byte[] sByte = Arrays.copyOfRange(signData, 32, 64); - byte vByte = signData[64]; - if (vByte < 27) { - vByte += 27; - } - v = ByteArray.toJsonHex(vByte); - r = ByteArray.toJsonHex(rByte); - s = ByteArray.toJsonHex(sByte); + Rsv rsv = Rsv.fromSignature(signature.toByteArray()); + r = ByteArray.toJsonHex(rsv.getR()); + s = ByteArray.toJsonHex(rsv.getS()); + v = ByteArray.toJsonHex(rsv.getV()); } private String parseInput(Transaction tx) { diff --git a/framework/src/main/java/org/tron/core/zen/ZksnarkInitService.java b/framework/src/main/java/org/tron/core/zen/ZksnarkInitService.java index a1f812426f7..dfc4b428836 100644 --- a/framework/src/main/java/org/tron/core/zen/ZksnarkInitService.java +++ b/framework/src/main/java/org/tron/core/zen/ZksnarkInitService.java @@ -3,6 +3,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; @@ -16,34 +17,43 @@ @Component public class ZksnarkInitService { + private static final AtomicBoolean initialized = new AtomicBoolean(false); + @PostConstruct private void init() { librustzcashInitZksnarkParams(); } public static void librustzcashInitZksnarkParams() { - logger.info("init zk param begin"); - - if (!JLibrustzcash.isOpenZen()) { - logger.info("zen switch is off, zen will not start."); + if (initialized.get()) { + logger.info("zk param already initialized"); return; } - String spendPath = getParamsFile("sapling-spend.params"); - String spendHash = "25fd9a0d1c1be0526c14662947ae95b758fe9f3d7fb7f55e9b4437830dcc6215a7ce3ea465" - + "914b157715b7a4d681389ea4aa84438190e185d5e4c93574d3a19a"; + synchronized (ZksnarkInitService.class) { + if (initialized.get()) { + logger.info("zk param already initialized"); + return; + } + logger.info("init zk param begin"); - String outputPath = getParamsFile("sapling-output.params"); - String outputHash = "a1cb23b93256adce5bce2cb09cefbc96a1d16572675ceb691e9a3626ec15b5b546926ff1c" - + "536cfe3a9df07d796b32fdfc3e5d99d65567257bf286cd2858d71a6"; + String spendPath = getParamsFile("sapling-spend.params"); + String spendHash = "25fd9a0d1c1be0526c14662947ae95b758fe9f3d7fb7f55e9b4437830dcc6215a7ce3ea" + + "465914b157715b7a4d681389ea4aa84438190e185d5e4c93574d3a19a"; - try { - JLibrustzcash.librustzcashInitZksnarkParams( - new LibrustzcashParam.InitZksnarkParams(spendPath, spendHash, outputPath, outputHash)); - } catch (ZksnarkException e) { - throw new TronError(e, TronError.ErrCode.ZCASH_INIT); + String outputPath = getParamsFile("sapling-output.params"); + String outputHash = "a1cb23b93256adce5bce2cb09cefbc96a1d16572675ceb691e9a3626ec15b5b546926f" + + "f1c536cfe3a9df07d796b32fdfc3e5d99d65567257bf286cd2858d71a6"; + + try { + JLibrustzcash.librustzcashInitZksnarkParams( + new LibrustzcashParam.InitZksnarkParams(spendPath, spendHash, outputPath, outputHash)); + } catch (ZksnarkException e) { + throw new TronError(e, TronError.ErrCode.ZCASH_INIT); + } + initialized.set(true); + logger.info("init zk param done"); } - logger.info("init zk param done"); } private static String getParamsFile(String fileName) { @@ -61,4 +71,4 @@ private static String getParamsFile(String fileName) { } return fileOut.getAbsolutePath(); } -} \ No newline at end of file +} diff --git a/framework/src/main/java/org/tron/core/zen/address/SpendingKey.java b/framework/src/main/java/org/tron/core/zen/address/SpendingKey.java index 18f18af3742..f7f030d00e2 100644 --- a/framework/src/main/java/org/tron/core/zen/address/SpendingKey.java +++ b/framework/src/main/java/org/tron/core/zen/address/SpendingKey.java @@ -89,7 +89,7 @@ public DiversifierT defaultDiversifier() throws BadItemException, ZksnarkExcepti throw new BadItemException( "librustzcash_check_diversifier does not return valid diversifier"); } - blob[33] += 1; + blob[33] += (byte) 1; } finally { JLibsodium.freeState(state); } diff --git a/framework/src/main/java/org/tron/program/DBConvert.java b/framework/src/main/java/org/tron/program/DBConvert.java deleted file mode 100644 index 7b9d63544dc..00000000000 --- a/framework/src/main/java/org/tron/program/DBConvert.java +++ /dev/null @@ -1,413 +0,0 @@ -package org.tron.program; - -import static org.fusesource.leveldbjni.JniDBFactory.factory; -import static org.tron.common.math.Maths.max; - -import java.io.File; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import lombok.extern.slf4j.Slf4j; -import org.fusesource.leveldbjni.JniDBFactory; -import org.iq80.leveldb.CompressionType; -import org.iq80.leveldb.DB; -import org.iq80.leveldb.DBIterator; -import org.rocksdb.BlockBasedTableConfig; -import org.rocksdb.BloomFilter; -import org.rocksdb.ComparatorOptions; -import org.rocksdb.Options; -import org.rocksdb.RocksDB; -import org.rocksdb.RocksDBException; -import org.rocksdb.RocksIterator; -import org.rocksdb.Status; -import org.tron.common.utils.FileUtil; -import org.tron.common.utils.MarketOrderPriceComparatorForLevelDB; -import org.tron.common.utils.MarketOrderPriceComparatorForRockDB; -import org.tron.common.utils.PropUtil; - -@Slf4j -public class DBConvert implements Callable { - - static { - RocksDB.loadLibrary(); - } - - private final String srcDir; - private final String dstDir; - private final String dbName; - private final Path srcDbPath; - private final Path dstDbPath; - - private long srcDbKeyCount = 0L; - private long dstDbKeyCount = 0L; - private long srcDbKeySum = 0L; - private long dstDbKeySum = 0L; - private long srcDbValueSum = 0L; - private long dstDbValueSum = 0L; - private final long startTime; - private static final int CPUS = Runtime.getRuntime().availableProcessors(); - private static final int BATCH = 256; - private static final String CHECKPOINT_V2_DIR_NAME = "checkpoint"; - - - @Override - public Boolean call() throws Exception { - return doConvert(); - } - - public DBConvert(String src, String dst, String name) { - this.srcDir = src; - this.dstDir = dst; - this.dbName = name; - this.srcDbPath = Paths.get(this.srcDir, name); - this.dstDbPath = Paths.get(this.dstDir, name); - this.startTime = System.currentTimeMillis(); - } - - public static org.iq80.leveldb.Options newDefaultLevelDbOptions() { - org.iq80.leveldb.Options dbOptions = new org.iq80.leveldb.Options(); - dbOptions.createIfMissing(true); - dbOptions.paranoidChecks(true); - dbOptions.verifyChecksums(true); - dbOptions.compressionType(CompressionType.SNAPPY); - dbOptions.blockSize(4 * 1024); - dbOptions.writeBufferSize(10 * 1024 * 1024); - dbOptions.cacheSize(10 * 1024 * 1024L); - dbOptions.maxOpenFiles(1000); - return dbOptions; - } - - public static void main(String[] args) { - int code = run(args); - logger.info("exit code {}.", code); - System.out.printf("exit code %d.\n", code); - System.exit(code); - } - - public static int run(String[] args) { - String dbSrc; - String dbDst; - if (args.length < 2) { - dbSrc = "output-directory/database"; - dbDst = "output-directory-dst/database"; - } else { - dbSrc = args[0]; - dbDst = args[1]; - } - File dbDirectory = new File(dbSrc); - if (!dbDirectory.exists()) { - logger.info(" {} does not exist.", dbSrc); - return 404; - } - List files = Arrays.stream(Objects.requireNonNull(dbDirectory.listFiles())) - .filter(File::isDirectory) - .filter(e -> !CHECKPOINT_V2_DIR_NAME.equals(e.getName())) - .collect(Collectors.toList()); - - // add checkpoint v2 convert - File cpV2Dir = new File(Paths.get(dbSrc, CHECKPOINT_V2_DIR_NAME).toString()); - List cpList = null; - if (cpV2Dir.exists()) { - cpList = Arrays.stream(Objects.requireNonNull(cpV2Dir.listFiles())) - .filter(File::isDirectory) - .collect(Collectors.toList()); - } - - if (files.isEmpty()) { - logger.info("{} does not contain any database.", dbSrc); - return 0; - } - final long time = System.currentTimeMillis(); - final List> res = new ArrayList<>(); - - final ThreadPoolExecutor esDb = new ThreadPoolExecutor( - CPUS, 16 * CPUS, 1, TimeUnit.MINUTES, - new ArrayBlockingQueue<>(CPUS, true), Executors.defaultThreadFactory(), - new ThreadPoolExecutor.CallerRunsPolicy()); - - esDb.allowCoreThreadTimeOut(true); - - files.forEach(f -> res.add(esDb.submit(new DBConvert(dbSrc, dbDst, f.getName())))); - // convert v2 - if (cpList != null) { - cpList.forEach(f -> res.add(esDb.submit( - new DBConvert(dbSrc + "/" + CHECKPOINT_V2_DIR_NAME, - dbDst + "/" + CHECKPOINT_V2_DIR_NAME, f.getName())))); - } - - int fails = res.size(); - - for (Future re : res) { - try { - if (re.get()) { - fails--; - } - } catch (InterruptedException e) { - logger.error("{}", e); - Thread.currentThread().interrupt(); - } catch (ExecutionException e) { - logger.error("{}", e); - } - } - - esDb.shutdown(); - logger.info("database convert use {} seconds total.", - (System.currentTimeMillis() - time) / 1000); - if (fails > 0) { - logger.error("failed!!!!!!!!!!!!!!!!!!!!!!!! size:{}", fails); - } - return fails; - } - - public DB newLevelDb(Path db) throws Exception { - DB database; - File file = db.toFile(); - org.iq80.leveldb.Options dbOptions = newDefaultLevelDbOptions(); - if ("market_pair_price_to_order".equalsIgnoreCase(this.dbName)) { - dbOptions.comparator(new MarketOrderPriceComparatorForLevelDB()); - } - database = factory.open(file, dbOptions); - return database; - } - - private Options newDefaultRocksDbOptions() { - Options options = new Options(); - options.setCreateIfMissing(true); - options.setIncreaseParallelism(1); - options.setNumLevels(7); - options.setMaxOpenFiles(5000); - options.setTargetFileSizeBase(64 * 1024 * 1024); - options.setTargetFileSizeMultiplier(1); - options.setMaxBytesForLevelBase(512 * 1024 * 1024); - options.setMaxBackgroundCompactions(max(1, Runtime.getRuntime().availableProcessors(), true)); - options.setLevel0FileNumCompactionTrigger(4); - options.setLevelCompactionDynamicLevelBytes(true); - if ("market_pair_price_to_order".equalsIgnoreCase(this.dbName)) { - options.setComparator(new MarketOrderPriceComparatorForRockDB(new ComparatorOptions())); - } - final BlockBasedTableConfig tableCfg; - options.setTableFormatConfig(tableCfg = new BlockBasedTableConfig()); - tableCfg.setBlockSize(64 * 1024); - tableCfg.setBlockCacheSize(32 * 1024 * 1024); - tableCfg.setCacheIndexAndFilterBlocks(true); - tableCfg.setPinL0FilterAndIndexBlocksInCache(true); - tableCfg.setFilter(new BloomFilter(10, false)); - options.prepareForBulkLoad(); - return options; - } - - public RocksDB newRocksDb(Path db) { - RocksDB database = null; - try (Options options = newDefaultRocksDbOptions()) { - database = RocksDB.open(options, db.toString()); - } catch (Exception e) { - logger.error("{}", e); - } - return database; - } - - private void batchInsert(RocksDB rocks, List keys, List values) - throws Exception { - try (org.rocksdb.WriteBatch batch = new org.rocksdb.WriteBatch()) { - for (int i = 0; i < keys.size(); i++) { - byte[] k = keys.get(i); - byte[] v = values.get(i); - batch.put(k, v); - } - write(rocks, batch); - } - keys.clear(); - values.clear(); - } - - /** - * https://github.com/facebook/rocksdb/issues/6625 - * @param rocks db - * @param batch write batch - * @throws Exception RocksDBException - */ - private void write(RocksDB rocks, org.rocksdb.WriteBatch batch) throws Exception { - try { - rocks.write(new org.rocksdb.WriteOptions(), batch); - } catch (RocksDBException e) { - // retry - if (maybeRetry(e)) { - TimeUnit.MILLISECONDS.sleep(1); - write(rocks, batch); - } else { - throw e; - } - } - } - - private boolean maybeRetry(RocksDBException e) { - boolean retry = false; - if (e.getStatus() != null) { - retry = e.getStatus().getCode() == Status.Code.TryAgain - || e.getStatus().getCode() == Status.Code.Busy - || e.getStatus().getCode() == Status.Code.Incomplete; - } - return retry || (e.getMessage() != null && ("Write stall".equalsIgnoreCase(e.getMessage()) - || ("Incomplete").equalsIgnoreCase(e.getMessage()))); - } - - /** - * https://github.com/facebook/rocksdb/wiki/RocksDB-FAQ . - * What's the fastest way to load data into RocksDB? - * @param level leveldb - * @param rocks rocksdb - * @return if ok - */ - public boolean convertLevelToRocksBatchIterator(DB level, RocksDB rocks) { - // convert - List keys = new ArrayList<>(BATCH); - List values = new ArrayList<>(BATCH); - try (DBIterator levelIterator = level.iterator( - new org.iq80.leveldb.ReadOptions().fillCache(false))) { - - JniDBFactory.pushMemoryPool(1024 * 1024); - levelIterator.seekToFirst(); - - while (levelIterator.hasNext()) { - Map.Entry entry = levelIterator.next(); - byte[] key = entry.getKey(); - byte[] value = entry.getValue(); - srcDbKeyCount++; - srcDbKeySum = byteArrayToIntWithOne(srcDbKeySum, key); - srcDbValueSum = byteArrayToIntWithOne(srcDbValueSum, value); - keys.add(key); - values.add(value); - if (keys.size() >= BATCH) { - try { - batchInsert(rocks, keys, values); - } catch (Exception e) { - logger.error("{}", e); - return false; - } - } - } - - if (!keys.isEmpty()) { - try { - batchInsert(rocks, keys, values); - } catch (Exception e) { - logger.error("{}", e); - return false; - } - } - // check - check(rocks); - } catch (Exception e) { - logger.error("{}", e); - return false; - } finally { - try { - level.close(); - rocks.close(); - JniDBFactory.popMemoryPool(); - } catch (Exception e1) { - logger.error("{}", e1); - } - } - return dstDbKeyCount == srcDbKeyCount && dstDbKeySum == srcDbKeySum - && dstDbValueSum == srcDbValueSum; - } - - private void check(RocksDB rocks) throws RocksDBException { - logger.info("check database {} start", this.dbName); - // manually call CompactRange() - logger.info("compact database {} start", this.dbName); - rocks.compactRange(); - logger.info("compact database {} end", this.dbName); - // check - try (org.rocksdb.ReadOptions r = new org.rocksdb.ReadOptions().setFillCache(false); - RocksIterator rocksIterator = rocks.newIterator(r)) { - for (rocksIterator.seekToFirst(); rocksIterator.isValid(); rocksIterator.next()) { - byte[] key = rocksIterator.key(); - byte[] value = rocksIterator.value(); - dstDbKeyCount++; - dstDbKeySum = byteArrayToIntWithOne(dstDbKeySum, key); - dstDbValueSum = byteArrayToIntWithOne(dstDbValueSum, value); - } - } - logger.info("check database {} end", this.dbName); - } - - public boolean createEngine(String dir) { - String enginePath = dir + File.separator + "engine.properties"; - - if (!FileUtil.createFileIfNotExists(enginePath)) { - return false; - } - - return PropUtil.writeProperty(enginePath, "ENGINE", "ROCKSDB"); - } - - public boolean checkDone(String dir) { - String enginePath = dir + File.separator + "engine.properties"; - return FileUtil.isExists(enginePath); - - } - - public boolean doConvert() throws Exception { - - if (checkDone(this.dstDbPath.toString())) { - logger.info(" {} is done, skip it.", this.dbName); - return true; - } - - File levelDbFile = srcDbPath.toFile(); - if (!levelDbFile.exists()) { - logger.info(" {} does not exist.", srcDbPath.toString()); - return false; - } - - DB level = newLevelDb(srcDbPath); - - if (this.dstDbPath.toFile().exists()) { - logger.info(" {} begin to clear exist database directory", this.dbName); - FileUtil.deleteDir(this.dstDbPath.toFile()); - logger.info(" {} clear exist database directory done.", this.dbName); - } - - FileUtil.createDirIfNotExists(dstDir); - RocksDB rocks = newRocksDb(dstDbPath); - - logger.info("Convert database {} start", this.dbName); - boolean result = convertLevelToRocksBatchIterator(level, rocks) - && createEngine(dstDbPath.toString()); - long etime = System.currentTimeMillis(); - - if (result) { - logger.info("Convert database {} successful end with {} key-value {} minutes", - this.dbName, this.srcDbKeyCount, (etime - this.startTime) / 1000.0 / 60); - } else { - logger.info("Convert database {} failure", this.dbName); - if (this.dstDbPath.toFile().exists()) { - logger.info(" {} begin to clear exist database directory", this.dbName); - FileUtil.deleteDir(this.dstDbPath.toFile()); - logger.info(" {} clear exist database directory done.", this.dbName); - } - } - return result; - } - - public long byteArrayToIntWithOne(long sum, byte[] b) { - for (byte oneByte : b) { - sum += oneByte; - } - return sum; - } -} \ No newline at end of file diff --git a/framework/src/main/java/org/tron/program/FullNode.java b/framework/src/main/java/org/tron/program/FullNode.java index bd275de544c..e17ce8c8531 100644 --- a/framework/src/main/java/org/tron/program/FullNode.java +++ b/framework/src/main/java/org/tron/program/FullNode.java @@ -21,12 +21,20 @@ public class FullNode { */ public static void main(String[] args) { ExitManager.initExceptionHandler(); - logger.info("Full node running."); Args.setParam(args, Constant.TESTNET_CONF); CommonParameter parameter = Args.getInstance(); LogService.load(parameter.getLogbackPath()); + if (parameter.isSolidityNode()) { + SolidityNode.start(); + return; + } + if (parameter.isKeystore()) { + KeystoreFactory.start(); + return; + } + logger.info("Full node running."); if (Args.getInstance().isDebug()) { logger.info("in debug mode, it won't check energy time"); } else { diff --git a/framework/src/main/java/org/tron/program/KeystoreFactory.java b/framework/src/main/java/org/tron/program/KeystoreFactory.java index bfd2df22856..8199d7e9076 100755 --- a/framework/src/main/java/org/tron/program/KeystoreFactory.java +++ b/framework/src/main/java/org/tron/program/KeystoreFactory.java @@ -1,6 +1,5 @@ package org.tron.program; -import com.beust.jcommander.JCommander; import java.io.File; import java.io.IOException; import java.util.Scanner; @@ -11,8 +10,6 @@ import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.ByteArray; import org.tron.common.utils.Utils; -import org.tron.core.Constant; -import org.tron.core.config.args.Args; import org.tron.core.exception.CipherException; import org.tron.keystore.Credentials; import org.tron.keystore.WalletUtils; @@ -22,15 +19,8 @@ public class KeystoreFactory { private static final String FilePath = "Wallet"; - public static void main(String[] args) { - Args.setParam(args, Constant.TESTNET_CONF); + public static void start() { KeystoreFactory cli = new KeystoreFactory(); - - JCommander.newBuilder() - .addObject(cli) - .build() - .parse(args); - cli.run(); } diff --git a/framework/src/main/java/org/tron/program/SolidityNode.java b/framework/src/main/java/org/tron/program/SolidityNode.java index b774ab03aaa..3367141e2a5 100644 --- a/framework/src/main/java/org/tron/program/SolidityNode.java +++ b/framework/src/main/java/org/tron/program/SolidityNode.java @@ -5,21 +5,17 @@ import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.atomic.AtomicLong; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.BooleanUtils; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.util.ObjectUtils; import org.tron.common.application.Application; import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; import org.tron.common.client.DatabaseGrpcClient; -import org.tron.common.exit.ExitManager; import org.tron.common.parameter.CommonParameter; import org.tron.common.prometheus.Metrics; import org.tron.core.ChainBaseManager; -import org.tron.core.Constant; import org.tron.core.capsule.BlockCapsule; import org.tron.core.config.DefaultConfig; -import org.tron.core.config.args.Args; import org.tron.core.db.Manager; import org.tron.core.exception.TronError; import org.tron.protos.Protocol.Block; @@ -55,25 +51,12 @@ public SolidityNode(Manager dbManager) { /** * Start the SolidityNode. */ - public static void main(String[] args) { - ExitManager.initExceptionHandler(); + public static void start() { logger.info("Solidity node is running."); - Args.setParam(args, Constant.TESTNET_CONF); CommonParameter parameter = CommonParameter.getInstance(); - - logger.info("index switch is {}", - BooleanUtils.toStringOnOff(BooleanUtils - .toBoolean(parameter.getStorage().getIndexSwitch()))); - if (ObjectUtils.isEmpty(parameter.getTrustNodeAddr())) { - logger.error("Trust node is not set."); - return; - } - parameter.setSolidityNode(true); - - if (parameter.isHelp()) { - logger.info("Here is the help message."); - return; + throw new TronError(new IllegalArgumentException("Trust node is not set."), + TronError.ErrCode.SOLID_NODE_INIT); } // init metrics first Metrics.init(); @@ -88,11 +71,11 @@ public static void main(String[] args) { context.registerShutdownHook(); appT.startup(); SolidityNode node = new SolidityNode(appT.getDbManager()); - node.start(); + node.run(); appT.blockUntilShutdown(); } - private void start() { + private void run() { try { new Thread(this::getBlock).start(); new Thread(this::processBlock).start(); diff --git a/framework/src/main/resources/config.conf b/framework/src/main/resources/config.conf index d434d9c7203..55e4b8c55d9 100644 --- a/framework/src/main/resources/config.conf +++ b/framework/src/main/resources/config.conf @@ -5,7 +5,7 @@ net { storage { # Directory for storing persistent data - db.engine = "LEVELDB", + db.engine = "LEVELDB", // deprecated for arm, because arm only support "ROCKSDB". db.sync = false, db.directory = "database", index.directory = "index", @@ -19,7 +19,7 @@ storage { # Otherwise, db configs will remain default and data will be stored in # the path of "output-directory" or which is set by "-d" ("--output-directory"). - # setting can impove leveldb performance .... start + # setting can impove leveldb performance .... start, deprecated for arm # node: if this will increase process fds,you may be check your ulimit if 'too many open files' error occurs # see https://github.com/tronprotocol/tips/blob/master/tip-343.md for detail # if you find block sync has lower performance,you can try this settings @@ -32,21 +32,21 @@ storage { #defaultL = { # maxOpenFiles = 1000 #} - # setting can impove leveldb performance .... end + # setting can impove leveldb performance .... end, deprecated for arm # Attention: name is a required field that must be set !!! properties = [ // { // name = "account", // path = "storage_directory_test", - // createIfMissing = true, + // createIfMissing = true, // deprecated for arm start // paranoidChecks = true, // verifyChecksums = true, // compressionType = 1, // compressed with snappy // blockSize = 4096, // 4 KB = 4 * 1024 B // writeBufferSize = 10485760, // 10 MB = 10 * 1024 * 1024 B // cacheSize = 10485760, // 10 MB = 10 * 1024 * 1024 B - // maxOpenFiles = 100 + // maxOpenFiles = 100 // deprecated for arm end // }, // { // name = "account-index", @@ -101,7 +101,7 @@ storage { # data root setting, for check data, currently, only reward-vi is used. # merkleRoot = { - # reward-vi = 9debcb9924055500aaae98cdee10501c5c39d4daa75800a996f4bdda73dbccd8 // main-net, Sha256Hash, hexString + # reward-vi = 9debcb9924055500aaae98cdee10501c5c39d4daa75800a996f4bdda73dbccd8 // main-net, Sha256Hash, hexString # } } @@ -119,13 +119,13 @@ node.discovery = { #} node.backup { + # udp listen port, each member should have the same configuration + port = 10001 + # my priority, each member should use different priority priority = 8 - # udp listen port, each member should have the save configuration - port = 10001 - - # time interval to send keepAlive message, each member should have the save configuration + # time interval to send keepAlive message, each member should have the same configuration keepAliveInterval = 3000 # peer's ip list, can't contain mine @@ -166,12 +166,14 @@ node { udpNettyWorkThreadNum = 1 + # Number of validate sign thread, default availableProcessors + # validateSignThreadNum = 16 + maxConnections = 30 + minConnections = 8 - minActiveConnections = 3 - # Number of validate sign thread, default availableProcessors / 2 - # validateSignThreadNum = 16 + minActiveConnections = 3 maxConnectionsWithSameIp = 2 @@ -214,19 +216,6 @@ node { PBFTPort = 8092 } - # use your ipv6 address for node discovery and tcp connection, default false - enableIpv6 = false - - # if your node's highest block num is below than all your pees', try to acquire new connection. default false - effectiveCheckEnable = false - - dns { - # dns urls to get nodes, url format tree://{pubkey}@{domain}, default empty - treeUrls = [ - #"tree://AKMQMNAJJBL73LXWPXDI4I5ZWWIZ4AWO34DWQ636QOBBXNFXH3LQS@main.trondisco.net", - ] - } - rpc { enable = true port = 50051 @@ -234,6 +223,7 @@ node { solidityPort = 50061 PBFTEnable = true PBFTPort = 50071 + # Number of gRPC thread, default availableProcessors / 2 # thread = 16 @@ -274,6 +264,74 @@ node { # Limits the maximum number (default 700) of transaction from network layer # netMaxTrxPerSecond = 700 + # Whether to enable the node detection function, default false + # nodeDetectEnable = false + + # use your ipv6 address for node discovery and tcp connection, default false + # enableIpv6 = false + + # if your node's highest block num is below than all your pees', try to acquire new connection. default false + # effectiveCheckEnable = false + + # Dynamic loading configuration function, disabled by default + # dynamicConfig = { + # enable = false + # Configuration file change check interval, default is 600 seconds + # checkInterval = 600 + # } + + dns { + # dns urls to get nodes, url format tree://{pubkey}@{domain}, default empty + treeUrls = [ + #"tree://AKMQMNAJJBL73LXWPXDI4I5ZWWIZ4AWO34DWQ636QOBBXNFXH3LQS@main.trondisco.net", + ] + + # enable or disable dns publish, default false + # publish = false + + # dns domain to publish nodes, required if publish is true + # dnsDomain = "nodes1.example.org" + + # dns private key used to publish, required if publish is true, hex string of length 64 + # dnsPrivate = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" + + # known dns urls to publish if publish is true, url format tree://{pubkey}@{domain}, default empty + # knownUrls = [ + #"tree://APFGGTFOBVE2ZNAB3CSMNNX6RRK3ODIRLP2AA5U4YFAA6MSYZUYTQ@nodes2.example.org", + # ] + + # staticNodes = [ + # static nodes to published on dns + # Sample entries: + # "ip:port", + # "ip:port" + # ] + + # merge several nodes into a leaf of tree, should be 1~5 + # maxMergeSize = 5 + + # only nodes change percent is bigger then the threshold, we update data on dns + # changeThreshold = 0.1 + + # dns server to publish, required if publish is true, only aws or aliyun is support + # serverType = "aws" + + # access key id of aws or aliyun api, required if publish is true, string + # accessKeyId = "your-key-id" + + # access key secret of aws or aliyun api, required if publish is true, string + # accessKeySecret = "your-key-secret" + + # if publish is true and serverType is aliyun, it's endpoint of aws dns server, string + # aliyunDnsEndpoint = "alidns.aliyuncs.com" + + # if publish is true and serverType is aws, it's region of aws api, such as "eu-south-1", string + # awsRegion = "us-east-1" + + # if publish is true and server-type is aws, it's host zone id of aws's domain, string + # awsHostZoneId = "your-host-zone-id" + } + # open the history query APIs(http&GRPC) when node is a lite fullNode, # like {getBlockByNum, getBlockByID, getTransactionByID...}. # default: false. @@ -294,11 +352,11 @@ node { # The maximum blocks range to retrieve logs for eth_getLogs, default value is 5000, # should be > 0, otherwise means no limit. - # maxBlockRange = 5000 + maxBlockRange = 5000 # The maximum number of allowed topics within a topic criteria, default value is 1000, # should be > 0, otherwise means no limit. - # maxSubTopics = 1000 + maxSubTopics = 1000 } # Disabled api list, it will work for http, rpc and pbft, both fullnode and soliditynode, @@ -319,7 +377,7 @@ rate.limiter = { # before do the request and release the resource after got the reponse automaticlly. permit should be a Integer. # QpsRateLimiterAdapter: qps is the average request count in one second supported by the server, it could be a Double or a Integer. # IPQPSRateLimiterAdapter: similar to the QpsRateLimiterAdapter, qps could be a Double or a Integer. - # If do not set, the "default strategy" is set.The "default startegy" is based on QpsRateLimiterAdapter, the qps is set as 10000. + # If do not set, the "default strategy" is set.The "default startegy" is based on QpsRateLimiterAdapter, the qps is set as 1000. # # Sample entries: # @@ -363,9 +421,14 @@ rate.limiter = { # }, ] + # global qps, default 50000 + # global.qps = 50000 + # IP-based global qps, default 10000 + # global.ip.qps = 10000 } + seed.node = { # List of the seed nodes # Seed nodes are stable full nodes @@ -375,18 +438,18 @@ seed.node = { # "ip:port" # ] ip.list = [ - "54.236.37.243:18888", - "52.53.189.99:18888", - "18.196.99.16:18888", - "34.253.187.192:18888", - "52.56.56.149:18888", - "35.180.51.163:18888", - "54.252.224.209:18888", - "18.228.15.36:18888", - "52.15.93.92:18888", - "34.220.77.106:18888", - "13.127.47.162:18888", - "13.124.62.58:18888", + "3.225.171.164:18888", + "52.8.46.215:18888", + "3.79.71.167:18888", + "108.128.110.16:18888", + "18.133.82.227:18888", + "35.180.81.133:18888", + "13.210.151.5:18888", + "18.231.27.82:18888", + "3.12.212.122:18888", + "52.24.128.7:18888", + "15.207.144.3:18888", + "3.39.38.55:18888", "54.151.226.240:18888", "35.174.93.198:18888", "18.210.241.149:18888", @@ -404,7 +467,9 @@ seed.node = { "54.82.161.39:18888", "54.179.207.68:18888", "18.142.82.44:18888", - "18.163.230.203:18888" + "18.163.230.203:18888", + # "[2a05:d014:1f2f:2600:1b15:921:d60b:4c60]:18888", // use this if support ipv6 + # "[2600:1f18:7260:f400:8947:ebf3:78a0:282b]:18888", // use this if support ipv6 ] } @@ -595,7 +660,7 @@ block = { proposalExpireTime = 259200000 // 3 day: 259200000(ms) } -# Transaction reference block, default is "solid", configure to "head" may accur TaPos error +# Transaction reference block, default is "solid", configure to "head" may cause TaPos error # trx.reference.block = "solid" // head;solid; # This property sets the number of milliseconds after the creation of the transaction that is expired, default value is 60000. @@ -611,7 +676,8 @@ vm = { # Indicates whether the node stores featured internal transactions, such as freeze, vote and so on # saveFeaturedInternalTx = false - # Indicates whether the node stores the details of the internal transactions generated by the CANCELALLUNFREEZEV2 opcode, such as bandwidth/energy/tronpower cancel amount. + # Indicates whether the node stores the details of the internal transactions generated by the + # CANCELALLUNFREEZEV2 opcode, such as bandwidth/energy/tronpower cancel amount. # saveCancelAllUnfreezeV2Details = false # In rare cases, transactions that will be within the specified maximum execution time (default 10(ms)) are re-executed and packaged @@ -635,21 +701,32 @@ event.subscribe = { bindport = 5555 // bind port sendqueuelength = 1000 //max length of send queue } + version = 0 + # Specify the starting block number to sync historical events. This is only applicable when version = 1. + # After performing a full event sync, set this value to 0 or a negative number. + # startSyncBlockNum = 1 path = "" // absolute path of plugin server = "" // target server address to receive event triggers - dbconfig = "" // dbname|username|password - contractParse = true, + // dbname|username|password, if you want to create indexes for collections when the collections + // are not exist, you can add version and set it to 2, as dbname|username|password|version + // if you use version 2 and one collection not exists, it will create index automaticaly; + // if you use version 2 and one collection exists, it will not create index, you must create index manually; + dbconfig = "" + contractParse = true topics = [ { triggerName = "block" // block trigger, the value can't be modified enable = false topic = "block" // plugin topic, the value could be modified + solidified = false // if set true, just need solidified block, default is false }, { triggerName = "transaction" enable = false topic = "transaction" + solidified = false + ethCompatible = false // if set true, add transactionIndex, cumulativeEnergyUsed, preCumulativeLogCount, logList, energyUnitPrice, default is false }, { triggerName = "contractevent" @@ -660,9 +737,10 @@ event.subscribe = { triggerName = "contractlog" enable = false topic = "contractlog" + redundancy = false // if set true, contractevent will also be regarded as contractlog }, { - triggerName = "solidity" // solidity block event trigger, the value can't be modified + triggerName = "solidity" // solidity block trigger(just include solidity block number and timestamp), the value can't be modified enable = true // the default value is true topic = "solidity" }, @@ -675,6 +753,7 @@ event.subscribe = { triggerName = "soliditylog" enable = false topic = "soliditylog" + redundancy = false // if set true, solidityevent will also be regarded as soliditylog } ] @@ -689,5 +768,5 @@ event.subscribe = { "" // contract topic you want to subscribe, if it's set to "", you will receive contract logs/events with any contract topic. ] } - } + diff --git a/framework/src/test/java/org/springframework/http/InvalidMediaTypeException.java b/framework/src/test/java/org/springframework/http/InvalidMediaTypeException.java new file mode 100644 index 00000000000..3b1e41f1756 --- /dev/null +++ b/framework/src/test/java/org/springframework/http/InvalidMediaTypeException.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.http; + +import org.springframework.util.InvalidMimeTypeException; + +/** + * Exception thrown from {@link MediaType#parseMediaType(String)} in case of + * encountering an invalid media type specification String. + * + * @author Juergen Hoeller + * @since 3.2.2 + */ +@SuppressWarnings("serial") +public class InvalidMediaTypeException extends IllegalArgumentException { + + private final String mediaType; + + + /** + * Create a new InvalidMediaTypeException for the given media type. + * + * @param mediaType the offending media type + * @param message a detail message indicating the invalid part + */ + public InvalidMediaTypeException(String mediaType, String message) { + super("Invalid media type \"" + mediaType + "\": " + message); + this.mediaType = mediaType; + } + + /** + * Constructor that allows wrapping {@link InvalidMimeTypeException}. + */ + InvalidMediaTypeException(InvalidMimeTypeException ex) { + super(ex.getMessage(), ex); + this.mediaType = ex.getMimeType(); + } + + + /** + * Return the offending media type. + */ + public String getMediaType() { + return this.mediaType; + } + +} \ No newline at end of file diff --git a/framework/src/test/java/org/springframework/http/MediaType.java b/framework/src/test/java/org/springframework/http/MediaType.java new file mode 100644 index 00000000000..84962970235 --- /dev/null +++ b/framework/src/test/java/org/springframework/http/MediaType.java @@ -0,0 +1,841 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.http; + +import java.io.Serializable; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.InvalidMimeTypeException; +import org.springframework.util.MimeType; +import org.springframework.util.MimeTypeUtils; +import org.springframework.util.StringUtils; + +/** + * A subclass of {@link MimeType} that adds support for quality parameters + * as defined in the HTTP specification. + * + * @author Arjen Poutsma + * @author Juergen Hoeller + * @author Rossen Stoyanchev + * @author Sebastien Deleuze + * @author Kazuki Shimizu + * @author Sam Brannen + * @see + * HTTP 1.1: Semantics and Content, section 3.1.1.1 + * @since 3.0 + */ +public class MediaType extends MimeType implements Serializable { + + /** + * Public constant media type that includes all media ranges (i.e. "*/*"). + */ + public static final MediaType ALL; + /** + * A String equivalent of {@link MediaType#ALL}. + */ + public static final String ALL_VALUE = "*/*"; + /** + * Public constant media type for {@code application/atom+xml}. + */ + public static final MediaType APPLICATION_ATOM_XML; + /** + * A String equivalent of {@link MediaType#APPLICATION_ATOM_XML}. + */ + public static final String APPLICATION_ATOM_XML_VALUE = "application/atom+xml"; + /** + * Public constant media type for {@code application/cbor}. + * + * @since 5.2 + */ + public static final MediaType APPLICATION_CBOR; + /** + * A String equivalent of {@link MediaType#APPLICATION_CBOR}. + * + * @since 5.2 + */ + public static final String APPLICATION_CBOR_VALUE = "application/cbor"; + /** + * Public constant media type for {@code application/x-www-form-urlencoded}. + */ + public static final MediaType APPLICATION_FORM_URLENCODED; + /** + * A String equivalent of {@link MediaType#APPLICATION_FORM_URLENCODED}. + */ + public static final String APPLICATION_FORM_URLENCODED_VALUE = + "application/x-www-form-urlencoded"; + /** + * Public constant media type for {@code application/graphql+json}. + * + * @see GraphQL over HTTP spec + * @since 5.3.19 + */ + public static final MediaType APPLICATION_GRAPHQL; + /** + * A String equivalent of {@link MediaType#APPLICATION_GRAPHQL}. + * + * @since 5.3.19 + */ + public static final String APPLICATION_GRAPHQL_VALUE = "application/graphql+json"; + /** + * Public constant media type for {@code application/json}. + */ + public static final MediaType APPLICATION_JSON; + /** + * A String equivalent of {@link MediaType#APPLICATION_JSON}. + * + * @see #APPLICATION_JSON_UTF8_VALUE + */ + public static final String APPLICATION_JSON_VALUE = "application/json"; + /** + * Public constant media type for {@code application/json;charset=UTF-8}. + * + * @deprecated as of 5.2 in favor of {@link #APPLICATION_JSON} + * since major browsers like Chrome + * + * now comply with the specification and interpret correctly UTF-8 special + * characters without requiring a {@code charset=UTF-8} parameter. + */ + @Deprecated + public static final MediaType APPLICATION_JSON_UTF8; + /** + * A String equivalent of {@link MediaType#APPLICATION_JSON_UTF8}. + * + * @deprecated as of 5.2 in favor of {@link #APPLICATION_JSON_VALUE} + * since major browsers like Chrome + * + * now comply with the specification and interpret correctly UTF-8 special + * characters without requiring a {@code charset=UTF-8} parameter. + */ + @Deprecated + public static final String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8"; + /** + * Public constant media type for {@code application/octet-stream}. + */ + public static final MediaType APPLICATION_OCTET_STREAM; + /** + * A String equivalent of {@link MediaType#APPLICATION_OCTET_STREAM}. + */ + public static final String APPLICATION_OCTET_STREAM_VALUE = "application/octet-stream"; + /** + * Public constant media type for {@code application/pdf}. + * + * @since 4.3 + */ + public static final MediaType APPLICATION_PDF; + /** + * A String equivalent of {@link MediaType#APPLICATION_PDF}. + * + * @since 4.3 + */ + public static final String APPLICATION_PDF_VALUE = "application/pdf"; + /** + * Public constant media type for {@code application/problem+json}. + * + * @see + * Problem Details for HTTP APIs, 6.1. application/problem+json + * @since 5.0 + */ + public static final MediaType APPLICATION_PROBLEM_JSON; + /** + * A String equivalent of {@link MediaType#APPLICATION_PROBLEM_JSON}. + * + * @since 5.0 + */ + public static final String APPLICATION_PROBLEM_JSON_VALUE = "application/problem+json"; + /** + * Public constant media type for {@code application/problem+json}. + * + * @see + * Problem Details for HTTP APIs, 6.1. application/problem+json + * @since 5.0 + * @deprecated as of 5.2 in favor of {@link #APPLICATION_PROBLEM_JSON} + * since major browsers like Chrome + * + * now comply with the specification and interpret correctly UTF-8 special + * characters without requiring a {@code charset=UTF-8} parameter. + */ + @Deprecated + public static final MediaType APPLICATION_PROBLEM_JSON_UTF8; + /** + * A String equivalent of {@link MediaType#APPLICATION_PROBLEM_JSON_UTF8}. + * + * @since 5.0 + * @deprecated as of 5.2 in favor of {@link #APPLICATION_PROBLEM_JSON_VALUE} + * since major browsers like Chrome + * + * now comply with the specification and interpret correctly UTF-8 special + * characters without requiring a {@code charset=UTF-8} parameter. + */ + @Deprecated + public static final String APPLICATION_PROBLEM_JSON_UTF8_VALUE = + "application/problem+json;charset=UTF-8"; + /** + * Public constant media type for {@code application/problem+xml}. + * + * @see + * Problem Details for HTTP APIs, 6.2. application/problem+xml + * @since 5.0 + */ + public static final MediaType APPLICATION_PROBLEM_XML; + /** + * A String equivalent of {@link MediaType#APPLICATION_PROBLEM_XML}. + * + * @since 5.0 + */ + public static final String APPLICATION_PROBLEM_XML_VALUE = "application/problem+xml"; + /** + * Public constant media type for {@code application/rss+xml}. + * + * @since 4.3.6 + */ + public static final MediaType APPLICATION_RSS_XML; + /** + * A String equivalent of {@link MediaType#APPLICATION_RSS_XML}. + * + * @since 4.3.6 + */ + public static final String APPLICATION_RSS_XML_VALUE = "application/rss+xml"; + /** + * Public constant media type for {@code application/x-ndjson}. + * + * @since 5.3 + */ + public static final MediaType APPLICATION_NDJSON; + /** + * A String equivalent of {@link MediaType#APPLICATION_NDJSON}. + * + * @since 5.3 + */ + public static final String APPLICATION_NDJSON_VALUE = "application/x-ndjson"; + /** + * Public constant media type for {@code application/stream+json}. + * + * @since 5.0 + * @deprecated as of 5.3, see notice on {@link #APPLICATION_STREAM_JSON_VALUE}. + */ + @Deprecated + public static final MediaType APPLICATION_STREAM_JSON; + /** + * A String equivalent of {@link MediaType#APPLICATION_STREAM_JSON}. + * + * @since 5.0 + * @deprecated as of 5.3 since it originates from the W3C Activity Streams + * specification which has a more specific purpose and has been since + * replaced with a different mime type. Use {@link #APPLICATION_NDJSON} as + * a replacement or any other line-delimited JSON format (e.g. JSON Lines, + * JSON Text Sequences). + */ + @Deprecated + public static final String APPLICATION_STREAM_JSON_VALUE = "application/stream+json"; + /** + * Public constant media type for {@code application/xhtml+xml}. + */ + public static final MediaType APPLICATION_XHTML_XML; + /** + * A String equivalent of {@link MediaType#APPLICATION_XHTML_XML}. + */ + public static final String APPLICATION_XHTML_XML_VALUE = "application/xhtml+xml"; + /** + * Public constant media type for {@code application/xml}. + */ + public static final MediaType APPLICATION_XML; + /** + * A String equivalent of {@link MediaType#APPLICATION_XML}. + */ + public static final String APPLICATION_XML_VALUE = "application/xml"; + /** + * Public constant media type for {@code image/gif}. + */ + public static final MediaType IMAGE_GIF; + /** + * A String equivalent of {@link MediaType#IMAGE_GIF}. + */ + public static final String IMAGE_GIF_VALUE = "image/gif"; + /** + * Public constant media type for {@code image/jpeg}. + */ + public static final MediaType IMAGE_JPEG; + /** + * A String equivalent of {@link MediaType#IMAGE_JPEG}. + */ + public static final String IMAGE_JPEG_VALUE = "image/jpeg"; + /** + * Public constant media type for {@code image/png}. + */ + public static final MediaType IMAGE_PNG; + /** + * A String equivalent of {@link MediaType#IMAGE_PNG}. + */ + public static final String IMAGE_PNG_VALUE = "image/png"; + /** + * Public constant media type for {@code multipart/form-data}. + */ + public static final MediaType MULTIPART_FORM_DATA; + /** + * A String equivalent of {@link MediaType#MULTIPART_FORM_DATA}. + */ + public static final String MULTIPART_FORM_DATA_VALUE = "multipart/form-data"; + /** + * Public constant media type for {@code multipart/mixed}. + * + * @since 5.2 + */ + public static final MediaType MULTIPART_MIXED; + /** + * A String equivalent of {@link MediaType#MULTIPART_MIXED}. + * + * @since 5.2 + */ + public static final String MULTIPART_MIXED_VALUE = "multipart/mixed"; + /** + * Public constant media type for {@code multipart/related}. + * + * @since 5.2.5 + */ + public static final MediaType MULTIPART_RELATED; + /** + * A String equivalent of {@link MediaType#MULTIPART_RELATED}. + * + * @since 5.2.5 + */ + public static final String MULTIPART_RELATED_VALUE = "multipart/related"; + /** + * Public constant media type for {@code text/event-stream}. + * + * @see Server-Sent Events W3C recommendation + * @since 4.3.6 + */ + public static final MediaType TEXT_EVENT_STREAM; + /** + * A String equivalent of {@link MediaType#TEXT_EVENT_STREAM}. + * + * @since 4.3.6 + */ + public static final String TEXT_EVENT_STREAM_VALUE = "text/event-stream"; + /** + * Public constant media type for {@code text/html}. + */ + public static final MediaType TEXT_HTML; + /** + * A String equivalent of {@link MediaType#TEXT_HTML}. + */ + public static final String TEXT_HTML_VALUE = "text/html"; + /** + * Public constant media type for {@code text/markdown}. + * + * @since 4.3 + */ + public static final MediaType TEXT_MARKDOWN; + /** + * A String equivalent of {@link MediaType#TEXT_MARKDOWN}. + * + * @since 4.3 + */ + public static final String TEXT_MARKDOWN_VALUE = "text/markdown"; + /** + * Public constant media type for {@code text/plain}. + */ + public static final MediaType TEXT_PLAIN; + /** + * A String equivalent of {@link MediaType#TEXT_PLAIN}. + */ + public static final String TEXT_PLAIN_VALUE = "text/plain"; + /** + * Public constant media type for {@code text/xml}. + */ + public static final MediaType TEXT_XML; + /** + * A String equivalent of {@link MediaType#TEXT_XML}. + */ + public static final String TEXT_XML_VALUE = "text/xml"; + private static final long serialVersionUID = 2069937152339670231L; + private static final String PARAM_QUALITY_FACTOR = "q"; + /** + * Comparator used by {@link #sortByQualityValue(List)}. + */ + public static final Comparator QUALITY_VALUE_COMPARATOR = (mediaType1, mediaType2) -> { + double quality1 = mediaType1.getQualityValue(); + double quality2 = mediaType2.getQualityValue(); + int qualityComparison = Double.compare(quality2, quality1); + if (qualityComparison != 0) { + return qualityComparison; // audio/*;q=0.7 < audio/*;q=0.3 + } else if (mediaType1.isWildcardType() && !mediaType2.isWildcardType()) { // */* < audio/* + return 1; + } else if (mediaType2.isWildcardType() && !mediaType1.isWildcardType()) { // audio/* > */* + return -1; + } else if (!mediaType1.getType().equals(mediaType2.getType())) { // audio/basic == text/html + return 0; + } else { // mediaType1.getType().equals(mediaType2.getType()) + if (mediaType1.isWildcardSubtype() && !mediaType2.isWildcardSubtype()) { + // audio/* < audio/basic + return 1; + } else if (mediaType2.isWildcardSubtype() && !mediaType1.isWildcardSubtype()) { + // audio/basic > audio/* + return -1; + } else if (!mediaType1.getSubtype().equals(mediaType2.getSubtype())) { + // audio/basic == audio/wave + return 0; + } else { + int paramsSize1 = mediaType1.getParameters().size(); + int paramsSize2 = mediaType2.getParameters().size(); + return Integer.compare(paramsSize2, paramsSize1); // audio/basic;level=1 < audio/basic + } + } + }; + /** + * Comparator used by {@link #sortBySpecificity(List)}. + */ + public static final Comparator SPECIFICITY_COMPARATOR = + new SpecificityComparator() { + + @Override + protected int compareParameters(MediaType mediaType1, MediaType mediaType2) { + double quality1 = mediaType1.getQualityValue(); + double quality2 = mediaType2.getQualityValue(); + int qualityComparison = Double.compare(quality2, quality1); + if (qualityComparison != 0) { + return qualityComparison; // audio/*;q=0.7 < audio/*;q=0.3 + } + return super.compareParameters(mediaType1, mediaType2); + } + }; + + static { + // Not using "valueOf' to avoid static init cost + ALL = new MediaType("*", "*"); + APPLICATION_ATOM_XML = new MediaType("application", "atom+xml"); + APPLICATION_CBOR = new MediaType("application", "cbor"); + APPLICATION_FORM_URLENCODED = new MediaType("application", "x-www-form-urlencoded"); + APPLICATION_GRAPHQL = new MediaType("application", "graphql+json"); + APPLICATION_JSON = new MediaType("application", "json"); + APPLICATION_JSON_UTF8 = new MediaType("application", "json", StandardCharsets.UTF_8); + APPLICATION_NDJSON = new MediaType("application", "x-ndjson"); + APPLICATION_OCTET_STREAM = new MediaType("application", "octet-stream"); + APPLICATION_PDF = new MediaType("application", "pdf"); + APPLICATION_PROBLEM_JSON = new MediaType("application", "problem+json"); + APPLICATION_PROBLEM_JSON_UTF8 = new MediaType("application", "problem+json", + StandardCharsets.UTF_8); + APPLICATION_PROBLEM_XML = new MediaType("application", "problem+xml"); + APPLICATION_RSS_XML = new MediaType("application", "rss+xml"); + APPLICATION_STREAM_JSON = new MediaType("application", "stream+json"); + APPLICATION_XHTML_XML = new MediaType("application", "xhtml+xml"); + APPLICATION_XML = new MediaType("application", "xml"); + IMAGE_GIF = new MediaType("image", "gif"); + IMAGE_JPEG = new MediaType("image", "jpeg"); + IMAGE_PNG = new MediaType("image", "png"); + MULTIPART_FORM_DATA = new MediaType("multipart", "form-data"); + MULTIPART_MIXED = new MediaType("multipart", "mixed"); + MULTIPART_RELATED = new MediaType("multipart", "related"); + TEXT_EVENT_STREAM = new MediaType("text", "event-stream"); + TEXT_HTML = new MediaType("text", "html"); + TEXT_MARKDOWN = new MediaType("text", "markdown"); + TEXT_PLAIN = new MediaType("text", "plain"); + TEXT_XML = new MediaType("text", "xml"); + } + + /** + * Create a new {@code MediaType} for the given primary type. + *

The {@linkplain #getSubtype() subtype} is set to "*", parameters empty. + * + * @param type the primary type + * @throws IllegalArgumentException if any of the parameters contain illegal characters + */ + public MediaType(String type) { + super(type); + } + + /** + * Create a new {@code MediaType} for the given primary type and subtype. + *

The parameters are empty. + * + * @param type the primary type + * @param subtype the subtype + * @throws IllegalArgumentException if any of the parameters contain illegal characters + */ + public MediaType(String type, String subtype) { + super(type, subtype, Collections.emptyMap()); + } + + /** + * Create a new {@code MediaType} for the given type, subtype, and character set. + * + * @param type the primary type + * @param subtype the subtype + * @param charset the character set + * @throws IllegalArgumentException if any of the parameters contain illegal characters + */ + public MediaType(String type, String subtype, Charset charset) { + super(type, subtype, charset); + } + + /** + * Create a new {@code MediaType} for the given type, subtype, and quality value. + * + * @param type the primary type + * @param subtype the subtype + * @param qualityValue the quality value + * @throws IllegalArgumentException if any of the parameters contain illegal characters + */ + public MediaType(String type, String subtype, double qualityValue) { + this(type, subtype, Collections.singletonMap(PARAM_QUALITY_FACTOR, + Double.toString(qualityValue))); + } + + /** + * Copy-constructor that copies the type, subtype and parameters of the given + * {@code MediaType}, and allows to set the specified character set. + * + * @param other the other media type + * @param charset the character set + * @throws IllegalArgumentException if any of the parameters contain illegal characters + * @since 4.3 + */ + public MediaType(MediaType other, Charset charset) { + super(other, charset); + } + + /** + * Copy-constructor that copies the type and subtype of the given {@code MediaType}, + * and allows for different parameters. + * + * @param other the other media type + * @param parameters the parameters, may be {@code null} + * @throws IllegalArgumentException if any of the parameters contain illegal characters + */ + public MediaType(MediaType other, @Nullable Map parameters) { + super(other.getType(), other.getSubtype(), parameters); + } + + + /** + * Create a new {@code MediaType} for the given type, subtype, and parameters. + * + * @param type the primary type + * @param subtype the subtype + * @param parameters the parameters, may be {@code null} + * @throws IllegalArgumentException if any of the parameters contain illegal characters + */ + public MediaType(String type, String subtype, @Nullable Map parameters) { + super(type, subtype, parameters); + } + + /** + * Create a new {@code MediaType} for the given {@link MimeType}. + * The type, subtype and parameters information is copied and {@code MediaType}-specific + * checks on parameters are performed. + * + * @param mimeType the MIME type + * @throws IllegalArgumentException if any of the parameters contain illegal characters + * @since 5.3 + */ + public MediaType(MimeType mimeType) { + super(mimeType); + getParameters().forEach(this::checkParameters); + } + + /** + * Parse the given String value into a {@code MediaType} object, + * with this method name following the 'valueOf' naming convention + * (as supported by {@link org.springframework.core.convert.ConversionService}. + * + * @param value the string to parse + * @throws InvalidMediaTypeException if the media type value cannot be parsed + * @see #parseMediaType(String) + */ + public static MediaType valueOf(String value) { + return parseMediaType(value); + } + + /** + * Parse the given String into a single {@code MediaType}. + * + * @param mediaType the string to parse + * @return the media type + * @throws InvalidMediaTypeException if the media type value cannot be parsed + */ + public static MediaType parseMediaType(String mediaType) { + MimeType type; + try { + type = MimeTypeUtils.parseMimeType(mediaType); + } catch (InvalidMimeTypeException ex) { + throw new InvalidMediaTypeException(ex); + } + try { + return new MediaType(type); + } catch (IllegalArgumentException ex) { + throw new InvalidMediaTypeException(mediaType, ex.getMessage()); + } + } + + /** + * Parse the comma-separated string into a list of {@code MediaType} objects. + *

This method can be used to parse an Accept or Content-Type header. + * + * @param mediaTypes the string to parse + * @return the list of media types + * @throws InvalidMediaTypeException if the media type value cannot be parsed + */ + public static List parseMediaTypes(@Nullable String mediaTypes) { + if (!StringUtils.hasLength(mediaTypes)) { + return Collections.emptyList(); + } + // Avoid using java.util.stream.Stream in hot paths + List tokenizedTypes = MimeTypeUtils.tokenize(mediaTypes); + List result = new ArrayList<>(tokenizedTypes.size()); + for (String type : tokenizedTypes) { + if (StringUtils.hasText(type)) { + result.add(parseMediaType(type)); + } + } + return result; + } + + /** + * Parse the given list of (potentially) comma-separated strings into a + * list of {@code MediaType} objects. + *

This method can be used to parse an Accept or Content-Type header. + * + * @param mediaTypes the string to parse + * @return the list of media types + * @throws InvalidMediaTypeException if the media type value cannot be parsed + * @since 4.3.2 + */ + public static List parseMediaTypes(@Nullable List mediaTypes) { + if (CollectionUtils.isEmpty(mediaTypes)) { + return Collections.emptyList(); + } else if (mediaTypes.size() == 1) { + return parseMediaTypes(mediaTypes.get(0)); + } else { + List result = new ArrayList<>(8); + for (String mediaType : mediaTypes) { + result.addAll(parseMediaTypes(mediaType)); + } + return result; + } + } + + /** + * Re-create the given mime types as media types. + * + * @since 5.0 + */ + public static List asMediaTypes(List mimeTypes) { + List mediaTypes = new ArrayList<>(mimeTypes.size()); + for (MimeType mimeType : mimeTypes) { + mediaTypes.add(MediaType.asMediaType(mimeType)); + } + return mediaTypes; + } + + /** + * Re-create the given mime type as a media type. + * + * @since 5.0 + */ + public static MediaType asMediaType(MimeType mimeType) { + if (mimeType instanceof MediaType) { + return (MediaType) mimeType; + } + return new MediaType(mimeType.getType(), mimeType.getSubtype(), mimeType.getParameters()); + } + + /** + * Return a string representation of the given list of {@code MediaType} objects. + *

This method can be used to for an {@code Accept} or {@code Content-Type} header. + * + * @param mediaTypes the media types to create a string representation for + * @return the string representation + */ + public static String toString(Collection mediaTypes) { + return MimeTypeUtils.toString(mediaTypes); + } + + /** + * Sorts the given list of {@code MediaType} objects by specificity. + *

Given two media types: + *

    + *
  1. if either media type has a {@linkplain #isWildcardType() wildcard type}, + * then the media type without the wildcard is ordered before the other.
  2. + *
  3. if the two media types have different {@linkplain #getType() types}, + * then they are considered equal and remain their current order.
  4. + *
  5. if either media type has a {@linkplain #isWildcardSubtype() wildcard subtype}, + * then the media type without the wildcard is sorted before the other.
  6. + *
  7. if the two media types have different {@linkplain #getSubtype() subtypes}, + * then they are considered equal and remain their current order.
  8. + *
  9. if the two media types have different {@linkplain #getQualityValue() quality value}, + * then the media type with the highest quality value is ordered before the other.
  10. + *
  11. if the two media types have a different amount of + * {@linkplain #getParameter(String) parameters}, then the + * media type with the most parameters is ordered before the other.
  12. + *
+ *

For example: + *

audio/basic < audio/* < */*
+ *
audio/* < audio/*;q=0.7; audio/*;q=0.3
+ *
audio/basic;level=1 < audio/basic
+ *
audio/basic == text/html
+ *
audio/basic == audio/wave
+ * + * @param mediaTypes the list of media types to be sorted + * @see HTTP 1.1: Semantics + * and Content, section 5.3.2 + */ + public static void sortBySpecificity(List mediaTypes) { + Assert.notNull(mediaTypes, "'mediaTypes' must not be null"); + if (mediaTypes.size() > 1) { + mediaTypes.sort(SPECIFICITY_COMPARATOR); + } + } + + /** + * Sorts the given list of {@code MediaType} objects by quality value. + *

Given two media types: + *

    + *
  1. if the two media types have different {@linkplain #getQualityValue() quality value}, + * then the media type with the highest quality value is ordered before the other.
  2. + *
  3. if either media type has a {@linkplain #isWildcardType() wildcard type}, + * then the media type without the wildcard is ordered before the other.
  4. + *
  5. if the two media types have different {@linkplain #getType() types}, + * then they are considered equal and remain their current order.
  6. + *
  7. if either media type has a {@linkplain #isWildcardSubtype() wildcard subtype}, + * then the media type without the wildcard is sorted before the other.
  8. + *
  9. if the two media types have different {@linkplain #getSubtype() subtypes}, + * then they are considered equal and remain their current order.
  10. + *
  11. if the two media types have a different amount of + * {@linkplain #getParameter(String) parameters}, then the + * media type with the most parameters is ordered before the other.
  12. + *
+ * + * @param mediaTypes the list of media types to be sorted + * @see #getQualityValue() + */ + public static void sortByQualityValue(List mediaTypes) { + Assert.notNull(mediaTypes, "'mediaTypes' must not be null"); + if (mediaTypes.size() > 1) { + mediaTypes.sort(QUALITY_VALUE_COMPARATOR); + } + } + + /** + * Sorts the given list of {@code MediaType} objects by specificity as the + * primary criteria and quality value the secondary. + * + * @see MediaType#sortBySpecificity(List) + * @see MediaType#sortByQualityValue(List) + */ + public static void sortBySpecificityAndQuality(List mediaTypes) { + Assert.notNull(mediaTypes, "'mediaTypes' must not be null"); + if (mediaTypes.size() > 1) { + mediaTypes.sort( + MediaType.SPECIFICITY_COMPARATOR.thenComparing(MediaType.QUALITY_VALUE_COMPARATOR)); + } + } + + @Override + protected void checkParameters(String parameter, String value) { + super.checkParameters(parameter, value); + if (PARAM_QUALITY_FACTOR.equals(parameter)) { + String unquotedValue = unquote(value); + double d = Double.parseDouble(unquotedValue); + Assert.isTrue(d >= 0D && d <= 1D, + () -> "Invalid quality value \"" + unquotedValue + "\": should be between 0.0 and 1.0"); + } + } + + /** + * Return the quality factor, as indicated by a {@code q} parameter, if any. + * Defaults to {@code 1.0}. + * + * @return the quality factor as double value + */ + public double getQualityValue() { + String qualityFactor = getParameter(PARAM_QUALITY_FACTOR); + return (qualityFactor != null ? Double.parseDouble(unquote(qualityFactor)) : 1D); + } + + /** + * Indicate whether this {@code MediaType} includes the given media type. + *

For instance, {@code text/*} includes {@code text/plain} and {@code text/html}, + * and {@code application/*+xml} includes {@code application/soap+xml}, etc. + * This method is not symmetric. + *

Simply calls {@link MimeType#includes(MimeType)} but declared with a + * {@code MediaType} parameter for binary backwards compatibility. + * + * @param other the reference media type with which to compare + * @return {@code true} if this media type includes the given media type; + * {@code false} otherwise + */ + public boolean includes(@Nullable MediaType other) { + return super.includes(other); + } + + /** + * Indicate whether this {@code MediaType} is compatible with the given media type. + *

For instance, {@code text/*} is compatible with {@code text/plain}, + * {@code text/html}, and vice versa. In effect, this method is similar to + * {@link #includes}, except that it is symmetric. + *

Simply calls {@link MimeType#isCompatibleWith(MimeType)} but declared with a + * {@code MediaType} parameter for binary backwards compatibility. + * + * @param other the reference media type with which to compare + * @return {@code true} if this media type is compatible with the given media type; + * {@code false} otherwise + */ + public boolean isCompatibleWith(@Nullable MediaType other) { + return super.isCompatibleWith(other); + } + + /** + * Return a replica of this instance with the quality value of the given {@code MediaType}. + * + * @return the same instance if the given MediaType doesn't have a quality value, + * or a new one otherwise + */ + public MediaType copyQualityValue(MediaType mediaType) { + if (!mediaType.getParameters().containsKey(PARAM_QUALITY_FACTOR)) { + return this; + } + Map params = new LinkedHashMap<>(getParameters()); + params.put(PARAM_QUALITY_FACTOR, mediaType.getParameters().get(PARAM_QUALITY_FACTOR)); + return new MediaType(this, params); + } + + /** + * Return a replica of this instance with its quality value removed. + * + * @return the same instance if the media type doesn't contain a quality value, + * or a new one otherwise + */ + public MediaType removeQualityValue() { + if (!getParameters().containsKey(PARAM_QUALITY_FACTOR)) { + return this; + } + Map params = new LinkedHashMap<>(getParameters()); + params.remove(PARAM_QUALITY_FACTOR); + return new MediaType(this, params); + } + +} \ No newline at end of file diff --git a/framework/src/test/java/org/tron/common/runtime/vm/Create2Test.java b/framework/src/test/java/org/tron/common/runtime/vm/Create2Test.java index f400b3215ee..6fa2801c51f 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/Create2Test.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/Create2Test.java @@ -19,9 +19,9 @@ import org.tron.core.Wallet; import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; -import org.tron.core.exception.JsonRpcInvalidParamsException; import org.tron.core.exception.ReceiptCheckErrException; import org.tron.core.exception.VMIllegalException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; import org.tron.core.services.NodeInfoService; import org.tron.core.services.jsonrpc.TronJsonRpcImpl; import org.tron.core.vm.config.ConfigLoader; diff --git a/framework/src/test/java/org/tron/common/storage/leveldb/LevelDbDataSourceImplTest.java b/framework/src/test/java/org/tron/common/storage/leveldb/LevelDbDataSourceImplTest.java index bf18b988f19..c8b29c3020d 100644 --- a/framework/src/test/java/org/tron/common/storage/leveldb/LevelDbDataSourceImplTest.java +++ b/framework/src/test/java/org/tron/common/storage/leveldb/LevelDbDataSourceImplTest.java @@ -28,6 +28,7 @@ import com.google.common.collect.Sets; import java.io.File; import java.io.IOException; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -38,15 +39,24 @@ import java.util.Set; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import org.iq80.leveldb.DBException; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import org.rocksdb.RocksDB; +import org.tron.common.parameter.CommonParameter; +import org.tron.common.storage.WriteOptionsWrapper; +import org.tron.common.storage.rocksdb.RocksDbDataSourceImpl; import org.tron.common.utils.ByteArray; import org.tron.common.utils.FileUtil; +import org.tron.common.utils.PropUtil; import org.tron.common.utils.PublicMethod; +import org.tron.common.utils.StorageUtils; import org.tron.core.Constant; import org.tron.core.config.args.Args; import org.tron.core.db2.common.WrappedByteArray; @@ -73,6 +83,14 @@ public class LevelDbDataSourceImplTest { private byte[] key5 = "00000005aa".getBytes(); private byte[] key6 = "00000006aa".getBytes(); + + @Rule + public final ExpectedException exception = ExpectedException.none(); + + static { + RocksDB.loadLibrary(); + } + /** * Release resources. */ @@ -102,8 +120,19 @@ public void testPutGet() { assertNotNull(dataSourceTest.getData(key)); assertEquals(1, dataSourceTest.allKeys().size()); + assertEquals(1, dataSourceTest.getTotal()); + assertEquals(1, dataSourceTest.allValues().size()); assertEquals("50000", ByteArray.toStr(dataSourceTest.getData(key1.getBytes()))); + dataSourceTest.deleteData(key); + assertNull(dataSourceTest.getData(key)); + assertEquals(0, dataSourceTest.getTotal()); + dataSourceTest.iterator().forEachRemaining(entry -> Assert.fail("iterator should be empty")); + dataSourceTest.stream().forEach(entry -> Assert.fail("stream should be empty")); + dataSourceTest.stat(); dataSourceTest.closeDB(); + dataSourceTest.stat(); // stat again + exception.expect(DBException.class); + dataSourceTest.deleteData(key); } @Test @@ -142,6 +171,23 @@ public void testupdateByBatchInner() { assertEquals("50000", ByteArray.toStr(dataSource.getData(key1.getBytes()))); assertEquals("10000", ByteArray.toStr(dataSource.getData(key2.getBytes()))); assertEquals(2, dataSource.allKeys().size()); + + rows.clear(); + rows.put(key1.getBytes(), null); + rows.put(key2.getBytes(), null); + dataSource.updateByBatch(rows, WriteOptionsWrapper.getInstance()); + assertEquals(0, dataSource.allKeys().size()); + + rows.clear(); + rows.put(key1.getBytes(), value1.getBytes()); + rows.put(key2.getBytes(), null); + dataSource.updateByBatch(rows); + assertEquals("50000", ByteArray.toStr(dataSource.getData(key1.getBytes()))); + assertEquals(1, dataSource.allKeys().size()); + rows.clear(); + rows.put(null, null); + exception.expect(RuntimeException.class); + dataSource.updateByBatch(rows); dataSource.closeDB(); } @@ -354,6 +400,118 @@ public void initDbTest() { assertEquals(TronError.ErrCode.LEVELDB_INIT, thrown.getErrCode()); } + @Test + public void testCheckOrInitEngine() { + String dir = + Args.getInstance().getOutputDirectory() + Args.getInstance().getStorage().getDbDirectory(); + String enginePath = dir + File.separator + "test_engine" + File.separator + "engine.properties"; + FileUtil.createDirIfNotExists(dir + File.separator + "test_engine"); + FileUtil.createFileIfNotExists(enginePath); + PropUtil.writeProperty(enginePath, "ENGINE", "LEVELDB"); + Assert.assertEquals("LEVELDB", PropUtil.readProperty(enginePath, "ENGINE")); + + LevelDbDataSourceImpl dataSource; + dataSource = new LevelDbDataSourceImpl(dir, "test_engine"); + dataSource.initDB(); + dataSource.closeDB(); + + System.gc(); + PropUtil.writeProperty(enginePath, "ENGINE", "ROCKSDB"); + Assert.assertEquals("ROCKSDB", PropUtil.readProperty(enginePath, "ENGINE")); + try { + dataSource = new LevelDbDataSourceImpl(dir, "test_engine"); + dataSource.initDB(); + } catch (Exception e) { + Assert.assertEquals(String.format( + "Cannot open RocksDB database '%s' with LevelDB engine." + + " Set db.engine=ROCKSDB or use LevelDB database. ", "test_engine"), + e.getMessage()); + } + } + + @Test + public void testLevelDbOpenRocksDb() { + String name = "test_openRocksDb"; + String output = Paths + .get(StorageUtils.getOutputDirectoryByDbName(name), CommonParameter + .getInstance().getStorage().getDbDirectory()).toString(); + RocksDbDataSourceImpl rocksDb = new RocksDbDataSourceImpl(output, name); + rocksDb.initDB(); + rocksDb.putData(key1, value1); + rocksDb.closeDB(); + LevelDbDataSourceImpl levelDB = + new LevelDbDataSourceImpl(StorageUtils.getOutputDirectoryByDbName(name), name); + exception.expectMessage(String.format( + "Cannot open RocksDB database '%s' with LevelDB engine." + + " Set db.engine=ROCKSDB or use LevelDB database. ", name)); + levelDB.initDB(); + } + + @Test + public void testNewInstance() { + dataSourceTest.closeDB(); + LevelDbDataSourceImpl newInst = dataSourceTest.newInstance(); + newInst.initDB(); + assertFalse(newInst.flush()); + newInst.closeDB(); + LevelDbDataSourceImpl empty = new LevelDbDataSourceImpl(); + empty.setDBName("empty"); + assertEquals("empty", empty.getDBName()); + String name = "newInst2"; + LevelDbDataSourceImpl newInst2 = new LevelDbDataSourceImpl( + StorageUtils.getOutputDirectoryByDbName(name), + name); + newInst2.initDB(); + newInst2.closeDB(); + } + + @Test + public void testGetNext() { + LevelDbDataSourceImpl dataSource = new LevelDbDataSourceImpl( + Args.getInstance().getOutputDirectory(), "test_getNext_key"); + dataSource.initDB(); + dataSource.resetDb(); + putSomeKeyValue(dataSource); + // case: normal + Map seekKvLimitNext = dataSource.getNext("0000000300".getBytes(), 2); + Map hashMap = Maps.newHashMap(); + hashMap.put(ByteArray.toStr(key3), ByteArray.toStr(value3)); + hashMap.put(ByteArray.toStr(key4), ByteArray.toStr(value4)); + seekKvLimitNext.forEach((key, value) -> { + String keyStr = ByteArray.toStr(key); + Assert.assertTrue("getNext", hashMap.containsKey(keyStr)); + Assert.assertEquals(ByteArray.toStr(value), hashMap.get(keyStr)); + }); + // case: targetKey greater than all existed keys + seekKvLimitNext = dataSource.getNext("0000000700".getBytes(), 2); + Assert.assertEquals(0, seekKvLimitNext.size()); + // case: limit<=0 + seekKvLimitNext = dataSource.getNext("0000000300".getBytes(), 0); + Assert.assertEquals(0, seekKvLimitNext.size()); + dataSource.resetDb(); + dataSource.closeDB(); + } + + @Test + public void testGetlatestValues() { + LevelDbDataSourceImpl dataSource = new LevelDbDataSourceImpl( + Args.getInstance().getOutputDirectory(), "test_getlatestValues_key"); + dataSource.initDB(); + dataSource.resetDb(); + putSomeKeyValue(dataSource); + // case: normal + Set seekKeyLimitNext = dataSource.getlatestValues(2); + Set hashSet = Sets.newHashSet(ByteArray.toStr(value5), ByteArray.toStr(value6)); + seekKeyLimitNext.forEach(value -> { + Assert.assertTrue(hashSet.contains(ByteArray.toStr(value))); + }); + // case: limit<=0 + seekKeyLimitNext = dataSource.getlatestValues(0); + assertEquals(0, seekKeyLimitNext.size()); + dataSource.resetDb(); + dataSource.closeDB(); + } + private void makeExceptionDb(String dbName) { LevelDbDataSourceImpl dataSource = new LevelDbDataSourceImpl( Args.getInstance().getOutputDirectory(), "test_initDb"); diff --git a/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java b/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java index c6fce30e3af..8f42c44e3b9 100644 --- a/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java +++ b/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java @@ -10,6 +10,8 @@ import com.google.common.collect.Sets; import java.io.File; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -24,13 +26,20 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import org.rocksdb.RocksDBException; +import org.tron.common.error.TronDBException; +import org.tron.common.parameter.CommonParameter; +import org.tron.common.storage.WriteOptionsWrapper; import org.tron.common.storage.rocksdb.RocksDbDataSourceImpl; import org.tron.common.utils.ByteArray; import org.tron.common.utils.FileUtil; import org.tron.common.utils.PropUtil; import org.tron.common.utils.PublicMethod; +import org.tron.common.utils.StorageUtils; import org.tron.core.config.args.Args; import org.tron.core.db2.common.WrappedByteArray; import org.tron.core.exception.TronError; @@ -55,6 +64,9 @@ public class RocksDbDataSourceImplTest { private byte[] key5 = "00000005aa".getBytes(); private byte[] key6 = "00000006aa".getBytes(); + @Rule + public final ExpectedException expectedException = ExpectedException.none(); + /** * Release resources. */ @@ -84,8 +96,18 @@ public void testPutGet() { assertNotNull(dataSourceTest.getData(key)); assertEquals(1, dataSourceTest.allKeys().size()); + assertEquals(1, dataSourceTest.getTotal()); + assertEquals(1, dataSourceTest.allValues().size()); assertEquals("50000", ByteArray.toStr(dataSourceTest.getData(key1.getBytes()))); + dataSourceTest.deleteData(key); + assertNull(dataSourceTest.getData(key)); + assertEquals(0, dataSourceTest.getTotal()); + dataSourceTest.iterator().forEachRemaining(entry -> Assert.fail("iterator should be empty")); + dataSourceTest.stat(); dataSourceTest.closeDB(); + dataSourceTest.stat(); // stat again + expectedException.expect(TronDBException.class); + dataSourceTest.deleteData(key); } @Test @@ -124,6 +146,23 @@ public void testupdateByBatchInner() { assertEquals("50000", ByteArray.toStr(dataSource.getData(key1.getBytes()))); assertEquals("10000", ByteArray.toStr(dataSource.getData(key2.getBytes()))); assertEquals(2, dataSource.allKeys().size()); + + rows.clear(); + rows.put(key1.getBytes(), null); + rows.put(key2.getBytes(), null); + dataSource.updateByBatch(rows, WriteOptionsWrapper.getInstance()); + assertEquals(0, dataSource.allKeys().size()); + + rows.clear(); + rows.put(key1.getBytes(), value1.getBytes()); + rows.put(key2.getBytes(), null); + dataSource.updateByBatch(rows); + assertEquals("50000", ByteArray.toStr(dataSource.getData(key1.getBytes()))); + assertEquals(1, dataSource.allKeys().size()); + rows.clear(); + rows.put(null, null); + expectedException.expect(RuntimeException.class); + dataSource.updateByBatch(rows); dataSource.closeDB(); } @@ -276,8 +315,9 @@ public void testCheckOrInitEngine() { try { dataSource.initDB(); } catch (Exception e) { - Assert.assertEquals(String.format("failed to check database: %s, engine do not match", - "test_engine"), + Assert.assertEquals(String.format( + "Cannot open LevelDB database '%s' with RocksDB engine." + + " Set db.engine=LEVELDB or use RocksDB database. ", "test_engine"), e.getMessage()); } Assert.assertNull(dataSource.getDatabase()); @@ -396,6 +436,103 @@ public void initDbTest() { assertEquals(TronError.ErrCode.ROCKSDB_INIT, thrown.getErrCode()); } + @Test + public void testRocksDbOpenLevelDb() { + String name = "test_openLevelDb"; + String output = Paths + .get(StorageUtils.getOutputDirectoryByDbName(name), CommonParameter + .getInstance().getStorage().getDbDirectory()).toString(); + LevelDbDataSourceImpl levelDb = new LevelDbDataSourceImpl( + StorageUtils.getOutputDirectoryByDbName(name), name); + levelDb.initDB(); + levelDb.putData(key1, value1); + levelDb.closeDB(); + RocksDbDataSourceImpl rocksDb = new RocksDbDataSourceImpl(output, name); + expectedException.expectMessage( + String.format( + "Cannot open LevelDB database '%s' with RocksDB engine." + + " Set db.engine=LEVELDB or use RocksDB database. ", name)); + rocksDb.initDB(); + } + + @Test + public void testRocksDbOpenLevelDb2() { + String name = "test_openLevelDb2"; + String output = Paths + .get(StorageUtils.getOutputDirectoryByDbName(name), CommonParameter + .getInstance().getStorage().getDbDirectory()).toString(); + LevelDbDataSourceImpl levelDb = new LevelDbDataSourceImpl( + StorageUtils.getOutputDirectoryByDbName(name), name); + levelDb.initDB(); + levelDb.putData(key1, value1); + levelDb.closeDB(); + // delete engine.properties file to simulate the case that db.engine is not set. + File engineFile = Paths + .get(output, name, "engine.properties").toFile(); + if (engineFile.exists()) { + engineFile.delete(); + } + Assert.assertFalse(engineFile.exists()); + RocksDbDataSourceImpl rocksDb = new RocksDbDataSourceImpl(output, name); + expectedException.expectMessage( + String.format( + "Cannot open LevelDB database '%s' with RocksDB engine." + + " Set db.engine=LEVELDB or use RocksDB database. ", name)); + rocksDb.initDB(); + } + + @Test + public void testNewInstance() { + dataSourceTest.closeDB(); + RocksDbDataSourceImpl newInst = dataSourceTest.newInstance(); + newInst.initDB(); + assertFalse(newInst.flush()); + newInst.closeDB(); + RocksDbDataSourceImpl empty = new RocksDbDataSourceImpl(); + empty.setDBName("empty"); + assertEquals("empty", empty.getDBName()); + String output = Paths + .get(StorageUtils.getOutputDirectoryByDbName("newInst2"), CommonParameter + .getInstance().getStorage().getDbDirectory()).toString(); + RocksDbDataSourceImpl newInst2 = new RocksDbDataSourceImpl(output, "newInst2"); + newInst2.initDB(); + newInst2.closeDB(); + } + + @Test + public void backupAndDelete() throws RocksDBException { + RocksDbDataSourceImpl dataSource = new RocksDbDataSourceImpl( + Args.getInstance().getOutputDirectory(), "backupAndDelete"); + dataSource.initDB(); + putSomeKeyValue(dataSource); + Path dir = Paths.get(Args.getInstance().getOutputDirectory(), "backup"); + String path = dir + File.separator; + FileUtil.createDirIfNotExists(path); + dataSource.backup(path); + File backDB = Paths.get(dir.toString(),dataSource.getDBName()).toFile(); + Assert.assertTrue(backDB.exists()); + dataSource.deleteDbBakPath(path); + Assert.assertFalse(backDB.exists()); + dataSource.closeDB(); + } + + @Test + public void testGetTotal() { + RocksDbDataSourceImpl dataSource = new RocksDbDataSourceImpl( + Args.getInstance().getOutputDirectory(), "test_getTotal_key"); + dataSource.initDB(); + dataSource.resetDb(); + + Map dataMapset = Maps.newHashMap(); + dataMapset.put(key1, value1); + dataMapset.put(key2, value2); + dataMapset.put(key3, value3); + dataMapset.forEach(dataSource::putData); + Assert.assertEquals(dataMapset.size(), dataSource.getTotal()); + dataSource.resetDb(); + dataSource.closeDB(); + } + private void makeExceptionDb(String dbName) { RocksDbDataSourceImpl dataSource = new RocksDbDataSourceImpl( Args.getInstance().getOutputDirectory(), "test_initDb"); diff --git a/framework/src/test/java/org/tron/common/utils/HashCodeTest.java b/framework/src/test/java/org/tron/common/utils/HashCodeTest.java new file mode 100644 index 00000000000..36f9435c1aa --- /dev/null +++ b/framework/src/test/java/org/tron/common/utils/HashCodeTest.java @@ -0,0 +1,23 @@ +package org.tron.common.utils; + +import java.util.Objects; +import org.junit.Assert; +import org.junit.Test; +import org.tron.core.capsule.AccountCapsule; +import org.tron.core.vm.repository.Type; +import org.tron.core.vm.repository.Value; +import org.tron.protos.Protocol; + +public class HashCodeTest { + + @Test + public void test() { + Type type = new Type(); + type.setType(Type.NORMAL); + Assert.assertEquals(Integer.valueOf(Type.NORMAL).hashCode(), type.hashCode()); + Protocol.Account account = Protocol.Account.newBuilder().setBalance(100).build(); + Value value = Value.create(new AccountCapsule(account.toByteArray())); + Assert.assertEquals(Integer.valueOf( + type.hashCode() + Objects.hashCode(account)).hashCode(), value.hashCode()); + } +} diff --git a/framework/src/test/java/org/tron/common/utils/ObjectSizeUtilTest.java b/framework/src/test/java/org/tron/common/utils/ObjectSizeUtilTest.java deleted file mode 100644 index c4c72991979..00000000000 --- a/framework/src/test/java/org/tron/common/utils/ObjectSizeUtilTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * java-tron is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * java-tron is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.tron.common.utils; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -public class ObjectSizeUtilTest { - - @Test - public void testGetObjectSize() { - - Person person = new Person(); - assertEquals(48, com.carrotsearch.sizeof.RamUsageEstimator.sizeOf(person)); - Person person1 = new Person(1, "tom", new int[]{}); - assertEquals(112, com.carrotsearch.sizeof.RamUsageEstimator.sizeOf(person1)); - - Person person2 = new Person(1, "tom", new int[]{100}); - assertEquals(120, com.carrotsearch.sizeof.RamUsageEstimator.sizeOf(person2)); - - Person person3 = new Person(1, "tom", new int[]{100, 100}); - assertEquals(120, com.carrotsearch.sizeof.RamUsageEstimator.sizeOf(person3)); - Person person4 = new Person(1, "tom", new int[]{100, 100, 100}); - assertEquals(128, com.carrotsearch.sizeof.RamUsageEstimator.sizeOf(person4)); - Person person5 = new Person(1, "tom", new int[]{100, 100, 100, 100}); - assertEquals(128, com.carrotsearch.sizeof.RamUsageEstimator.sizeOf(person5)); - Person person6 = new Person(1, "tom", new int[]{100, 100, 100, 100, 100}); - assertEquals(136, com.carrotsearch.sizeof.RamUsageEstimator.sizeOf(person6)); - - } - - class Person { - - int age; - String name; - int[] scores; - - public Person() { - } - - public Person(int age, String name, int[] scores) { - this.age = age; - this.name = name; - this.scores = scores; - } - } - -} diff --git a/framework/src/test/java/org/tron/common/utils/client/utils/TransactionUtils.java b/framework/src/test/java/org/tron/common/utils/client/utils/TransactionUtils.java index b6226d01aae..63ffe1b58ff 100644 --- a/framework/src/test/java/org/tron/common/utils/client/utils/TransactionUtils.java +++ b/framework/src/test/java/org/tron/common/utils/client/utils/TransactionUtils.java @@ -14,6 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +import static org.tron.core.capsule.TransactionCapsule.getBase64FromByteString; import com.google.protobuf.ByteString; import java.security.SignatureException; @@ -116,20 +117,6 @@ public static byte[] getOwner(Transaction.Contract contract) { } } - /** - * constructor. - */ - - public static String getBase64FromByteString(ByteString sign) { - byte[] r = sign.substring(0, 32).toByteArray(); - byte[] s = sign.substring(32, 64).toByteArray(); - byte v = sign.byteAt(64); - if (v < 27) { - v += 27; //revId -> v - } - ECDSASignature signature = ECDSASignature.fromComponents(r, s, v); - return signature.toBase64(); - } /* * 1. check hash diff --git a/framework/src/test/java/org/tron/core/CoreExceptionTest.java b/framework/src/test/java/org/tron/core/CoreExceptionTest.java index 89feaba338c..f82b0efe326 100644 --- a/framework/src/test/java/org/tron/core/CoreExceptionTest.java +++ b/framework/src/test/java/org/tron/core/CoreExceptionTest.java @@ -29,11 +29,6 @@ import org.tron.core.exception.HeaderNotFound; import org.tron.core.exception.HighFreqException; import org.tron.core.exception.ItemNotFoundException; -import org.tron.core.exception.JsonRpcInternalException; -import org.tron.core.exception.JsonRpcInvalidParamsException; -import org.tron.core.exception.JsonRpcInvalidRequestException; -import org.tron.core.exception.JsonRpcMethodNotFoundException; -import org.tron.core.exception.JsonRpcTooManyResultException; import org.tron.core.exception.NonCommonBlockException; import org.tron.core.exception.NonUniqueObjectException; import org.tron.core.exception.P2pException; @@ -56,6 +51,11 @@ import org.tron.core.exception.ValidateSignatureException; import org.tron.core.exception.ZkProofValidateException; import org.tron.core.exception.ZksnarkException; +import org.tron.core.exception.jsonrpc.JsonRpcInternalException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidRequestException; +import org.tron.core.exception.jsonrpc.JsonRpcMethodNotFoundException; +import org.tron.core.exception.jsonrpc.JsonRpcTooManyResultException; public class CoreExceptionTest { diff --git a/framework/src/test/java/org/tron/core/ShieldWalletTest.java b/framework/src/test/java/org/tron/core/ShieldWalletTest.java index f8d5db1a44c..6e35d600ce7 100644 --- a/framework/src/test/java/org/tron/core/ShieldWalletTest.java +++ b/framework/src/test/java/org/tron/core/ShieldWalletTest.java @@ -7,6 +7,7 @@ import java.math.BigInteger; import javax.annotation.Resource; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; import org.tron.api.GrpcAPI.PrivateParameters; import org.tron.api.GrpcAPI.PrivateParametersWithoutAsk; @@ -29,13 +30,14 @@ public class ShieldWalletTest extends BaseTest { @Resource private Wallet wallet; - static { - Args.setParam(new String[] {"-d", dbPath()}, Constant.TEST_CONF); + @BeforeClass + public static void init() { + Args.setParam(new String[]{"-d", dbPath()}, Constant.TEST_CONF); + librustzcashInitZksnarkParams(); } @Test public void testCreateShieldedTransaction1() { - librustzcashInitZksnarkParams(); String transactionStr1 = new String(ByteArray.fromHexString( "0x7b0a20202020227472616e73706172656e745f66726f6d5f61646472657373223a202234433930413" + "73241433344414546324536383932343545463430303839443634314345414337373433323433414233" @@ -68,7 +70,6 @@ public void testCreateShieldedTransaction1() { @Test public void testCreateShieldedTransaction2() { - librustzcashInitZksnarkParams(); String transactionStr2 = new String(ByteArray.fromHexString( "7b0a202020202261736b223a20223938666430333136376632333437623534643737323338343137663" + "6373038643537323939643938376362613838353564653037626532346236316464653064222c0a2020" @@ -176,7 +177,6 @@ public void testCreateShieldedTransaction2() { @Test public void testCreateShieldedTransactionWithoutSpendAuthSig() { - librustzcashInitZksnarkParams(); String transactionStr3 = new String(ByteArray.fromHexString( "7b0a2020202022616b223a2022373161643638633466353035373464356164333735343863626538363" + "63031663732393662393161306362303535353733313462373830383437323730326465222c0a202020" @@ -286,7 +286,6 @@ public void testCreateShieldedTransactionWithoutSpendAuthSig() { @Test public void testGetNewShieldedAddress() { - librustzcashInitZksnarkParams(); try { ShieldedAddressInfo shieldedAddressInfo = wallet.getNewShieldedAddress(); Assert.assertNotNull(shieldedAddressInfo); @@ -297,8 +296,7 @@ public void testGetNewShieldedAddress() { @Test public void testCreateShieldedContractParameters() throws ContractExeException { - librustzcashInitZksnarkParams(); - Args.getInstance().setFullNodeAllowShieldedTransactionArgs(true); + Args.getInstance().setAllowShieldedTransactionApi(true); Wallet wallet1 = spy(new Wallet()); doReturn(BigInteger.valueOf(1).toByteArray()) @@ -340,8 +338,7 @@ public void testCreateShieldedContractParameters() throws ContractExeException { @Test public void testCreateShieldedContractParameters2() throws ContractExeException { - librustzcashInitZksnarkParams(); - Args.getInstance().setFullNodeAllowShieldedTransactionArgs(true); + Args.getInstance().setAllowShieldedTransactionApi(true); Wallet wallet1 = spy(new Wallet()); doReturn(BigInteger.valueOf(1).toByteArray()) @@ -416,8 +413,7 @@ public void testCreateShieldedContractParameters2() throws ContractExeException @Test public void testCreateShieldedContractParametersWithoutAsk() throws ContractExeException { - librustzcashInitZksnarkParams(); - Args.getInstance().setFullNodeAllowShieldedTransactionArgs(true); + Args.getInstance().setAllowShieldedTransactionApi(true); Wallet wallet1 = spy(new Wallet()); doReturn(BigInteger.valueOf(1).toByteArray()) diff --git a/framework/src/test/java/org/tron/core/ShieldedTRC20BuilderTest.java b/framework/src/test/java/org/tron/core/ShieldedTRC20BuilderTest.java index 2c97473b6c3..c2c4bfe3006 100644 --- a/framework/src/test/java/org/tron/core/ShieldedTRC20BuilderTest.java +++ b/framework/src/test/java/org/tron/core/ShieldedTRC20BuilderTest.java @@ -1,7 +1,5 @@ package org.tron.core; -import static org.tron.core.zksnark.LibrustzcashTest.librustzcashInitZksnarkParams; - import com.google.protobuf.ByteString; import java.math.BigInteger; import java.util.Arrays; @@ -12,7 +10,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.bouncycastle.util.encoders.Hex; import org.junit.Assert; -import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.tron.api.GrpcAPI; @@ -68,7 +66,6 @@ public class ShieldedTRC20BuilderTest extends BaseTest { SHIELDED_CONTRACT_ADDRESS = WalletClient.decodeFromBase58Check(SHIELDED_CONTRACT_ADDRESS_STR); DEFAULT_OVK = ByteArray .fromHexString("030c8c2bc59fb3eb8afb047a8ea4b028743d23e7d38c6fa30908358431e2314d"); - ZksnarkInitService.librustzcashInitZksnarkParams(); PUBLIC_TO_ADDRESS = WalletClient.decodeFromBase58Check(PUBLIC_TO_ADDRESS_STR); } @@ -76,8 +73,9 @@ public class ShieldedTRC20BuilderTest extends BaseTest { VerifyTransferProof transferContract = new VerifyTransferProof(); VerifyBurnProof burnContract = new VerifyBurnProof(); - @Before - public void before() { + @BeforeClass + public static void initZksnarkParams() { + ZksnarkInitService.librustzcashInitZksnarkParams(); } @Ignore @@ -2172,7 +2170,6 @@ public void createShieldedContractParametersWithoutAskForBurn1to2() @Ignore @Test public void getTriggerInputForForMint() throws Exception { - librustzcashInitZksnarkParams(); SpendingKey sk = SpendingKey.random(); ExpandedSpendingKey expsk = sk.expandedSpendingKey(); byte[] ovk = expsk.getOvk(); @@ -2241,7 +2238,6 @@ public void getTriggerInputForForMint() throws Exception { public void testScanShieldedTRC20NotesByIvk() throws Exception { int statNum = 1; int endNum = 100; - librustzcashInitZksnarkParams(); SpendingKey sk = SpendingKey.decode(priKey); FullViewingKey fvk = sk.fullViewingKey(); byte[] ivk = fvk.inViewingKey().value; @@ -2273,7 +2269,6 @@ public void testscanShieldedTRC20NotesByOvk() throws Exception { public void isShieldedTRC20ContractNoteSpent() throws Exception { int statNum = 9200; int endNum = 9240; - librustzcashInitZksnarkParams(); SpendingKey sk = SpendingKey.decode(priKey); FullViewingKey fvk = sk.fullViewingKey(); byte[] ivk = fvk.inViewingKey().value; @@ -2350,7 +2345,6 @@ private byte[] decodePath(byte[] encodedPath) { private GrpcAPI.PrivateShieldedTRC20Parameters mintParams(String privKey, long value, String contractAddr, byte[] rcm) throws ZksnarkException, ContractValidateException { - librustzcashInitZksnarkParams(); long fromAmount = value; SpendingKey sk = SpendingKey.decode(privKey); ExpandedSpendingKey expsk = sk.expandedSpendingKey(); diff --git a/framework/src/test/java/org/tron/core/WalletMockTest.java b/framework/src/test/java/org/tron/core/WalletMockTest.java index 098ba9aee61..ab7ad7ba10c 100644 --- a/framework/src/test/java/org/tron/core/WalletMockTest.java +++ b/framework/src/test/java/org/tron/core/WalletMockTest.java @@ -835,7 +835,7 @@ public void testGetTriggerInputForShieldedTRC20Contract() { CommonParameter commonParameterMock = mock(Args.class); try (MockedStatic mockedStatic = mockStatic(CommonParameter.class)) { when(CommonParameter.getInstance()).thenReturn(commonParameterMock); - when(commonParameterMock.isFullNodeAllowShieldedTransactionArgs()).thenReturn(true); + when(commonParameterMock.isAllowShieldedTransactionApi()).thenReturn(true); assertThrows(ZksnarkException.class, () -> { wallet.getTriggerInputForShieldedTRC20Contract(triggerParam.build()); @@ -866,7 +866,7 @@ public void testGetTriggerInputForShieldedTRC20Contract1() CommonParameter commonParameterMock = mock(Args.class); try (MockedStatic mockedStatic = mockStatic(CommonParameter.class)) { when(CommonParameter.getInstance()).thenReturn(commonParameterMock); - when(commonParameterMock.isFullNodeAllowShieldedTransactionArgs()).thenReturn(true); + when(commonParameterMock.isAllowShieldedTransactionApi()).thenReturn(true); GrpcAPI.BytesMessage reponse = wallet.getTriggerInputForShieldedTRC20Contract(triggerParam.build()); @@ -1319,4 +1319,4 @@ public void testGetContractInfo1() throws Exception { wallet.getContractInfo(bytesMessage); assertNotNull(smartContractDataWrapper); } -} \ No newline at end of file +} diff --git a/framework/src/test/java/org/tron/core/actuator/ShieldedTransferActuatorTest.java b/framework/src/test/java/org/tron/core/actuator/ShieldedTransferActuatorTest.java index b71ba432018..cb95194f3d3 100755 --- a/framework/src/test/java/org/tron/core/actuator/ShieldedTransferActuatorTest.java +++ b/framework/src/test/java/org/tron/core/actuator/ShieldedTransferActuatorTest.java @@ -85,7 +85,7 @@ public class ShieldedTransferActuatorTest extends BaseTest { */ @BeforeClass public static void init() throws ZksnarkException { - Args.setFullNodeAllowShieldedTransaction(true); + Args.getInstance().setAllowShieldedTransactionApi(true); librustzcashInitZksnarkParams(); } @@ -950,7 +950,7 @@ public void publicAddressAToShieldAddressNoToAddressFailure() { */ @Test public void publicToShieldAddressAndShieldToPublicAddressWithZoreValueSuccess() { - Args.setFullNodeAllowShieldedTransaction(true); + Args.getInstance().setAllowShieldedTransactionApi(true); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); long fee = dbManager.getDynamicPropertiesStore().getShieldedTransactionFee(); diff --git a/framework/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java b/framework/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java index 717c62b01a8..1f0be4b1f7c 100644 --- a/framework/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java +++ b/framework/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java @@ -138,12 +138,63 @@ public void testWithdraw() { @Test public void testStrictMath() { long supply = 1_000_000_000_000_000_000L; - ExchangeProcessor processor = new ExchangeProcessor(supply, false); - long anotherTokenQuant = processor.exchange(4732214, 2202692725330L, 29218); - processor = new ExchangeProcessor(supply, true); - long result = processor.exchange(4732214, 2202692725330L, 29218); - Assert.assertNotEquals(anotherTokenQuant, result); + long[][] testData = { + {4732214L, 2202692725330L, 29218L}, + {5618633L, 556559904655L, 1L}, + {9299554L, 1120271441185L, 7000L}, + {62433133L, 12013267997895L, 100000L}, + {64212664L, 725836766395L, 50000L}, + {64126212L, 2895100109660L, 5000L}, + {56459055L, 3288380567368L, 165000L}, + {21084707L, 1589204008960L, 50000L}, + {24120521L, 1243764649177L, 20000L}, + {836877L, 212532333234L, 5293L}, + {55879741L, 13424854054078L, 250000L}, + {66388882L, 11300012790454L, 300000L}, + {94470955L, 7941038150919L, 2000L}, + {13613746L, 5012660712983L, 122L}, + {71852829L, 5262251868618L, 396L}, + {3857658L, 446109245044L, 20637L}, + {35491863L, 3887393269796L, 100L}, + {295632118L, 1265298439004L, 500000L}, + {49320113L, 1692106302503L, 123267L}, + {10966984L, 6222910652894L, 2018L}, + {41634280L, 2004508994767L, 865L}, + {10087714L, 6765558834714L, 1009L}, + {42270078L, 210360843525L, 200000L}, + {571091915L, 655011397250L, 2032520L}, + {51026781L, 1635726339365L, 37L}, + {61594L, 312318864132L, 500L}, + {11616684L, 5875978057357L, 20L}, + {60584529L, 1377717821301L, 78132L}, + {29818073L, 3033545989651L, 182L}, + {3855280L, 834647482043L, 16L}, + {58310711L, 1431562205655L, 200000L}, + {60226263L, 1386036785882L, 178226L}, + {3537634L, 965771433992L, 225L}, + {3760534L, 908700758784L, 328L}, + {80913L, 301864126445L, 4L}, + {3789271L, 901842209723L, 1L}, + {4051904L, 843419481286L, 1005L}, + {89141L, 282107742510L, 100L}, + {90170L, 282854635378L, 26L}, + {4229852L, 787503315944L, 137L}, + {4259884L, 781975090197L, 295L}, + {3627657L, 918682223700L, 34L}, + {813519L, 457546358759L, 173L}, + {89626L, 327856173057L, 27L}, + {97368L, 306386489550L, 50L}, + {93712L, 305866015731L, 4L}, + {3281260L, 723656594544L, 40L}, + {3442652L, 689908773685L, 18L}, + }; + + for (long[] data : testData) { + ExchangeProcessor processor = new ExchangeProcessor(supply, false); + long anotherTokenQuant = processor.exchange(data[0], data[1], data[2]); + processor = new ExchangeProcessor(supply, true); + long result = processor.exchange(data[0], data[1], data[2]); + Assert.assertNotEquals(anotherTokenQuant, result); + } } - - } 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 4bb8e7e4909..4b656e463be 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 @@ -57,7 +57,7 @@ public void destroy() { @Test public void get() { - Args.setParam(new String[] {"-c", Constant.TEST_CONF}, Constant.TESTNET_CONF); + Args.setParam(new String[] {"-c", Constant.TEST_CONF, "--keystore"}, Constant.TESTNET_CONF); CommonParameter parameter = Args.getInstance(); @@ -127,6 +127,8 @@ public void get() { Assert.assertEquals(address, ByteArray.toHexString(Args.getLocalWitnesses() .getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine()))); + + Assert.assertTrue(parameter.isKeystore()); } @Test diff --git a/framework/src/test/java/org/tron/core/db/AccountStoreTest.java b/framework/src/test/java/org/tron/core/db/AccountStoreTest.java index 9249a3358dc..aab64df16c7 100755 --- a/framework/src/test/java/org/tron/core/db/AccountStoreTest.java +++ b/framework/src/test/java/org/tron/core/db/AccountStoreTest.java @@ -1,20 +1,29 @@ package org.tron.core.db; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; import com.google.protobuf.ByteString; +import com.typesafe.config.Config; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.annotation.Resource; 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.core.Constant; import org.tron.core.capsule.AccountCapsule; import org.tron.core.config.args.Args; import org.tron.core.db2.ISession; +import org.tron.core.exception.TronError; +import org.tron.core.net.peer.PeerManager; import org.tron.core.store.AccountStore; import org.tron.core.store.AssetIssueStore; import org.tron.core.store.DynamicPropertiesStore; @@ -61,6 +70,21 @@ public void init() { init = true; } + @Test + public void setAccountTest() throws Exception { + Field field = AccountStore.class.getDeclaredField("assertsAddress"); + field.setAccessible(true); + field.set(AccountStore.class, new HashMap<>()); + Config config = mock(Config.class); + Mockito.when(config.getObjectList("genesis.block.assets")).thenReturn(new ArrayList<>()); + try { + AccountStore.setAccount(config); + Assert.fail(); + } catch (Throwable e) { + Assert.assertTrue(e instanceof TronError); + } + } + @Test public void get() { //test get and has Method diff --git a/framework/src/test/java/org/tron/core/db2/CheckpointV2Test.java b/framework/src/test/java/org/tron/core/db2/CheckpointV2Test.java index dff2d376fd5..fb7f1987e9f 100644 --- a/framework/src/test/java/org/tron/core/db2/CheckpointV2Test.java +++ b/framework/src/test/java/org/tron/core/db2/CheckpointV2Test.java @@ -4,7 +4,7 @@ import com.google.common.primitives.Bytes; import com.google.common.primitives.Longs; import com.google.protobuf.ByteString; -import java.io.File; +import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -13,11 +13,12 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.tron.common.application.Application; import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; -import org.tron.common.utils.FileUtil; import org.tron.common.utils.Sha256Hash; import org.tron.core.Constant; import org.tron.core.capsule.BlockCapsule; @@ -34,10 +35,12 @@ public class CheckpointV2Test { private TronApplicationContext context; private Application appT; private TestRevokingTronStore tronDatabase; + @Rule + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before - public void init() { - Args.setParam(new String[]{"-d", "output_SnapshotManager_test"}, + public void init() throws IOException { + Args.setParam(new String[]{"-d", temporaryFolder.newFolder().toString()}, Constant.TEST_CONF); Args.getInstance().getStorage().setCheckpointVersion(2); Args.getInstance().getStorage().setCheckpointSync(true); @@ -54,9 +57,6 @@ public void removeDb() { Args.clearParam(); context.destroy(); tronDatabase.close(); - FileUtil.deleteDir(new File("output_SnapshotManager_test")); - revokingDatabase.getCheckTmpStore().close(); - tronDatabase.close(); } @Test diff --git a/framework/src/test/java/org/tron/core/db2/RevokingDbWithCacheNewValueTest.java b/framework/src/test/java/org/tron/core/db2/RevokingDbWithCacheNewValueTest.java index 2290df86978..f371f2348a7 100644 --- a/framework/src/test/java/org/tron/core/db2/RevokingDbWithCacheNewValueTest.java +++ b/framework/src/test/java/org/tron/core/db2/RevokingDbWithCacheNewValueTest.java @@ -1,22 +1,22 @@ package org.tron.core.db2; -import java.io.File; +import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.tron.common.application.Application; import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; import org.tron.common.utils.ByteArray; -import org.tron.common.utils.FileUtil; import org.tron.common.utils.SessionOptional; import org.tron.core.Constant; import org.tron.core.capsule.utils.MarketUtils; @@ -34,12 +34,14 @@ public class RevokingDbWithCacheNewValueTest { private TronApplicationContext context; private Application appT; private TestRevokingTronStore tronDatabase; + @Rule + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); private String databasePath = ""; @Before - public void init() { - databasePath = "output_revokingStore_test_" + RandomStringUtils.randomAlphanumeric(10); + public void init() throws IOException { + databasePath = temporaryFolder.newFolder().toString(); Args.setParam(new String[]{"-d", databasePath}, Constant.TEST_CONF); context = new TronApplicationContext(DefaultConfig.class); @@ -51,7 +53,6 @@ public void removeDb() { Args.clearParam(); context.destroy(); tronDatabase.close(); - FileUtil.deleteDir(new File(databasePath)); } @Test diff --git a/framework/src/test/java/org/tron/core/db2/SnapshotImplTest.java b/framework/src/test/java/org/tron/core/db2/SnapshotImplTest.java index aab6f656b1f..649056aa151 100644 --- a/framework/src/test/java/org/tron/core/db2/SnapshotImplTest.java +++ b/framework/src/test/java/org/tron/core/db2/SnapshotImplTest.java @@ -3,16 +3,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import java.io.File; +import java.io.IOException; import java.lang.reflect.Constructor; import org.junit.After; -import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.tron.common.application.Application; import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; -import org.tron.common.utils.FileUtil; import org.tron.core.Constant; import org.tron.core.config.DefaultConfig; import org.tron.core.config.args.Args; @@ -26,10 +26,12 @@ public class SnapshotImplTest { private TronApplicationContext context; private Application appT; private SnapshotManager revokingDatabase; + @Rule + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before - public void init() { - Args.setParam(new String[]{"-d", "output_revokingStore_test"}, Constant.TEST_CONF); + public void init() throws IOException { + Args.setParam(new String[]{"-d", temporaryFolder.newFolder().toString()}, Constant.TEST_CONF); context = new TronApplicationContext(DefaultConfig.class); appT = ApplicationFactory.create(context); @@ -44,10 +46,7 @@ public void init() { public void removeDb() { Args.clearParam(); context.destroy(); - FileUtil.deleteDir(new File("output_revokingStore_test")); - tronDatabase.close(); - revokingDatabase.shutdown(); } /** diff --git a/framework/src/test/java/org/tron/core/db2/SnapshotManagerTest.java b/framework/src/test/java/org/tron/core/db2/SnapshotManagerTest.java index 134dc99e51c..d6fd319e6a0 100644 --- a/framework/src/test/java/org/tron/core/db2/SnapshotManagerTest.java +++ b/framework/src/test/java/org/tron/core/db2/SnapshotManagerTest.java @@ -6,7 +6,7 @@ import com.google.common.collect.Maps; import com.google.common.primitives.Longs; import com.google.protobuf.ByteString; -import java.io.File; +import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -15,11 +15,12 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.tron.common.application.Application; import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; -import org.tron.common.utils.FileUtil; import org.tron.common.utils.Sha256Hash; import org.tron.core.Constant; import org.tron.core.capsule.BlockCapsule; @@ -40,11 +41,13 @@ public class SnapshotManagerTest { private TronApplicationContext context; private Application appT; private TestRevokingTronStore tronDatabase; + @Rule + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before - public void init() { - Args.setParam(new String[]{"-d", "output_SnapshotManager_test"}, + public void init() throws IOException { + Args.setParam(new String[]{"-d", temporaryFolder.newFolder().toString()}, Constant.TEST_CONF); context = new TronApplicationContext(DefaultConfig.class); appT = ApplicationFactory.create(context); @@ -59,9 +62,6 @@ public void removeDb() { Args.clearParam(); context.destroy(); tronDatabase.close(); - FileUtil.deleteDir(new File("output_SnapshotManager_test")); - revokingDatabase.getCheckTmpStore().close(); - tronDatabase.close(); } @Test diff --git a/framework/src/test/java/org/tron/core/db2/SnapshotRootTest.java b/framework/src/test/java/org/tron/core/db2/SnapshotRootTest.java index 70b4d9eff30..635cc018cc2 100644 --- a/framework/src/test/java/org/tron/core/db2/SnapshotRootTest.java +++ b/framework/src/test/java/org/tron/core/db2/SnapshotRootTest.java @@ -1,10 +1,13 @@ package org.tron.core.db2; import com.google.common.collect.Sets; -import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import lombok.AllArgsConstructor; @@ -13,7 +16,9 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.springframework.util.CollectionUtils; import org.tron.common.application.Application; import org.tron.common.application.ApplicationFactory; @@ -45,11 +50,13 @@ public class SnapshotRootTest { "exchange","market_order","account-trace","contract-state","trans")); private Set allDBNames; private Set allRevokingDBNames; + @Rule + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before - public void init() { - Args.setParam(new String[]{"-d", "output_revokingStore_test"}, Constant.TEST_CONF); + public void init() throws IOException { + Args.setParam(new String[]{"-d", temporaryFolder.newFolder().toString()}, Constant.TEST_CONF); context = new TronApplicationContext(DefaultConfig.class); appT = ApplicationFactory.create(context); } @@ -58,7 +65,6 @@ public void init() { public void removeDb() { Args.clearParam(); context.destroy(); - FileUtil.deleteDir(new File("output_revokingStore_test")); } @Test @@ -133,7 +139,9 @@ public void testSecondCacheCheck() throws ItemNotFoundException { revokingDatabase = context.getBean(SnapshotManager.class); allRevokingDBNames = parseRevokingDBNames(context); - allDBNames = Arrays.stream(new File("output_revokingStore_test/database").list()) + Path path = Paths.get(Args.getInstance().getOutputDirectory(), + Args.getInstance().getStorage().getDbDirectory()); + allDBNames = Arrays.stream(Objects.requireNonNull(path.toFile().list())) .collect(Collectors.toSet()); if (CollectionUtils.isEmpty(allDBNames)) { throw new ItemNotFoundException("No DBs found"); @@ -152,10 +160,13 @@ public void testSecondCacheCheckAddDb() revokingDatabase = context.getBean(SnapshotManager.class); allRevokingDBNames = parseRevokingDBNames(context); allRevokingDBNames.add("secondCheckTestDB"); - FileUtil.createDirIfNotExists("output_revokingStore_test/database/secondCheckTestDB"); - allDBNames = Arrays.stream(new File("output_revokingStore_test/database").list()) + Path path = Paths.get(Args.getInstance().getOutputDirectory(), + Args.getInstance().getStorage().getDbDirectory()); + Path secondCheckTestDB = Paths.get(path.toString(), "secondCheckTestDB"); + FileUtil.createDirIfNotExists(secondCheckTestDB.toString()); + allDBNames = Arrays.stream(Objects.requireNonNull(path.toFile().list())) .collect(Collectors.toSet()); - FileUtil.deleteDir(new File("output_revokingStore_test/database/secondCheckTestDB")); + FileUtil.deleteDir(secondCheckTestDB.toFile()); if (CollectionUtils.isEmpty(allDBNames)) { throw new ItemNotFoundException("No DBs found"); } diff --git a/framework/src/test/java/org/tron/core/exception/TronErrorTest.java b/framework/src/test/java/org/tron/core/exception/TronErrorTest.java index b4c3dc4b07f..98d5596e251 100644 --- a/framework/src/test/java/org/tron/core/exception/TronErrorTest.java +++ b/framework/src/test/java/org/tron/core/exception/TronErrorTest.java @@ -59,7 +59,6 @@ public void testTronError() { @Test public void ZksnarkInitTest() { try (MockedStatic mock = mockStatic(JLibrustzcash.class)) { - mock.when(JLibrustzcash::isOpenZen).thenReturn(true); mock.when(() -> JLibrustzcash.librustzcashInitZksnarkParams(any())) .thenAnswer(invocation -> { throw new ZksnarkException("Zksnark init failed"); diff --git a/framework/src/test/java/org/tron/core/jsonrpc/ApiUtilTest.java b/framework/src/test/java/org/tron/core/jsonrpc/ApiUtilTest.java index 570e7ed3498..f62d47d5367 100644 --- a/framework/src/test/java/org/tron/core/jsonrpc/ApiUtilTest.java +++ b/framework/src/test/java/org/tron/core/jsonrpc/ApiUtilTest.java @@ -4,10 +4,13 @@ import static org.tron.keystore.Wallet.generateRandomBytes; import com.google.protobuf.ByteString; +import org.junit.AfterClass; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; import org.tron.common.utils.ByteArray; import org.tron.core.capsule.BlockCapsule; +import org.tron.core.config.args.Args; import org.tron.core.services.jsonrpc.JsonRpcApiUtil; import org.tron.protos.Protocol.Block; import org.tron.protos.Protocol.BlockHeader; @@ -16,6 +19,16 @@ public class ApiUtilTest { + @BeforeClass + public static void init() { + Args.setParam(new String[]{}, "config-localtest.conf"); + } + + @AfterClass + public static void clear() { + Args.clearParam(); + } + @Test public void testGetBlockID() { byte[] mockedHash = generateRandomBytes(128); diff --git a/framework/src/test/java/org/tron/core/jsonrpc/JsonRpcTest.java b/framework/src/test/java/org/tron/core/jsonrpc/JsonRpcTest.java index bef0b5a1593..bd357101da3 100644 --- a/framework/src/test/java/org/tron/core/jsonrpc/JsonRpcTest.java +++ b/framework/src/test/java/org/tron/core/jsonrpc/JsonRpcTest.java @@ -18,7 +18,7 @@ import org.tron.common.utils.ByteArray; import org.tron.common.utils.ByteUtil; import org.tron.common.utils.Commons; -import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; import org.tron.core.services.jsonrpc.JsonRpcApiUtil; import org.tron.core.services.jsonrpc.TronJsonRpc.FilterRequest; import org.tron.core.services.jsonrpc.filters.LogBlockQuery; diff --git a/framework/src/test/java/org/tron/core/jsonrpc/JsonrpcServiceTest.java b/framework/src/test/java/org/tron/core/jsonrpc/JsonrpcServiceTest.java index 0f2214c5c9c..f6f4a35c1b7 100644 --- a/framework/src/test/java/org/tron/core/jsonrpc/JsonrpcServiceTest.java +++ b/framework/src/test/java/org/tron/core/jsonrpc/JsonrpcServiceTest.java @@ -1,6 +1,7 @@ package org.tron.core.jsonrpc; import static org.tron.core.services.jsonrpc.JsonRpcApiUtil.getByJsonBlockId; +import static org.tron.core.services.jsonrpc.TronJsonRpcImpl.TAG_PENDING_SUPPORT_ERROR; import com.alibaba.fastjson.JSON; import com.google.gson.JsonArray; @@ -33,9 +34,12 @@ import org.tron.core.capsule.AccountCapsule; import org.tron.core.capsule.BlockCapsule; import org.tron.core.capsule.TransactionCapsule; +import org.tron.core.capsule.TransactionInfoCapsule; +import org.tron.core.capsule.TransactionRetCapsule; import org.tron.core.capsule.utils.BlockUtil; import org.tron.core.config.args.Args; -import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInternalException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; import org.tron.core.services.NodeInfoService; import org.tron.core.services.interfaceJsonRpcOnPBFT.JsonRpcServiceOnPBFT; import org.tron.core.services.interfaceJsonRpcOnSolidity.JsonRpcServiceOnSolidity; @@ -44,6 +48,7 @@ import org.tron.core.services.jsonrpc.TronJsonRpcImpl; import org.tron.core.services.jsonrpc.filters.LogFilterWrapper; import org.tron.core.services.jsonrpc.types.BlockResult; +import org.tron.core.services.jsonrpc.types.TransactionReceipt; import org.tron.core.services.jsonrpc.types.TransactionResult; import org.tron.protos.Protocol; import org.tron.protos.Protocol.Transaction.Contract.ContractType; @@ -127,6 +132,7 @@ public void init() { (Wallet.getAddressPreFixString() + "ED738B3A0FE390EAA71B768B6D02CDBD18FB207B")))) .build(); + transactionCapsule1 = new TransactionCapsule(transferContract1, ContractType.TransferContract); transactionCapsule1.setBlockNum(blockCapsule1.getNum()); TransactionCapsule transactionCapsule2 = new TransactionCapsule(transferContract2, @@ -155,6 +161,59 @@ public void init() { dbManager.getTransactionStore() .put(transactionCapsule3.getTransactionId().getBytes(), transactionCapsule3); + dbManager.getTransactionStore() + .put(transactionCapsule3.getTransactionId().getBytes(), transactionCapsule3); + + blockCapsule0.getTransactions().forEach(tx -> { + TransactionCapsule transactionCapsule = new TransactionCapsule(tx.getInstance()); + transactionCapsule.setBlockNum(blockCapsule0.getNum()); + dbManager.getTransactionStore() + .put(transactionCapsule.getTransactionId().getBytes(), transactionCapsule); + }); + + TransactionRetCapsule transactionRetCapsule0 = new TransactionRetCapsule(); + blockCapsule0.getTransactions().forEach(tx -> { + TransactionInfoCapsule transactionInfoCapsule = new TransactionInfoCapsule(); + transactionInfoCapsule.setId(tx.getTransactionId().getBytes()); + transactionInfoCapsule.setBlockNumber(blockCapsule0.getNum()); + transactionRetCapsule0.addTransactionInfo(transactionInfoCapsule.getInstance()); + }); + dbManager.getTransactionRetStore().put( + ByteArray.fromLong(blockCapsule0.getNum()), transactionRetCapsule0); + + List logs = new ArrayList<>(); + logs.add(Protocol.TransactionInfo.Log.newBuilder() + .setAddress(ByteString.copyFrom("address1".getBytes())) + .setData(ByteString.copyFrom("data1".getBytes())) + .addTopics(ByteString.copyFrom("topic1".getBytes())) + .build()); + logs.add(Protocol.TransactionInfo.Log.newBuilder() + .setAddress(ByteString.copyFrom("address2".getBytes())) + .setData(ByteString.copyFrom("data2".getBytes())) + .addTopics(ByteString.copyFrom("topic2".getBytes())) + .build()); + + TransactionRetCapsule transactionRetCapsule1 = new TransactionRetCapsule(); + blockCapsule1.getTransactions().forEach(tx -> { + TransactionInfoCapsule transactionInfoCapsule = new TransactionInfoCapsule(); + transactionInfoCapsule.setId(tx.getTransactionId().getBytes()); + transactionInfoCapsule.setBlockNumber(blockCapsule1.getNum()); + transactionInfoCapsule.addAllLog(logs); + transactionRetCapsule1.addTransactionInfo(transactionInfoCapsule.getInstance()); + }); + dbManager.getTransactionRetStore() + .put(ByteArray.fromLong(blockCapsule1.getNum()), transactionRetCapsule1); + + TransactionRetCapsule transactionRetCapsule2 = new TransactionRetCapsule(); + blockCapsule2.getTransactions().forEach(tx -> { + TransactionInfoCapsule transactionInfoCapsule = new TransactionInfoCapsule(); + transactionInfoCapsule.setId(tx.getTransactionId().getBytes()); + transactionInfoCapsule.setBlockNumber(blockCapsule2.getNum()); + transactionRetCapsule2.addTransactionInfo(transactionInfoCapsule.getInstance()); + }); + dbManager.getTransactionRetStore() + .put(ByteArray.fromLong(blockCapsule2.getNum()), transactionRetCapsule2); + tronJsonRpc = new TronJsonRpcImpl(nodeInfoService, wallet, dbManager); } @@ -434,7 +493,8 @@ public void testGetByJsonBlockId() { getByJsonBlockId("0xxabc", wallet); Assert.fail("Expected to be thrown"); } catch (Exception e) { - Assert.assertEquals("For input string: \"xabc\"", e.getMessage()); + // https://bugs.openjdk.org/browse/JDK-8176425, from JDK 12, the exception message is changed + Assert.assertTrue(e.getMessage().startsWith("For input string: \"xabc\"")); } } @@ -968,4 +1028,76 @@ public void testNewFilterFinalizedBlock() { Assert.assertEquals("invalid block range params", e.getMessage()); } } + + @Test + public void testGetBlockReceipts() { + + try { + List transactionReceiptList = tronJsonRpc.getBlockReceipts("0x2710"); + Assert.assertFalse(transactionReceiptList.isEmpty()); + for (TransactionReceipt transactionReceipt: transactionReceiptList) { + TransactionReceipt transactionReceipt1 + = tronJsonRpc.getTransactionReceipt(transactionReceipt.getTransactionHash()); + + Assert.assertEquals( + JSON.toJSONString(transactionReceipt), JSON.toJSONString(transactionReceipt1)); + } + } catch (JsonRpcInvalidParamsException | JsonRpcInternalException e) { + throw new RuntimeException(e); + } + + try { + List transactionReceiptList = tronJsonRpc.getBlockReceipts("earliest"); + Assert.assertFalse(transactionReceiptList.isEmpty()); + } catch (JsonRpcInvalidParamsException | JsonRpcInternalException e) { + throw new RuntimeException(e); + } + + try { + List transactionReceiptList = tronJsonRpc.getBlockReceipts("latest"); + Assert.assertFalse(transactionReceiptList.isEmpty()); + } catch (JsonRpcInvalidParamsException | JsonRpcInternalException e) { + throw new RuntimeException(e); + } + + try { + List transactionReceiptList = tronJsonRpc.getBlockReceipts("finalized"); + Assert.assertFalse(transactionReceiptList.isEmpty()); + } catch (JsonRpcInvalidParamsException | JsonRpcInternalException e) { + throw new RuntimeException(e); + } + + try { + tronJsonRpc.getBlockReceipts("pending"); + Assert.fail(); + } catch (Exception e) { + Assert.assertEquals(TAG_PENDING_SUPPORT_ERROR, e.getMessage()); + } + + try { + tronJsonRpc.getBlockReceipts("test"); + Assert.fail(); + } catch (Exception e) { + Assert.assertEquals("invalid block number", e.getMessage()); + } + + try { + List transactionReceiptList = tronJsonRpc.getBlockReceipts("0x2"); + Assert.assertNull(transactionReceiptList); + } catch (JsonRpcInvalidParamsException | JsonRpcInternalException e) { + throw new RuntimeException(e); + } + + } + + @Test + public void testWeb3ClientVersion() { + try { + String[] versions = tronJsonRpc.web3ClientVersion().split("/"); + String javaVersion = versions[versions.length - 1]; + Assert.assertTrue("Java1.8".equals(javaVersion) || "Java17".equals(javaVersion)); + } catch (Exception e) { + Assert.fail(); + } + } } diff --git a/framework/src/test/java/org/tron/core/jsonrpc/LogBlockQueryTest.java b/framework/src/test/java/org/tron/core/jsonrpc/LogBlockQueryTest.java new file mode 100644 index 00000000000..deae8babb32 --- /dev/null +++ b/framework/src/test/java/org/tron/core/jsonrpc/LogBlockQueryTest.java @@ -0,0 +1,100 @@ +package org.tron.core.jsonrpc; + +import java.lang.reflect.Method; +import java.util.BitSet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import javax.annotation.Resource; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.tron.common.BaseTest; +import org.tron.core.Constant; +import org.tron.core.config.args.Args; +import org.tron.core.services.jsonrpc.TronJsonRpc.FilterRequest; +import org.tron.core.services.jsonrpc.filters.LogBlockQuery; +import org.tron.core.services.jsonrpc.filters.LogFilterWrapper; +import org.tron.core.store.SectionBloomStore; + +public class LogBlockQueryTest extends BaseTest { + + @Resource + SectionBloomStore sectionBloomStore; + private ExecutorService sectionExecutor; + private Method partialMatchMethod; + private static final long CURRENT_MAX_BLOCK_NUM = 50000L; + + static { + Args.setParam(new String[] {"--output-directory", dbPath()}, Constant.TEST_CONF); + } + + @Before + public void setup() throws Exception { + sectionExecutor = Executors.newFixedThreadPool(5); + + // Get private method through reflection + partialMatchMethod = LogBlockQuery.class.getDeclaredMethod("partialMatch", + int[][].class, int.class); + partialMatchMethod.setAccessible(true); + + BitSet bitSet = new BitSet(SectionBloomStore.BLOCK_PER_SECTION); + bitSet.set(0, SectionBloomStore.BLOCK_PER_SECTION); + sectionBloomStore.put(0, 1, bitSet); + sectionBloomStore.put(0, 2, bitSet); + sectionBloomStore.put(0, 3, bitSet); + BitSet bitSet2 = new BitSet(SectionBloomStore.BLOCK_PER_SECTION); + bitSet2.set(0); + sectionBloomStore.put(1, 1, bitSet2); + sectionBloomStore.put(1, 2, bitSet2); + sectionBloomStore.put(1, 3, bitSet2); + } + + @Test + public void testPartialMatch() throws Exception { + // Create a basic LogFilterWrapper + LogFilterWrapper logFilterWrapper = new LogFilterWrapper( + new FilterRequest("0x0", "0x1", null, null, null), + CURRENT_MAX_BLOCK_NUM, null, false); + + LogBlockQuery logBlockQuery = new LogBlockQuery(logFilterWrapper, sectionBloomStore, + CURRENT_MAX_BLOCK_NUM, sectionExecutor); + + int section = 0; + + // Create a hit condition + int[][] bitIndexes = new int[][] { + {1, 2, 3}, // topic0 + {4, 5, 6} // topic1 + }; + + // topic0 hit section 0 + BitSet result = (BitSet) partialMatchMethod.invoke(logBlockQuery, bitIndexes, section); + Assert.assertNotNull(result); + Assert.assertEquals(SectionBloomStore.BLOCK_PER_SECTION, result.cardinality()); + + // topic0 hit section 1 + result = (BitSet) partialMatchMethod.invoke(logBlockQuery, bitIndexes, 1); + Assert.assertNotNull(result); + Assert.assertEquals(1, result.cardinality()); + + // not exist section 2 + result = (BitSet) partialMatchMethod.invoke(logBlockQuery, bitIndexes, 2); + Assert.assertNotNull(result); + Assert.assertTrue(result.isEmpty()); + + //not hit + bitIndexes = new int[][] { + {1, 2, 4}, // topic0 + {3, 5, 6} // topic1 + }; + result = (BitSet) partialMatchMethod.invoke(logBlockQuery, bitIndexes, section); + Assert.assertNotNull(result); + Assert.assertTrue(result.isEmpty()); + + // null condition + bitIndexes = new int[0][]; + result = (BitSet) partialMatchMethod.invoke(logBlockQuery, bitIndexes, section); + Assert.assertNotNull(result); + Assert.assertTrue(result.isEmpty()); + } +} \ No newline at end of file diff --git a/framework/src/test/java/org/tron/core/jsonrpc/LogMatchExactlyTest.java b/framework/src/test/java/org/tron/core/jsonrpc/LogMatchExactlyTest.java index 600cc52b58e..f55e3bc2cfa 100644 --- a/framework/src/test/java/org/tron/core/jsonrpc/LogMatchExactlyTest.java +++ b/framework/src/test/java/org/tron/core/jsonrpc/LogMatchExactlyTest.java @@ -9,7 +9,7 @@ import org.tron.common.runtime.vm.DataWord; import org.tron.common.runtime.vm.LogInfo; import org.tron.common.utils.ByteArray; -import org.tron.core.exception.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; import org.tron.core.services.jsonrpc.TronJsonRpc.FilterRequest; import org.tron.core.services.jsonrpc.TronJsonRpc.LogFilterElement; import org.tron.core.services.jsonrpc.filters.LogFilter; diff --git a/framework/src/test/java/org/tron/core/net/BaseNet.java b/framework/src/test/java/org/tron/core/net/BaseNet.java index 65771bae952..bdaab1b4301 100644 --- a/framework/src/test/java/org/tron/core/net/BaseNet.java +++ b/framework/src/test/java/org/tron/core/net/BaseNet.java @@ -1,24 +1,10 @@ package org.tron.core.net; -import io.netty.bootstrap.Bootstrap; -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.DefaultMessageSizeEstimator; -import io.netty.channel.FixedRecvByteBufAllocator; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.handler.codec.ByteToMessageDecoder; -import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; -import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; -import io.netty.handler.timeout.ReadTimeoutHandler; -import io.netty.handler.timeout.WriteTimeoutHandler; -import java.io.File; import java.io.IOException; import java.util.Collection; +import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; import org.junit.AfterClass; import org.junit.Assert; @@ -29,7 +15,6 @@ import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; import org.tron.common.parameter.CommonParameter; -import org.tron.common.utils.FileUtil; import org.tron.common.utils.PublicMethod; import org.tron.common.utils.ReflectUtils; import org.tron.core.Constant; @@ -53,30 +38,6 @@ public class BaseNet { private static ExecutorService executorService = Executors.newFixedThreadPool(1); - public static Channel connect(ByteToMessageDecoder decoder) throws InterruptedException { - NioEventLoopGroup group = new NioEventLoopGroup(1); - Bootstrap b = new Bootstrap(); - b.group(group).channel(NioSocketChannel.class) - .handler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(256 * 1024)); - ch.config().setOption(ChannelOption.SO_RCVBUF, 256 * 1024); - ch.config().setOption(ChannelOption.SO_BACKLOG, 1024); - ch.pipeline() - .addLast("readTimeoutHandler", new ReadTimeoutHandler(600, TimeUnit.SECONDS)) - .addLast("writeTimeoutHandler", new WriteTimeoutHandler(600, TimeUnit.SECONDS)); - ch.pipeline().addLast("protoPender", new ProtobufVarint32LengthFieldPrepender()); - ch.pipeline().addLast("lengthDecode", new ProtobufVarint32FrameDecoder()); - ch.pipeline().addLast("handshakeHandler", decoder); - ch.closeFuture(); - } - }).option(ChannelOption.SO_KEEPALIVE, true) - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000) - .option(ChannelOption.MESSAGE_SIZE_ESTIMATOR, DefaultMessageSizeEstimator.DEFAULT); - return b.connect(Constant.LOCAL_HOST, port).sync().channel(); - } - @BeforeClass public static void init() throws Exception { executorService.execute(() -> { @@ -123,10 +84,12 @@ public static void init() throws Exception { @AfterClass public static void destroy() { - Collection peerConnections = ReflectUtils - .invokeMethod(tronNetDelegate, "getActivePeer"); - for (PeerConnection peer : peerConnections) { - peer.getChannel().close(); + if (Objects.nonNull(tronNetDelegate)) { + Collection peerConnections = ReflectUtils + .invokeMethod(tronNetDelegate, "getActivePeer"); + for (PeerConnection peer : peerConnections) { + peer.getChannel().close(); + } } Args.clearParam(); context.destroy(); diff --git a/framework/src/test/java/org/tron/core/net/P2pRateLimiterTest.java b/framework/src/test/java/org/tron/core/net/P2pRateLimiterTest.java new file mode 100644 index 00000000000..8a1d9c52749 --- /dev/null +++ b/framework/src/test/java/org/tron/core/net/P2pRateLimiterTest.java @@ -0,0 +1,23 @@ +package org.tron.core.net; + +import static org.tron.core.net.message.MessageTypes.FETCH_INV_DATA; +import static org.tron.core.net.message.MessageTypes.SYNC_BLOCK_CHAIN; + +import org.junit.Assert; +import org.junit.Test; + +public class P2pRateLimiterTest { + @Test + public void test() { + P2pRateLimiter limiter = new P2pRateLimiter(); + limiter.register(SYNC_BLOCK_CHAIN.asByte(), 2); + limiter.acquire(SYNC_BLOCK_CHAIN.asByte()); + boolean ret = limiter.tryAcquire(SYNC_BLOCK_CHAIN.asByte()); + Assert.assertTrue(ret); + limiter.tryAcquire(SYNC_BLOCK_CHAIN.asByte()); + ret = limiter.tryAcquire(SYNC_BLOCK_CHAIN.asByte()); + Assert.assertFalse(ret); + ret = limiter.tryAcquire(FETCH_INV_DATA.asByte()); + Assert.assertTrue(ret); + } +} diff --git a/framework/src/test/java/org/tron/core/net/messagehandler/FetchInvDataMsgHandlerTest.java b/framework/src/test/java/org/tron/core/net/messagehandler/FetchInvDataMsgHandlerTest.java index 5fd6d6725ba..43036ce142a 100644 --- a/framework/src/test/java/org/tron/core/net/messagehandler/FetchInvDataMsgHandlerTest.java +++ b/framework/src/test/java/org/tron/core/net/messagehandler/FetchInvDataMsgHandlerTest.java @@ -1,5 +1,7 @@ package org.tron.core.net.messagehandler; +import static org.tron.core.net.message.MessageTypes.FETCH_INV_DATA; + import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.lang.reflect.Field; @@ -13,6 +15,7 @@ import org.tron.common.utils.Sha256Hash; import org.tron.core.capsule.BlockCapsule; import org.tron.core.config.Parameter; +import org.tron.core.net.P2pRateLimiter; import org.tron.core.net.TronNetDelegate; import org.tron.core.net.message.adv.BlockMessage; import org.tron.core.net.message.adv.FetchInvDataMessage; @@ -55,6 +58,9 @@ public void testProcessMessage() throws Exception { Mockito.when(advService.getMessage(new Item(blockId, Protocol.Inventory.InventoryType.BLOCK))) .thenReturn(new BlockMessage(blockCapsule)); ReflectUtils.setFieldValue(fetchInvDataMsgHandler, "advService", advService); + P2pRateLimiter p2pRateLimiter = new P2pRateLimiter(); + p2pRateLimiter.register(FETCH_INV_DATA.asByte(), 2); + Mockito.when(peer.getP2pRateLimiter()).thenReturn(p2pRateLimiter); fetchInvDataMsgHandler.processMessage(peer, new FetchInvDataMessage(blockIds, Protocol.Inventory.InventoryType.BLOCK)); @@ -74,6 +80,9 @@ public void testSyncFetchCheck() { Cache advInvSpread = CacheBuilder.newBuilder().maximumSize(100) .expireAfterWrite(1, TimeUnit.HOURS).recordStats().build(); Mockito.when(peer.getAdvInvSpread()).thenReturn(advInvSpread); + P2pRateLimiter p2pRateLimiter = new P2pRateLimiter(); + p2pRateLimiter.register(FETCH_INV_DATA.asByte(), 2); + Mockito.when(peer.getP2pRateLimiter()).thenReturn(p2pRateLimiter); FetchInvDataMsgHandler fetchInvDataMsgHandler = new FetchInvDataMsgHandler(); @@ -93,4 +102,36 @@ public void testSyncFetchCheck() { Assert.assertEquals(e.getMessage(), "minBlockNum: 16000, blockNum: 10000"); } } + + @Test + public void testRateLimiter() { + BlockCapsule.BlockId blockId = new BlockCapsule.BlockId(Sha256Hash.ZERO_HASH, 10000L); + List blockIds = new LinkedList<>(); + for (int i = 0; i <= 100; i++) { + blockIds.add(blockId); + } + FetchInvDataMessage msg = + new FetchInvDataMessage(blockIds, Protocol.Inventory.InventoryType.BLOCK); + PeerConnection peer = Mockito.mock(PeerConnection.class); + Mockito.when(peer.isNeedSyncFromUs()).thenReturn(true); + Cache advInvSpread = CacheBuilder.newBuilder().maximumSize(100) + .expireAfterWrite(1, TimeUnit.HOURS).recordStats().build(); + Mockito.when(peer.getAdvInvSpread()).thenReturn(advInvSpread); + P2pRateLimiter p2pRateLimiter = new P2pRateLimiter(); + p2pRateLimiter.register(FETCH_INV_DATA.asByte(), 1); + p2pRateLimiter.acquire(FETCH_INV_DATA.asByte()); + Mockito.when(peer.getP2pRateLimiter()).thenReturn(p2pRateLimiter); + FetchInvDataMsgHandler fetchInvDataMsgHandler = new FetchInvDataMsgHandler(); + + try { + fetchInvDataMsgHandler.processMessage(peer, msg); + } catch (Exception e) { + Assert.assertEquals("fetch too many blocks, size:101", e.getMessage()); + } + try { + fetchInvDataMsgHandler.processMessage(peer, msg); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().endsWith("rate limit")); + } + } } diff --git a/framework/src/test/java/org/tron/core/net/messagehandler/SyncBlockChainMsgHandlerTest.java b/framework/src/test/java/org/tron/core/net/messagehandler/SyncBlockChainMsgHandlerTest.java index e654e1c9cc2..eccab2aeb00 100644 --- a/framework/src/test/java/org/tron/core/net/messagehandler/SyncBlockChainMsgHandlerTest.java +++ b/framework/src/test/java/org/tron/core/net/messagehandler/SyncBlockChainMsgHandlerTest.java @@ -55,6 +55,7 @@ public void init() throws Exception { @Test public void testProcessMessage() throws Exception { try { + peer.setRemainNum(1); handler.processMessage(peer, new SyncBlockChainMessage(new ArrayList<>())); } catch (P2pException e) { Assert.assertEquals("SyncBlockChain blockIds is empty", e.getMessage()); @@ -71,6 +72,10 @@ public void testProcessMessage() throws Exception { Assert.assertNotNull(message.toString()); Assert.assertNotNull(((BlockInventoryMessage) message).getAnswerMessage()); Assert.assertFalse(f); + method.invoke(handler, peer, message); + method.invoke(handler, peer, message); + f = (boolean)method.invoke(handler, peer, message); + Assert.assertFalse(f); Method method1 = handler.getClass().getDeclaredMethod( "getLostBlockIds", List.class, BlockId.class); diff --git a/framework/src/test/java/org/tron/core/net/services/HandShakeServiceTest.java b/framework/src/test/java/org/tron/core/net/services/HandShakeServiceTest.java index f4fabce5d64..54ee84cee6c 100644 --- a/framework/src/test/java/org/tron/core/net/services/HandShakeServiceTest.java +++ b/framework/src/test/java/org/tron/core/net/services/HandShakeServiceTest.java @@ -21,7 +21,6 @@ import org.mockito.Mockito; import org.springframework.context.ApplicationContext; import org.tron.common.application.TronApplicationContext; -import org.tron.common.utils.ByteArray; import org.tron.common.utils.ReflectUtils; import org.tron.common.utils.Sha256Hash; import org.tron.core.ChainBaseManager; @@ -34,6 +33,7 @@ import org.tron.core.net.message.handshake.HelloMessage; import org.tron.core.net.peer.PeerConnection; import org.tron.core.net.peer.PeerManager; +import org.tron.core.net.service.handshake.HandshakeService; import org.tron.p2p.P2pConfig; import org.tron.p2p.base.Parameter; import org.tron.p2p.connection.Channel; @@ -101,6 +101,7 @@ public void testOkHelloMessage() Node node = new Node(NetUtil.getNodeId(), a1.getAddress().getHostAddress(), null, a1.getPort()); HelloMessage helloMessage = new HelloMessage(node, System.currentTimeMillis(), ChainBaseManager.getChainBaseManager()); + Assert.assertNotNull(helloMessage.toString()); Assert.assertEquals(Version.getVersion(), new String(helloMessage.getHelloMessage().getCodeVersion().toByteArray())); @@ -126,13 +127,27 @@ public void testInvalidHelloMessage() { //block hash is empty try { BlockCapsule.BlockId hid = ChainBaseManager.getChainBaseManager().getHeadBlockId(); - Protocol.HelloMessage.BlockId hBlockId = Protocol.HelloMessage.BlockId.newBuilder() - .setHash(ByteString.copyFrom(new byte[0])) + Protocol.HelloMessage.BlockId okBlockId = Protocol.HelloMessage.BlockId.newBuilder() + .setHash(ByteString.copyFrom(new byte[32])) .setNumber(hid.getNum()) .build(); - builder.setHeadBlockId(hBlockId); + Protocol.HelloMessage.BlockId invalidBlockId = Protocol.HelloMessage.BlockId.newBuilder() + .setHash(ByteString.copyFrom(new byte[31])) + .setNumber(hid.getNum()) + .build(); + builder.setHeadBlockId(invalidBlockId); HelloMessage helloMessage = new HelloMessage(builder.build().toByteArray()); - Assert.assertTrue(!helloMessage.valid()); + Assert.assertFalse(helloMessage.valid()); + + builder.setHeadBlockId(okBlockId); + builder.setGenesisBlockId(invalidBlockId); + HelloMessage helloMessage2 = new HelloMessage(builder.build().toByteArray()); + Assert.assertFalse(helloMessage2.valid()); + + builder.setGenesisBlockId(okBlockId); + builder.setSolidBlockId(invalidBlockId); + HelloMessage helloMessage3 = new HelloMessage(builder.build().toByteArray()); + Assert.assertFalse(helloMessage3.valid()); } catch (Exception e) { Assert.fail(); } @@ -214,7 +229,7 @@ public void testLowAndGenesisBlockNum() throws NoSuchMethodException { Node node2 = new Node(NetUtil.getNodeId(), a1.getAddress().getHostAddress(), null, 10002); - //lowestBlockNum > headBlockNum + //peer's lowestBlockNum > my headBlockNum => peer is light, LIGHT_NODE_SYNC_FAIL Protocol.HelloMessage.Builder builder = getHelloMessageBuilder(node2, System.currentTimeMillis(), ChainBaseManager.getChainBaseManager()); @@ -226,7 +241,7 @@ public void testLowAndGenesisBlockNum() throws NoSuchMethodException { Assert.fail(); } - //genesisBlock is not equal + //genesisBlock is not equal => INCOMPATIBLE_CHAIN builder = getHelloMessageBuilder(node2, System.currentTimeMillis(), ChainBaseManager.getChainBaseManager()); BlockCapsule.BlockId gid = ChainBaseManager.getChainBaseManager().getGenesisBlockId(); @@ -242,9 +257,11 @@ public void testLowAndGenesisBlockNum() throws NoSuchMethodException { Assert.fail(); } - //solidityBlock <= us, but not contained + // peer's solidityBlock <= my solidityBlock, but not contained + // and my lowestBlockNum <= peer's solidityBlock => FORKED builder = getHelloMessageBuilder(node2, System.currentTimeMillis(), ChainBaseManager.getChainBaseManager()); + BlockCapsule.BlockId sid = ChainBaseManager.getChainBaseManager().getSolidBlockId(); Random gen = new Random(); @@ -262,6 +279,46 @@ public void testLowAndGenesisBlockNum() throws NoSuchMethodException { } catch (Exception e) { Assert.fail(); } + + // peer's solidityBlock <= my solidityBlock, but not contained + // and my lowestBlockNum > peer's solidityBlock => i am light, LIGHT_NODE_SYNC_FAIL + ChainBaseManager.getChainBaseManager().setLowestBlockNum(2); + try { + HelloMessage helloMessage = new HelloMessage(builder.build().toByteArray()); + method.invoke(p2pEventHandler, peer, helloMessage.getSendBytes()); + } catch (Exception e) { + Assert.fail(); + } + } + + @Test + public void testProcessHelloMessage() { + InetSocketAddress a1 = new InetSocketAddress("127.0.0.1", 10001); + Channel c1 = mock(Channel.class); + Mockito.when(c1.getInetSocketAddress()).thenReturn(a1); + Mockito.when(c1.getInetAddress()).thenReturn(a1.getAddress()); + PeerManager.add(ctx, c1); + PeerConnection p = PeerManager.getPeers().get(0); + + try { + Node node = new Node(NetUtil.getNodeId(), a1.getAddress().getHostAddress(), + null, a1.getPort()); + Protocol.HelloMessage.Builder builder = + getHelloMessageBuilder(node, System.currentTimeMillis(), + ChainBaseManager.getChainBaseManager()); + BlockCapsule.BlockId hid = ChainBaseManager.getChainBaseManager().getHeadBlockId(); + Protocol.HelloMessage.BlockId invalidBlockId = Protocol.HelloMessage.BlockId.newBuilder() + .setHash(ByteString.copyFrom(new byte[31])) + .setNumber(hid.getNum()) + .build(); + builder.setHeadBlockId(invalidBlockId); + + HelloMessage helloMessage = new HelloMessage(builder.build().toByteArray()); + HandshakeService handshakeService = new HandshakeService(); + handshakeService.processHelloMessage(p, helloMessage); + } catch (Exception e) { + Assert.fail(); + } } private Protocol.HelloMessage.Builder getHelloMessageBuilder(Node from, long timestamp, diff --git a/framework/src/test/java/org/tron/core/net/services/RelayServiceTest.java b/framework/src/test/java/org/tron/core/net/services/RelayServiceTest.java index 5e22e538e80..2ed09019fc9 100644 --- a/framework/src/test/java/org/tron/core/net/services/RelayServiceTest.java +++ b/framework/src/test/java/org/tron/core/net/services/RelayServiceTest.java @@ -1,8 +1,9 @@ package org.tron.core.net.services; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; -import com.google.common.collect.Lists; import com.google.protobuf.ByteString; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -12,7 +13,6 @@ import java.util.List; import java.util.Set; import javax.annotation.Resource; - import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Hex; import org.junit.Assert; @@ -21,19 +21,27 @@ import org.mockito.Mockito; import org.springframework.context.ApplicationContext; import org.tron.common.BaseTest; +import org.tron.common.crypto.SignInterface; +import org.tron.common.crypto.SignUtils; +import org.tron.common.parameter.CommonParameter; +import org.tron.common.utils.ByteArray; import org.tron.common.utils.ReflectUtils; +import org.tron.common.utils.Sha256Hash; import org.tron.core.ChainBaseManager; import org.tron.core.Constant; import org.tron.core.capsule.BlockCapsule; import org.tron.core.capsule.WitnessCapsule; import org.tron.core.config.args.Args; import org.tron.core.net.P2pEventHandlerImpl; +import org.tron.core.net.TronNetDelegate; +import org.tron.core.net.TronNetService; import org.tron.core.net.message.adv.BlockMessage; import org.tron.core.net.message.handshake.HelloMessage; import org.tron.core.net.peer.Item; import org.tron.core.net.peer.PeerConnection; import org.tron.core.net.peer.PeerManager; import org.tron.core.net.service.relay.RelayService; +import org.tron.p2p.P2pConfig; import org.tron.p2p.connection.Channel; import org.tron.p2p.discover.Node; import org.tron.p2p.utils.NetUtil; @@ -44,11 +52,13 @@ public class RelayServiceTest extends BaseTest { @Resource private RelayService service; - @Resource - private PeerConnection peer; + @Resource private P2pEventHandlerImpl p2pEventHandler; + @Resource + private TronNetService tronNetService; + /** * init context. */ @@ -67,8 +77,12 @@ public void test() throws Exception { } private void initWitness() { - byte[] key = Hex.decode("A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F"); + // key: 0154435f065a57fec6af1e12eaa2fa600030639448d7809f4c65bdcf8baed7e5 + // Hex: A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01 + // Base58: 27bi7CD8d94AgXY3XFS9A9vx78Si5MqrECz + byte[] key = Hex.decode("A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01");//exist already WitnessCapsule witnessCapsule = chainBaseManager.getWitnessStore().get(key); + System.out.println(witnessCapsule.getInstance()); witnessCapsule.setVoteCount(1000); chainBaseManager.getWitnessStore().put(key, witnessCapsule); List list = new ArrayList<>(); @@ -83,7 +97,7 @@ public void testGetNextWitnesses() throws Exception { "getNextWitnesses", ByteString.class, Integer.class); method.setAccessible(true); Set s1 = (Set) method.invoke( - service, getFromHexString("A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F"), 3); + service, getFromHexString("A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01"), 3); Assert.assertEquals(3, s1.size()); assertContains(s1, "A0299F3DB80A24B20A254B89CE639D59132F157F13"); assertContains(s1, "A0807337F180B62A77576377C1D0C9C24DF5C0DD62"); @@ -93,35 +107,51 @@ public void testGetNextWitnesses() throws Exception { service, getFromHexString("A0FAB5FBF6AFB681E4E37E9D33BDDB7E923D6132E5"), 3); Assert.assertEquals(3, s2.size()); assertContains(s2, "A014EEBE4D30A6ACB505C8B00B218BDC4733433C68"); - assertContains(s2, "A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F"); + assertContains(s2, "A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01"); assertContains(s2, "A0299F3DB80A24B20A254B89CE639D59132F157F13"); Set s3 = (Set) method.invoke( - service, getFromHexString("A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F"), 1); + service, getFromHexString("A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01"), 1); Assert.assertEquals(1, s3.size()); assertContains(s3, "A0299F3DB80A24B20A254B89CE639D59132F157F13"); } private void testBroadcast() { try { + PeerConnection peer = new PeerConnection(); + InetSocketAddress a1 = new InetSocketAddress("127.0.0.2", 10001); + Channel c1 = mock(Channel.class); + Mockito.when(c1.getInetSocketAddress()).thenReturn(a1); + Mockito.when(c1.getInetAddress()).thenReturn(a1.getAddress()); + doNothing().when(c1).send((byte[]) any()); + + peer.setChannel(c1); peer.setAddress(getFromHexString("A0299F3DB80A24B20A254B89CE639D59132F157F13")); peer.setNeedSyncFromPeer(false); peer.setNeedSyncFromUs(false); - List peers = Lists.newArrayList(); + List peers = new ArrayList<>(); peers.add(peer); - ReflectUtils.setFieldValue(p2pEventHandler, "activePeers", peers); + + TronNetDelegate tronNetDelegate = Mockito.mock(TronNetDelegate.class); + Mockito.doReturn(peers).when(tronNetDelegate).getActivePeer(); + + Field field = service.getClass().getDeclaredField("tronNetDelegate"); + field.setAccessible(true); + field.set(service, tronNetDelegate); + BlockCapsule blockCapsule = new BlockCapsule(chainBaseManager.getHeadBlockNum() + 1, chainBaseManager.getHeadBlockId(), - 0, getFromHexString("A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F")); + 0, getFromHexString("A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01")); BlockMessage msg = new BlockMessage(blockCapsule); service.broadcast(msg); Item item = new Item(blockCapsule.getBlockId(), Protocol.Inventory.InventoryType.BLOCK); Assert.assertEquals(1, peer.getAdvInvSpread().size()); Assert.assertNotNull(peer.getAdvInvSpread().getIfPresent(item)); peer.getChannel().close(); - } catch (NullPointerException e) { - System.out.println(e); + } catch (Exception e) { + logger.info("", e); + assert false; } } @@ -135,20 +165,32 @@ private ByteString getFromHexString(String s) { } private void testCheckHelloMessage() { - ByteString address = getFromHexString("A04711BF7AFBDF44557DEFBDF4C4E7AA6138C6331F"); + String key = "0154435f065a57fec6af1e12eaa2fa600030639448d7809f4c65bdcf8baed7e5"; + ByteString address = getFromHexString("A08A8D690BF36806C36A7DAE3AF796643C1AA9CC01"); InetSocketAddress a1 = new InetSocketAddress("127.0.0.1", 10001); Node node = new Node(NetUtil.getNodeId(), a1.getAddress().getHostAddress(), null, a1.getPort()); + + SignInterface cryptoEngine = SignUtils.fromPrivate(ByteArray.fromHexString(key), + Args.getInstance().isECKeyCryptoEngine()); HelloMessage helloMessage = new HelloMessage(node, System.currentTimeMillis(), ChainBaseManager.getChainBaseManager()); + ByteString sig = ByteString.copyFrom(cryptoEngine.Base64toBytes(cryptoEngine + .signHash(Sha256Hash.of(CommonParameter.getInstance() + .isECKeyCryptoEngine(), ByteArray.fromLong(helloMessage + .getTimestamp())).getBytes()))); helloMessage.setHelloMessage(helloMessage.getHelloMessage().toBuilder() - .setAddress(address).build()); + .setAddress(address) + .setSignature(sig) + .build()); + Channel c1 = mock(Channel.class); Mockito.when(c1.getInetSocketAddress()).thenReturn(a1); Mockito.when(c1.getInetAddress()).thenReturn(a1.getAddress()); Channel c2 = mock(Channel.class); Mockito.when(c2.getInetSocketAddress()).thenReturn(a1); Mockito.when(c2.getInetAddress()).thenReturn(a1.getAddress()); + Args.getInstance().fastForward = true; ApplicationContext ctx = (ApplicationContext) ReflectUtils.getFieldObject(p2pEventHandler, "ctx"); @@ -158,14 +200,23 @@ private void testCheckHelloMessage() { PeerConnection peer2 = PeerManager.add(ctx, c2); assert peer2 != null; peer2.setAddress(address); + + ReflectUtils.setFieldValue(tronNetService, "p2pConfig", new P2pConfig()); + try { Field field = service.getClass().getDeclaredField("witnessScheduleStore"); field.setAccessible(true); field.set(service, chainBaseManager.getWitnessScheduleStore()); + + Field field2 = service.getClass().getDeclaredField("manager"); + field2.setAccessible(true); + field2.set(service, dbManager); + boolean res = service.checkHelloMessage(helloMessage, c1); - Assert.assertFalse(res); + Assert.assertTrue(res); } catch (Exception e) { - logger.info("{}", e.getMessage()); + logger.info("", e); + assert false; } } } \ No newline at end of file diff --git a/framework/src/test/java/org/tron/core/net/services/SyncServiceTest.java b/framework/src/test/java/org/tron/core/net/services/SyncServiceTest.java index c2883fb349d..e5b111a7abe 100644 --- a/framework/src/test/java/org/tron/core/net/services/SyncServiceTest.java +++ b/framework/src/test/java/org/tron/core/net/services/SyncServiceTest.java @@ -19,6 +19,7 @@ import org.springframework.context.ApplicationContext; import org.tron.common.application.TronApplicationContext; import org.tron.common.utils.ReflectUtils; +import org.tron.common.utils.Sha256Hash; import org.tron.core.Constant; import org.tron.core.capsule.BlockCapsule; import org.tron.core.config.DefaultConfig; @@ -91,6 +92,13 @@ public void testStartSync() { ReflectUtils.setFieldValue(peer, "tronState", TronState.INIT); + try { + peer.setBlockBothHave(new BlockCapsule.BlockId(Sha256Hash.ZERO_HASH, -1)); + service.syncNext(peer); + } catch (Exception e) { + // no need to deal with + } + service.startSync(peer); } catch (Exception e) { // no need to deal with diff --git a/framework/src/test/java/org/tron/core/services/ProposalServiceTest.java b/framework/src/test/java/org/tron/core/services/ProposalServiceTest.java index 300a38a0916..e81c75948b7 100644 --- a/framework/src/test/java/org/tron/core/services/ProposalServiceTest.java +++ b/framework/src/test/java/org/tron/core/services/ProposalServiceTest.java @@ -1,7 +1,9 @@ package org.tron.core.services; +import static org.tron.core.Constant.MAX_PROPOSAL_EXPIRE_TIME; import static org.tron.core.utils.ProposalUtil.ProposalType.CONSENSUS_LOGIC_OPTIMIZATION; import static org.tron.core.utils.ProposalUtil.ProposalType.ENERGY_FEE; +import static org.tron.core.utils.ProposalUtil.ProposalType.PROPOSAL_EXPIRE_TIME; import static org.tron.core.utils.ProposalUtil.ProposalType.TRANSACTION_FEE; import static org.tron.core.utils.ProposalUtil.ProposalType.WITNESS_127_PAY_PER_BLOCK; @@ -13,6 +15,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.tron.common.BaseTest; +import org.tron.common.parameter.CommonParameter; import org.tron.core.Constant; import org.tron.core.capsule.ProposalCapsule; import org.tron.core.config.args.Args; @@ -131,4 +134,21 @@ public void testUpdateConsensusLogicOptimization() { Assert.assertTrue(dbManager.getDynamicPropertiesStore().disableJavaLangMath()); } + @Test + public void testProposalExpireTime() { + long defaultWindow = dbManager.getDynamicPropertiesStore().getProposalExpireTime(); + long proposalExpireTime = CommonParameter.getInstance().getProposalExpireTime(); + Assert.assertEquals(proposalExpireTime, defaultWindow); + + Proposal proposal = Proposal.newBuilder().putParameters(PROPOSAL_EXPIRE_TIME.getCode(), + 31536000000L).build(); + ProposalCapsule proposalCapsule = new ProposalCapsule(proposal); + proposalCapsule.setExpirationTime(1627279200000L); + boolean result = ProposalService.process(dbManager, proposalCapsule); + Assert.assertTrue(result); + + long window = dbManager.getDynamicPropertiesStore().getProposalExpireTime(); + Assert.assertEquals(MAX_PROPOSAL_EXPIRE_TIME - 3000, window); + } + } \ No newline at end of file diff --git a/framework/src/test/java/org/tron/core/services/RpcApiServicesTest.java b/framework/src/test/java/org/tron/core/services/RpcApiServicesTest.java index 3ae090d3caf..3af0b8fb9b2 100644 --- a/framework/src/test/java/org/tron/core/services/RpcApiServicesTest.java +++ b/framework/src/test/java/org/tron/core/services/RpcApiServicesTest.java @@ -60,8 +60,6 @@ import org.tron.core.config.DefaultConfig; import org.tron.core.config.args.Args; import org.tron.core.db.Manager; -import org.tron.core.services.interfaceOnPBFT.RpcApiServiceOnPBFT; -import org.tron.core.services.interfaceOnSolidity.RpcApiServiceOnSolidity; import org.tron.protos.Protocol; import org.tron.protos.Protocol.Account; import org.tron.protos.Protocol.Block; @@ -144,11 +142,11 @@ public static void init() throws IOException { getInstance().setMetricsPrometheusPort(PublicMethod.chooseRandomPort()); getInstance().setMetricsPrometheusEnable(true); getInstance().setP2pDisable(true); - String fullNode = String.format("%s:%d", getInstance().getNodeLanIp(), + String fullNode = String.format("%s:%d", Constant.LOCAL_HOST, getInstance().getRpcPort()); - String solidityNode = String.format("%s:%d", getInstance().getNodeLanIp(), + String solidityNode = String.format("%s:%d", Constant.LOCAL_HOST, getInstance().getRpcOnSolidityPort()); - String pBFTNode = String.format("%s:%d", getInstance().getNodeLanIp(), + String pBFTNode = String.format("%s:%d", Constant.LOCAL_HOST, getInstance().getRpcOnPBFTPort()); ManagedChannel channelFull = ManagedChannelBuilder.forTarget(fullNode) diff --git a/framework/src/test/java/org/tron/core/services/filter/HttpApiAccessFilterTest.java b/framework/src/test/java/org/tron/core/services/filter/HttpApiAccessFilterTest.java index 420d890aa48..0d2c9c9ae78 100644 --- a/framework/src/test/java/org/tron/core/services/filter/HttpApiAccessFilterTest.java +++ b/framework/src/test/java/org/tron/core/services/filter/HttpApiAccessFilterTest.java @@ -38,7 +38,7 @@ public class HttpApiAccessFilterTest extends BaseTest { static { Args.setParam(new String[]{"-d", dbPath()}, Constant.TEST_CONF); - Args.getInstance().setFullNodeAllowShieldedTransactionArgs(false); + Args.getInstance().setAllowShieldedTransactionApi(false); Args.getInstance().setFullNodeHttpEnable(true); Args.getInstance().setFullNodeHttpPort(PublicMethod.chooseRandomPort()); Args.getInstance().setPBFTHttpEnable(true); diff --git a/framework/src/test/java/org/tron/core/services/filter/LiteFnQueryGrpcInterceptorTest.java b/framework/src/test/java/org/tron/core/services/filter/LiteFnQueryGrpcInterceptorTest.java index 84869ea0750..d98e2c9267e 100644 --- a/framework/src/test/java/org/tron/core/services/filter/LiteFnQueryGrpcInterceptorTest.java +++ b/framework/src/test/java/org/tron/core/services/filter/LiteFnQueryGrpcInterceptorTest.java @@ -25,9 +25,6 @@ import org.tron.core.Constant; import org.tron.core.config.DefaultConfig; import org.tron.core.config.args.Args; -import org.tron.core.services.RpcApiService; -import org.tron.core.services.interfaceOnPBFT.RpcApiServiceOnPBFT; -import org.tron.core.services.interfaceOnSolidity.RpcApiServiceOnSolidity; @Slf4j public class LiteFnQueryGrpcInterceptorTest { @@ -62,11 +59,11 @@ public static void init() throws IOException { Args.getInstance().setRpcPBFTEnable(true); Args.getInstance().setRpcOnPBFTPort(PublicMethod.chooseRandomPort()); Args.getInstance().setP2pDisable(true); - String fullnode = String.format("%s:%d", Args.getInstance().getNodeLanIp(), + String fullnode = String.format("%s:%d", Constant.LOCAL_HOST, Args.getInstance().getRpcPort()); - String solidityNode = String.format("%s:%d", Args.getInstance().getNodeLanIp(), + String solidityNode = String.format("%s:%d", Constant.LOCAL_HOST, Args.getInstance().getRpcOnSolidityPort()); - String pBFTNode = String.format("%s:%d", Args.getInstance().getNodeLanIp(), + String pBFTNode = String.format("%s:%d", Constant.LOCAL_HOST, Args.getInstance().getRpcOnPBFTPort()); channelFull = ManagedChannelBuilder.forTarget(fullnode) .usePlaintext() diff --git a/framework/src/test/java/org/tron/core/services/filter/LiteFnQueryHttpFilterTest.java b/framework/src/test/java/org/tron/core/services/filter/LiteFnQueryHttpFilterTest.java index 0f0bdf1eb1f..978042a8578 100644 --- a/framework/src/test/java/org/tron/core/services/filter/LiteFnQueryHttpFilterTest.java +++ b/framework/src/test/java/org/tron/core/services/filter/LiteFnQueryHttpFilterTest.java @@ -31,7 +31,7 @@ public class LiteFnQueryHttpFilterTest extends BaseTest { static { Args.setParam(new String[]{"-d", dbPath()}, Constant.TEST_CONF); - Args.getInstance().setFullNodeAllowShieldedTransactionArgs(false); + Args.getInstance().setAllowShieldedTransactionApi(false); Args.getInstance().setRpcEnable(false); Args.getInstance().setRpcSolidityEnable(false); Args.getInstance().setRpcPBFTEnable(false); diff --git a/framework/src/test/java/org/tron/core/services/filter/RpcApiAccessInterceptorTest.java b/framework/src/test/java/org/tron/core/services/filter/RpcApiAccessInterceptorTest.java index 900ca304e7d..ce7efabef0c 100644 --- a/framework/src/test/java/org/tron/core/services/filter/RpcApiAccessInterceptorTest.java +++ b/framework/src/test/java/org/tron/core/services/filter/RpcApiAccessInterceptorTest.java @@ -36,8 +36,6 @@ import org.tron.core.config.DefaultConfig; import org.tron.core.config.args.Args; import org.tron.core.services.RpcApiService; -import org.tron.core.services.interfaceOnPBFT.RpcApiServiceOnPBFT; -import org.tron.core.services.interfaceOnSolidity.RpcApiServiceOnSolidity; import org.tron.protos.Protocol.Transaction; @Slf4j @@ -63,11 +61,11 @@ public static void init() throws IOException { Args.getInstance().setRpcPBFTEnable(true); Args.getInstance().setRpcOnPBFTPort(PublicMethod.chooseRandomPort()); Args.getInstance().setP2pDisable(true); - String fullNode = String.format("%s:%d", Args.getInstance().getNodeLanIp(), + String fullNode = String.format("%s:%d", Constant.LOCAL_HOST, Args.getInstance().getRpcPort()); - String solidityNode = String.format("%s:%d", Args.getInstance().getNodeLanIp(), + String solidityNode = String.format("%s:%d", Constant.LOCAL_HOST, Args.getInstance().getRpcOnSolidityPort()); - String pBFTNode = String.format("%s:%d", Args.getInstance().getNodeLanIp(), + String pBFTNode = String.format("%s:%d", Constant.LOCAL_HOST, Args.getInstance().getRpcOnPBFTPort()); ManagedChannel channelFull = ManagedChannelBuilder.forTarget(fullNode) diff --git a/framework/src/test/java/org/tron/core/services/http/GetRewardServletTest.java b/framework/src/test/java/org/tron/core/services/http/GetRewardServletTest.java index 404e154a4c3..bd367fc3700 100644 --- a/framework/src/test/java/org/tron/core/services/http/GetRewardServletTest.java +++ b/framework/src/test/java/org/tron/core/services/http/GetRewardServletTest.java @@ -58,7 +58,7 @@ public MockHttpServletRequest createRequest(String contentType) { @Before public void init() { manager.getDynamicPropertiesStore().saveChangeDelegation(1); - byte[] sr = decodeFromBase58Check("27VZHn9PFZwNh7o2EporxmLkpe157iWZVkh"); + byte[] sr = decodeFromBase58Check("27bi7CD8d94AgXY3XFS9A9vx78Si5MqrECz"); delegationStore.setBrokerage(0, sr, 10); delegationStore.setWitnessVote(0, sr, 100000000); } @@ -66,7 +66,7 @@ public void init() { @Test public void getRewardValueByJsonTest() { int expect = 138181; - String jsonParam = "{\"address\": \"27VZHn9PFZwNh7o2EporxmLkpe157iWZVkh\"}"; + String jsonParam = "{\"address\": \"27bi7CD8d94AgXY3XFS9A9vx78Si5MqrECz\"}"; MockHttpServletRequest request = createRequest("application/json"); MockHttpServletResponse response = new MockHttpServletResponse(); request.setContent(jsonParam.getBytes()); @@ -84,7 +84,7 @@ public void getRewardValueByJsonTest() { @Test public void getRewardByJsonUTF8Test() { int expect = 138181; - String jsonParam = "{\"address\": \"27VZHn9PFZwNh7o2EporxmLkpe157iWZVkh\"}"; + String jsonParam = "{\"address\": \"27bi7CD8d94AgXY3XFS9A9vx78Si5MqrECz\"}"; MockHttpServletRequest request = createRequest("application/json; charset=utf-8"); MockHttpServletResponse response = new MockHttpServletResponse(); request.setContent(jsonParam.getBytes()); @@ -105,7 +105,7 @@ public void getRewardValueTest() { MockHttpServletRequest request = createRequest("application/x-www-form-urlencoded"); MockHttpServletResponse response = new MockHttpServletResponse(); mortgageService.payStandbyWitness(); - request.addParameter("address", "27VZHn9PFZwNh7o2EporxmLkpe157iWZVkh"); + request.addParameter("address", "27bi7CD8d94AgXY3XFS9A9vx78Si5MqrECz"); getRewardServlet.doPost(request, response); try { String contentAsString = response.getContentAsString(); diff --git a/framework/src/test/java/org/tron/core/services/jsonrpc/BuildArgumentsTest.java b/framework/src/test/java/org/tron/core/services/jsonrpc/BuildArgumentsTest.java index f9e264c515f..952e9c81467 100644 --- a/framework/src/test/java/org/tron/core/services/jsonrpc/BuildArgumentsTest.java +++ b/framework/src/test/java/org/tron/core/services/jsonrpc/BuildArgumentsTest.java @@ -8,8 +8,8 @@ import org.tron.core.Constant; import org.tron.core.Wallet; import org.tron.core.config.args.Args; -import org.tron.core.exception.JsonRpcInvalidParamsException; -import org.tron.core.exception.JsonRpcInvalidRequestException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidRequestException; import org.tron.core.services.jsonrpc.types.BuildArguments; import org.tron.core.services.jsonrpc.types.CallArguments; import org.tron.protos.Protocol; diff --git a/framework/src/test/java/org/tron/core/services/jsonrpc/CallArgumentsTest.java b/framework/src/test/java/org/tron/core/services/jsonrpc/CallArgumentsTest.java index 19dd76e5e07..1d7f568453b 100644 --- a/framework/src/test/java/org/tron/core/services/jsonrpc/CallArgumentsTest.java +++ b/framework/src/test/java/org/tron/core/services/jsonrpc/CallArgumentsTest.java @@ -8,8 +8,8 @@ import org.tron.core.Constant; import org.tron.core.Wallet; import org.tron.core.config.args.Args; -import org.tron.core.exception.JsonRpcInvalidParamsException; -import org.tron.core.exception.JsonRpcInvalidRequestException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidRequestException; import org.tron.core.services.jsonrpc.types.CallArguments; import org.tron.protos.Protocol; diff --git a/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcErrorResolverTest.java b/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcErrorResolverTest.java new file mode 100644 index 00000000000..d8e64308ab8 --- /dev/null +++ b/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcErrorResolverTest.java @@ -0,0 +1,75 @@ +package org.tron.core.services.jsonrpc; + +import com.fasterxml.jackson.databind.JsonNode; +import com.googlecode.jsonrpc4j.ErrorData; +import com.googlecode.jsonrpc4j.ErrorResolver.JsonError; +import com.googlecode.jsonrpc4j.JsonRpcError; +import com.googlecode.jsonrpc4j.JsonRpcErrors; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import org.junit.Assert; +import org.junit.Test; +import org.tron.core.exception.jsonrpc.JsonRpcException; +import org.tron.core.exception.jsonrpc.JsonRpcInternalException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidParamsException; +import org.tron.core.exception.jsonrpc.JsonRpcInvalidRequestException; + +public class JsonRpcErrorResolverTest { + + private final JsonRpcErrorResolver resolver = JsonRpcErrorResolver.INSTANCE; + + @JsonRpcErrors({ + @JsonRpcError(exception = JsonRpcInvalidRequestException.class, code = -32600, data = "{}"), + @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), + @JsonRpcError(exception = JsonRpcInternalException.class, code = -32000, data = "{}"), + @JsonRpcError(exception = JsonRpcException.class, code = -1) + }) + public void dummyMethod() { + } + + @Test + public void testResolveErrorWithTronException() throws Exception { + + String message = "JsonRpcInvalidRequestException"; + + JsonRpcException exception = new JsonRpcInvalidRequestException(message); + Method method = this.getClass().getMethod("dummyMethod"); + List arguments = new ArrayList<>(); + + JsonError error = resolver.resolveError(exception, method, arguments); + Assert.assertNotNull(error); + Assert.assertEquals(-32600, error.code); + Assert.assertEquals(message, error.message); + Assert.assertEquals("{}", error.data); + + message = "JsonRpcInternalException"; + String data = "JsonRpcInternalException data"; + exception = new JsonRpcInternalException(message, data); + error = resolver.resolveError(exception, method, arguments); + + Assert.assertNotNull(error); + Assert.assertEquals(-32000, error.code); + Assert.assertEquals(message, error.message); + Assert.assertEquals(data, error.data); + + exception = new JsonRpcInternalException(message, null); + error = resolver.resolveError(exception, method, arguments); + + Assert.assertNotNull(error); + Assert.assertEquals(-32000, error.code); + Assert.assertEquals(message, error.message); + Assert.assertEquals("{}", error.data); + + message = "JsonRpcException"; + exception = new JsonRpcException(message, null); + error = resolver.resolveError(exception, method, arguments); + + Assert.assertNotNull(error); + Assert.assertEquals(-1, error.code); + Assert.assertEquals(message, error.message); + Assert.assertTrue(error.data instanceof ErrorData); + + } + +} \ No newline at end of file diff --git a/framework/src/test/java/org/tron/core/services/jsonrpc/TransactionReceiptTest.java b/framework/src/test/java/org/tron/core/services/jsonrpc/TransactionReceiptTest.java index f10526e30a4..23bc11e293f 100644 --- a/framework/src/test/java/org/tron/core/services/jsonrpc/TransactionReceiptTest.java +++ b/framework/src/test/java/org/tron/core/services/jsonrpc/TransactionReceiptTest.java @@ -8,31 +8,32 @@ import org.tron.common.utils.ByteArray; import org.tron.core.Constant; import org.tron.core.Wallet; +import org.tron.core.capsule.BlockCapsule; import org.tron.core.capsule.TransactionRetCapsule; import org.tron.core.config.args.Args; +import org.tron.core.exception.jsonrpc.JsonRpcInternalException; import org.tron.core.services.jsonrpc.types.TransactionReceipt; +import org.tron.core.services.jsonrpc.types.TransactionReceipt.TransactionContext; import org.tron.core.store.TransactionRetStore; import org.tron.protos.Protocol; public class TransactionReceiptTest extends BaseTest { - @Resource - private Wallet wallet; + @Resource private Wallet wallet; - @Resource - private TransactionRetStore transactionRetStore; + @Resource private TransactionRetStore transactionRetStore; static { - Args.setParam(new String[]{"-d", dbPath()}, Constant.TEST_CONF); + Args.setParam(new String[] {"-d", dbPath()}, Constant.TEST_CONF); } @Test - public void testTransactionReceipt() { + public void testTransactionReceipt() throws JsonRpcInternalException { Protocol.TransactionInfo transactionInfo = Protocol.TransactionInfo.newBuilder() .setId(ByteString.copyFrom("1".getBytes())) .setContractAddress(ByteString.copyFrom("address1".getBytes())) .setReceipt(Protocol.ResourceReceipt.newBuilder() - .setEnergyUsageTotal(0L) + .setEnergyUsageTotal(100L) .setResult(Protocol.Transaction.Result.contractResult.DEFAULT) .build()) .addLog(Protocol.TransactionInfo.Log.newBuilder() @@ -50,17 +51,49 @@ public void testTransactionReceipt() { raw.addContract(contract.build()); Protocol.Transaction transaction = Protocol.Transaction.newBuilder().setRawData(raw).build(); - TransactionReceipt transactionReceipt = new TransactionReceipt( - Protocol.Block.newBuilder().setBlockHeader( - Protocol.BlockHeader.newBuilder().setRawData( - Protocol.BlockHeader.raw.newBuilder().setNumber(1))).addTransactions( - transaction).build(), transactionInfo, wallet); + Protocol.Block block = Protocol.Block.newBuilder().setBlockHeader( + Protocol.BlockHeader.newBuilder().setRawData( + Protocol.BlockHeader.raw.newBuilder().setNumber(1))).addTransactions( + transaction).build(); - Assert.assertEquals(transactionReceipt.getBlockNumber(),"0x1"); - Assert.assertEquals(transactionReceipt.getTransactionIndex(),"0x0"); - Assert.assertEquals(transactionReceipt.getLogs().length,1); - Assert.assertEquals(transactionReceipt.getBlockHash(), - "0x0000000000000001464f071c8a336fd22eb5145dff1b245bda013ec89add8497"); - } + BlockCapsule blockCapsule = new BlockCapsule(block); + long energyFee = wallet.getEnergyFee(blockCapsule.getTimeStamp()); + TransactionReceipt.TransactionContext context + = new TransactionContext(0, 2, 3); + + TransactionReceipt transactionReceipt = + new TransactionReceipt(blockCapsule, transactionInfo, context, energyFee); + + Assert.assertNotNull(transactionReceipt); + String blockHash = "0x0000000000000001464f071c8a336fd22eb5145dff1b245bda013ec89add8497"; + + // assert basic fields + Assert.assertEquals(transactionReceipt.getBlockHash(), blockHash); + Assert.assertEquals(transactionReceipt.getBlockNumber(), "0x1"); + Assert.assertEquals(transactionReceipt.getTransactionHash(), "0x31"); + Assert.assertEquals(transactionReceipt.getTransactionIndex(), "0x0"); + Assert.assertEquals(transactionReceipt.getCumulativeGasUsed(), ByteArray.toJsonHex(102)); + Assert.assertEquals(transactionReceipt.getGasUsed(), ByteArray.toJsonHex(100)); + Assert.assertEquals(transactionReceipt.getEffectiveGasPrice(), ByteArray.toJsonHex(energyFee)); + Assert.assertEquals(transactionReceipt.getStatus(), "0x1"); + // assert contract fields + Assert.assertEquals(transactionReceipt.getFrom(), ByteArray.toJsonHexAddress(new byte[0])); + Assert.assertEquals(transactionReceipt.getTo(), ByteArray.toJsonHexAddress(new byte[0])); + Assert.assertNull(transactionReceipt.getContractAddress()); + + // assert logs fields + Assert.assertEquals(transactionReceipt.getLogs().length, 1); + Assert.assertEquals(transactionReceipt.getLogs()[0].getLogIndex(), "0x3"); + Assert.assertEquals( + transactionReceipt.getLogs()[0].getBlockHash(), blockHash); + Assert.assertEquals(transactionReceipt.getLogs()[0].getBlockNumber(), "0x1"); + Assert.assertEquals(transactionReceipt.getLogs()[0].getTransactionHash(), "0x31"); + Assert.assertEquals(transactionReceipt.getLogs()[0].getTransactionIndex(), "0x0"); + + // assert default fields + Assert.assertNull(transactionReceipt.getRoot()); + Assert.assertEquals(transactionReceipt.getType(), "0x0"); + Assert.assertEquals(transactionReceipt.getLogsBloom(), ByteArray.toJsonHex(new byte[256])); + } } diff --git a/framework/src/test/java/org/tron/core/zksnark/LibrustzcashTest.java b/framework/src/test/java/org/tron/core/zksnark/LibrustzcashTest.java index 049fb2528b1..f3852952cc7 100644 --- a/framework/src/test/java/org/tron/core/zksnark/LibrustzcashTest.java +++ b/framework/src/test/java/org/tron/core/zksnark/LibrustzcashTest.java @@ -84,7 +84,8 @@ public static void init() { }, "config-test-mainnet.conf" ); - Args.setFullNodeAllowShieldedTransaction(true); + Args.getInstance().setAllowShieldedTransactionApi(true); + ZksnarkInitService.librustzcashInitZksnarkParams(); } private static int randomInt(int minInt, int maxInt) { @@ -115,10 +116,6 @@ public static void test(byte[] K, byte[] ovk, byte[] cv, byte[] cm, byte[] epk) null, 0, cipher_nonce, K))); } - public static void librustzcashInitZksnarkParams() { - ZksnarkInitService.librustzcashInitZksnarkParams(); - } - @Test public void testLibsodium() throws ZksnarkException { byte[] K = new byte[32]; @@ -275,7 +272,6 @@ public long benchmarkCreateSpend() throws ZksnarkException { @Ignore @Test public void calBenchmarkSpendConcurrent() throws Exception { - librustzcashInitZksnarkParams(); System.out.println("--- load ok ---"); int count = 2; @@ -307,7 +303,6 @@ public void calBenchmarkSpendConcurrent() throws Exception { @Test public void calBenchmarkSpend() throws ZksnarkException { - librustzcashInitZksnarkParams(); System.out.println("--- load ok ---"); int count = 2; @@ -374,7 +369,6 @@ public long benchmarkCreateSaplingSpend() throws BadItemException, ZksnarkExcept @Test public void calBenchmarkCreateSaplingSpend() throws BadItemException, ZksnarkException { - librustzcashInitZksnarkParams(); System.out.println("--- load ok ---"); int count = 2; @@ -451,7 +445,6 @@ public long benchmarkCreateSaplingOutput() throws BadItemException, ZksnarkExcep @Test public void calBenchmarkCreateSaplingOutPut() throws BadItemException, ZksnarkException { - librustzcashInitZksnarkParams(); System.out.println("--- load ok ---"); int count = 2; @@ -479,7 +472,6 @@ public void calBenchmarkCreateSaplingOutPut() throws BadItemException, ZksnarkEx @Test public void checkVerifyOutErr() throws ZksnarkException { - librustzcashInitZksnarkParams(); System.out.println("--- load ok ---"); // expect fail diff --git a/framework/src/test/java/org/tron/core/zksnark/SaplingNoteTest.java b/framework/src/test/java/org/tron/core/zksnark/SaplingNoteTest.java index da4df70d9ac..34913c98ccc 100644 --- a/framework/src/test/java/org/tron/core/zksnark/SaplingNoteTest.java +++ b/framework/src/test/java/org/tron/core/zksnark/SaplingNoteTest.java @@ -22,7 +22,7 @@ public class SaplingNoteTest { @BeforeClass public static void init() { - Args.setFullNodeAllowShieldedTransaction(true); + Args.getInstance().setAllowShieldedTransactionApi(true); // Args.getInstance().setAllowShieldedTransaction(1); ZksnarkInitService.librustzcashInitZksnarkParams(); } diff --git a/framework/src/test/java/org/tron/core/zksnark/SendCoinShieldTest.java b/framework/src/test/java/org/tron/core/zksnark/SendCoinShieldTest.java index 7746066abfa..e7dfa06d094 100644 --- a/framework/src/test/java/org/tron/core/zksnark/SendCoinShieldTest.java +++ b/framework/src/test/java/org/tron/core/zksnark/SendCoinShieldTest.java @@ -17,6 +17,7 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.tron.api.GrpcAPI; @@ -118,6 +119,11 @@ public class SendCoinShieldTest extends BaseTest { .fromHexString("030c8c2bc59fb3eb8afb047a8ea4b028743d23e7d38c6fa30908358431e2314d"); } + @BeforeClass + public static void initZksnarkParams() { + ZksnarkInitService.librustzcashInitZksnarkParams(); + } + /** * Init data. */ @@ -219,10 +225,6 @@ private IncrementalMerkleVoucherContainer createSimpleMerkleVoucherContainer(byt return tree.toVoucher(); } - private void librustzcashInitZksnarkParams() { - ZksnarkInitService.librustzcashInitZksnarkParams(); - } - @Test public void testStringRevert() { byte[] bytes = ByteArray @@ -235,7 +237,6 @@ public void testStringRevert() { @Test public void testGenerateSpendProof() throws Exception { - librustzcashInitZksnarkParams(); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); SpendingKey sk = SpendingKey .decode("ff2c06269315333a9207f817d2eca0ac555ca8f90196976324c7756504e7c9ee"); @@ -270,7 +271,6 @@ public void testGenerateSpendProof() throws Exception { @Test public void generateOutputProof() throws ZksnarkException { - librustzcashInitZksnarkParams(); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); SpendingKey spendingKey = SpendingKey.random(); FullViewingKey fullViewingKey = spendingKey.fullViewingKey(); @@ -289,7 +289,6 @@ public void generateOutputProof() throws ZksnarkException { @Test public void verifyOutputProof() throws ZksnarkException { - librustzcashInitZksnarkParams(); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); SpendingKey spendingKey = SpendingKey.random(); FullViewingKey fullViewingKey = spendingKey.fullViewingKey(); @@ -321,7 +320,6 @@ public void verifyOutputProof() throws ZksnarkException { @Test public void testDecryptReceiveWithIvk() throws ZksnarkException { //verify c_enc - librustzcashInitZksnarkParams(); ZenTransactionBuilder builder = new ZenTransactionBuilder(); SpendingKey spendingKey = SpendingKey.random(); @@ -385,9 +383,6 @@ public String byte2intstring(byte[] input) { @Test public void testDecryptReceiveWithOvk() throws Exception { - //decode c_out with ovk. - librustzcashInitZksnarkParams(); - // construct payment address SpendingKey spendingKey2 = SpendingKey .decode("ff2c06269315333a9207f817d2eca0ac555ca8f90196976324c7756504e7c9ee"); @@ -467,7 +462,6 @@ public void pushShieldedTransactionAndDecryptWithIvk() AccountResourceInsufficientException, InvalidProtocolBufferException, ZksnarkException { long ctx = JLibrustzcash.librustzcashSaplingProvingCtxInit(); - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); dbManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(1000 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -556,7 +550,6 @@ public void pushShieldedTransactionAndDecryptWithOvk() AccountResourceInsufficientException, InvalidProtocolBufferException, ZksnarkException { long ctx = JLibrustzcash.librustzcashSaplingProvingCtxInit(); - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); dbManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(1000 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -643,10 +636,8 @@ private byte[] getHash() { @Ignore @Test public void checkZksnark() throws BadItemException, ZksnarkException { - librustzcashInitZksnarkParams(); long ctx = JLibrustzcash.librustzcashSaplingProvingCtxInit(); // generate spend proof - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); dbManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(4010 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -679,7 +670,6 @@ public void checkZksnark() throws BadItemException, ZksnarkException { @Test public void testVerifySpendProof() throws BadItemException, ZksnarkException { - librustzcashInitZksnarkParams(); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); SpendingKey sk = SpendingKey .decode("ff2c06269315333a9207f817d2eca0ac555ca8f90196976324c7756504e7c9ee"); @@ -717,7 +707,6 @@ public void testVerifySpendProof() throws BadItemException, ZksnarkException { public void saplingBindingSig() throws BadItemException, ZksnarkException { long ctx = JLibrustzcash.librustzcashSaplingProvingCtxInit(); // generate spend proof - librustzcashInitZksnarkParams(); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); SpendingKey sk = SpendingKey .decode("ff2c06269315333a9207f817d2eca0ac555ca8f90196976324c7756504e7c9ee"); @@ -756,7 +745,6 @@ public void pushShieldedTransaction() ContractExeException, AccountResourceInsufficientException, ZksnarkException { long ctx = JLibrustzcash.librustzcashSaplingProvingCtxInit(); // generate spend proof - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); dbManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(4010 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -789,7 +777,6 @@ public void pushShieldedTransaction() @Test public void finalCheck() throws BadItemException, ZksnarkException { long ctx = JLibrustzcash.librustzcashSaplingProvingCtxInit(); - librustzcashInitZksnarkParams(); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); // generate spend proof SpendingKey sk = SpendingKey @@ -965,7 +952,6 @@ public void getSpendingKey() throws Exception { @Test public void testTwoCMWithDiffSkInOneTx() throws Exception { // generate spend proof - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(110 * 1000000L); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1025,7 +1011,6 @@ private void executeTx(TransactionCapsule transactionCap) throws Exception { @Test public void testValueBalance() throws Exception { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); //case 1, a public input, no input cm, an output cm, no public output { @@ -1246,7 +1231,6 @@ public void testValueBalance() throws Exception { @Test public void TestCreateMultipleTxAtTheSameTime() throws Exception { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); List txList = Lists.newArrayList(); //case 1, a public input, no input cm, an output cm, no public output @@ -1364,7 +1348,6 @@ public void TestCreateMultipleTxAtTheSameTime() throws Exception { @Test public void TestCtxGeneratesTooMuchProof() throws Exception { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); //case 3, no public input, an input cm, no output cm, a public output { @@ -1439,7 +1422,6 @@ public SpendDescriptionCapsule generateSpendProof(SpendDescriptionInfo spend, lo @Test public void TestGeneratesProofWithDiffCtx() throws Exception { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); //case 3, no public input, an input cm, no output cm, a public output @@ -1498,7 +1480,6 @@ public SpendDescriptionCapsule generateSpendProof(SpendDescriptionInfo spend, lo @Test public void TestGeneratesProofWithWrongAlpha() throws Exception { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); //case 3, no public input, an input cm, no output cm, a public output { @@ -1536,7 +1517,6 @@ public void TestGeneratesProofWithWrongAlpha() throws Exception { @Test public void TestGeneratesProofWithWrongRcm() throws Exception { long ctx = JLibrustzcash.librustzcashSaplingProvingCtxInit(); - librustzcashInitZksnarkParams(); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); // generate spend proof SpendingKey sk = SpendingKey.random(); @@ -1557,7 +1537,6 @@ public void TestGeneratesProofWithWrongRcm() throws Exception { @Test public void TestWrongAsk() throws Exception { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); //case 3, no public input, an input cm, no output cm, a public output @@ -1667,7 +1646,6 @@ private TransactionCapsule generateDefaultBuilder(ZenTransactionBuilder builder) @Test public void TestDefaultBuilder() throws Exception { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); dbManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(1000 * 1000000L); @@ -1678,7 +1656,6 @@ public void TestDefaultBuilder() throws Exception { @Test public void TestWrongSpendRk() throws Exception { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); { @@ -1716,7 +1693,6 @@ public SpendDescriptionCapsule generateSpendProof(SpendDescriptionInfo spend, lo @Test public void TestWrongSpendProof() throws Exception { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); { @@ -1761,7 +1737,6 @@ public SpendDescriptionCapsule generateSpendProof(SpendDescriptionInfo spend, lo @Test public void TestWrongNf() throws Exception { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); { @@ -1800,7 +1775,6 @@ public SpendDescriptionCapsule generateSpendProof(SpendDescriptionInfo spend, lo @Test public void TestWrongAnchor() throws Exception { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); { ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet) { diff --git a/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java b/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java index 2a7545f7a9b..4012029e8ae 100755 --- a/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java +++ b/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java @@ -17,6 +17,7 @@ import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.tron.api.GrpcAPI.BytesMessage; import org.tron.api.GrpcAPI.DecryptNotes; @@ -129,7 +130,12 @@ public class ShieldedReceiveTest extends BaseTest { static { Args.setParam(new String[]{"--output-directory", dbPath()}, "config-localtest.conf"); ADDRESS_ONE_PRIVATE_KEY = getRandomPrivateKey(); - FROM_ADDRESS = getHexAddressByPrivateKey(ADDRESS_ONE_PRIVATE_KEY);; + FROM_ADDRESS = getHexAddressByPrivateKey(ADDRESS_ONE_PRIVATE_KEY); + } + + @BeforeClass + public static void initZksnarkParams() { + ZksnarkInitService.librustzcashInitZksnarkParams(); } /** @@ -145,10 +151,6 @@ public void init() { init = true; } - private static void librustzcashInitZksnarkParams() { - ZksnarkInitService.librustzcashInitZksnarkParams(); - } - private static byte[] randomUint256() { return org.tron.keystore.Wallet.generateRandomBytes(32); } @@ -244,7 +246,6 @@ public void testSetShieldedTransactionFee() { */ @Test public void testCreateBeforeAllowZksnark() throws ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(0); createCapsule(); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -284,7 +285,6 @@ public void testCreateBeforeAllowZksnark() throws ZksnarkException { @Test public void testBroadcastBeforeAllowZksnark() throws ZksnarkException, SignatureFormatException, SignatureException, PermissionException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(0);// or 1 createCapsule(); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -309,21 +309,18 @@ public void testBroadcastBeforeAllowZksnark() transactionCap = TransactionUtils.addTransactionSign(transactionCap.getInstance(), ADDRESS_ONE_PRIVATE_KEY, chainBaseManager.getAccountStore()); try { - dbManager.pushTransaction(transactionCap); - Assert.assertFalse(true); + boolean res = dbManager.pushTransaction(transactionCap); + Assert.assertFalse(res); } catch (Exception e) { - Assert.assertTrue(e instanceof ContractValidateException); - Assert.assertEquals( - "Not support Shielded Transaction, need to be opened by the committee", - e.getMessage()); + Assert.fail(e.getMessage()); } } /* - * generate spendproof, dataToBeSigned, outputproof example dynamically according to the params file + * generate spendproof, dataToBeSigned, + * outputproof example dynamically according to the params file */ public String[] generateSpendAndOutputParams() throws ZksnarkException, BadItemException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -460,7 +457,6 @@ private long benchmarkVerifyOutput(String outputParams) throws ZksnarkException @Test public void calBenchmarkVerifySpend() throws ZksnarkException, BadItemException { - librustzcashInitZksnarkParams(); System.out.println("--- load ok ---"); int count = 10; @@ -492,7 +488,6 @@ public void calBenchmarkVerifySpend() throws ZksnarkException, BadItemException @Test public void calBenchmarkVerifyOutput() throws ZksnarkException, BadItemException { - librustzcashInitZksnarkParams(); System.out.println("--- load ok ---"); int count = 2; @@ -588,7 +583,6 @@ private ZenTransactionBuilder generateBuilderWithoutColumnInDescription( @Test public void testReceiveDescriptionWithEmptyCv() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -634,7 +628,6 @@ public void testReceiveDescriptionWithEmptyCv() @Test public void testReceiveDescriptionWithEmptyCm() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -677,7 +670,6 @@ public void testReceiveDescriptionWithEmptyCm() @Test public void testReceiveDescriptionWithEmptyEpk() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -719,7 +711,6 @@ public void testReceiveDescriptionWithEmptyEpk() @Test public void testReceiveDescriptionWithEmptyZkproof() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -762,7 +753,6 @@ public void testReceiveDescriptionWithEmptyZkproof() @Test public void testReceiveDescriptionWithEmptyCenc() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); dbManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); dbManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -805,7 +795,6 @@ public void testReceiveDescriptionWithEmptyCenc() @Test public void testReceiveDescriptionWithEmptyCout() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1063,7 +1052,6 @@ private ZenTransactionBuilder generateBuilder(ZenTransactionBuilder builder, lon @Test public void testReceiveDescriptionWithWrongCv() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1092,7 +1080,6 @@ public void testReceiveDescriptionWithWrongCv() @Test public void testReceiveDescriptionWithWrongZkproof() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1121,7 +1108,6 @@ public void testReceiveDescriptionWithWrongZkproof() @Test public void testReceiveDescriptionWithWrongD() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1152,7 +1138,6 @@ public void testReceiveDescriptionWithWrongD() @Test public void testReceiveDescriptionWithWrongPkd() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1183,7 +1168,6 @@ public void testReceiveDescriptionWithWrongPkd() @Test public void testReceiveDescriptionWithWrongValue() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1212,7 +1196,6 @@ public void testReceiveDescriptionWithWrongValue() @Test public void testReceiveDescriptionWithWrongRcm() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1241,7 +1224,6 @@ public void testReceiveDescriptionWithWrongRcm() @Test public void testNotMatchAskAndNsk() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1292,7 +1274,6 @@ public void testNotMatchAskAndNsk() @Test public void testRandomOvk() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1336,7 +1317,6 @@ public void testRandomOvk() //@Test not used public void testSameInputCm() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1385,7 +1365,6 @@ public void testSameInputCm() @Test public void testSameOutputCm() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1437,7 +1416,6 @@ public void testSameOutputCm() @Test public void testShieldInputInsufficient() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1482,7 +1460,6 @@ public void testShieldInputInsufficient() */ @Test public void testTransparentInputInsufficient() throws RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); long ctx = JLibrustzcash.librustzcashSaplingProvingCtxInit(); @@ -1731,7 +1708,6 @@ public TransactionCapsule generateTransactionCapsule(ZenTransactionBuilder build public void testSignWithoutFromAddress() throws BadItemException, ContractValidateException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1771,7 +1747,6 @@ public void testSignWithoutFromAddress() public void testSignWithoutFromAmout() throws BadItemException, ContractValidateException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1810,7 +1785,6 @@ public void testSignWithoutFromAmout() @Test public void testSignWithoutSpendDescription() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1856,7 +1830,6 @@ public void testSignWithoutSpendDescription() @Test public void testSignWithoutReceiveDescription() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1903,7 +1876,6 @@ public void testSignWithoutReceiveDescription() public void testSignWithoutToAddress() throws BadItemException, ContractValidateException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1943,7 +1915,6 @@ public void testSignWithoutToAddress() public void testSignWithoutToAmount() throws BadItemException, ContractValidateException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -1982,7 +1953,6 @@ public void testSignWithoutToAmount() @Test public void testSpendSignatureWithWrongColumn() throws BadItemException, RuntimeException, ZksnarkException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -2100,7 +2070,6 @@ public void testSpendSignatureWithWrongColumn() @Test public void testIsolateSignature() throws ZksnarkException, BadItemException, ContractValidateException, ContractExeException { - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -2235,7 +2204,6 @@ public void testMemoTooLong() throws ContractValidateException, TooBigTransactio AccountResourceInsufficientException, InvalidProtocolBufferException, ZksnarkException { long ctx = JLibrustzcash.librustzcashSaplingProvingCtxInit(); - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -2318,7 +2286,6 @@ public void testMemoNotEnough() throws ContractValidateException, TooBigTransact AccountResourceInsufficientException, InvalidProtocolBufferException, ZksnarkException { long ctx = JLibrustzcash.librustzcashSaplingProvingCtxInit(); - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(100 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); @@ -2412,7 +2379,6 @@ public void pushSameSkAndScanAndSpend() throws Exception { dbManager.pushBlock(new BlockCapsule(block)); //create transactions - librustzcashInitZksnarkParams(); chainBaseManager.getDynamicPropertiesStore().saveAllowShieldedTransaction(1); chainBaseManager.getDynamicPropertiesStore().saveTotalShieldedPoolValue(1000 * 1000000L); ZenTransactionBuilder builder = new ZenTransactionBuilder(wallet); diff --git a/framework/src/test/java/org/tron/keystroe/CredentialsTest.java b/framework/src/test/java/org/tron/keystroe/CredentialsTest.java index ce992c3443f..2642129e00a 100644 --- a/framework/src/test/java/org/tron/keystroe/CredentialsTest.java +++ b/framework/src/test/java/org/tron/keystroe/CredentialsTest.java @@ -1,6 +1,5 @@ package org.tron.keystroe; -import lombok.var; import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; @@ -11,24 +10,24 @@ public class CredentialsTest { @Test public void test_equality() { - var aObject = new Object(); - var si = Mockito.mock(SignInterface.class); - var si2 = Mockito.mock(SignInterface.class); - var si3 = Mockito.mock(SignInterface.class); - var address = "TQhZ7W1RudxFdzJMw6FvMnujPxrS6sFfmj".getBytes(); - var address2 = "TNCmcTdyrYKMtmE1KU2itzeCX76jGm5Not".getBytes(); + Object aObject = new Object(); + SignInterface si = Mockito.mock(SignInterface.class); + SignInterface si2 = Mockito.mock(SignInterface.class); + SignInterface si3 = Mockito.mock(SignInterface.class); + byte[] address = "TQhZ7W1RudxFdzJMw6FvMnujPxrS6sFfmj".getBytes(); + byte[] address2 = "TNCmcTdyrYKMtmE1KU2itzeCX76jGm5Not".getBytes(); Mockito.when(si.getAddress()).thenReturn(address); Mockito.when(si2.getAddress()).thenReturn(address); Mockito.when(si3.getAddress()).thenReturn(address2); - var aCredential = Credentials.create(si); + Credentials aCredential = Credentials.create(si); Assert.assertFalse(aObject.equals(aCredential)); Assert.assertFalse(aCredential.equals(aObject)); Assert.assertFalse(aCredential.equals(null)); - var anotherCredential = Credentials.create(si); - Assert.assertTrue(aCredential.equals(anotherCredential)); - var aCredential2 = Credentials.create(si2); + Credentials anotherCredential = Credentials.create(si); Assert.assertTrue(aCredential.equals(anotherCredential)); - var aCredential3 = Credentials.create(si3); + Credentials aCredential2 = Credentials.create(si2); + Assert.assertTrue(aCredential.equals(anotherCredential)); + Credentials aCredential3 = Credentials.create(si3); Assert.assertFalse(aCredential.equals(aCredential3)); } } diff --git a/framework/src/test/java/org/tron/program/DBConvertTest.java b/framework/src/test/java/org/tron/program/DBConvertTest.java deleted file mode 100644 index 7b3f797d627..00000000000 --- a/framework/src/test/java/org/tron/program/DBConvertTest.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.tron.program; - -import static org.fusesource.leveldbjni.JniDBFactory.factory; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.UUID; -import org.iq80.leveldb.DB; -import org.iq80.leveldb.Options; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.tron.common.utils.ByteArray; -import org.tron.common.utils.FileUtil; -import org.tron.common.utils.MarketOrderPriceComparatorForLevelDB; -import org.tron.core.capsule.MarketOrderIdListCapsule; -import org.tron.core.capsule.utils.MarketUtils; - -public class DBConvertTest { - - - private static final String INPUT_DIRECTORY = "output-directory/convert-database/"; - private static final String OUTPUT_DIRECTORY = "output-directory/convert-database-dest/"; - private static final String ACCOUNT = "account"; - private static final String MARKET = "market_pair_price_to_order"; - - - @BeforeClass - public static void init() throws IOException { - if (new File(INPUT_DIRECTORY).mkdirs()) { - initDB(new File(INPUT_DIRECTORY,ACCOUNT)); - initDB(new File(INPUT_DIRECTORY,MARKET)); - } - } - - private static void initDB(File file) throws IOException { - Options dbOptions = DBConvert.newDefaultLevelDbOptions(); - if (file.getName().contains("market_pair_price_to_order")) { - dbOptions.comparator(new MarketOrderPriceComparatorForLevelDB()); - try (DB db = factory.open(file,dbOptions)) { - - byte[] sellTokenID1 = ByteArray.fromString("100"); - byte[] buyTokenID1 = ByteArray.fromString("200"); - byte[] pairPriceKey1 = MarketUtils.createPairPriceKey( - sellTokenID1, - buyTokenID1, - 1000L, - 2001L - ); - byte[] pairPriceKey2 = MarketUtils.createPairPriceKey( - sellTokenID1, - buyTokenID1, - 1000L, - 2002L - ); - byte[] pairPriceKey3 = MarketUtils.createPairPriceKey( - sellTokenID1, - buyTokenID1, - 1000L, - 2003L - ); - - MarketOrderIdListCapsule capsule1 = new MarketOrderIdListCapsule(ByteArray.fromLong(1), - ByteArray.fromLong(1)); - MarketOrderIdListCapsule capsule2 = new MarketOrderIdListCapsule(ByteArray.fromLong(2), - ByteArray.fromLong(2)); - MarketOrderIdListCapsule capsule3 = new MarketOrderIdListCapsule(ByteArray.fromLong(3), - ByteArray.fromLong(3)); - - //Use out-of-order insertion,key in store should be 1,2,3 - db.put(pairPriceKey1, capsule1.getData()); - db.put(pairPriceKey2, capsule2.getData()); - db.put(pairPriceKey3, capsule3.getData()); - } - - } else { - try (DB db = factory.open(file,dbOptions)) { - for (int i = 0; i < 100; i++) { - byte[] bytes = UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8); - db.put(bytes, bytes); - } - } - } - - } - - @AfterClass - public static void destroy() { - FileUtil.deleteDir(new File(INPUT_DIRECTORY)); - FileUtil.deleteDir(new File(OUTPUT_DIRECTORY)); - } - - @Test - public void testRun() { - String[] args = new String[] { INPUT_DIRECTORY, OUTPUT_DIRECTORY }; - Assert.assertEquals(0, DBConvert.run(args)); - } - - @Test - public void testNotExist() { - String[] args = new String[] {OUTPUT_DIRECTORY + File.separator + UUID.randomUUID(), - OUTPUT_DIRECTORY}; - Assert.assertEquals(404, DBConvert.run(args)); - } - - @Test - public void testEmpty() { - File file = new File(OUTPUT_DIRECTORY + File.separator + UUID.randomUUID()); - file.mkdirs(); - file.deleteOnExit(); - String[] args = new String[] {file.toString(), OUTPUT_DIRECTORY}; - Assert.assertEquals(0, DBConvert.run(args)); - } -} diff --git a/framework/src/test/java/org/tron/program/SolidityNodeTest.java b/framework/src/test/java/org/tron/program/SolidityNodeTest.java index a95d07c0c11..cb2be8cd688 100755 --- a/framework/src/test/java/org/tron/program/SolidityNodeTest.java +++ b/framework/src/test/java/org/tron/program/SolidityNodeTest.java @@ -1,5 +1,8 @@ package org.tron.program; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + import javax.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; @@ -8,6 +11,7 @@ import org.tron.common.client.DatabaseGrpcClient; import org.tron.core.Constant; import org.tron.core.config.args.Args; +import org.tron.core.exception.TronError; import org.tron.core.services.RpcApiService; import org.tron.core.services.http.solidity.SolidityNodeHttpApiService; import org.tron.protos.Protocol.Block; @@ -22,14 +26,19 @@ public class SolidityNodeTest extends BaseTest { SolidityNodeHttpApiService solidityNodeHttpApiService; static { - Args.setParam(new String[]{"-d", dbPath()}, Constant.TEST_CONF); - Args.getInstance().setSolidityNode(true); + Args.setParam(new String[]{"-d", dbPath(), "--solidity"}, Constant.TEST_CONF); } @Test public void testSolidityArgs() { Assert.assertNotNull(Args.getInstance().getTrustNodeAddr()); Assert.assertTrue(Args.getInstance().isSolidityNode()); + String trustNodeAddr = Args.getInstance().getTrustNodeAddr(); + Args.getInstance().setTrustNodeAddr(null); + TronError thrown = assertThrows(TronError.class, + SolidityNode::start); + assertEquals(TronError.ErrCode.SOLID_NODE_INIT, thrown.getErrCode()); + Args.getInstance().setTrustNodeAddr(trustNodeAddr); } @Test diff --git a/framework/src/test/resources/config-localtest.conf b/framework/src/test/resources/config-localtest.conf index ff31369a915..50a3f97d8b7 100644 --- a/framework/src/test/resources/config-localtest.conf +++ b/framework/src/test/resources/config-localtest.conf @@ -90,7 +90,7 @@ node { minParticipationRate = 0 - fullNodeAllowShieldedTransaction = true + allowShieldedTransactionApi = true zenTokenId = 1000001 diff --git a/framework/src/test/resources/config-test.conf b/framework/src/test/resources/config-test.conf index eaa6659a8c4..f7884eec831 100644 --- a/framework/src/test/resources/config-test.conf +++ b/framework/src/test/resources/config-test.conf @@ -327,7 +327,7 @@ genesis.block = { voteCount = 96 }, { - address: 27VZHn9PFZwNh7o2EporxmLkpe157iWZVkh + address: 27bi7CD8d94AgXY3XFS9A9vx78Si5MqrECz url = "http://AlphaLyrae.org", voteCount = 95 } diff --git a/gradle/jdk17/java-tron.vmoptions b/gradle/jdk17/java-tron.vmoptions new file mode 100644 index 00000000000..91accd05016 --- /dev/null +++ b/gradle/jdk17/java-tron.vmoptions @@ -0,0 +1,8 @@ +-XX:+UseZGC +-Xlog:gc*:file=gc.log:time,uptime,level,tags:filecount=50,filesize=100M +-XX:ReservedCodeCacheSize=256m +-XX:+UseCodeCacheFlushing +-XX:MetaspaceSize=256m +-XX:MaxMetaspaceSize=512m +-XX:MaxDirectMemorySize=1g +-XX:+HeapDumpOnOutOfMemoryError \ No newline at end of file diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index b3c879f6b40..53d4958f1e5 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -150,28 +150,12 @@ - - - + + + - - - - - - - - - - - - - - - - - - + + @@ -179,9 +163,9 @@ - - - + + + @@ -189,9 +173,9 @@ - - - + + + @@ -199,9 +183,9 @@ - - - + + + @@ -209,9 +193,9 @@ - - - + + + @@ -219,15 +203,15 @@ - - - + + + - - + + - - + + @@ -235,15 +219,15 @@ - - - + + + - - + + - - + + @@ -251,15 +235,15 @@ - - - + + + - - + + - - + + @@ -269,6 +253,9 @@ + + + @@ -483,19 +470,6 @@ - - - - - - - - - - - - - @@ -547,9 +521,16 @@ + + + + + + + @@ -728,6 +709,14 @@ + + + + + + + + @@ -820,12 +809,15 @@ - - - + + + - - + + + + + @@ -909,9 +901,16 @@ + + + + + + + @@ -1019,6 +1018,9 @@ + + + @@ -1086,27 +1088,14 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + @@ -1139,6 +1128,14 @@ + + + + + + + + @@ -1298,9 +1295,9 @@ - - - + + + @@ -1393,16 +1390,16 @@ - - - - - + + + + + @@ -1540,28 +1537,28 @@ - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + @@ -1597,6 +1594,9 @@ + + + @@ -1666,65 +1666,65 @@ - - - + + + - - + + - - - + + + - - + + - - - + + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + @@ -1807,14 +1807,6 @@ - - - - - - - - @@ -1823,27 +1815,19 @@ - - - - - - - - - - - + + + - - - + + + @@ -1943,6 +1927,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -2080,12 +2088,12 @@ - - - + + + - - + + @@ -2112,6 +2120,14 @@ + + + + + + + + @@ -2207,81 +2223,86 @@ - - - - - - + + + - - - - + + - - + + - - - - - - + + + - - - - + + - - + + - - - + + + + + + - - + + - - - + + + - - + + + + + - - - + + + + + + - - + + - - - + + + - - + + + + + - - - + + + + + + - - + + - - - + + + diff --git a/platform/build.gradle b/platform/build.gradle new file mode 100644 index 00000000000..a94aad3cf17 --- /dev/null +++ b/platform/build.gradle @@ -0,0 +1,17 @@ +description = "platform – a distributed consensus arithmetic for blockchain." + +sourceSets { + main { + java.srcDirs = rootProject.archInfo.sourceSets.main.java.srcDirs + } + test { + java.srcDirs = rootProject.archInfo.sourceSets.test.java.srcDirs + } +} + +dependencies { + api group: 'org.fusesource.leveldbjni', name: 'leveldbjni-all', version: '1.8' + api group: 'org.rocksdb', name: 'rocksdbjni', version: "${rootProject.archInfo.requires.RocksdbVersion}" + api group: 'commons-io', name: 'commons-io', version: '2.18.0' + api 'io.github.tronprotocol:zksnark-java-sdk:1.0.0' exclude(group: 'commons-io', module: 'commons-io') +} diff --git a/platform/src/main/java/arm/org/tron/common/math/MathWrapper.java b/platform/src/main/java/arm/org/tron/common/math/MathWrapper.java new file mode 100644 index 00000000000..12395dffcea --- /dev/null +++ b/platform/src/main/java/arm/org/tron/common/math/MathWrapper.java @@ -0,0 +1,254 @@ +package org.tron.common.math; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * This class is deprecated and should not be used in new code, + * for cross-platform consistency, please use {@link StrictMathWrapper} instead, + * especially for floating-point calculations. + */ +@Deprecated +public class MathWrapper { + + private static final Map powData = Collections.synchronizedMap(new HashMap<>()); + private static final String EXPONENT = "3f40624dd2f1a9fc"; // 1/2000 = 0.0005 + + public static double pow(double a, double b) { + double strictResult = StrictMath.pow(a, b); + return powData.getOrDefault(new PowData(a, b), strictResult); + } + + /** + * This static block is used to initialize the data map. + */ + static { + // init main-net pow data start + addPowData("3ff0192278704be3", EXPONENT, "3ff000033518c576"); // 4137160(block) + addPowData("3ff000002fc6a33f", EXPONENT, "3ff0000000061d86"); // 4065476 + addPowData("3ff00314b1e73ecf", EXPONENT, "3ff0000064ea3ef8"); // 4071538 + addPowData("3ff0068cd52978ae", EXPONENT, "3ff00000d676966c"); // 4109544 + addPowData("3ff0032fda05447d", EXPONENT, "3ff0000068636fe0"); // 4123826 + addPowData("3ff00051c09cc796", EXPONENT, "3ff000000a76c20e"); // 4166806 + addPowData("3ff00bef8115b65d", EXPONENT, "3ff0000186893de0"); // 4225778 + addPowData("3ff009b0b2616930", EXPONENT, "3ff000013d27849e"); // 4251796 + addPowData("3ff00364ba163146", EXPONENT, "3ff000006f26a9dc"); // 4257157 + addPowData("3ff019be4095d6ae", EXPONENT, "3ff0000348e9f02a"); // 4260583 + addPowData("3ff0123e52985644", EXPONENT, "3ff0000254797fd0"); // 4367125 + addPowData("3ff0126d052860e2", EXPONENT, "3ff000025a6cde26"); // 4402197 + addPowData("3ff0001632cccf1b", EXPONENT, "3ff0000002d76406"); // 4405788 + addPowData("3ff0000965922b01", EXPONENT, "3ff000000133e966"); // 4490332 + addPowData("3ff00005c7692d61", EXPONENT, "3ff0000000bd5d34"); // 4499056 + addPowData("3ff015cba20ec276", EXPONENT, "3ff00002c84cef0e"); // 4518035 + addPowData("3ff00002f453d343", EXPONENT, "3ff000000060cf4e"); // 4533215 + addPowData("3ff006ea73f88946", EXPONENT, "3ff00000e26d4ea2"); // 4647814 + addPowData("3ff00a3632db72be", EXPONENT, "3ff000014e3382a6"); // 4766695 + addPowData("3ff000c0e8df0274", EXPONENT, "3ff0000018b0aeb2"); // 4771494 + addPowData("3ff00015c8f06afe", EXPONENT, "3ff0000002c9d73e"); // 4793587 + addPowData("3ff00068def18101", EXPONENT, "3ff000000d6c3cac"); // 4801947 + addPowData("3ff01349f3ac164b", EXPONENT, "3ff000027693328a"); // 4916843 + addPowData("3ff00e86a7859088", EXPONENT, "3ff00001db256a52"); // 4924111 + addPowData("3ff00000c2a51ab7", EXPONENT, "3ff000000018ea20"); // 5098864 + addPowData("3ff020fb74e9f170", EXPONENT, "3ff00004346fbfa2"); // 5133963 + addPowData("3ff00001ce277ce7", EXPONENT, "3ff00000003b27dc"); // 5139389 + addPowData("3ff005468a327822", EXPONENT, "3ff00000acc20750"); // 5151258 + addPowData("3ff00006666f30ff", EXPONENT, "3ff0000000d1b80e"); // 5185021 + addPowData("3ff000045a0b2035", EXPONENT, "3ff00000008e98e6"); // 5295829 + addPowData("3ff00e00380e10d7", EXPONENT, "3ff00001c9ff83c8"); // 5380897 + addPowData("3ff00c15de2b0d5e", EXPONENT, "3ff000018b6eaab6"); // 5400886 + addPowData("3ff00042afe6956a", EXPONENT, "3ff0000008892244"); // 5864127 + addPowData("3ff0005b7357c2d4", EXPONENT, "3ff000000bb48572"); // 6167339 + addPowData("3ff00033d5ab51c8", EXPONENT, "3ff0000006a279c8"); // 6240974 + addPowData("3ff0000046d74585", EXPONENT, "3ff0000000091150"); // 6279093 + addPowData("3ff0010403f34767", EXPONENT, "3ff0000021472146"); // 6428736 + addPowData("3ff00496fe59bc98", EXPONENT, "3ff000009650a4ca"); // 6432355,6493373 + addPowData("3ff0012e43815868", EXPONENT, "3ff0000026af266e"); // 6555029 + addPowData("3ff00021f6080e3c", EXPONENT, "3ff000000458d16a"); // 7092933 + addPowData("3ff000489c0f28bd", EXPONENT, "3ff00000094b3072"); // 7112412 + addPowData("3ff00009d3df2e9c", EXPONENT, "3ff00000014207b4"); // 7675535 + addPowData("3ff000def05fa9c8", EXPONENT, "3ff000001c887cdc"); // 7860324 + addPowData("3ff0013bca543227", EXPONENT, "3ff00000286a42d2"); // 8292427 + addPowData("3ff0021a2f14a0ee", EXPONENT, "3ff0000044deb040"); // 8517311 + addPowData("3ff0002cc166be3c", EXPONENT, "3ff0000005ba841e"); // 8763101 + addPowData("3ff0000cc84e613f", EXPONENT, "3ff0000001a2da46"); // 9269124 + addPowData("3ff000057b83c83f", EXPONENT, "3ff0000000b3a640"); // 9631452 + // init main-net pow data end + // add pow data + } + + private static void addPowData(String a, String b, String ret) { + powData.put(new PowData(hexToDouble(a), hexToDouble(b)), hexToDouble(ret)); + } + + private static double hexToDouble(String input) { + // Convert the hex string to a long + long hexAsLong = Long.parseLong(input, 16); + // and then convert the long to a double + return Double.longBitsToDouble(hexAsLong); + } + + private static class PowData { + final double a; + final double b; + + public PowData(double a, double b) { + this.a = a; + this.b = b; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PowData powData = (PowData) o; + return Double.compare(powData.a, a) == 0 && Double.compare(powData.b, b) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(a, b); + } + } + + /** + * *** methods are same as {@link java.lang.Math} methods, guaranteed by the call start *** + */ + + /** + * finally calls {@link java.lang.Math#addExact(long, long)} + */ + + public static long addExact(long x, long y) { + return StrictMath.addExact(x, y); + } + + /** + * finally calls {@link java.lang.Math#addExact(int, int)} + */ + + public static int addExact(int x, int y) { + return StrictMath.addExact(x, y); + } + + /** + * finally calls {@link java.lang.Math#subtractExact(long, long)} + */ + + public static long subtractExact(long x, long y) { + return StrictMath.subtractExact(x, y); + } + + /** + * finally calls {@link java.lang.Math#floorMod(long, long)} + */ + public static long multiplyExact(long x, long y) { + return StrictMath.multiplyExact(x, y); + } + + public static long multiplyExact(long x, int y) { + return multiplyExact(x, (long) y); + } + + public static int multiplyExact(int x, int y) { + return StrictMath.multiplyExact(x, y); + } + + /** + * finally calls {@link java.lang.Math#floorDiv(long, long)} + */ + public static long floorDiv(long x, long y) { + return StrictMath.floorDiv(x, y); + } + + public static long floorDiv(long x, int y) { + return floorDiv(x, (long) y); + } + + /** + * finally calls {@link java.lang.Math#min(int, int)} + */ + public static int min(int a, int b) { + return StrictMath.min(a, b); + } + + /** + * finally calls {@link java.lang.Math#min(long, long)} + */ + public static long min(long a, long b) { + return StrictMath.min(a, b); + } + + /** + * finally calls {@link java.lang.Math#max(int, int)} + */ + public static int max(int a, int b) { + return StrictMath.max(a, b); + } + + /** + * finally calls {@link java.lang.Math#max(long, long)} + */ + public static long max(long a, long b) { + return StrictMath.max(a, b); + } + + /** + * finally calls {@link java.lang.Math#round(float)} + */ + public static int round(float a) { + return StrictMath.round(a); + } + + /** + * finally calls {@link java.lang.Math#round(double)} + */ + public static long round(double a) { + return StrictMath.round(a); + } + + /** + * finally calls {@link java.lang.Math#signum(double)} + */ + public static double signum(double d) { + return StrictMath.signum(d); + } + + /** + * finally calls {@link java.lang.Math#signum(float)} + */ + public static long abs(long a) { + return StrictMath.abs(a); + } + + /** + * *** methods are same as {@link java.lang.Math} methods, guaranteed by the call end *** + */ + + /** + * *** methods are same as {@link java.lang.Math} methods by mathematical algorithms*** + * / + + + /** + * mathematical integer: ceil(i) = floor(i) = i + * @return the smallest (closest to negative infinity) double value that is greater + * than or equal to the argument and is equal to a mathematical integer. + */ + public static double ceil(double a) { + return StrictMath.ceil(a); + } + + /** + * *** methods are no matters *** + */ + public static double random() { + return StrictMath.random(); + } + +} diff --git a/platform/src/main/java/arm/org/tron/common/utils/MarketOrderPriceComparatorForRocksDB.java b/platform/src/main/java/arm/org/tron/common/utils/MarketOrderPriceComparatorForRocksDB.java new file mode 100644 index 00000000000..26c246faf0e --- /dev/null +++ b/platform/src/main/java/arm/org/tron/common/utils/MarketOrderPriceComparatorForRocksDB.java @@ -0,0 +1,32 @@ +package org.tron.common.utils; + +import java.nio.ByteBuffer; +import org.rocksdb.AbstractComparator; +import org.rocksdb.ComparatorOptions; + +public class MarketOrderPriceComparatorForRocksDB extends AbstractComparator { + + public MarketOrderPriceComparatorForRocksDB(final ComparatorOptions copt) { + super(copt); + } + + @Override + public String name() { + return "MarketOrderPriceComparator"; + } + + @Override + public int compare(final ByteBuffer a, final ByteBuffer b) { + return MarketComparator.comparePriceKey(convertDataToBytes(a), convertDataToBytes(b)); + } + + /** + * DirectSlice.data().array will throw UnsupportedOperationException. + * */ + public byte[] convertDataToBytes(ByteBuffer buf) { + byte[] bytes = new byte[buf.remaining()]; + buf.get(bytes); + return bytes; + } + +} diff --git a/platform/src/main/java/common/org/tron/common/arch/Arch.java b/platform/src/main/java/common/org/tron/common/arch/Arch.java new file mode 100644 index 00000000000..20744d755a4 --- /dev/null +++ b/platform/src/main/java/common/org/tron/common/arch/Arch.java @@ -0,0 +1,86 @@ +package org.tron.common.arch; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j(topic = "arch") +public final class Arch { + + private Arch() { + } + + public static String withAll() { + final StringBuilder info = new StringBuilder(); + info.append("os.name").append(": ").append(getOsName()).append("\n"); + info.append("os.arch").append(": ").append(getOsArch()).append("\n"); + info.append("bit.model").append(": ").append(getBitModel()).append("\n"); + info.append("java.version").append(": ").append(javaVersion()).append("\n"); + info.append("java.specification.version").append(": ").append(javaSpecificationVersion()) + .append("\n"); + info.append("java.vendor").append(": ").append(javaVendor()).append("\n"); + return info.toString(); + } + + public static String getOsName() { + return System.getProperty("os.name").toLowerCase().trim(); + + } + public static String getOsArch() { + return System.getProperty("os.arch").toLowerCase().trim(); + } + + public static int getBitModel() { + String prop = System.getProperty("sun.arch.data.model"); + if (prop == null) { + prop = System.getProperty("com.ibm.vm.bitmode"); + } + if (prop != null) { + return Integer.parseInt(prop); + } + // GraalVM support, see https://github.com/fusesource/jansi/issues/162 + String arch = System.getProperty("os.arch"); + if (arch.endsWith("64") && "Substrate VM".equals(System.getProperty("java.vm.name"))) { + return 64; + } + return -1; // we don't know... + } + + public static String javaVersion() { + return System.getProperty("java.version").toLowerCase().trim(); + } + + public static String javaSpecificationVersion() { + return System.getProperty("java.specification.version").toLowerCase().trim(); + } + + public static String javaVendor() { + return System.getProperty("java.vendor").toLowerCase().trim(); + } + + public static boolean isArm64() { + String osArch = getOsArch(); + return osArch.contains("arm64") || osArch.contains("aarch64"); + } + + public static boolean isX86() { + return !isArm64(); + } + + public static boolean isJava8() { + return javaSpecificationVersion().equals("1.8"); + } + + public static void throwUnsupportedJavaException() { + if (isX86() && !isJava8()) { + logger.info(withAll()); + throw new UnsupportedOperationException(String.format( + "Java %s is required for %s architecture. Detected version %s", + "1.8 ", getOsArch(), javaSpecificationVersion())); + } + } + + public static void throwUnsupportedArm64Exception() { + if (isArm64()) { + throw new UnsupportedOperationException("unsupported on " + getOsArch() + " architecture"); + } + } +} diff --git a/plugins/src/main/java/org/tron/plugins/utils/MarketUtils.java b/platform/src/main/java/common/org/tron/common/utils/MarketComparator.java similarity index 50% rename from plugins/src/main/java/org/tron/plugins/utils/MarketUtils.java rename to platform/src/main/java/common/org/tron/common/utils/MarketComparator.java index dbd578a59a3..c2742d4d10b 100644 --- a/plugins/src/main/java/org/tron/plugins/utils/MarketUtils.java +++ b/platform/src/main/java/common/org/tron/common/utils/MarketComparator.java @@ -1,71 +1,10 @@ -package org.tron.plugins.utils; +package org.tron.common.utils; import java.math.BigInteger; -import org.tron.plugins.utils.ByteArray; -public class MarketUtils { +public class MarketComparator { - public static final int TOKEN_ID_LENGTH = ByteArray - .fromString(Long.toString(Long.MAX_VALUE)).length; // 19 - - - - /** - * In order to avoid the difference between the data of same key stored and fetched by hashMap and - * levelDB, when creating the price key, we will find the GCD (Greatest Common Divisor) of - * sellTokenQuantity and buyTokenQuantity. - */ - public static byte[] createPairPriceKey(byte[] sellTokenId, byte[] buyTokenId, - long sellTokenQuantity, long buyTokenQuantity) { - - byte[] sellTokenQuantityBytes; - byte[] buyTokenQuantityBytes; - - // cal the GCD - long gcd = findGCD(sellTokenQuantity, buyTokenQuantity); - if (gcd == 0) { - sellTokenQuantityBytes = ByteArray.fromLong(sellTokenQuantity); - buyTokenQuantityBytes = ByteArray.fromLong(buyTokenQuantity); - } else { - sellTokenQuantityBytes = ByteArray.fromLong(sellTokenQuantity / gcd); - buyTokenQuantityBytes = ByteArray.fromLong(buyTokenQuantity / gcd); - } - - return doCreatePairPriceKey(sellTokenId, buyTokenId, - sellTokenQuantityBytes, buyTokenQuantityBytes); - } - - public static long findGCD(long number1, long number2) { - if (number1 == 0 || number2 == 0) { - return 0; - } - return calGCD(number1, number2); - } - - private static long calGCD(long number1, long number2) { - if (number2 == 0) { - return number1; - } - return calGCD(number2, number1 % number2); - } - - - private static byte[] doCreatePairPriceKey(byte[] sellTokenId, byte[] buyTokenId, - byte[] sellTokenQuantity, byte[] buyTokenQuantity) { - byte[] result = new byte[TOKEN_ID_LENGTH + TOKEN_ID_LENGTH - + sellTokenQuantity.length + buyTokenQuantity.length]; - - System.arraycopy(sellTokenId, 0, result, 0, sellTokenId.length); - System.arraycopy(buyTokenId, 0, result, TOKEN_ID_LENGTH, buyTokenId.length); - System.arraycopy(sellTokenQuantity, 0, result, - TOKEN_ID_LENGTH + TOKEN_ID_LENGTH, - sellTokenQuantity.length); - System.arraycopy(buyTokenQuantity, 0, result, - TOKEN_ID_LENGTH + TOKEN_ID_LENGTH + buyTokenQuantity.length, - buyTokenQuantity.length); - - return result; - } + public static final int TOKEN_ID_LENGTH = Long.toString(Long.MAX_VALUE).getBytes().length; // 19 public static int comparePriceKey(byte[] o1, byte[] o2) { @@ -76,7 +15,7 @@ public static int comparePriceKey(byte[] o1, byte[] o2) { System.arraycopy(o1, 0, pair1, 0, TOKEN_ID_LENGTH * 2); System.arraycopy(o2, 0, pair2, 0, TOKEN_ID_LENGTH * 2); - int pairResult = ByteArray.compareUnsigned(pair1, pair2); + int pairResult = compareUnsigned(pair1, pair2); if (pairResult != 0) { return pairResult; } @@ -100,10 +39,10 @@ public static int comparePriceKey(byte[] o1, byte[] o2) { System.arraycopy(o2, TOKEN_ID_LENGTH + TOKEN_ID_LENGTH + longByteNum, getBuyTokenQuantity2, 0, longByteNum); - long sellTokenQuantity1 = ByteArray.toLong(getSellTokenQuantity1); - long buyTokenQuantity1 = ByteArray.toLong(getBuyTokenQuantity1); - long sellTokenQuantity2 = ByteArray.toLong(getSellTokenQuantity2); - long buyTokenQuantity2 = ByteArray.toLong(getBuyTokenQuantity2); + long sellTokenQuantity1 = toLong(getSellTokenQuantity1); + long buyTokenQuantity1 = toLong(getBuyTokenQuantity1); + long sellTokenQuantity2 = toLong(getSellTokenQuantity2); + long buyTokenQuantity2 = toLong(getBuyTokenQuantity2); if ((sellTokenQuantity1 == 0 || buyTokenQuantity1 == 0) && (sellTokenQuantity2 == 0 || buyTokenQuantity2 == 0)) { @@ -145,4 +84,41 @@ public static int comparePrice(long price1SellQuantity, long price1BuyQuantity, return price1BuyQuantityBI.multiply(price2SellQuantityBI) .compareTo(price2BuyQuantityBI.multiply(price1SellQuantityBI)); } + + /** + * copy from org.bouncycastle.util.Arrays.compareUnsigned + */ + private static int compareUnsigned(byte[] a, byte[] b) { + if (a == b) { + return 0; + } + if (a == null) { + return -1; + } + if (b == null) { + return 1; + } + int minLen = StrictMath.min(a.length, b.length); + for (int i = 0; i < minLen; ++i) { + int aVal = a[i] & 0xFF; + int bVal = b[i] & 0xFF; + if (aVal < bVal) { + return -1; + } + if (aVal > bVal) { + return 1; + } + } + if (a.length < b.length) { + return -1; + } + if (a.length > b.length) { + return 1; + } + return 0; + } + + public static long toLong(byte[] b) { + return (b == null || b.length == 0) ? 0 : new BigInteger(1, b).longValue(); + } } diff --git a/chainbase/src/main/java/org/tron/common/utils/MarketOrderPriceComparatorForLevelDB.java b/platform/src/main/java/common/org/tron/common/utils/MarketOrderPriceComparatorForLevelDB.java similarity index 87% rename from chainbase/src/main/java/org/tron/common/utils/MarketOrderPriceComparatorForLevelDB.java rename to platform/src/main/java/common/org/tron/common/utils/MarketOrderPriceComparatorForLevelDB.java index c4c519f68f1..efb7219b211 100644 --- a/chainbase/src/main/java/org/tron/common/utils/MarketOrderPriceComparatorForLevelDB.java +++ b/platform/src/main/java/common/org/tron/common/utils/MarketOrderPriceComparatorForLevelDB.java @@ -1,7 +1,5 @@ package org.tron.common.utils; -import org.tron.core.capsule.utils.MarketUtils; - public class MarketOrderPriceComparatorForLevelDB implements org.iq80.leveldb.DBComparator { @Override @@ -26,7 +24,7 @@ public byte[] findShortSuccessor(byte[] key) { */ @Override public int compare(byte[] o1, byte[] o2) { - return MarketUtils.comparePriceKey(o1, o2); + return MarketComparator.comparePriceKey(o1, o2); } } diff --git a/common/src/main/java/org/tron/common/math/MathWrapper.java b/platform/src/main/java/x86/org/tron/common/math/MathWrapper.java similarity index 100% rename from common/src/main/java/org/tron/common/math/MathWrapper.java rename to platform/src/main/java/x86/org/tron/common/math/MathWrapper.java diff --git a/chainbase/src/main/java/org/tron/common/utils/MarketOrderPriceComparatorForRockDB.java b/platform/src/main/java/x86/org/tron/common/utils/MarketOrderPriceComparatorForRocksDB.java similarity index 70% rename from chainbase/src/main/java/org/tron/common/utils/MarketOrderPriceComparatorForRockDB.java rename to platform/src/main/java/x86/org/tron/common/utils/MarketOrderPriceComparatorForRocksDB.java index d3812f0f6bc..be406ff658d 100644 --- a/chainbase/src/main/java/org/tron/common/utils/MarketOrderPriceComparatorForRockDB.java +++ b/platform/src/main/java/x86/org/tron/common/utils/MarketOrderPriceComparatorForRocksDB.java @@ -3,11 +3,10 @@ import org.rocksdb.ComparatorOptions; import org.rocksdb.DirectSlice; import org.rocksdb.util.DirectBytewiseComparator; -import org.tron.core.capsule.utils.MarketUtils; -public class MarketOrderPriceComparatorForRockDB extends DirectBytewiseComparator { +public class MarketOrderPriceComparatorForRocksDB extends DirectBytewiseComparator { - public MarketOrderPriceComparatorForRockDB(final ComparatorOptions copt) { + public MarketOrderPriceComparatorForRocksDB(final ComparatorOptions copt) { super(copt); } @@ -18,7 +17,7 @@ public String name() { @Override public int compare(final DirectSlice a, final DirectSlice b) { - return MarketUtils.comparePriceKey(convertDataToBytes(a), convertDataToBytes(b)); + return MarketComparator.comparePriceKey(convertDataToBytes(a), convertDataToBytes(b)); } /** diff --git a/plugins/README.md b/plugins/README.md index 0db6f2e6143..db25811882f 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -2,7 +2,7 @@ This package contains a set of tools for TRON, the followings are the documentation for each tool. -## DB Archive +## DB Archive(Requires x86 + LevelDB) DB archive provides the ability to reformat the manifest according to the current `database`, parameters are compatible with the previous `ArchiveManifest`. @@ -26,7 +26,7 @@ DB archive provides the ability to reformat the manifest according to the curren ``` -## DB Convert +## DB Convert(Requires x86 + LevelDB) DB convert provides a helper which can convert LevelDB data to RocksDB data, parameters are compatible with previous `DBConvert`. @@ -34,15 +34,13 @@ DB convert provides a helper which can convert LevelDB data to RocksDB data, par - ``: Input path for leveldb, default: output-directory/database. - ``: Output path for rocksdb, default: output-directory-dst/database. -- `--safe`: In safe mode, read data from leveldb then put into rocksdb, it's a very time-consuming procedure. If not, just change engine.properties from leveldb to rocksdb, rocksdb - is compatible with leveldb for the current version. This may not be the case in the future, default: false. - `-h | --help`: Provide the help info. ### Examples: ```shell script # full command - java -jar Toolkit.jar db convert [-h] [--safe] + java -jar Toolkit.jar db convert [-h] # examples java -jar Toolkit.jar db convert output-directory/database /tmp/database ``` @@ -66,7 +64,7 @@ DB copy provides a helper which can copy LevelDB or RocksDB data quickly on the java -jar Toolkit.jar db cp output-directory/database /tmp/databse ``` -## DB Lite +## DB Lite(LevelDB unavailable on ARM) DB lite provides lite database, parameters are compatible with previous `LiteFullNodeTool`. @@ -134,7 +132,7 @@ Execute move command. java -jar Toolkit.jar db mv -c main_net_config.conf -d /data/tron/output-directory ``` -## DB Root +## DB Root(LevelDB unavailable on ARM) DB root provides a helper which can compute merkle root for tiny db. diff --git a/plugins/build.gradle b/plugins/build.gradle index 01afaa01708..40d68e19d2f 100644 --- a/plugins/build.gradle +++ b/plugins/build.gradle @@ -20,6 +20,15 @@ configurations.getByName('checkstyleConfig') { transitive = false } +sourceSets { + main { + java.srcDirs = rootProject.archInfo.sourceSets.main.java.srcDirs + } + test { + java.srcDirs = rootProject.archInfo.sourceSets.test.java.srcDirs + } +} + dependencies { //local libraries implementation fileTree(dir: 'libs', include: '*.jar') @@ -29,9 +38,18 @@ dependencies { implementation group: 'com.typesafe', name: 'config', version: '1.3.2' implementation group: 'me.tongfei', name: 'progressbar', version: '0.9.3' implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.69' - implementation group: 'org.rocksdb', name: 'rocksdbjni', version: '5.15.10' - implementation 'io.github.tronprotocol:leveldbjni-all:1.18.2' - implementation 'io.github.tronprotocol:leveldb:1.18.2' + if (rootProject.archInfo.isArm64) { + testRuntimeOnly group: 'org.fusesource.hawtjni', name: 'hawtjni-runtime', version: '1.18' // for test + implementation project(":platform") + } else { + implementation project(":platform"), { + exclude(group: 'org.fusesource.leveldbjni', module: 'leveldbjni-all') + exclude(group: 'io.github.tronprotocol', module: 'zksnark-java-sdk') + exclude(group: 'commons-io', module: 'commons-io') + } + implementation 'io.github.tronprotocol:leveldbjni-all:1.18.2' + implementation 'io.github.tronprotocol:leveldb:1.18.2' + } implementation project(":protocol") } @@ -76,6 +94,17 @@ test { destinationFile = file("../framework/build/jacoco/jacocoTest1.exec") classDumpDir = file("$buildDir/jacoco/classpathdumps") } + + if (rootProject.archInfo.isArm64) { + exclude 'org/tron/plugins/leveldb/**' + filter { + excludeTestsMatching '*.*leveldb*' + excludeTestsMatching '*.*Leveldb*' + excludeTestsMatching '*.*LevelDB*' + excludeTestsMatching '*.*LevelDb*' + excludeTestsMatching '*.*Archive*' + } + } } jacocoTestReport { @@ -94,7 +123,7 @@ def binaryRelease(taskName, jarName, mainClass) { from(sourceSets.main.output) { include "/**" } - dependsOn project(':protocol').jar // explicit_dependency + dependsOn (project(':protocol').jar, project(':platform').jar) // explicit_dependency from { configurations.runtimeClasspath.collect { // https://docs.gradle.org/current/userguide/upgrading_version_6.html#changes_6.3 it.isDirectory() ? it : zipTree(it) @@ -127,7 +156,7 @@ def createScript(project, mainClass, name) { } } } -applicationDistribution.from("../gradle/java-tron.vmoptions") { +applicationDistribution.from(rootProject.archInfo.VMOptions) { into "bin" } createScript(project, 'org.tron.plugins.ArchiveManifest', 'ArchiveManifest') diff --git a/plugins/src/main/java/arm/org/tron/plugins/ArchiveManifest.java b/plugins/src/main/java/arm/org/tron/plugins/ArchiveManifest.java new file mode 100644 index 00000000000..b7848cf4c6f --- /dev/null +++ b/plugins/src/main/java/arm/org/tron/plugins/ArchiveManifest.java @@ -0,0 +1,29 @@ +package org.tron.plugins; + +import lombok.extern.slf4j.Slf4j; +import org.tron.common.arch.Arch; + +/** + * ARM architecture only supports RocksDB, + * which does not require manifest rebuilding (manifest rebuilding is a LevelDB-only feature). + * This command is not supported but retained for compatibility. + **/ +@Slf4j(topic = "archive") +public class ArchiveManifest { + + public static void main(String[] args) { + int exitCode = run(args); + System.exit(exitCode); + } + + public static int run(String[] args) { + String tips = String.format( + "%s architecture only supports RocksDB, which does not require manifest rebuilding " + + "(manifest rebuilding is a LevelDB-only feature).", + Arch.getOsArch()); + System.out.println(tips); + logger.warn(tips); + return 0; + } + +} diff --git a/plugins/src/main/java/arm/org/tron/plugins/DbArchive.java b/plugins/src/main/java/arm/org/tron/plugins/DbArchive.java new file mode 100644 index 00000000000..03c52f33f02 --- /dev/null +++ b/plugins/src/main/java/arm/org/tron/plugins/DbArchive.java @@ -0,0 +1,50 @@ +package org.tron.plugins; + +import java.util.concurrent.Callable; +import lombok.extern.slf4j.Slf4j; +import org.tron.common.arch.Arch; +import picocli.CommandLine; +import picocli.CommandLine.Option; + +/** + * ARM architecture only supports RocksDB, + * which does not require manifest rebuilding (manifest rebuilding is a LevelDB-only feature). + * This command is not supported but retained for compatibility. + **/ +@Slf4j(topic = "archive") +@CommandLine.Command(name = "archive", description = "A helper to rewrite leveldb manifest.") +public class DbArchive implements Callable { + + @CommandLine.Spec + CommandLine.Model.CommandSpec spec; + @Option(names = {"-d", "--database-directory"}, + defaultValue = "output-directory/database", + description = "java-tron database directory. Default: ${DEFAULT-VALUE}") + private String databaseDirectory; + + @Option(names = {"-b", "--batch-size"}, + defaultValue = "80000", + description = "deal manifest batch size. Default: ${DEFAULT-VALUE}") + private int maxBatchSize; + + @Option(names = {"-m", "--manifest-size"}, + defaultValue = "0", + description = "manifest min size(M) to archive. Default: ${DEFAULT-VALUE}") + private int maxManifestSize; + + @Option(names = {"-h", "--help"}) + private boolean help; + + + @Override + public Integer call() throws Exception { + String tips = String.format( + "%s architecture only supports RocksDB, which does not require manifest rebuilding " + + "(manifest rebuilding is a LevelDB-only feature).", + Arch.getOsArch()); + spec.commandLine().getErr().println(spec.commandLine().getColorScheme().errorText(tips)); + logger.warn(tips); + return 0; + } + +} diff --git a/plugins/src/main/java/org/tron/plugins/Db.java b/plugins/src/main/java/common/org/tron/plugins/Db.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/Db.java rename to plugins/src/main/java/common/org/tron/plugins/Db.java diff --git a/plugins/src/main/java/org/tron/plugins/DbConvert.java b/plugins/src/main/java/common/org/tron/plugins/DbConvert.java similarity index 91% rename from plugins/src/main/java/org/tron/plugins/DbConvert.java rename to plugins/src/main/java/common/org/tron/plugins/DbConvert.java index a75b235bbcf..37ea6bdeca4 100644 --- a/plugins/src/main/java/org/tron/plugins/DbConvert.java +++ b/plugins/src/main/java/common/org/tron/plugins/DbConvert.java @@ -20,6 +20,7 @@ import org.rocksdb.RocksDBException; import org.rocksdb.RocksIterator; import org.rocksdb.Status; +import org.tron.common.arch.Arch; import org.tron.plugins.utils.DBUtils; import org.tron.plugins.utils.FileUtils; import picocli.CommandLine; @@ -49,20 +50,19 @@ public class DbConvert implements Callable { description = "Output path for rocksdb. Default: ${DEFAULT-VALUE}") private File dest; - @CommandLine.Option(names = {"--safe"}, - description = "In safe mode, read data from leveldb then put rocksdb." - + "If not, just change engine.properties from leveldb to rocksdb," - + "rocksdb is compatible with leveldb for current version." - + "This may not be the case in the future." - + "Default: ${DEFAULT-VALUE}") - private boolean safe; - @CommandLine.Option(names = {"-h", "--help"}) private boolean help; @Override public Integer call() throws Exception { + if (Arch.isArm64()) { + String tips = String.format("This command is not supported on %s architecture.", + Arch.getOsArch()); + spec.commandLine().getErr().println(spec.commandLine().getColorScheme().errorText(tips)); + logger.error(tips); + return 0; + } if (help) { spec.commandLine().usage(System.out); return 0; @@ -95,12 +95,12 @@ public Integer call() throws Exception { final long time = System.currentTimeMillis(); List services = new ArrayList<>(); files.forEach(f -> services.add( - new DbConverter(src.getPath(), dest.getPath(), f.getName(), safe))); + new DbConverter(src.getPath(), dest.getPath(), f.getName()))); cpList.forEach(f -> services.add( new DbConverter( Paths.get(src.getPath(), DBUtils.CHECKPOINT_DB_V2).toString(), Paths.get(dest.getPath(), DBUtils.CHECKPOINT_DB_V2).toString(), - f.getName(), safe))); + f.getName()))); List fails = ProgressBar.wrap(services.stream(), "convert task").parallel().map( dbConverter -> { try { @@ -140,15 +140,12 @@ static class DbConverter implements Converter { private long srcDbValueSum = 0L; private long dstDbValueSum = 0L; - private boolean safe; - - public DbConverter(String srcDir, String dstDir, String name, boolean safe) { + public DbConverter(String srcDir, String dstDir, String name) { this.srcDir = srcDir; this.dstDir = dstDir; this.dbName = name; this.srcDbPath = Paths.get(this.srcDir, name); this.dstDbPath = Paths.get(this.dstDir, name); - this.safe = safe; } @Override @@ -178,23 +175,15 @@ public boolean doConvert() throws Exception { FileUtils.createDirIfNotExists(dstDir); logger.info("Convert database {} start", this.dbName); - if (safe) { - convertLevelToRocks(); - compact(); - } else { - FileUtils.copyDir(Paths.get(srcDir), Paths.get(dstDir), dbName); - } + convertLevelToRocks(); + compact(); + boolean result = check() && createEngine(dstDbPath.toString()); long etime = System.currentTimeMillis(); if (result) { - if (safe) { - logger.info("Convert database {} successful end with {} key-value {} minutes", - this.dbName, this.srcDbKeyCount, (etime - startTime) / 1000.0 / 60); - } else { - logger.info("Convert database {} successful end {} minutes", - this.dbName, (etime - startTime) / 1000.0 / 60); - } + logger.info("Convert database {} successful end with {} key-value {} minutes", + this.dbName, this.srcDbKeyCount, (etime - startTime) / 1000.0 / 60); } else { logger.info("Convert database {} failure", this.dbName); @@ -310,9 +299,6 @@ private void compact() throws RocksDBException { } private boolean check() throws RocksDBException { - if (!safe) { - return true; - } try ( RocksDB rocks = DBUtils.newRocksDbReadOnly(this.dstDbPath); org.rocksdb.ReadOptions r = new org.rocksdb.ReadOptions().setFillCache(false); diff --git a/plugins/src/main/java/org/tron/plugins/DbCopy.java b/plugins/src/main/java/common/org/tron/plugins/DbCopy.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/DbCopy.java rename to plugins/src/main/java/common/org/tron/plugins/DbCopy.java diff --git a/plugins/src/main/java/org/tron/plugins/DbLite.java b/plugins/src/main/java/common/org/tron/plugins/DbLite.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/DbLite.java rename to plugins/src/main/java/common/org/tron/plugins/DbLite.java diff --git a/plugins/src/main/java/org/tron/plugins/DbMove.java b/plugins/src/main/java/common/org/tron/plugins/DbMove.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/DbMove.java rename to plugins/src/main/java/common/org/tron/plugins/DbMove.java diff --git a/plugins/src/main/java/org/tron/plugins/DbRoot.java b/plugins/src/main/java/common/org/tron/plugins/DbRoot.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/DbRoot.java rename to plugins/src/main/java/common/org/tron/plugins/DbRoot.java diff --git a/plugins/src/main/java/org/tron/plugins/Toolkit.java b/plugins/src/main/java/common/org/tron/plugins/Toolkit.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/Toolkit.java rename to plugins/src/main/java/common/org/tron/plugins/Toolkit.java diff --git a/plugins/src/main/java/org/tron/plugins/utils/ByteArray.java b/plugins/src/main/java/common/org/tron/plugins/utils/ByteArray.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/utils/ByteArray.java rename to plugins/src/main/java/common/org/tron/plugins/utils/ByteArray.java diff --git a/plugins/src/main/java/org/tron/plugins/utils/CryptoUitls.java b/plugins/src/main/java/common/org/tron/plugins/utils/CryptoUitls.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/utils/CryptoUitls.java rename to plugins/src/main/java/common/org/tron/plugins/utils/CryptoUitls.java diff --git a/plugins/src/main/java/org/tron/plugins/utils/DBUtils.java b/plugins/src/main/java/common/org/tron/plugins/utils/DBUtils.java similarity index 94% rename from plugins/src/main/java/org/tron/plugins/utils/DBUtils.java rename to plugins/src/main/java/common/org/tron/plugins/utils/DBUtils.java index f8559d5dba8..507a8ad798e 100644 --- a/plugins/src/main/java/org/tron/plugins/utils/DBUtils.java +++ b/plugins/src/main/java/common/org/tron/plugins/utils/DBUtils.java @@ -16,8 +16,9 @@ import org.rocksdb.Options; import org.rocksdb.RocksDB; import org.rocksdb.RocksDBException; -import org.tron.plugins.comparator.MarketOrderPriceComparatorForLevelDB; -import org.tron.plugins.comparator.MarketOrderPriceComparatorForRockDB; +import org.tron.common.arch.Arch; +import org.tron.common.utils.MarketOrderPriceComparatorForLevelDB; +import org.tron.common.utils.MarketOrderPriceComparatorForRocksDB; import org.tron.protos.Protocol; public class DBUtils { @@ -65,6 +66,7 @@ static Operator valueOf(byte b) { public static final String ROCKSDB = "ROCKSDB"; public static DB newLevelDb(Path db) throws IOException { + Arch.throwUnsupportedArm64Exception(); File file = db.toFile(); org.iq80.leveldb.Options dbOptions = newDefaultLevelDbOptions(); if (MARKET_PAIR_PRICE_TO_ORDER.equalsIgnoreCase(file.getName())) { @@ -115,7 +117,7 @@ private static Options newDefaultRocksDbOptions(boolean forBulkLoad) { public static RocksDB newRocksDb(Path db) throws RocksDBException { try (Options options = newDefaultRocksDbOptions(false)) { if (MARKET_PAIR_PRICE_TO_ORDER.equalsIgnoreCase(db.getFileName().toString())) { - options.setComparator(new MarketOrderPriceComparatorForRockDB(new ComparatorOptions())); + options.setComparator(new MarketOrderPriceComparatorForRocksDB(new ComparatorOptions())); } return RocksDB.open(options, db.toString()); } @@ -124,7 +126,7 @@ public static RocksDB newRocksDb(Path db) throws RocksDBException { public static RocksDB newRocksDbForBulkLoad(Path db) throws RocksDBException { try (Options options = newDefaultRocksDbOptions(true)) { if (MARKET_PAIR_PRICE_TO_ORDER.equalsIgnoreCase(db.getFileName().toString())) { - options.setComparator(new MarketOrderPriceComparatorForRockDB(new ComparatorOptions())); + options.setComparator(new MarketOrderPriceComparatorForRocksDB(new ComparatorOptions())); } return RocksDB.open(options, db.toString()); } @@ -134,7 +136,7 @@ public static RocksDB newRocksDbForBulkLoad(Path db) throws RocksDBException { public static RocksDB newRocksDbReadOnly(Path db) throws RocksDBException { try (Options options = newDefaultRocksDbOptions(false)) { if (MARKET_PAIR_PRICE_TO_ORDER.equalsIgnoreCase(db.getFileName().toString())) { - options.setComparator(new MarketOrderPriceComparatorForRockDB(new ComparatorOptions())); + options.setComparator(new MarketOrderPriceComparatorForRocksDB(new ComparatorOptions())); } return RocksDB.openReadOnly(options, db.toString()); } diff --git a/plugins/src/main/java/org/tron/plugins/utils/FileUtils.java b/plugins/src/main/java/common/org/tron/plugins/utils/FileUtils.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/utils/FileUtils.java rename to plugins/src/main/java/common/org/tron/plugins/utils/FileUtils.java diff --git a/plugins/src/main/java/common/org/tron/plugins/utils/MarketUtils.java b/plugins/src/main/java/common/org/tron/plugins/utils/MarketUtils.java new file mode 100644 index 00000000000..9bcfd5e71ce --- /dev/null +++ b/plugins/src/main/java/common/org/tron/plugins/utils/MarketUtils.java @@ -0,0 +1,68 @@ +package org.tron.plugins.utils; + +public class MarketUtils { + + public static final int TOKEN_ID_LENGTH = ByteArray + .fromString(Long.toString(Long.MAX_VALUE)).length; // 19 + + + + /** + * In order to avoid the difference between the data of same key stored and fetched by hashMap and + * levelDB, when creating the price key, we will find the GCD (Greatest Common Divisor) of + * sellTokenQuantity and buyTokenQuantity. + */ + public static byte[] createPairPriceKey(byte[] sellTokenId, byte[] buyTokenId, + long sellTokenQuantity, long buyTokenQuantity) { + + byte[] sellTokenQuantityBytes; + byte[] buyTokenQuantityBytes; + + // cal the GCD + long gcd = findGCD(sellTokenQuantity, buyTokenQuantity); + if (gcd == 0) { + sellTokenQuantityBytes = ByteArray.fromLong(sellTokenQuantity); + buyTokenQuantityBytes = ByteArray.fromLong(buyTokenQuantity); + } else { + sellTokenQuantityBytes = ByteArray.fromLong(sellTokenQuantity / gcd); + buyTokenQuantityBytes = ByteArray.fromLong(buyTokenQuantity / gcd); + } + + return doCreatePairPriceKey(sellTokenId, buyTokenId, + sellTokenQuantityBytes, buyTokenQuantityBytes); + } + + public static long findGCD(long number1, long number2) { + if (number1 == 0 || number2 == 0) { + return 0; + } + return calGCD(number1, number2); + } + + private static long calGCD(long number1, long number2) { + if (number2 == 0) { + return number1; + } + return calGCD(number2, number1 % number2); + } + + + private static byte[] doCreatePairPriceKey(byte[] sellTokenId, byte[] buyTokenId, + byte[] sellTokenQuantity, byte[] buyTokenQuantity) { + byte[] result = new byte[TOKEN_ID_LENGTH + TOKEN_ID_LENGTH + + sellTokenQuantity.length + buyTokenQuantity.length]; + + System.arraycopy(sellTokenId, 0, result, 0, sellTokenId.length); + System.arraycopy(buyTokenId, 0, result, TOKEN_ID_LENGTH, buyTokenId.length); + System.arraycopy(sellTokenQuantity, 0, result, + TOKEN_ID_LENGTH + TOKEN_ID_LENGTH, + sellTokenQuantity.length); + System.arraycopy(buyTokenQuantity, 0, result, + TOKEN_ID_LENGTH + TOKEN_ID_LENGTH + buyTokenQuantity.length, + buyTokenQuantity.length); + + return result; + } + + +} diff --git a/plugins/src/main/java/org/tron/plugins/utils/MerkleRoot.java b/plugins/src/main/java/common/org/tron/plugins/utils/MerkleRoot.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/utils/MerkleRoot.java rename to plugins/src/main/java/common/org/tron/plugins/utils/MerkleRoot.java diff --git a/plugins/src/main/java/org/tron/plugins/utils/Sha256Hash.java b/plugins/src/main/java/common/org/tron/plugins/utils/Sha256Hash.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/utils/Sha256Hash.java rename to plugins/src/main/java/common/org/tron/plugins/utils/Sha256Hash.java diff --git a/plugins/src/main/java/org/tron/plugins/utils/db/DBInterface.java b/plugins/src/main/java/common/org/tron/plugins/utils/db/DBInterface.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/utils/db/DBInterface.java rename to plugins/src/main/java/common/org/tron/plugins/utils/db/DBInterface.java diff --git a/plugins/src/main/java/org/tron/plugins/utils/db/DBIterator.java b/plugins/src/main/java/common/org/tron/plugins/utils/db/DBIterator.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/utils/db/DBIterator.java rename to plugins/src/main/java/common/org/tron/plugins/utils/db/DBIterator.java diff --git a/plugins/src/main/java/org/tron/plugins/utils/db/DbTool.java b/plugins/src/main/java/common/org/tron/plugins/utils/db/DbTool.java similarity index 85% rename from plugins/src/main/java/org/tron/plugins/utils/db/DbTool.java rename to plugins/src/main/java/common/org/tron/plugins/utils/db/DbTool.java index 429025e8f8b..cf4c69505bc 100644 --- a/plugins/src/main/java/org/tron/plugins/utils/db/DbTool.java +++ b/plugins/src/main/java/common/org/tron/plugins/utils/db/DbTool.java @@ -18,8 +18,8 @@ public class DbTool { private static final String KEY_ENGINE = "ENGINE"; private static final String ENGINE_FILE = "engine.properties"; - private static final String FILE_SEPARATOR = File.separator; private static final String ROCKSDB = "ROCKSDB"; + private static final String LEVELDB = "LEVELDB"; private static final Map dbMap = Maps.newConcurrentMap(); @@ -162,8 +162,7 @@ public static void close() { } private static DbType getDbType(String sourceDir, String dbName) { - String engineFile = String.format("%s%s%s%s%s", sourceDir, FILE_SEPARATOR, - dbName, FILE_SEPARATOR, ENGINE_FILE); + String engineFile = Paths.get(sourceDir, dbName, ENGINE_FILE).toString(); if (!new File(engineFile).exists()) { return DbType.LevelDB; } @@ -175,13 +174,22 @@ private static DbType getDbType(String sourceDir, String dbName) { } } - private static LevelDBImpl openLevelDb(Path db, String name) throws IOException { - return new LevelDBImpl(DBUtils.newLevelDb(db), name); + public static LevelDBImpl openLevelDb(Path db, String name) throws IOException { + LevelDBImpl leveldb = new LevelDBImpl(DBUtils.newLevelDb(db), name); + tryInitEngineFile(db, LEVELDB); + return leveldb; } - private static RocksDBImpl openRocksDb(Path db, String name) throws RocksDBException { - return new RocksDBImpl(DBUtils.newRocksDb(db), name); + public static RocksDBImpl openRocksDb(Path db, String name) throws RocksDBException { + RocksDBImpl rocksdb = new RocksDBImpl(DBUtils.newRocksDb(db), name); + tryInitEngineFile(db, ROCKSDB); + return rocksdb; } - + private static void tryInitEngineFile(Path db, String engine) { + String engineFile = Paths.get(db.toString(), ENGINE_FILE).toString(); + if (FileUtils.createFileIfNotExists(engineFile)) { + FileUtils.writeProperty(engineFile, KEY_ENGINE, engine); + } + } } diff --git a/plugins/src/main/java/org/tron/plugins/utils/db/LevelDBImpl.java b/plugins/src/main/java/common/org/tron/plugins/utils/db/LevelDBImpl.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/utils/db/LevelDBImpl.java rename to plugins/src/main/java/common/org/tron/plugins/utils/db/LevelDBImpl.java diff --git a/plugins/src/main/java/org/tron/plugins/utils/db/LevelDBIterator.java b/plugins/src/main/java/common/org/tron/plugins/utils/db/LevelDBIterator.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/utils/db/LevelDBIterator.java rename to plugins/src/main/java/common/org/tron/plugins/utils/db/LevelDBIterator.java diff --git a/plugins/src/main/java/org/tron/plugins/utils/db/RockDBIterator.java b/plugins/src/main/java/common/org/tron/plugins/utils/db/RockDBIterator.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/utils/db/RockDBIterator.java rename to plugins/src/main/java/common/org/tron/plugins/utils/db/RockDBIterator.java diff --git a/plugins/src/main/java/org/tron/plugins/utils/db/RocksDBImpl.java b/plugins/src/main/java/common/org/tron/plugins/utils/db/RocksDBImpl.java similarity index 100% rename from plugins/src/main/java/org/tron/plugins/utils/db/RocksDBImpl.java rename to plugins/src/main/java/common/org/tron/plugins/utils/db/RocksDBImpl.java diff --git a/plugins/src/main/java/org/tron/plugins/comparator/MarketOrderPriceComparatorForLevelDB.java b/plugins/src/main/java/org/tron/plugins/comparator/MarketOrderPriceComparatorForLevelDB.java deleted file mode 100644 index 0879f770e1f..00000000000 --- a/plugins/src/main/java/org/tron/plugins/comparator/MarketOrderPriceComparatorForLevelDB.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.tron.plugins.comparator; - -import org.iq80.leveldb.DBComparator; -import org.tron.plugins.utils.MarketUtils; - -public class MarketOrderPriceComparatorForLevelDB implements DBComparator { - - @Override - public String name() { - return "MarketOrderPriceComparator"; - } - - @Override - public byte[] findShortestSeparator(byte[] start, byte[] limit) { - return new byte[0]; - } - - @Override - public byte[] findShortSuccessor(byte[] key) { - return new byte[0]; - } - - @Override - public int compare(byte[] o1, byte[] o2) { - return MarketUtils.comparePriceKey(o1, o2); - } - -} \ No newline at end of file diff --git a/plugins/src/main/java/org/tron/plugins/comparator/MarketOrderPriceComparatorForRockDB.java b/plugins/src/main/java/org/tron/plugins/comparator/MarketOrderPriceComparatorForRockDB.java deleted file mode 100644 index cd718bdd2d7..00000000000 --- a/plugins/src/main/java/org/tron/plugins/comparator/MarketOrderPriceComparatorForRockDB.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.tron.plugins.comparator; - -import org.rocksdb.ComparatorOptions; -import org.rocksdb.DirectSlice; -import org.rocksdb.util.DirectBytewiseComparator; -import org.tron.plugins.utils.MarketUtils; - -public class MarketOrderPriceComparatorForRockDB extends DirectBytewiseComparator { - - public MarketOrderPriceComparatorForRockDB(final ComparatorOptions copt) { - super(copt); - } - - @Override - public String name() { - return "MarketOrderPriceComparator"; - } - - @Override - public int compare(final DirectSlice a, final DirectSlice b) { - return MarketUtils.comparePriceKey(convertDataToBytes(a), convertDataToBytes(b)); - } - - /** - * DirectSlice.data().array will throw UnsupportedOperationException. - * */ - public byte[] convertDataToBytes(DirectSlice directSlice) { - int capacity = directSlice.data().capacity(); - byte[] bytes = new byte[capacity]; - - for (int i = 0; i < capacity; i++) { - bytes[i] = directSlice.get(i); - } - - return bytes; - } - -} \ No newline at end of file diff --git a/plugins/src/main/java/org/tron/plugins/ArchiveManifest.java b/plugins/src/main/java/x86/org/tron/plugins/ArchiveManifest.java similarity index 98% rename from plugins/src/main/java/org/tron/plugins/ArchiveManifest.java rename to plugins/src/main/java/x86/org/tron/plugins/ArchiveManifest.java index 4d54df6d299..1d7a91027bf 100644 --- a/plugins/src/main/java/org/tron/plugins/ArchiveManifest.java +++ b/plugins/src/main/java/x86/org/tron/plugins/ArchiveManifest.java @@ -35,6 +35,7 @@ import org.iq80.leveldb.DB; import org.iq80.leveldb.Options; import org.iq80.leveldb.impl.Filename; +import org.tron.plugins.utils.DBUtils; import picocli.CommandLine; import picocli.CommandLine.Option; @@ -183,7 +184,7 @@ public boolean checkManifest(String dir) throws IOException { return false; } logger.info("CurrentName {}/{},size {} kb.", dir, currentName, current.length() / 1024); - if ("market_pair_price_to_order".equalsIgnoreCase(this.name)) { + if (DBUtils.MARKET_PAIR_PRICE_TO_ORDER.equalsIgnoreCase(this.name)) { logger.info("Db {} ignored.", this.name); return false; } diff --git a/plugins/src/main/java/org/tron/plugins/DbArchive.java b/plugins/src/main/java/x86/org/tron/plugins/DbArchive.java similarity index 98% rename from plugins/src/main/java/org/tron/plugins/DbArchive.java rename to plugins/src/main/java/x86/org/tron/plugins/DbArchive.java index e3032731ede..15bb281babf 100644 --- a/plugins/src/main/java/org/tron/plugins/DbArchive.java +++ b/plugins/src/main/java/x86/org/tron/plugins/DbArchive.java @@ -19,6 +19,7 @@ import org.iq80.leveldb.DB; import org.iq80.leveldb.Options; import org.iq80.leveldb.impl.Filename; +import org.tron.plugins.utils.DBUtils; import org.tron.plugins.utils.FileUtils; import picocli.CommandLine; import picocli.CommandLine.Option; @@ -163,7 +164,7 @@ public boolean checkManifest(String dir) throws IOException { return false; } logger.info("CurrentName {}/{},size {} kb.", dir, currentName, current.length() / 1024); - if ("market_pair_price_to_order".equalsIgnoreCase(this.name)) { + if (DBUtils.MARKET_PAIR_PRICE_TO_ORDER.equalsIgnoreCase(this.name)) { logger.info("Db {} ignored.", this.name); return false; } diff --git a/plugins/src/test/java/org/tron/plugins/DbCopyTest.java b/plugins/src/test/java/org/tron/plugins/DbCopyTest.java index 9e488a592aa..7548812b799 100644 --- a/plugins/src/test/java/org/tron/plugins/DbCopyTest.java +++ b/plugins/src/test/java/org/tron/plugins/DbCopyTest.java @@ -4,12 +4,23 @@ import java.util.UUID; import org.junit.Assert; import org.junit.Test; +import org.rocksdb.RocksDBException; +import org.tron.plugins.utils.db.DbTool; import picocli.CommandLine; public class DbCopyTest extends DbTest { @Test - public void testRun() { + public void testRunForLevelDB() throws RocksDBException, IOException { + init(DbTool.DbType.LevelDB); + String[] args = new String[] { "db", "cp", INPUT_DIRECTORY, + genarateTmpDir()}; + Assert.assertEquals(0, cli.execute(args)); + } + + @Test + public void testRunForRocksDB() throws RocksDBException, IOException { + init(DbTool.DbType.RocksDB); String[] args = new String[] { "db", "cp", INPUT_DIRECTORY, genarateTmpDir()}; Assert.assertEquals(0, cli.execute(args)); diff --git a/plugins/src/test/java/org/tron/plugins/DbLiteTest.java b/plugins/src/test/java/org/tron/plugins/DbLiteTest.java index b4c66c9820f..b0c7f3b96be 100644 --- a/plugins/src/test/java/org/tron/plugins/DbLiteTest.java +++ b/plugins/src/test/java/org/tron/plugins/DbLiteTest.java @@ -67,9 +67,10 @@ public void shutdown() throws InterruptedException { context.close(); } - public void init() throws IOException { + public void init(String dbType) throws IOException { dbPath = folder.newFolder().toString(); - Args.setParam(new String[]{"-d", dbPath, "-w", "--p2p-disable", "true"}, + Args.setParam(new String[]{ + "-d", dbPath, "-w", "--p2p-disable", "true", "--storage-db-engine", dbType}, "config-localtest.conf"); // allow account root Args.getInstance().setAllowAccountStateRoot(1); @@ -85,11 +86,11 @@ public void clear() { Args.clearParam(); } - void testTools(String dbType, int checkpointVersion) + public void testTools(String dbType, int checkpointVersion) throws InterruptedException, IOException { logger.info("dbType {}, checkpointVersion {}", dbType, checkpointVersion); dbPath = String.format("%s_%s_%d", dbPath, dbType, System.currentTimeMillis()); - init(); + init(dbType); final String[] argsForSnapshot = new String[]{"-o", "split", "-t", "snapshot", "--fn-data-path", dbPath + File.separator + databaseDir, "--dataset-path", @@ -101,7 +102,6 @@ void testTools(String dbType, int checkpointVersion) final String[] argsForMerge = new String[]{"-o", "merge", "--fn-data-path", dbPath + File.separator + databaseDir, "--dataset-path", dbPath + File.separator + "history"}; - Args.getInstance().getStorage().setDbEngine(dbType); Args.getInstance().getStorage().setCheckpointVersion(checkpointVersion); DbLite.setRecentBlks(3); // start fullNode diff --git a/plugins/src/test/java/org/tron/plugins/DbMoveTest.java b/plugins/src/test/java/org/tron/plugins/DbMoveTest.java index c1bc6b470fc..5b25739f272 100644 --- a/plugins/src/test/java/org/tron/plugins/DbMoveTest.java +++ b/plugins/src/test/java/org/tron/plugins/DbMoveTest.java @@ -1,52 +1,41 @@ package org.tron.plugins; -import static org.iq80.leveldb.impl.Iq80DBFactory.factory; - import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.file.Paths; -import java.util.UUID; import lombok.extern.slf4j.Slf4j; -import org.junit.AfterClass; +import org.junit.After; import org.junit.Assert; -import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; -import org.tron.plugins.utils.FileUtils; +import org.junit.rules.TemporaryFolder; +import org.rocksdb.RocksDBException; +import org.tron.plugins.utils.DBUtils; +import org.tron.plugins.utils.db.DbTool; import picocli.CommandLine; @Slf4j public class DbMoveTest { private static final String OUTPUT_DIRECTORY = "output-directory-toolkit"; - private static final String OUTPUT_DIRECTORY_DATABASE = - Paths.get(OUTPUT_DIRECTORY,"ori","database").toString(); - private static final String ENGINE = "ENGINE"; - private static final String LEVELDB = "LEVELDB"; - private static final String ACCOUNT = "account"; - private static final String TRANS = "trans"; - private static final String MARKET = "market_pair_price_to_order"; - private static final String ENGINE_FILE = "engine.properties"; + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); - @BeforeClass - public static void init() throws IOException { - File file = new File(OUTPUT_DIRECTORY_DATABASE, ACCOUNT); - factory.open(file, ArchiveManifest.newDefaultLevelDbOptions()).close(); - FileUtils.writeProperty(file + File.separator + ENGINE_FILE, ENGINE, LEVELDB); + private static final String ACCOUNT = "account"; + private static final String TRANS = "trans"; - file = new File(OUTPUT_DIRECTORY_DATABASE, MARKET); - factory.open(file, ArchiveManifest.newDefaultLevelDbOptions()).close(); - FileUtils.writeProperty(file + File.separator + ENGINE_FILE, ENGINE, LEVELDB); - file = new File(OUTPUT_DIRECTORY_DATABASE, TRANS); - factory.open(file, ArchiveManifest.newDefaultLevelDbOptions()).close(); - FileUtils.writeProperty(file + File.separator + ENGINE_FILE, ENGINE, LEVELDB); + private void init(DbTool.DbType dbType, String path) throws IOException, RocksDBException { + DbTool.getDB(path, ACCOUNT, dbType).close(); + DbTool.getDB(path, DBUtils.MARKET_PAIR_PRICE_TO_ORDER, dbType).close(); + DbTool.getDB(path, TRANS, dbType).close(); } - @AfterClass - public static void destroy() { + @After + public void destroy() { deleteDir(new File(OUTPUT_DIRECTORY)); } @@ -74,9 +63,23 @@ private static String getConfig(String config) { } @Test - public void testMv() { + public void testMvForLevelDB() throws RocksDBException, IOException { + File database = temporaryFolder.newFolder("database"); + init(DbTool.DbType.LevelDB, Paths.get(database.getPath()).toString()); + String[] args = new String[] {"db", "mv", "-d", + database.getParent(), "-c", + getConfig("config.conf")}; + CommandLine cli = new CommandLine(new Toolkit()); + Assert.assertEquals(0, cli.execute(args)); + Assert.assertEquals(2, cli.execute(args)); + } + + @Test + public void testMvForRocksDB() throws RocksDBException, IOException { + File database = temporaryFolder.newFolder("database"); + init(DbTool.DbType.RocksDB, Paths.get(database.getPath()).toString()); String[] args = new String[] {"db", "mv", "-d", - Paths.get(OUTPUT_DIRECTORY,"ori").toString(), "-c", + database.getParent(), "-c", getConfig("config.conf")}; CommandLine cli = new CommandLine(new Toolkit()); Assert.assertEquals(0, cli.execute(args)); @@ -84,9 +87,10 @@ public void testMv() { } @Test - public void testDuplicate() { + public void testDuplicate() throws IOException { + File output = temporaryFolder.newFolder(); String[] args = new String[] {"db", "mv", "-d", - Paths.get(OUTPUT_DIRECTORY,"ori").toString(), "-c", + output.getPath(), "-c", getConfig("config-duplicate.conf")}; CommandLine cli = new CommandLine(new Toolkit()); Assert.assertEquals(2, cli.execute(args)); @@ -107,20 +111,19 @@ public void testDicNotExist() { } @Test - public void testConfNotExist() { + public void testConfNotExist() throws IOException { + File output = temporaryFolder.newFolder(); String[] args = new String[] {"db", "mv", "-d", - Paths.get(OUTPUT_DIRECTORY,"ori").toString(), "-c", + output.getPath(), "-c", "config.conf"}; CommandLine cli = new CommandLine(new Toolkit()); Assert.assertEquals(2, cli.execute(args)); } @Test - public void testEmpty() { - File file = new File(OUTPUT_DIRECTORY_DATABASE + File.separator + UUID.randomUUID()); - file.mkdirs(); - file.deleteOnExit(); - String[] args = new String[] {"db", "mv", "-d", file.toString(), "-c", + public void testEmpty() throws IOException { + File output = temporaryFolder.newFolder(); + String[] args = new String[] {"db", "mv", "-d", output.getPath(), "-c", getConfig("config.conf")}; CommandLine cli = new CommandLine(new Toolkit()); diff --git a/plugins/src/test/java/org/tron/plugins/DbRootTest.java b/plugins/src/test/java/org/tron/plugins/DbRootTest.java index b86688f77d5..9d032a43103 100644 --- a/plugins/src/test/java/org/tron/plugins/DbRootTest.java +++ b/plugins/src/test/java/org/tron/plugins/DbRootTest.java @@ -9,10 +9,8 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.rocksdb.RocksDBException; -import org.tron.plugins.utils.DBUtils; import org.tron.plugins.utils.db.DBInterface; import org.tron.plugins.utils.db.DbTool; -import org.tron.plugins.utils.db.LevelDBImpl; import picocli.CommandLine; @Slf4j @@ -27,8 +25,18 @@ public class DbRootTest { private static final String EMPTY_DB = "empty"; private static final String ERROR_DB = "error"; + + @Test + public void testRootForLevelDB() throws RocksDBException, IOException { + testRoot(DbTool.DbType.LevelDB); + } + @Test - public void testRoot() throws IOException, RocksDBException { + public void testRootForRocksDB() throws RocksDBException, IOException { + testRoot(DbTool.DbType.RocksDB); + } + + public void testRoot(DbTool.DbType dbType) throws IOException, RocksDBException { File file = folder.newFolder(); @@ -36,8 +44,8 @@ public void testRoot() throws IOException, RocksDBException { Assert.assertTrue(database.mkdirs()); - try (DBInterface normal = DbTool.getDB(database.toString(), NORMAL_DB, DbTool.DbType.LevelDB); - DBInterface empty = DbTool.getDB(database.toString(), EMPTY_DB, DbTool.DbType.RocksDB)) { + try (DBInterface normal = DbTool.getDB(database.toString(), NORMAL_DB, dbType); + DBInterface empty = DbTool.getDB(database.toString(), EMPTY_DB, dbType)) { for (int i = 0; i < 10; i++) { normal.put(("" + i).getBytes(), (NORMAL_DB + "-" + i).getBytes()); } @@ -53,8 +61,7 @@ public void testRoot() throws IOException, RocksDBException { "--db", EMPTY_DB}; Assert.assertEquals(0, cli.execute(args)); - try (DBInterface errorDb = new LevelDBImpl( - DBUtils.newLevelDb(Paths.get(database.toString(), ERROR_DB)), ERROR_DB)) { + try (DBInterface errorDb = DbTool.getDB(database.toString(), ERROR_DB, dbType)) { for (int i = 0; i < 10; i++) { errorDb.put(("" + i).getBytes(), (ERROR_DB + "-" + i).getBytes()); } diff --git a/plugins/src/test/java/org/tron/plugins/DbTest.java b/plugins/src/test/java/org/tron/plugins/DbTest.java index 8605fa18d50..9337723e8ff 100644 --- a/plugins/src/test/java/org/tron/plugins/DbTest.java +++ b/plugins/src/test/java/org/tron/plugins/DbTest.java @@ -5,42 +5,43 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.util.UUID; -import org.iq80.leveldb.DB; -import org.junit.Before; import org.junit.Rule; import org.junit.rules.TemporaryFolder; +import org.rocksdb.RocksDBException; import org.tron.plugins.utils.ByteArray; import org.tron.plugins.utils.DBUtils; import org.tron.plugins.utils.MarketUtils; +import org.tron.plugins.utils.db.DBInterface; +import org.tron.plugins.utils.db.DbTool; import picocli.CommandLine; public class DbTest { - String INPUT_DIRECTORY; + public String INPUT_DIRECTORY; private static final String ACCOUNT = "account"; private static final String MARKET = DBUtils.MARKET_PAIR_PRICE_TO_ORDER; - CommandLine cli = new CommandLine(new Toolkit()); + public CommandLine cli = new CommandLine(new Toolkit()); String tmpDir = System.getProperty("java.io.tmpdir"); @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); - @Before - public void init() throws IOException { + public void init(DbTool.DbType dbType) throws IOException, RocksDBException { INPUT_DIRECTORY = temporaryFolder.newFolder().toString(); - initDB(new File(INPUT_DIRECTORY, ACCOUNT)); - initDB(new File(INPUT_DIRECTORY, MARKET)); - initDB(new File(INPUT_DIRECTORY, DBUtils.CHECKPOINT_DB_V2)); + initDB(INPUT_DIRECTORY, ACCOUNT, dbType); + initDB(INPUT_DIRECTORY, MARKET, dbType); + initDB(INPUT_DIRECTORY, DBUtils.CHECKPOINT_DB_V2, dbType); } - private static void initDB(File file) throws IOException { - if (DBUtils.CHECKPOINT_DB_V2.equalsIgnoreCase(file.getName())) { - File dbFile = new File(file, DBUtils.CHECKPOINT_DB_V2); + private static void initDB(String sourceDir, String dbName, DbTool.DbType dbType) + throws IOException, RocksDBException { + if (DBUtils.CHECKPOINT_DB_V2.equalsIgnoreCase(dbName)) { + File dbFile = new File(sourceDir, DBUtils.CHECKPOINT_DB_V2); if (dbFile.mkdirs()) { for (int i = 0; i < 3; i++) { - try (DB db = DBUtils.newLevelDb(Paths.get(dbFile.getPath(), - System.currentTimeMillis() + ""))) { + try (DBInterface db = DbTool.getDB(dbFile.getPath(), + System.currentTimeMillis() + "", dbType)) { for (int j = 0; j < 100; j++) { byte[] bytes = UUID.randomUUID().toString().getBytes(); db.put(bytes, bytes); @@ -50,8 +51,8 @@ private static void initDB(File file) throws IOException { } return; } - try (DB db = DBUtils.newLevelDb(file.toPath())) { - if (MARKET.equalsIgnoreCase(file.getName())) { + try (DBInterface db = DbTool.getDB(sourceDir, dbName, dbType)) { + if (MARKET.equalsIgnoreCase(dbName)) { byte[] sellTokenID1 = ByteArray.fromString("100"); byte[] buyTokenID1 = ByteArray.fromString("200"); byte[] pairPriceKey1 = MarketUtils.createPairPriceKey( diff --git a/plugins/src/test/java/org/tron/plugins/ArchiveManifestTest.java b/plugins/src/test/java/org/tron/plugins/leveldb/ArchiveManifestTest.java similarity index 69% rename from plugins/src/test/java/org/tron/plugins/ArchiveManifestTest.java rename to plugins/src/test/java/org/tron/plugins/leveldb/ArchiveManifestTest.java index 4fd9e537d05..f5880d82e39 100644 --- a/plugins/src/test/java/org/tron/plugins/ArchiveManifestTest.java +++ b/plugins/src/test/java/org/tron/plugins/leveldb/ArchiveManifestTest.java @@ -1,6 +1,4 @@ -package org.tron.plugins; - -import static org.iq80.leveldb.impl.Iq80DBFactory.factory; +package org.tron.plugins.leveldb; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -14,47 +12,41 @@ import java.nio.charset.StandardCharsets; import java.util.Properties; import java.util.UUID; - import lombok.extern.slf4j.Slf4j; -import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.rocksdb.RocksDBException; +import org.tron.plugins.ArchiveManifest; +import org.tron.plugins.utils.DBUtils; +import org.tron.plugins.utils.db.DbTool; @Slf4j public class ArchiveManifestTest { - private static final String OUTPUT_DIRECTORY = "output-directory/database/archiveManifest"; + @ClassRule + public static final TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private static String OUTPUT_DIRECTORY; - private static final String ENGINE = "ENGINE"; - private static final String LEVELDB = "LEVELDB"; - private static final String ROCKSDB = "ROCKSDB"; private static final String ACCOUNT = "account"; private static final String ACCOUNT_ROCKSDB = "account-rocksdb"; - private static final String MARKET = "market_pair_price_to_order"; - private static final String ENGINE_FILE = "engine.properties"; - @BeforeClass - public static void init() throws IOException { - File file = new File(OUTPUT_DIRECTORY,ACCOUNT); - factory.open(file,ArchiveManifest.newDefaultLevelDbOptions()).close(); - writeProperty(file.toString() + File.separator + ENGINE_FILE,ENGINE,LEVELDB); - - file = new File(OUTPUT_DIRECTORY,MARKET); - factory.open(file,ArchiveManifest.newDefaultLevelDbOptions()).close(); - writeProperty(file.toString() + File.separator + ENGINE_FILE,ENGINE,LEVELDB); + public static void init() throws IOException, RocksDBException { + OUTPUT_DIRECTORY = temporaryFolder.newFolder("database").toString(); + File file = new File(OUTPUT_DIRECTORY, ACCOUNT); + DbTool.openLevelDb(file.toPath(),ACCOUNT).close(); - file = new File(OUTPUT_DIRECTORY,ACCOUNT_ROCKSDB); - factory.open(file,ArchiveManifest.newDefaultLevelDbOptions()).close(); - writeProperty(file.toString() + File.separator + ENGINE_FILE,ENGINE,ROCKSDB); + file = new File(OUTPUT_DIRECTORY, DBUtils.MARKET_PAIR_PRICE_TO_ORDER); + DbTool.openLevelDb(file.toPath(), DBUtils.MARKET_PAIR_PRICE_TO_ORDER).close(); - } + file = new File(OUTPUT_DIRECTORY, ACCOUNT_ROCKSDB); + DbTool.openRocksDb(file.toPath(), ACCOUNT_ROCKSDB).close(); - @AfterClass - public static void destroy() { - deleteDir(new File(OUTPUT_DIRECTORY)); } @Test diff --git a/plugins/src/test/java/org/tron/plugins/DbArchiveTest.java b/plugins/src/test/java/org/tron/plugins/leveldb/DbArchiveTest.java similarity index 71% rename from plugins/src/test/java/org/tron/plugins/DbArchiveTest.java rename to plugins/src/test/java/org/tron/plugins/leveldb/DbArchiveTest.java index 10bed418764..69dca01e4f8 100644 --- a/plugins/src/test/java/org/tron/plugins/DbArchiveTest.java +++ b/plugins/src/test/java/org/tron/plugins/leveldb/DbArchiveTest.java @@ -1,6 +1,4 @@ -package org.tron.plugins; - -import static org.iq80.leveldb.impl.Iq80DBFactory.factory; +package org.tron.plugins.leveldb; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -12,48 +10,43 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; import java.util.Properties; import java.util.UUID; import lombok.extern.slf4j.Slf4j; -import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.rocksdb.RocksDBException; +import org.tron.plugins.Toolkit; +import org.tron.plugins.utils.DBUtils; +import org.tron.plugins.utils.db.DbTool; import picocli.CommandLine; @Slf4j public class DbArchiveTest { - private static final String OUTPUT_DIRECTORY = "output-directory/database/dbArchive"; + @ClassRule + public static final TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private static String OUTPUT_DIRECTORY; - private static final String ENGINE = "ENGINE"; - private static final String LEVELDB = "LEVELDB"; - private static final String ROCKSDB = "ROCKSDB"; private static final String ACCOUNT = "account"; private static final String ACCOUNT_ROCKSDB = "account-rocksdb"; - private static final String MARKET = "market_pair_price_to_order"; - private static final String ENGINE_FILE = "engine.properties"; @BeforeClass - public static void init() throws IOException { - File file = new File(OUTPUT_DIRECTORY,ACCOUNT); - factory.open(file,ArchiveManifest.newDefaultLevelDbOptions()).close(); - writeProperty(file.toString() + File.separator + ENGINE_FILE,ENGINE,LEVELDB); + public static void init() throws IOException, RocksDBException { + OUTPUT_DIRECTORY = temporaryFolder.newFolder("database").toString(); + File file = new File(OUTPUT_DIRECTORY, ACCOUNT); + DbTool.openLevelDb(file.toPath(),ACCOUNT).close(); - file = new File(OUTPUT_DIRECTORY,MARKET); - factory.open(file,ArchiveManifest.newDefaultLevelDbOptions()).close(); - writeProperty(file.toString() + File.separator + ENGINE_FILE,ENGINE,LEVELDB); + file = new File(OUTPUT_DIRECTORY, DBUtils.MARKET_PAIR_PRICE_TO_ORDER); + DbTool.openLevelDb(file.toPath(), DBUtils.MARKET_PAIR_PRICE_TO_ORDER).close(); - file = new File(OUTPUT_DIRECTORY,ACCOUNT_ROCKSDB); - factory.open(file,ArchiveManifest.newDefaultLevelDbOptions()).close(); - writeProperty(file.toString() + File.separator + ENGINE_FILE,ENGINE,ROCKSDB); - - } + file = new File(OUTPUT_DIRECTORY, ACCOUNT_ROCKSDB); + DbTool.openRocksDb(file.toPath(), ACCOUNT_ROCKSDB).close(); - @AfterClass - public static void destroy() { - deleteDir(new File(OUTPUT_DIRECTORY)); } @Test diff --git a/plugins/src/test/java/org/tron/plugins/DbConvertTest.java b/plugins/src/test/java/org/tron/plugins/leveldb/DbConvertTest.java similarity index 76% rename from plugins/src/test/java/org/tron/plugins/DbConvertTest.java rename to plugins/src/test/java/org/tron/plugins/leveldb/DbConvertTest.java index 150e47c9f65..d24604f0a0b 100644 --- a/plugins/src/test/java/org/tron/plugins/DbConvertTest.java +++ b/plugins/src/test/java/org/tron/plugins/leveldb/DbConvertTest.java @@ -1,27 +1,25 @@ -package org.tron.plugins; +package org.tron.plugins.leveldb; import java.io.IOException; import java.util.UUID; import org.junit.Assert; import org.junit.Test; +import org.rocksdb.RocksDBException; +import org.tron.plugins.DbTest; +import org.tron.plugins.Toolkit; +import org.tron.plugins.utils.db.DbTool; import picocli.CommandLine; public class DbConvertTest extends DbTest { @Test - public void testRun() throws IOException { + public void testRun() throws IOException, RocksDBException { + init(DbTool.DbType.LevelDB); String[] args = new String[] { "db", "convert", INPUT_DIRECTORY, temporaryFolder.newFolder().toString() }; Assert.assertEquals(0, cli.execute(args)); } - @Test - public void testRunWithSafe() throws IOException { - String[] args = new String[] { "db", "convert", INPUT_DIRECTORY, - temporaryFolder.newFolder().toString(),"--safe" }; - Assert.assertEquals(0, cli.execute(args)); - } - @Test public void testHelp() { String[] args = new String[] {"db", "convert", "-h"}; diff --git a/plugins/src/test/java/org/tron/plugins/DbLiteLevelDbTest.java b/plugins/src/test/java/org/tron/plugins/leveldb/DbLiteLevelDbTest.java similarity index 76% rename from plugins/src/test/java/org/tron/plugins/DbLiteLevelDbTest.java rename to plugins/src/test/java/org/tron/plugins/leveldb/DbLiteLevelDbTest.java index 792f93ad197..7666806e2b5 100644 --- a/plugins/src/test/java/org/tron/plugins/DbLiteLevelDbTest.java +++ b/plugins/src/test/java/org/tron/plugins/leveldb/DbLiteLevelDbTest.java @@ -1,7 +1,8 @@ -package org.tron.plugins; +package org.tron.plugins.leveldb; import java.io.IOException; import org.junit.Test; +import org.tron.plugins.DbLiteTest; public class DbLiteLevelDbTest extends DbLiteTest { diff --git a/plugins/src/test/java/org/tron/plugins/DbLiteLevelDbV2Test.java b/plugins/src/test/java/org/tron/plugins/leveldb/DbLiteLevelDbV2Test.java similarity index 76% rename from plugins/src/test/java/org/tron/plugins/DbLiteLevelDbV2Test.java rename to plugins/src/test/java/org/tron/plugins/leveldb/DbLiteLevelDbV2Test.java index ae48e1d66e9..de32ae29c7c 100644 --- a/plugins/src/test/java/org/tron/plugins/DbLiteLevelDbV2Test.java +++ b/plugins/src/test/java/org/tron/plugins/leveldb/DbLiteLevelDbV2Test.java @@ -1,7 +1,8 @@ -package org.tron.plugins; +package org.tron.plugins.leveldb; import java.io.IOException; import org.junit.Test; +import org.tron.plugins.DbLiteTest; public class DbLiteLevelDbV2Test extends DbLiteTest { diff --git a/plugins/src/test/java/org/tron/plugins/DbLiteRocksDbTest.java b/plugins/src/test/java/org/tron/plugins/rocksdb/DbLiteRocksDbTest.java similarity index 76% rename from plugins/src/test/java/org/tron/plugins/DbLiteRocksDbTest.java rename to plugins/src/test/java/org/tron/plugins/rocksdb/DbLiteRocksDbTest.java index e6910b1103a..2f9c92f9679 100644 --- a/plugins/src/test/java/org/tron/plugins/DbLiteRocksDbTest.java +++ b/plugins/src/test/java/org/tron/plugins/rocksdb/DbLiteRocksDbTest.java @@ -1,7 +1,8 @@ -package org.tron.plugins; +package org.tron.plugins.rocksdb; import java.io.IOException; import org.junit.Test; +import org.tron.plugins.DbLiteTest; public class DbLiteRocksDbTest extends DbLiteTest { diff --git a/plugins/src/test/java/org/tron/plugins/rocksdb/DbLiteRocksDbV2Test.java b/plugins/src/test/java/org/tron/plugins/rocksdb/DbLiteRocksDbV2Test.java new file mode 100644 index 00000000000..ab1067fefc3 --- /dev/null +++ b/plugins/src/test/java/org/tron/plugins/rocksdb/DbLiteRocksDbV2Test.java @@ -0,0 +1,13 @@ +package org.tron.plugins.rocksdb; + +import java.io.IOException; +import org.junit.Test; +import org.tron.plugins.DbLiteTest; + +public class DbLiteRocksDbV2Test extends DbLiteTest { + + @Test + public void testToolsWithRocksDB() throws InterruptedException, IOException { + testTools("ROCKSDB", 2); + } +} diff --git a/plugins/src/test/resources/config.conf b/plugins/src/test/resources/config.conf index 2bfca7dbdd7..77d15d521eb 100644 --- a/plugins/src/test/resources/config.conf +++ b/plugins/src/test/resources/config.conf @@ -1,11 +1,5 @@ storage { - # Directory for storing persistent data - db.engine = "LEVELDB", - db.sync = false, - db.directory = "database", - index.directory = "index", - transHistory.switch = "on", properties = [ { name = "account", diff --git a/settings.gradle b/settings.gradle index eb304444378..af32bfca702 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,4 +8,5 @@ include 'common' include 'example:actuator-example' include 'crypto' include 'plugins' +include 'platform' diff --git a/start.sh.simple b/start.sh.simple new file mode 100644 index 00000000000..72862d9bdfc --- /dev/null +++ b/start.sh.simple @@ -0,0 +1,195 @@ +#!/bin/bash +############################################################################# +# +# GNU LESSER GENERAL PUBLIC LICENSE +# Version 3, 29 June 2007 +# +# Copyright (C) [2007] [TRON Foundation], Inc. +# Everyone is permitted to copy and distribute verbatim copies +# of this license document, but changing it is not allowed. +# +# +# This version of the GNU Lesser General Public License incorporates +# the terms and conditions of version 3 of the GNU General Public +# License, supplemented by the additional permissions listed below. +# +# You can find java-tron at https://github.com/tronprotocol/java-tron/ +# +############################################################################## +# TRON Full Node Management Simple Script +# +# NOTE: This is a simple and concise script to start and stop the java-tron full node, +# designed for developers to quickly get started and learn. +# It may not be suitable for production environments. +# +# Usage: +# sh start.sh # Start the java-tron FullNode +# sh start.sh -s # Stop the java-tron FullNode +# sh start.sh [options] # Start with additional java-tron options,such as: -c config.conf -d /path_to_data, etc. +# +############################################################################## + + +# adjust JVM start +# Set the minimum and maximum heap size to 9G, adjust as needed +VM_XMS="9G" +# Set the maximum heap size to 9G, adjust as needed +VM_XMX="9G" +# Set the maximum direct memory size to 1G, adjust as needed +VM_MAX_DIRECT_MEMORY_SIZE="1G" +# adjust JVM end + +FULL_NODE_JAR="FullNode.jar" +FULL_START_OPT=() +PID="" +MAX_STOP_TIME=60 +JAVACMD="" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +log() { + local level="$1"; shift + local timestamp color="" + timestamp=$(date '+%Y-%m-%d %H:%M:%S') + case "$level" in + INFO) color="$GREEN" ;; + WARN) color="$YELLOW" ;; + ERROR) color="$RED" ;; + esac + printf "%b[%s] [%s]:%b %s\n" "$color" "$timestamp" "$level" "$NC" "$*" | tee -a "${SCRIPT_DIR}/start.log" +} + +info() { log INFO "$@"; } +warn() { log WARN "$@"; } +error() { log ERROR "$@"; } +die() { error "$@"; exit 1; } + +ulimit -n 65535 || warn "Failed to set ulimit -n 65535" + +findJava() { + if [ -n "${JAVA_HOME:-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + [ -x "$JAVACMD" ] || die "JAVA_HOME is invalid: $JAVA_HOME" + else + JAVACMD="java" + which java >/dev/null 2>&1 || die "JAVA_HOME not set and no 'java' in PATH" + fi + "$JAVACMD" -version > /dev/null 2>&1 || die "Java command not working" +} + +checkPid() { + # shellcheck disable=SC2009 + PID=$(ps -ef |grep $FULL_NODE_JAR |grep -v grep |awk '{print $2}') +} + + +stopService() { + checkPid + + if ! kill -0 "$PID" 2>/dev/null; then + info "java-tron is not running." + return 0 + fi + info "Stopping java-tron service (PID: $PID)" + + local count=1 + + while [ -n "$PID" ] && [ $count -le $MAX_STOP_TIME ]; do + kill -TERM "$PID" 2>/dev/null && info "Sent SIGTERM to java-tron (PID: $PID), attempt $count" + sleep 1 + checkPid + count=$((count + 1)) + done + + if [ -n "$PID" ]; then + warn "Forcing kill java-tron (PID: $PID) after $MAX_STOP_TIME seconds" + kill -KILL "$PID" 2>/dev/null + sleep 1 + checkPid + fi + + if [ -n "$PID" ]; then + die "Failed to stop the service (PID: $PID)" + else + info "java-tron stopped" + wait_with_info 2 "Cleaning up..." + fi +} + +startService() { + if [ -n "${FULL_START_OPT[*]}" ]; then + info "Starting java-tron service with options: ${FULL_START_OPT[*]}" + fi + if [ ! -f "$FULL_NODE_JAR" ]; then + die "$FULL_NODE_JAR not found in path $SCRIPT_DIR." + fi + + nohup "$JAVACMD" \ + -Xms"$VM_XMS" -Xmx"$VM_XMX" -XX:ReservedCodeCacheSize=256m \ + -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m \ + -XX:MaxDirectMemorySize="$VM_MAX_DIRECT_MEMORY_SIZE" \ + -Xloggc:gc.log -XX:+PrintGCDetails \ + -XX:+UseG1GC \ + -XX:MaxGCPauseMillis=40 \ + -XX:InitiatingHeapOccupancyPercent=45 \ + -XX:+HeapDumpOnOutOfMemoryError \ + -jar "$FULL_NODE_JAR" "${FULL_START_OPT[@]}" \ + >> start.log 2>&1 & + + + info "Waiting for the service to start..." + wait_with_info 5 "Starting..." + + checkPid + + if [ -n "$PID" ]; then + info "Started java-tron with PID $PID on $HOSTNAME." + else + die "Failed to start java-tron, see start.log or logs/tron.log for details." + fi +} + +wait_with_info() { + local seconds=$1 + local message=$2 + for i in $(seq "$seconds" -1 1); do + info "$message wait ($i) s" + sleep 1 + done +} + + +start() { + checkPid + if [ -n "$PID" ]; then + info "java-tron is already running (PID: $PID), to stop the service: sh start.sh -s" + return + fi + findJava + startService +} + +while [ -n "$1" ]; do + case "$1" in + -s) + stopService + exit 0 + ;; + *) + FULL_START_OPT+=("$@") + break + ;; + esac +done + +start + +exit 0 \ No newline at end of file