From 58b0571a55c396d8862bc5e035119c50a246b40a Mon Sep 17 00:00:00 2001 From: federico Date: Fri, 13 Jun 2025 17:23:44 +0800 Subject: [PATCH 01/13] feat(crypto): upgrade the bouncycastle denpendency --- build.gradle | 2 +- gradle/verification-metadata.xml | 10 +++++----- plugins/build.gradle | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 14b095b1795..20ebd253eca 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ subprojects { 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' + implementation group: 'org.bouncycastle', name: 'bcprov-jdk18on', version: '1.79' compileOnly 'org.projectlombok:lombok:1.18.12' annotationProcessor 'org.projectlombok:lombok:1.18.12' diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index b3c879f6b40..b337c0a36b2 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -1572,12 +1572,12 @@ - - - + + + - - + + diff --git a/plugins/build.gradle b/plugins/build.gradle index 01afaa01708..32f7a2550d7 100644 --- a/plugins/build.gradle +++ b/plugins/build.gradle @@ -28,7 +28,7 @@ dependencies { implementation group: 'info.picocli', name: 'picocli', version: '4.6.3' 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.bouncycastle', name: 'bcprov-jdk18on', version: '1.79' 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' @@ -157,4 +157,4 @@ task copyToParent(type: Copy) { -build.finalizedBy(copyToParent) \ No newline at end of file +build.finalizedBy(copyToParent) From 1a285fde6d1528831ffaa22f32e7c1e6fb5531b9 Mon Sep 17 00:00:00 2001 From: federico Date: Fri, 13 Jun 2025 23:28:27 +0800 Subject: [PATCH 02/13] fix(crypto): optimize the null localwitness --- .../java/org/tron/common/utils/LocalWitnesses.java | 8 ++++---- crypto/src/main/java/org/tron/common/crypto/ECKey.java | 2 +- .../src/main/java/org/tron/common/crypto/sm2/SM2.java | 2 +- .../src/main/java/org/tron/core/config/args/Args.java | 10 ++++++---- .../java/org/tron/core/consensus/ConsensusService.java | 2 +- .../org/tron/core/net/service/relay/RelayService.java | 8 ++++---- .../org/tron/core/config/args/LocalWitnessTest.java | 10 ++++++---- 7 files changed, 23 insertions(+), 19 deletions(-) diff --git a/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java b/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java index 940a107a2ac..9d6b7213b77 100644 --- a/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java +++ b/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java @@ -46,7 +46,7 @@ public LocalWitnesses(List privateKeys) { } public byte[] getWitnessAccountAddress(boolean isECKeyCryptoEngine) { - if (witnessAccountAddress == null) { + if (witnessAccountAddress == null && !this.privateKeys.isEmpty()) { byte[] privateKey = ByteArray.fromHexString(getPrivateKey()); final SignInterface cryptoEngine = SignUtils.fromPrivate(privateKey, isECKeyCryptoEngine); this.witnessAccountAddress = cryptoEngine.getAddress(); @@ -59,7 +59,7 @@ public void setWitnessAccountAddress(final byte[] localWitnessAccountAddress) { } public void initWitnessAccountAddress(boolean isECKeyCryptoEngine) { - if (witnessAccountAddress == null) { + if (witnessAccountAddress == null && !this.privateKeys.isEmpty()) { byte[] privateKey = ByteArray.fromHexString(getPrivateKey()); final SignInterface ecKey = SignUtils.fromPrivate(privateKey, isECKeyCryptoEngine); @@ -85,8 +85,8 @@ private void validate(String privateKey) { privateKey = privateKey.substring(2); } - if (StringUtils.isNotBlank(privateKey) - && privateKey.length() != ChainConstant.PRIVATE_KEY_LENGTH) { + if (StringUtils.isBlank(privateKey) || (StringUtils.isNotBlank(privateKey) + && privateKey.length() != ChainConstant.PRIVATE_KEY_LENGTH)) { throw new IllegalArgumentException( String.format("private key must be %d-bits hex string, actual: %d", ChainConstant.PRIVATE_KEY_LENGTH, privateKey.length())); diff --git a/crypto/src/main/java/org/tron/common/crypto/ECKey.java b/crypto/src/main/java/org/tron/common/crypto/ECKey.java index 5fe8b9ef359..40515d4f3aa 100644 --- a/crypto/src/main/java/org/tron/common/crypto/ECKey.java +++ b/crypto/src/main/java/org/tron/common/crypto/ECKey.java @@ -285,7 +285,7 @@ public static ECKey fromPrivate(BigInteger privKey) { * @return - */ public static ECKey fromPrivate(byte[] privKeyBytes) { - if (Objects.isNull(privKeyBytes)) { + if (Objects.isNull(privKeyBytes) || privKeyBytes.length == 0) { return null; } return fromPrivate(new BigInteger(1, privKeyBytes)); diff --git a/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java b/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java index c6aebba385a..64a7b1b3ed3 100644 --- a/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java +++ b/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java @@ -247,7 +247,7 @@ public static SM2 fromPrivate(BigInteger privKey) { * @return - */ public static SM2 fromPrivate(byte[] privKeyBytes) { - if (Objects.isNull(privKeyBytes)) { + if (Objects.isNull(privKeyBytes) || privKeyBytes.length == 0) { return null; } return fromPrivate(new BigInteger(1, privKeyBytes)); 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..53e2816c625 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 @@ -420,10 +420,12 @@ public static void setParam(final Config config) { } else if (config.hasPath(Constant.LOCAL_WITNESS)) { localWitnesses = new LocalWitnesses(); List localwitness = config.getStringList(Constant.LOCAL_WITNESS); - localWitnesses.setPrivateKeys(localwitness); - witnessAddressCheck(config); - localWitnesses.initWitnessAccountAddress(PARAMETER.isECKeyCryptoEngine()); - logger.debug("Got privateKey from config.conf"); + if (localwitness.size() > 0) { + localWitnesses.setPrivateKeys(localwitness); + witnessAddressCheck(config); + localWitnesses.initWitnessAccountAddress(PARAMETER.isECKeyCryptoEngine()); + logger.debug("Got privateKey from config.conf"); + } } else if (config.hasPath(Constant.LOCAL_WITNESS_KEYSTORE)) { localWitnesses = new LocalWitnesses(); List privateKeys = new ArrayList(); diff --git a/framework/src/main/java/org/tron/core/consensus/ConsensusService.java b/framework/src/main/java/org/tron/core/consensus/ConsensusService.java index ce1f1f1cf08..c7bc6c3673b 100644 --- a/framework/src/main/java/org/tron/core/consensus/ConsensusService.java +++ b/framework/src/main/java/org/tron/core/consensus/ConsensusService.java @@ -61,7 +61,7 @@ public void start() { logger.info("Add witness: {}, size: {}", Hex.toHexString(privateKeyAddress), miners.size()); } - } else { + } else if (privateKeys.size() == 1) { byte[] privateKey = fromHexString(Args.getLocalWitnesses().getPrivateKey()); byte[] privateKeyAddress = SignUtils.fromPrivate(privateKey, diff --git a/framework/src/main/java/org/tron/core/net/service/relay/RelayService.java b/framework/src/main/java/org/tron/core/net/service/relay/RelayService.java index 161e918336b..efed61fdbdb 100644 --- a/framework/src/main/java/org/tron/core/net/service/relay/RelayService.java +++ b/framework/src/main/java/org/tron/core/net/service/relay/RelayService.java @@ -66,12 +66,12 @@ public class RelayService { private List fastForwardNodes = parameter.getFastForwardNodes(); - private ByteString witnessAddress = ByteString - .copyFrom(Args.getLocalWitnesses().getWitnessAccountAddress(CommonParameter.getInstance() - .isECKeyCryptoEngine())); - private int keySize = Args.getLocalWitnesses().getPrivateKeys().size(); + private ByteString witnessAddress = keySize > 0 ? ByteString + .copyFrom(Args.getLocalWitnesses().getWitnessAccountAddress(CommonParameter.getInstance() + .isECKeyCryptoEngine())) : null; + private int maxFastForwardNum = Args.getInstance().getMaxFastForwardNum(); public void init() { diff --git a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java index 27d5effd6b1..022b220ba25 100644 --- a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java +++ b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java @@ -15,6 +15,8 @@ package org.tron.core.config.args; +import static org.junit.Assert.fail; + import com.google.common.collect.Lists; import org.junit.Assert; import org.junit.Before; @@ -42,16 +44,16 @@ public void whenSetNullPrivateKey() { Assert.assertNotNull(localWitness.getPublicKey()); } - @Test + @Test(expected = IllegalArgumentException.class) public void whenSetEmptyPrivateKey() { localWitness.setPrivateKeys(Lists.newArrayList("")); - Assert.assertNotNull(localWitness.getPrivateKey()); - Assert.assertNotNull(localWitness.getPublicKey()); + fail("private key must be 64-bits hex string"); } @Test(expected = IllegalArgumentException.class) public void whenSetBadFormatPrivateKey() { localWitness.setPrivateKeys(Lists.newArrayList("a111")); + fail("private key must be 64-bits hex string"); } @Test @@ -85,6 +87,6 @@ public void testConstructor() { Assert.assertNull(localWitnesses2.getPublicKey()); localWitnesses2.initWitnessAccountAddress(true); LocalWitnesses localWitnesses3 = new LocalWitnesses(); - Assert.assertNotNull(localWitnesses3.getWitnessAccountAddress(true)); + Assert.assertNull(localWitnesses3.getWitnessAccountAddress(true)); } } From 04eca9ffad740aa69bbc1b0f3f574af6d1e5dae9 Mon Sep 17 00:00:00 2001 From: federico Date: Tue, 17 Jun 2025 17:46:34 +0800 Subject: [PATCH 03/13] fix(metric): process the null witness address --- .../java/org/tron/core/metrics/node/NodeMetricManager.java | 6 ++++-- .../java/org/tron/core/zksnark/ShieldedReceiveTest.java | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java b/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java index a0aba129648..1d852e2b71e 100644 --- a/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java +++ b/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java @@ -36,8 +36,10 @@ private void setNodeInfo(NodeInfo nodeInfo) { nodeInfo.setIp(Args.getInstance().getNodeExternalIp()); - ByteString witnessAddress = ByteString.copyFrom(Args.getLocalWitnesses() - .getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine())); + byte[] witnessAccountAddress = Args.getLocalWitnesses() + .getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine()); + ByteString witnessAddress = + witnessAccountAddress != null ? ByteString.copyFrom(witnessAccountAddress) : null; if (chainBaseManager.getWitnessScheduleStore().getActiveWitnesses().contains(witnessAddress)) { nodeInfo.setNodeType(1); } else { 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..a7c4443b6aa 100755 --- a/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java +++ b/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java @@ -320,7 +320,8 @@ public void testBroadcastBeforeAllowZksnark() } /* - * 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(); From 5aefa931c826f72d85ecd1207741abf11adc11f5 Mon Sep 17 00:00:00 2001 From: federico Date: Mon, 30 Jun 2025 16:23:51 +0800 Subject: [PATCH 04/13] feat(crypto): optimize the code --- .../src/main/java/org/tron/common/utils/LocalWitnesses.java | 4 ++-- crypto/src/main/java/org/tron/common/crypto/ECKey.java | 2 +- crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java | 2 +- .../java/org/tron/core/metrics/node/NodeMetricManager.java | 5 +++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java b/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java index 9d6b7213b77..ea81dc06506 100644 --- a/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java +++ b/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java @@ -46,7 +46,7 @@ public LocalWitnesses(List privateKeys) { } public byte[] getWitnessAccountAddress(boolean isECKeyCryptoEngine) { - if (witnessAccountAddress == null && !this.privateKeys.isEmpty()) { + if (witnessAccountAddress == null && !CollectionUtils.isEmpty(privateKeys)) { byte[] privateKey = ByteArray.fromHexString(getPrivateKey()); final SignInterface cryptoEngine = SignUtils.fromPrivate(privateKey, isECKeyCryptoEngine); this.witnessAccountAddress = cryptoEngine.getAddress(); @@ -59,7 +59,7 @@ public void setWitnessAccountAddress(final byte[] localWitnessAccountAddress) { } public void initWitnessAccountAddress(boolean isECKeyCryptoEngine) { - if (witnessAccountAddress == null && !this.privateKeys.isEmpty()) { + if (witnessAccountAddress == null && !CollectionUtils.isEmpty(privateKeys)) { byte[] privateKey = ByteArray.fromHexString(getPrivateKey()); final SignInterface ecKey = SignUtils.fromPrivate(privateKey, isECKeyCryptoEngine); diff --git a/crypto/src/main/java/org/tron/common/crypto/ECKey.java b/crypto/src/main/java/org/tron/common/crypto/ECKey.java index 40515d4f3aa..acf89832bc8 100644 --- a/crypto/src/main/java/org/tron/common/crypto/ECKey.java +++ b/crypto/src/main/java/org/tron/common/crypto/ECKey.java @@ -285,7 +285,7 @@ public static ECKey fromPrivate(BigInteger privKey) { * @return - */ public static ECKey fromPrivate(byte[] privKeyBytes) { - if (Objects.isNull(privKeyBytes) || privKeyBytes.length == 0) { + if (ByteUtil.isNullOrZeroArray(privKeyBytes)) { return null; } return fromPrivate(new BigInteger(1, privKeyBytes)); diff --git a/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java b/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java index 64a7b1b3ed3..d7afb43abc7 100644 --- a/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java +++ b/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java @@ -247,7 +247,7 @@ public static SM2 fromPrivate(BigInteger privKey) { * @return - */ public static SM2 fromPrivate(byte[] privKeyBytes) { - if (Objects.isNull(privKeyBytes) || privKeyBytes.length == 0) { + if (ByteUtil.isNullOrZeroArray(privKeyBytes)) { return null; } return fromPrivate(new BigInteger(1, privKeyBytes)); diff --git a/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java b/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java index 1d852e2b71e..4ac1402b513 100644 --- a/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java +++ b/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java @@ -5,6 +5,7 @@ import org.springframework.stereotype.Component; import org.tron.common.backup.BackupManager; import org.tron.common.parameter.CommonParameter; +import org.tron.common.utils.ByteUtil; import org.tron.core.ChainBaseManager; import org.tron.core.config.args.Args; import org.tron.program.Version; @@ -38,8 +39,8 @@ private void setNodeInfo(NodeInfo nodeInfo) { byte[] witnessAccountAddress = Args.getLocalWitnesses() .getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine()); - ByteString witnessAddress = - witnessAccountAddress != null ? ByteString.copyFrom(witnessAccountAddress) : null; + ByteString witnessAddress = !ByteUtil.isNullOrZeroArray(witnessAccountAddress) ? ByteString + .copyFrom(witnessAccountAddress) : null; if (chainBaseManager.getWitnessScheduleStore().getActiveWitnesses().contains(witnessAddress)) { nodeInfo.setNodeType(1); } else { From 945271ab415b5069a595c538d1bf9410f409dca0 Mon Sep 17 00:00:00 2001 From: federico Date: Mon, 30 Jun 2025 19:14:26 +0800 Subject: [PATCH 05/13] feat(doc): add the comment --- .../src/main/java/org/tron/core/consensus/ConsensusService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/framework/src/main/java/org/tron/core/consensus/ConsensusService.java b/framework/src/main/java/org/tron/core/consensus/ConsensusService.java index c7bc6c3673b..300995fca57 100644 --- a/framework/src/main/java/org/tron/core/consensus/ConsensusService.java +++ b/framework/src/main/java/org/tron/core/consensus/ConsensusService.java @@ -72,6 +72,8 @@ public void start() { if (null == witnessCapsule) { logger.warn("Witness {} is not in witnessStore.", Hex.toHexString(witnessAddress)); } + // In multi-signature mode, the address derived from the private key may differ from + // witnessAddress. Miner miner = param.new Miner(privateKey, ByteString.copyFrom(privateKeyAddress), ByteString.copyFrom(witnessAddress)); miners.add(miner); From b99409428c0e50cc085333790a91df55a72c0430 Mon Sep 17 00:00:00 2001 From: federico Date: Mon, 7 Jul 2025 14:08:51 +0800 Subject: [PATCH 06/13] feat(test): add the nullWitnessAddress test --- .../core/net/services/RelayServiceTest.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) 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..ba659a3150a 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 @@ -5,6 +5,7 @@ import com.google.common.collect.Lists; import com.google.protobuf.ByteString; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.util.ArrayList; @@ -168,4 +169,28 @@ private void testCheckHelloMessage() { logger.info("{}", e.getMessage()); } } -} \ No newline at end of file + + @Test + public void testNullWitnessAddress() { + try { + Class clazz = service.getClass(); + + Field keySizeField = clazz.getDeclaredField("keySize"); + keySizeField.setAccessible(true); + keySizeField.set(service, 0); + + Field witnessAddressField = clazz.getDeclaredField("witnessAddress"); + witnessAddressField.setAccessible(true); + witnessAddressField.set(service, null); + + Method isActiveWitnessMethod = clazz.getDeclaredMethod("isActiveWitness"); + isActiveWitnessMethod.setAccessible(true); + + Object result = isActiveWitnessMethod.invoke(service); + Assert.assertFalse(Boolean.TRUE.equals(result)); + } catch (NoSuchMethodException | NoSuchFieldException | + IllegalAccessException | InvocationTargetException e) { + Assert.fail("Reflection invocation failed: " + e.getMessage()); + } + } +} From 3b6fe6c5e2fda58903135700ba904eae58917a02 Mon Sep 17 00:00:00 2001 From: federico Date: Wed, 9 Jul 2025 15:22:22 +0800 Subject: [PATCH 07/13] add witness config test --- .../core/config/args/LocalWitnessTest.java | 27 +++++++++++++++++++ .../core/net/services/RelayServiceTest.java | 4 +-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java index 022b220ba25..a5847596546 100644 --- a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java +++ b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java @@ -18,17 +18,24 @@ import static org.junit.Assert.fail; import com.google.common.collect.Lists; +import java.io.IOException; 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.utils.LocalWitnesses; import org.tron.common.utils.PublicMethod; +import org.tron.core.Constant; public class LocalWitnessTest { private final LocalWitnesses localWitness = new LocalWitnesses(); private static final String PRIVATE_KEY = PublicMethod.getRandomPrivateKey(); + @Rule + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Before public void setLocalWitness() { localWitness @@ -89,4 +96,24 @@ public void testConstructor() { LocalWitnesses localWitnesses3 = new LocalWitnesses(); Assert.assertNull(localWitnesses3.getWitnessAccountAddress(true)); } + + @Test + public void testLocalWitnessConfig() throws IOException { + Args.setParam( + new String[]{"--output-directory", temporaryFolder.newFolder().toString(), "--debug"}, + "config-localtest.conf"); + LocalWitnesses witness = Args.getLocalWitnesses(); + Assert.assertNotNull(witness.getPrivateKey()); + Assert.assertNotNull(witness.getWitnessAccountAddress(true)); + } + + @Test + public void testNullLocalWitnessConfig() throws IOException { + Args.setParam( + new String[]{"--output-directory", temporaryFolder.newFolder().toString(), "--debug"}, + Constant.TEST_CONF); + LocalWitnesses witness = Args.getLocalWitnesses(); + Assert.assertNull(witness.getPrivateKey()); + Assert.assertNull(witness.getWitnessAccountAddress(true)); + } } 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 ba659a3150a..8d3f3c02101 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 @@ -188,8 +188,8 @@ public void testNullWitnessAddress() { Object result = isActiveWitnessMethod.invoke(service); Assert.assertFalse(Boolean.TRUE.equals(result)); - } catch (NoSuchMethodException | NoSuchFieldException | - IllegalAccessException | InvocationTargetException e) { + } catch (NoSuchMethodException | NoSuchFieldException + | IllegalAccessException | InvocationTargetException e) { Assert.fail("Reflection invocation failed: " + e.getMessage()); } } From 614b1a49c3ec3a2e60bb712a58120cb5329ff556 Mon Sep 17 00:00:00 2001 From: federico Date: Wed, 30 Jul 2025 17:15:17 +0800 Subject: [PATCH 08/13] strengthen the private key validation --- .../org/tron/common/utils/LocalWitnesses.java | 12 ++- .../org/tron/common/utils/StringUtil.java | 10 +++ .../core/config/args/LocalWitnessTest.java | 78 +++++++++++++++++++ 3 files changed, 96 insertions(+), 4 deletions(-) diff --git a/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java b/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java index ea81dc06506..2dacba8a273 100644 --- a/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java +++ b/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java @@ -85,11 +85,15 @@ private void validate(String privateKey) { privateKey = privateKey.substring(2); } - if (StringUtils.isBlank(privateKey) || (StringUtils.isNotBlank(privateKey) - && privateKey.length() != ChainConstant.PRIVATE_KEY_LENGTH)) { + if (StringUtils.isBlank(privateKey) + || privateKey.length() != ChainConstant.PRIVATE_KEY_LENGTH) { throw new IllegalArgumentException( - String.format("private key must be %d-bits hex string, actual: %d", - ChainConstant.PRIVATE_KEY_LENGTH, privateKey.length())); + String.format("private key must be %d hex string, actual: %d", + ChainConstant.PRIVATE_KEY_LENGTH, + StringUtils.isBlank(privateKey) ? 0 : privateKey.length())); + } + if (!StringUtil.isHexadecimal(privateKey)) { + throw new IllegalArgumentException("private key must be hex string"); } } diff --git a/common/src/main/java/org/tron/common/utils/StringUtil.java b/common/src/main/java/org/tron/common/utils/StringUtil.java index ce3e95af46e..7ee2d163692 100644 --- a/common/src/main/java/org/tron/common/utils/StringUtil.java +++ b/common/src/main/java/org/tron/common/utils/StringUtil.java @@ -44,4 +44,14 @@ public static String createReadableString(ByteString string) { public static ByteString hexString2ByteString(String hexString) { return ByteString.copyFrom(ByteArray.fromHexString(hexString)); } + + public static boolean isHexadecimal(String str) { + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) { + return false; + } + } + return true; + } } diff --git a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java index a5847596546..49ea30b2a3f 100644 --- a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java +++ b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java @@ -74,6 +74,84 @@ public void whenSetPrefixPrivateKey() { Assert.assertNotNull(localWitness.getPrivateKey()); } + @Test + public void testValidPrivateKey() { + LocalWitnesses localWitnesses = new LocalWitnesses(); + + try { + localWitnesses.addPrivateKeys(PRIVATE_KEY); + Assert.assertEquals(1, localWitnesses.getPrivateKeys().size()); + Assert.assertEquals(PRIVATE_KEY, localWitnesses.getPrivateKeys().get(0)); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + @Test + public void testValidPrivateKeyWithPrefix() { + LocalWitnesses localWitnesses = new LocalWitnesses(); + + try { + localWitnesses.addPrivateKeys("0x" + PRIVATE_KEY); + Assert.assertEquals(1, localWitnesses.getPrivateKeys().size()); + Assert.assertEquals("0x" + PRIVATE_KEY, localWitnesses.getPrivateKeys().get(0)); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + @Test + public void testInvalidPrivateKey() { + LocalWitnesses localWitnesses = new LocalWitnesses(); + + try { + localWitnesses.addPrivateKeys(null); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + Assert.assertTrue(e.getMessage().contains("private key must be")); + } catch (Exception e) { + fail("should IllegalArgumentException,actual exception: " + e.getClass().getSimpleName()); + } + + try { + localWitnesses.addPrivateKeys(""); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + Assert.assertTrue(e.getMessage().contains("private key must be")); + } catch (Exception e) { + fail("should IllegalArgumentException,actual exception: " + e.getClass().getSimpleName()); + } + + try { + localWitnesses.addPrivateKeys(" "); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + Assert.assertTrue(e.getMessage().contains("private key must be")); + } catch (Exception e) { + fail("should IllegalArgumentException,actual exception: " + e.getClass().getSimpleName()); + } + + try { + String privateKey = "11111111111111111111111111111111111111111111111111111111111111 "; + localWitnesses.addPrivateKeys(privateKey); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + Assert.assertTrue(e.getMessage().contains("private key must be hex string")); + } catch (Exception e) { + fail("should IllegalArgumentException,actual exception: " + e.getClass().getSimpleName()); + } + + try { + String privateKey = "xy11111111111111111111111111111111111111111111111111111111111111"; + localWitnesses.addPrivateKeys(privateKey); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + Assert.assertTrue(e.getMessage().contains("private key must be hex string")); + } catch (Exception e) { + fail("should IllegalArgumentException,actual exception: " + e.getClass().getSimpleName()); + } + } + @Test public void getPrivateKey() { Assert.assertEquals(Lists From 041e47e8c3ad57915bbd6fc53b0b19de1b8faccd Mon Sep 17 00:00:00 2001 From: federico Date: Fri, 1 Aug 2025 11:17:29 +0800 Subject: [PATCH 09/13] increase the test coverage --- .../org/tron/common/utils/StringUtil.java | 9 ++++++- .../core/config/args/LocalWitnessTest.java | 26 ++++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/org/tron/common/utils/StringUtil.java b/common/src/main/java/org/tron/common/utils/StringUtil.java index 7ee2d163692..89924673f79 100644 --- a/common/src/main/java/org/tron/common/utils/StringUtil.java +++ b/common/src/main/java/org/tron/common/utils/StringUtil.java @@ -46,9 +46,16 @@ public static ByteString hexString2ByteString(String hexString) { } public static boolean isHexadecimal(String str) { + if (str == null || str.length() == 0) { + return false; + } + if (str.length() % 2 != 0) { + return false; + } + for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); - if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) { + if (Character.digit(c, 16) == -1) { return false; } } diff --git a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java index 49ea30b2a3f..76ed1ce323a 100644 --- a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java +++ b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java @@ -26,6 +26,7 @@ import org.junit.rules.TemporaryFolder; import org.tron.common.utils.LocalWitnesses; import org.tron.common.utils.PublicMethod; +import org.tron.common.utils.StringUtil; import org.tron.core.Constant; public class LocalWitnessTest { @@ -108,7 +109,7 @@ public void testInvalidPrivateKey() { localWitnesses.addPrivateKeys(null); fail("should throw IllegalArgumentException"); } catch (IllegalArgumentException e) { - Assert.assertTrue(e.getMessage().contains("private key must be")); + Assert.assertTrue(e.getMessage().contains("private key must be 64 hex string")); } catch (Exception e) { fail("should IllegalArgumentException,actual exception: " + e.getClass().getSimpleName()); } @@ -117,7 +118,7 @@ public void testInvalidPrivateKey() { localWitnesses.addPrivateKeys(""); fail("should throw IllegalArgumentException"); } catch (IllegalArgumentException e) { - Assert.assertTrue(e.getMessage().contains("private key must be")); + Assert.assertTrue(e.getMessage().contains("private key must be 64 hex string")); } catch (Exception e) { fail("should IllegalArgumentException,actual exception: " + e.getClass().getSimpleName()); } @@ -126,7 +127,16 @@ public void testInvalidPrivateKey() { localWitnesses.addPrivateKeys(" "); fail("should throw IllegalArgumentException"); } catch (IllegalArgumentException e) { - Assert.assertTrue(e.getMessage().contains("private key must be")); + Assert.assertTrue(e.getMessage().contains("private key must be 64 hex string")); + } catch (Exception e) { + fail("should IllegalArgumentException,actual exception: " + e.getClass().getSimpleName()); + } + + try { + localWitnesses.addPrivateKeys("11111"); + fail("should throw IllegalArgumentException"); + } catch (IllegalArgumentException e) { + Assert.assertTrue(e.getMessage().contains("private key must be 64 hex string")); } catch (Exception e) { fail("should IllegalArgumentException,actual exception: " + e.getClass().getSimpleName()); } @@ -152,6 +162,16 @@ public void testInvalidPrivateKey() { } } + @Test + public void testHexStringFormat() { + Assert.assertTrue(StringUtil.isHexadecimal("0123456789abcdefABCDEF")); + Assert.assertFalse(StringUtil.isHexadecimal(null)); + Assert.assertFalse(StringUtil.isHexadecimal("")); + Assert.assertFalse(StringUtil.isHexadecimal("abc")); + Assert.assertFalse(StringUtil.isHexadecimal(" ")); + Assert.assertFalse(StringUtil.isHexadecimal("123xyz")); + } + @Test public void getPrivateKey() { Assert.assertEquals(Lists From c33f99546ba3d5f4031dbb6431feea18b6016044 Mon Sep 17 00:00:00 2001 From: federico Date: Wed, 6 Aug 2025 12:07:20 +0800 Subject: [PATCH 10/13] optimiz the witnessAddress initialization --- .../org/tron/common/utils/LocalWitnesses.java | 22 +++++++------- .../org/tron/common/utils/StringUtil.java | 2 +- .../java/org/tron/common/crypto/ECKey.java | 3 +- .../java/org/tron/common/crypto/sm2/SM2.java | 3 +- .../java/org/tron/core/config/args/Args.java | 29 ++++++++++--------- .../tron/core/consensus/ConsensusService.java | 3 +- .../core/metrics/node/NodeMetricManager.java | 3 +- .../core/net/service/relay/RelayService.java | 8 ++--- .../tron/core/capsule/BlockCapsuleTest.java | 2 +- .../org/tron/core/config/args/ArgsTest.java | 6 ++-- .../core/config/args/LocalWitnessTest.java | 10 +++---- .../java/org/tron/core/db/ManagerTest.java | 2 +- .../tron/core/db/TransactionExpireTest.java | 10 +++---- .../core/net/services/RelayServiceTest.java | 10 +++++-- 14 files changed, 57 insertions(+), 56 deletions(-) diff --git a/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java b/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java index 2dacba8a273..af1355d9b45 100644 --- a/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java +++ b/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java @@ -16,6 +16,7 @@ package org.tron.common.utils; import com.google.common.collect.Lists; +import java.util.Arrays; import java.util.List; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -45,21 +46,18 @@ public LocalWitnesses(List privateKeys) { setPrivateKeys(privateKeys); } - public byte[] getWitnessAccountAddress(boolean isECKeyCryptoEngine) { - if (witnessAccountAddress == null && !CollectionUtils.isEmpty(privateKeys)) { - byte[] privateKey = ByteArray.fromHexString(getPrivateKey()); - final SignInterface cryptoEngine = SignUtils.fromPrivate(privateKey, isECKeyCryptoEngine); - this.witnessAccountAddress = cryptoEngine.getAddress(); + public byte[] getWitnessAccountAddress() { + if (witnessAccountAddress == null) { + return null; } - return witnessAccountAddress; - } - - public void setWitnessAccountAddress(final byte[] localWitnessAccountAddress) { - this.witnessAccountAddress = localWitnessAccountAddress; + return Arrays.copyOf(witnessAccountAddress, witnessAccountAddress.length); } - public void initWitnessAccountAddress(boolean isECKeyCryptoEngine) { - if (witnessAccountAddress == null && !CollectionUtils.isEmpty(privateKeys)) { + public void initWitnessAccountAddress(final byte[] witnessAddress, + boolean isECKeyCryptoEngine) { + if (witnessAddress != null) { + this.witnessAccountAddress = witnessAddress; + } else if (!CollectionUtils.isEmpty(privateKeys)) { byte[] privateKey = ByteArray.fromHexString(getPrivateKey()); final SignInterface ecKey = SignUtils.fromPrivate(privateKey, isECKeyCryptoEngine); diff --git a/common/src/main/java/org/tron/common/utils/StringUtil.java b/common/src/main/java/org/tron/common/utils/StringUtil.java index 89924673f79..412a70d7f9c 100644 --- a/common/src/main/java/org/tron/common/utils/StringUtil.java +++ b/common/src/main/java/org/tron/common/utils/StringUtil.java @@ -46,7 +46,7 @@ public static ByteString hexString2ByteString(String hexString) { } public static boolean isHexadecimal(String str) { - if (str == null || str.length() == 0) { + if (str == null || str.isEmpty()) { return false; } if (str.length() % 2 != 0) { diff --git a/crypto/src/main/java/org/tron/common/crypto/ECKey.java b/crypto/src/main/java/org/tron/common/crypto/ECKey.java index acf89832bc8..d0a6048aca1 100644 --- a/crypto/src/main/java/org/tron/common/crypto/ECKey.java +++ b/crypto/src/main/java/org/tron/common/crypto/ECKey.java @@ -55,6 +55,7 @@ import org.tron.common.crypto.jce.ECKeyPairGenerator; import org.tron.common.crypto.jce.TronCastleProvider; import org.tron.common.utils.BIUtil; +import org.tron.common.utils.ByteArray; import org.tron.common.utils.ByteUtil; @Slf4j(topic = "crypto") @@ -285,7 +286,7 @@ public static ECKey fromPrivate(BigInteger privKey) { * @return - */ public static ECKey fromPrivate(byte[] privKeyBytes) { - if (ByteUtil.isNullOrZeroArray(privKeyBytes)) { + if (ByteArray.isEmpty(privKeyBytes)) { return null; } return fromPrivate(new BigInteger(1, privKeyBytes)); diff --git a/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java b/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java index d7afb43abc7..b1d349efad3 100644 --- a/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java +++ b/crypto/src/main/java/org/tron/common/crypto/sm2/SM2.java @@ -41,6 +41,7 @@ import org.tron.common.crypto.SignatureInterface; import org.tron.common.crypto.jce.ECKeyFactory; import org.tron.common.crypto.jce.TronCastleProvider; +import org.tron.common.utils.ByteArray; import org.tron.common.utils.ByteUtil; /** @@ -247,7 +248,7 @@ public static SM2 fromPrivate(BigInteger privKey) { * @return - */ public static SM2 fromPrivate(byte[] privKeyBytes) { - if (ByteUtil.isNullOrZeroArray(privKeyBytes)) { + if (ByteArray.isEmpty(privKeyBytes)) { return null; } return fromPrivate(new BigInteger(1, privKeyBytes)); 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 53e2816c625..fc5e51ccd3c 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 @@ -405,33 +405,33 @@ public static void setParam(final Config config) { if (StringUtils.isNoneBlank(PARAMETER.privateKey)) { localWitnesses = (new LocalWitnesses(PARAMETER.privateKey)); + byte[] witnessAddress = null; if (StringUtils.isNoneBlank(PARAMETER.witnessAddress)) { - byte[] bytes = Commons.decodeFromBase58Check(PARAMETER.witnessAddress); - if (bytes != null) { - localWitnesses.setWitnessAccountAddress(bytes); + witnessAddress = Commons.decodeFromBase58Check(PARAMETER.witnessAddress); + if (witnessAddress != null) { logger.debug("Got localWitnessAccountAddress from cmd"); } else { PARAMETER.witnessAddress = ""; logger.warn(IGNORE_WRONG_WITNESS_ADDRESS_FORMAT); } } - localWitnesses.initWitnessAccountAddress(PARAMETER.isECKeyCryptoEngine()); + localWitnesses.initWitnessAccountAddress(witnessAddress, PARAMETER.isECKeyCryptoEngine()); logger.debug("Got privateKey from cmd"); } else if (config.hasPath(Constant.LOCAL_WITNESS)) { localWitnesses = new LocalWitnesses(); + byte[] witnessAddress = getWitnessAddress(config); List localwitness = config.getStringList(Constant.LOCAL_WITNESS); - if (localwitness.size() > 0) { + if (!localwitness.isEmpty()) { localWitnesses.setPrivateKeys(localwitness); - witnessAddressCheck(config); - localWitnesses.initWitnessAccountAddress(PARAMETER.isECKeyCryptoEngine()); logger.debug("Got privateKey from config.conf"); } + localWitnesses.initWitnessAccountAddress(witnessAddress, PARAMETER.isECKeyCryptoEngine()); } else if (config.hasPath(Constant.LOCAL_WITNESS_KEYSTORE)) { localWitnesses = new LocalWitnesses(); List privateKeys = new ArrayList(); if (PARAMETER.isWitness()) { List localwitness = config.getStringList(Constant.LOCAL_WITNESS_KEYSTORE); - if (localwitness.size() > 0) { + if (!localwitness.isEmpty()) { String fileName = System.getProperty("user.dir") + "/" + localwitness.get(0); String password; if (StringUtils.isEmpty(PARAMETER.password)) { @@ -455,8 +455,8 @@ public static void setParam(final Config config) { } } localWitnesses.setPrivateKeys(privateKeys); - witnessAddressCheck(config); - localWitnesses.initWitnessAccountAddress(PARAMETER.isECKeyCryptoEngine()); + byte[] witnessAddress = getWitnessAddress(config); + localWitnesses.initWitnessAccountAddress(witnessAddress, PARAMETER.isECKeyCryptoEngine()); logger.debug("Got privateKey from keystore"); } @@ -1775,17 +1775,18 @@ public static void setFullNodeAllowShieldedTransaction(boolean fullNodeAllowShie PARAMETER.fullNodeAllowShieldedTransactionArgs = fullNodeAllowShieldedTransaction; } - private static void witnessAddressCheck(Config config) { + private static byte[] getWitnessAddress(Config config) { + byte[] witnessAddress = null; if (config.hasPath(Constant.LOCAL_WITNESS_ACCOUNT_ADDRESS)) { - byte[] bytes = Commons + witnessAddress = Commons .decodeFromBase58Check(config.getString(Constant.LOCAL_WITNESS_ACCOUNT_ADDRESS)); - if (bytes != null) { - localWitnesses.setWitnessAccountAddress(bytes); + if (witnessAddress != null) { logger.debug("Got localWitnessAccountAddress from config.conf"); } else { logger.warn(IGNORE_WRONG_WITNESS_ADDRESS_FORMAT); } } + return witnessAddress; } /** diff --git a/framework/src/main/java/org/tron/core/consensus/ConsensusService.java b/framework/src/main/java/org/tron/core/consensus/ConsensusService.java index 300995fca57..ef8f30ef498 100644 --- a/framework/src/main/java/org/tron/core/consensus/ConsensusService.java +++ b/framework/src/main/java/org/tron/core/consensus/ConsensusService.java @@ -66,8 +66,7 @@ public void start() { fromHexString(Args.getLocalWitnesses().getPrivateKey()); byte[] privateKeyAddress = SignUtils.fromPrivate(privateKey, Args.getInstance().isECKeyCryptoEngine()).getAddress(); - byte[] witnessAddress = Args.getLocalWitnesses().getWitnessAccountAddress( - Args.getInstance().isECKeyCryptoEngine()); + byte[] witnessAddress = Args.getLocalWitnesses().getWitnessAccountAddress(); WitnessCapsule witnessCapsule = witnessStore.get(witnessAddress); if (null == witnessCapsule) { logger.warn("Witness {} is not in witnessStore.", Hex.toHexString(witnessAddress)); diff --git a/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java b/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java index 4ac1402b513..98bf92ac76e 100644 --- a/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java +++ b/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java @@ -37,8 +37,7 @@ private void setNodeInfo(NodeInfo nodeInfo) { nodeInfo.setIp(Args.getInstance().getNodeExternalIp()); - byte[] witnessAccountAddress = Args.getLocalWitnesses() - .getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine()); + byte[] witnessAccountAddress = Args.getLocalWitnesses().getWitnessAccountAddress(); ByteString witnessAddress = !ByteUtil.isNullOrZeroArray(witnessAccountAddress) ? ByteString .copyFrom(witnessAccountAddress) : null; if (chainBaseManager.getWitnessScheduleStore().getActiveWitnesses().contains(witnessAddress)) { diff --git a/framework/src/main/java/org/tron/core/net/service/relay/RelayService.java b/framework/src/main/java/org/tron/core/net/service/relay/RelayService.java index efed61fdbdb..61ae6326e9f 100644 --- a/framework/src/main/java/org/tron/core/net/service/relay/RelayService.java +++ b/framework/src/main/java/org/tron/core/net/service/relay/RelayService.java @@ -66,11 +66,11 @@ public class RelayService { private List fastForwardNodes = parameter.getFastForwardNodes(); - private int keySize = Args.getLocalWitnesses().getPrivateKeys().size(); + private final int keySize = Args.getLocalWitnesses().getPrivateKeys().size(); - private ByteString witnessAddress = keySize > 0 ? ByteString - .copyFrom(Args.getLocalWitnesses().getWitnessAccountAddress(CommonParameter.getInstance() - .isECKeyCryptoEngine())) : null; + private final ByteString witnessAddress = + Args.getLocalWitnesses().getWitnessAccountAddress() != null ? ByteString + .copyFrom(Args.getLocalWitnesses().getWitnessAccountAddress()) : null; private int maxFastForwardNum = Args.getInstance().getMaxFastForwardNum(); diff --git a/framework/src/test/java/org/tron/core/capsule/BlockCapsuleTest.java b/framework/src/test/java/org/tron/core/capsule/BlockCapsuleTest.java index 3c86d893895..552a014a97b 100644 --- a/framework/src/test/java/org/tron/core/capsule/BlockCapsuleTest.java +++ b/framework/src/test/java/org/tron/core/capsule/BlockCapsuleTest.java @@ -134,7 +134,7 @@ public void testHasWitnessSignature() { localWitnesses = new LocalWitnesses(); localWitnesses.setPrivateKeys(Arrays.asList(privateKey)); - localWitnesses.initWitnessAccountAddress(true); + localWitnesses.initWitnessAccountAddress(null, true); Args.setLocalWitnesses(localWitnesses); Assert.assertFalse(blockCapsule0.hasWitnessSignature()); 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..5f299794dd1 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 @@ -65,10 +65,10 @@ public void get() { localWitnesses = new LocalWitnesses(); localWitnesses.setPrivateKeys(Arrays.asList(privateKey)); - localWitnesses.initWitnessAccountAddress(true); + localWitnesses.initWitnessAccountAddress(null, true); Args.setLocalWitnesses(localWitnesses); address = ByteArray.toHexString(Args.getLocalWitnesses() - .getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine())); + .getWitnessAccountAddress()); Assert.assertEquals(Constant.ADD_PRE_FIX_STRING_TESTNET, DecodeUtil.addressPreFixString); Assert.assertEquals(0, parameter.getBackupPriority()); @@ -126,7 +126,7 @@ public void get() { Assert.assertEquals(address, ByteArray.toHexString(Args.getLocalWitnesses() - .getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine()))); + .getWitnessAccountAddress())); } @Test diff --git a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java index 76ed1ce323a..ac685f57cea 100644 --- a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java +++ b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java @@ -184,15 +184,15 @@ public void testConstructor() { LocalWitnesses localWitnesses = new LocalWitnesses(PublicMethod.getRandomPrivateKey()); LocalWitnesses localWitnesses1 = new LocalWitnesses(Lists.newArrayList(PublicMethod.getRandomPrivateKey())); - localWitnesses.setWitnessAccountAddress(new byte[0]); + localWitnesses.initWitnessAccountAddress(new byte[0], true); Assert.assertNotNull(localWitnesses1.getPublicKey()); LocalWitnesses localWitnesses2 = new LocalWitnesses(); Assert.assertNull(localWitnesses2.getPrivateKey()); Assert.assertNull(localWitnesses2.getPublicKey()); - localWitnesses2.initWitnessAccountAddress(true); + localWitnesses2.initWitnessAccountAddress(null, true); LocalWitnesses localWitnesses3 = new LocalWitnesses(); - Assert.assertNull(localWitnesses3.getWitnessAccountAddress(true)); + Assert.assertNull(localWitnesses3.getWitnessAccountAddress()); } @Test @@ -202,7 +202,7 @@ public void testLocalWitnessConfig() throws IOException { "config-localtest.conf"); LocalWitnesses witness = Args.getLocalWitnesses(); Assert.assertNotNull(witness.getPrivateKey()); - Assert.assertNotNull(witness.getWitnessAccountAddress(true)); + Assert.assertNotNull(witness.getWitnessAccountAddress()); } @Test @@ -212,6 +212,6 @@ public void testNullLocalWitnessConfig() throws IOException { Constant.TEST_CONF); LocalWitnesses witness = Args.getLocalWitnesses(); Assert.assertNull(witness.getPrivateKey()); - Assert.assertNull(witness.getWitnessAccountAddress(true)); + Assert.assertNull(witness.getWitnessAccountAddress()); } } diff --git a/framework/src/test/java/org/tron/core/db/ManagerTest.java b/framework/src/test/java/org/tron/core/db/ManagerTest.java index db219377b74..d05334c5b94 100755 --- a/framework/src/test/java/org/tron/core/db/ManagerTest.java +++ b/framework/src/test/java/org/tron/core/db/ManagerTest.java @@ -136,7 +136,7 @@ public void init() throws IOException { localWitnesses = new LocalWitnesses(); localWitnesses.setPrivateKeys(Arrays.asList(privateKey)); - localWitnesses.initWitnessAccountAddress(true); + localWitnesses.initWitnessAccountAddress(null, true); Args.setLocalWitnesses(localWitnesses); blockCapsule2 = diff --git a/framework/src/test/java/org/tron/core/db/TransactionExpireTest.java b/framework/src/test/java/org/tron/core/db/TransactionExpireTest.java index 420b54525e4..f563203b71a 100644 --- a/framework/src/test/java/org/tron/core/db/TransactionExpireTest.java +++ b/framework/src/test/java/org/tron/core/db/TransactionExpireTest.java @@ -57,7 +57,7 @@ private void initLocalWitness() { String randomPrivateKey = PublicMethod.getRandomPrivateKey(); LocalWitnesses localWitnesses = new LocalWitnesses(); localWitnesses.setPrivateKeys(Arrays.asList(randomPrivateKey)); - localWitnesses.initWitnessAccountAddress(true); + localWitnesses.initWitnessAccountAddress(null, true); Args.setLocalWitnesses(localWitnesses); } @@ -85,7 +85,7 @@ public void testExpireTransaction() { TransferContract transferContract = TransferContract.newBuilder() .setAmount(1L) .setOwnerAddress(ByteString.copyFrom(Args.getLocalWitnesses() - .getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine()))) + .getWitnessAccountAddress())) .setToAddress(ByteString.copyFrom(ByteArray.fromHexString( (Wallet.getAddressPreFixString() + "A389132D6639FBDA4FBC8B659264E6B7C90DB086")))) .build(); @@ -116,8 +116,7 @@ public void testExpireTransactionNew() { .saveLatestBlockHeaderTimestamp(blockCapsule.getTimeStamp()); dbManager.updateRecentBlock(blockCapsule); initLocalWitness(); - byte[] address = Args.getLocalWitnesses() - .getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine()); + byte[] address = Args.getLocalWitnesses().getWitnessAccountAddress(); ByteString addressByte = ByteString.copyFrom(address); AccountCapsule accountCapsule = new AccountCapsule(Protocol.Account.newBuilder().setAddress(addressByte).build()); @@ -157,8 +156,7 @@ public void testTransactionApprovedList() { dbManager.updateRecentBlock(blockCapsule); initLocalWitness(); - byte[] address = Args.getLocalWitnesses() - .getWitnessAccountAddress(CommonParameter.getInstance().isECKeyCryptoEngine()); + byte[] address = Args.getLocalWitnesses().getWitnessAccountAddress(); TransferContract transferContract = TransferContract.newBuilder() .setAmount(1L) .setOwnerAddress(ByteString.copyFrom(address)) 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 8d3f3c02101..eb42ab05719 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 @@ -186,10 +186,14 @@ public void testNullWitnessAddress() { Method isActiveWitnessMethod = clazz.getDeclaredMethod("isActiveWitness"); isActiveWitnessMethod.setAccessible(true); - Object result = isActiveWitnessMethod.invoke(service); - Assert.assertFalse(Boolean.TRUE.equals(result)); + Boolean result = (Boolean) isActiveWitnessMethod.invoke(service); + Assert.assertNotEquals(Boolean.TRUE, result); + + witnessAddressField.set(service, ByteString.copyFrom(new byte[21])); + result = (Boolean) isActiveWitnessMethod.invoke(service); + Assert.assertNotEquals(Boolean.TRUE, result); } catch (NoSuchMethodException | NoSuchFieldException - | IllegalAccessException | InvocationTargetException e) { + | IllegalAccessException | InvocationTargetException e) { Assert.fail("Reflection invocation failed: " + e.getMessage()); } } From 34b4f21564fc2b009318f9fb159a3cc2758fbb47 Mon Sep 17 00:00:00 2001 From: federico Date: Wed, 6 Aug 2025 22:57:19 +0800 Subject: [PATCH 11/13] simplify the localWitness --- .../main/java/org/tron/common/utils/LocalWitnesses.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java b/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java index af1355d9b45..812e4d7fa5b 100644 --- a/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java +++ b/chainbase/src/main/java/org/tron/common/utils/LocalWitnesses.java @@ -16,7 +16,6 @@ package org.tron.common.utils; import com.google.common.collect.Lists; -import java.util.Arrays; import java.util.List; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -33,6 +32,7 @@ public class LocalWitnesses { @Getter private List privateKeys = Lists.newArrayList(); + @Getter private byte[] witnessAccountAddress; public LocalWitnesses() { @@ -46,13 +46,6 @@ public LocalWitnesses(List privateKeys) { setPrivateKeys(privateKeys); } - public byte[] getWitnessAccountAddress() { - if (witnessAccountAddress == null) { - return null; - } - return Arrays.copyOf(witnessAccountAddress, witnessAccountAddress.length); - } - public void initWitnessAccountAddress(final byte[] witnessAddress, boolean isECKeyCryptoEngine) { if (witnessAddress != null) { From a28e337c6e58b7d840c7c934ef7f67beedcecd4a Mon Sep 17 00:00:00 2001 From: federico Date: Thu, 14 Aug 2025 19:31:49 +0800 Subject: [PATCH 12/13] refactor the code --- .../java/org/tron/core/config/args/Args.java | 77 +-------- .../core/config/args/WitnessInitializer.java | 150 ++++++++++++++++++ .../core/metrics/node/NodeMetricManager.java | 5 +- .../core/config/args/LocalWitnessTest.java | 2 +- .../core/zksnark/ShieldedReceiveTest.java | 2 +- 5 files changed, 155 insertions(+), 81 deletions(-) create mode 100644 framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java 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 ff604f6556f..92a021280c4 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 @@ -53,7 +53,6 @@ import org.tron.common.args.Witness; import org.tron.common.config.DbBackupConfig; import org.tron.common.cron.CronExpression; -import org.tron.common.crypto.SignInterface; import org.tron.common.logsfilter.EventPluginConfig; import org.tron.common.logsfilter.FilterQuery; import org.tron.common.logsfilter.TriggerConfig; @@ -62,7 +61,6 @@ import org.tron.common.parameter.CommonParameter; import org.tron.common.parameter.RateLimiterInitialization; import org.tron.common.setting.RocksDbSettings; -import org.tron.common.utils.ByteArray; import org.tron.common.utils.Commons; import org.tron.common.utils.LocalWitnesses; import org.tron.core.Constant; @@ -70,11 +68,8 @@ import org.tron.core.config.Configuration; import org.tron.core.config.Parameter.NetConstants; import org.tron.core.config.Parameter.NodeConstant; -import org.tron.core.exception.CipherException; import org.tron.core.exception.TronError; import org.tron.core.store.AccountStore; -import org.tron.keystore.Credentials; -import org.tron.keystore.WalletUtils; import org.tron.p2p.P2pConfig; import org.tron.p2p.dns.update.DnsType; import org.tron.p2p.dns.update.PublishConfig; @@ -412,63 +407,7 @@ public static void setParam(final Config config) { PARAMETER.cryptoEngine = config.hasPath(Constant.CRYPTO_ENGINE) ? config .getString(Constant.CRYPTO_ENGINE) : Constant.ECKey_ENGINE; - if (StringUtils.isNoneBlank(PARAMETER.privateKey)) { - localWitnesses = (new LocalWitnesses(PARAMETER.privateKey)); - byte[] witnessAddress = null; - if (StringUtils.isNoneBlank(PARAMETER.witnessAddress)) { - witnessAddress = Commons.decodeFromBase58Check(PARAMETER.witnessAddress); - if (witnessAddress != null) { - logger.debug("Got localWitnessAccountAddress from cmd"); - } else { - PARAMETER.witnessAddress = ""; - logger.warn(IGNORE_WRONG_WITNESS_ADDRESS_FORMAT); - } - } - localWitnesses.initWitnessAccountAddress(witnessAddress, PARAMETER.isECKeyCryptoEngine()); - logger.debug("Got privateKey from cmd"); - } else if (config.hasPath(Constant.LOCAL_WITNESS)) { - localWitnesses = new LocalWitnesses(); - byte[] witnessAddress = getWitnessAddress(config); - List localwitness = config.getStringList(Constant.LOCAL_WITNESS); - if (!localwitness.isEmpty()) { - localWitnesses.setPrivateKeys(localwitness); - logger.debug("Got privateKey from config.conf"); - } - localWitnesses.initWitnessAccountAddress(witnessAddress, PARAMETER.isECKeyCryptoEngine()); - } else if (config.hasPath(Constant.LOCAL_WITNESS_KEYSTORE)) { - localWitnesses = new LocalWitnesses(); - List privateKeys = new ArrayList(); - if (PARAMETER.isWitness()) { - List localwitness = config.getStringList(Constant.LOCAL_WITNESS_KEYSTORE); - if (!localwitness.isEmpty()) { - String fileName = System.getProperty("user.dir") + "/" + localwitness.get(0); - String password; - if (StringUtils.isEmpty(PARAMETER.password)) { - System.out.println("Please input your password."); - password = WalletUtils.inputPassword(); - } else { - password = PARAMETER.password; - PARAMETER.password = null; - } - - try { - Credentials credentials = WalletUtils - .loadCredentials(password, new File(fileName)); - SignInterface sign = credentials.getSignInterface(); - String prikey = ByteArray.toHexString(sign.getPrivateKey()); - privateKeys.add(prikey); - } catch (IOException | CipherException e) { - logger.error("Witness node start failed!"); - throw new TronError(e, TronError.ErrCode.WITNESS_KEYSTORE_LOAD); - } - } - } - localWitnesses.setPrivateKeys(privateKeys); - byte[] witnessAddress = getWitnessAddress(config); - localWitnesses.initWitnessAccountAddress(witnessAddress, PARAMETER.isECKeyCryptoEngine()); - logger.debug("Got privateKey from keystore"); - } - + localWitnesses = new WitnessInitializer(config).initLocalWitnesses(); if (PARAMETER.isWitness() && CollectionUtils.isEmpty(localWitnesses.getPrivateKeys())) { throw new TronError("This is a witness node, but localWitnesses is null", @@ -1819,20 +1758,6 @@ public static void logConfig() { logger.info("\n"); } - private static byte[] getWitnessAddress(Config config) { - byte[] witnessAddress = null; - if (config.hasPath(Constant.LOCAL_WITNESS_ACCOUNT_ADDRESS)) { - witnessAddress = Commons - .decodeFromBase58Check(config.getString(Constant.LOCAL_WITNESS_ACCOUNT_ADDRESS)); - if (witnessAddress != null) { - logger.debug("Got localWitnessAccountAddress from config.conf"); - } else { - logger.warn(IGNORE_WRONG_WITNESS_ADDRESS_FORMAT); - } - } - return witnessAddress; - } - /** * get output directory. */ diff --git a/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java b/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java new file mode 100644 index 00000000000..e3b889a5acf --- /dev/null +++ b/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java @@ -0,0 +1,150 @@ +package org.tron.core.config.args; + +import com.typesafe.config.Config; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.tron.common.crypto.SignInterface; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.Commons; +import org.tron.common.utils.LocalWitnesses; +import org.tron.core.Constant; +import org.tron.core.exception.CipherException; +import org.tron.core.exception.TronError; +import org.tron.keystore.Credentials; +import org.tron.keystore.WalletUtils; + +@Slf4j +public class WitnessInitializer { + + private final Config config; + + private LocalWitnesses localWitnesses; + + public WitnessInitializer(Config config) { + this.config = config; + } + + public LocalWitnesses initLocalWitnesses() { + localWitnesses = new LocalWitnesses(); + + if (!Args.PARAMETER.isWitness()) { + return localWitnesses; + } + + if (tryInitFromCommandLine()) { + return localWitnesses; + } + + if (tryInitFromConfig()) { + return localWitnesses; + } + + tryInitFromKeystore(); + + return localWitnesses; + } + + private boolean tryInitFromCommandLine() { + if (StringUtils.isBlank(Args.PARAMETER.privateKey)) { + return false; + } + + byte[] witnessAddress = null; + this.localWitnesses = new LocalWitnesses(Args.PARAMETER.privateKey); + if (StringUtils.isNotEmpty(Args.PARAMETER.witnessAddress)) { + witnessAddress = Commons.decodeFromBase58Check(Args.PARAMETER.witnessAddress); + if (witnessAddress == null) { + throw new TronError("LocalWitnessAccountAddress format from cmd is incorrect", + TronError.ErrCode.WITNESS_INIT); + } + logger.debug("Got localWitnessAccountAddress from cmd"); + } + + this.localWitnesses.initWitnessAccountAddress(witnessAddress, + Args.PARAMETER.isECKeyCryptoEngine()); + logger.debug("Got privateKey from cmd"); + return true; + } + + private boolean tryInitFromConfig() { + if (!config.hasPath(Constant.LOCAL_WITNESS) || config.getStringList(Constant.LOCAL_WITNESS) + .isEmpty()) { + return false; + } + + List localWitness = config.getStringList(Constant.LOCAL_WITNESS); + this.localWitnesses.setPrivateKeys(localWitness); + logger.debug("Got privateKey from config.conf"); + byte[] witnessAddress = getWitnessAddress(); + this.localWitnesses.initWitnessAccountAddress(witnessAddress, + Args.PARAMETER.isECKeyCryptoEngine()); + return true; + } + + private void tryInitFromKeystore() { + if (!config.hasPath(Constant.LOCAL_WITNESS_KEYSTORE) + || config.getStringList(Constant.LOCAL_WITNESS_KEYSTORE).isEmpty()) { + return; + } + + List localWitness = config.getStringList(Constant.LOCAL_WITNESS_KEYSTORE); + if (localWitness.size() > 1) { + logger.warn( + "Multiple keystores detected. Only the first keystore will be used as witness, all " + + "others will be ignored."); + } + + List privateKeys = new ArrayList<>(); + String fileName = System.getProperty("user.dir") + "/" + localWitness.get(0); + String password; + if (StringUtils.isEmpty(Args.PARAMETER.password)) { + System.out.println("Please input your password."); + password = WalletUtils.inputPassword(); + } else { + password = Args.PARAMETER.password; + Args.PARAMETER.password = null; + } + + try { + Credentials credentials = WalletUtils + .loadCredentials(password, new File(fileName)); + SignInterface sign = credentials.getSignInterface(); + String prikey = ByteArray.toHexString(sign.getPrivateKey()); + privateKeys.add(prikey); + } catch (IOException | CipherException e) { + logger.error("Witness node start failed!"); + throw new TronError(e, TronError.ErrCode.WITNESS_KEYSTORE_LOAD); + } + + this.localWitnesses.setPrivateKeys(privateKeys); + byte[] witnessAddress = getWitnessAddress(); + this.localWitnesses.initWitnessAccountAddress(witnessAddress, + Args.PARAMETER.isECKeyCryptoEngine()); + logger.debug("Got privateKey from keystore"); + } + + private byte[] getWitnessAddress() { + if (!config.hasPath(Constant.LOCAL_WITNESS_ACCOUNT_ADDRESS)) { + return null; + } + + if (localWitnesses.getPrivateKeys().size() != 1) { + throw new TronError( + "LocalWitnessAccountAddress can only be set when there is only one private key", + TronError.ErrCode.WITNESS_INIT); + } + byte[] witnessAddress = Commons + .decodeFromBase58Check(config.getString(Constant.LOCAL_WITNESS_ACCOUNT_ADDRESS)); + if (witnessAddress != null) { + logger.debug("Got localWitnessAccountAddress from config.conf"); + } else { + throw new TronError("LocalWitnessAccountAddress format from config is incorrect", + TronError.ErrCode.WITNESS_INIT); + } + return witnessAddress; + } +} diff --git a/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java b/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java index 98bf92ac76e..9a5ecb33213 100644 --- a/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java +++ b/framework/src/main/java/org/tron/core/metrics/node/NodeMetricManager.java @@ -4,8 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.tron.common.backup.BackupManager; -import org.tron.common.parameter.CommonParameter; -import org.tron.common.utils.ByteUtil; +import org.tron.common.utils.ByteArray; import org.tron.core.ChainBaseManager; import org.tron.core.config.args.Args; import org.tron.program.Version; @@ -38,7 +37,7 @@ private void setNodeInfo(NodeInfo nodeInfo) { nodeInfo.setIp(Args.getInstance().getNodeExternalIp()); byte[] witnessAccountAddress = Args.getLocalWitnesses().getWitnessAccountAddress(); - ByteString witnessAddress = !ByteUtil.isNullOrZeroArray(witnessAccountAddress) ? ByteString + ByteString witnessAddress = !ByteArray.isEmpty(witnessAccountAddress) ? ByteString .copyFrom(witnessAccountAddress) : null; if (chainBaseManager.getWitnessScheduleStore().getActiveWitnesses().contains(witnessAddress)) { nodeInfo.setNodeType(1); diff --git a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java index ac685f57cea..8b9da2c7bc3 100644 --- a/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java +++ b/framework/src/test/java/org/tron/core/config/args/LocalWitnessTest.java @@ -198,7 +198,7 @@ public void testConstructor() { @Test public void testLocalWitnessConfig() throws IOException { Args.setParam( - new String[]{"--output-directory", temporaryFolder.newFolder().toString(), "--debug"}, + new String[]{"--output-directory", temporaryFolder.newFolder().toString(), "-w", "--debug"}, "config-localtest.conf"); LocalWitnesses witness = Args.getLocalWitnesses(); Assert.assertNotNull(witness.getPrivateKey()); 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 4012029e8ae..013d58b63ca 100755 --- a/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java +++ b/framework/src/test/java/org/tron/core/zksnark/ShieldedReceiveTest.java @@ -128,7 +128,7 @@ public class ShieldedReceiveTest extends BaseTest { private static boolean init; static { - Args.setParam(new String[]{"--output-directory", dbPath()}, "config-localtest.conf"); + Args.setParam(new String[]{"--output-directory", dbPath(), "-w"}, "config-localtest.conf"); ADDRESS_ONE_PRIVATE_KEY = getRandomPrivateKey(); FROM_ADDRESS = getHexAddressByPrivateKey(ADDRESS_ONE_PRIVATE_KEY); } From 997fc41df70cbb92c53100436cd11964105fb084 Mon Sep 17 00:00:00 2001 From: federico Date: Tue, 19 Aug 2025 13:41:38 +0800 Subject: [PATCH 13/13] add the test unit --- .../core/config/args/WitnessInitializer.java | 3 +- .../org/tron/common/crypto/ECKeyTest.java | 6 + .../org/tron/common/crypto/SM2KeyTest.java | 6 + .../config/args/WitnessInitializerTest.java | 268 ++++++++++++++++++ 4 files changed, 281 insertions(+), 2 deletions(-) create mode 100644 framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java diff --git a/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java b/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java index e3b889a5acf..2ea3a449ef4 100644 --- a/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java +++ b/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java @@ -26,11 +26,10 @@ public class WitnessInitializer { public WitnessInitializer(Config config) { this.config = config; + this.localWitnesses = new LocalWitnesses(); } public LocalWitnesses initLocalWitnesses() { - localWitnesses = new LocalWitnesses(); - if (!Args.PARAMETER.isWitness()) { return localWitnesses; } diff --git a/framework/src/test/java/org/tron/common/crypto/ECKeyTest.java b/framework/src/test/java/org/tron/common/crypto/ECKeyTest.java index 4e7d45ee8d7..273672e8342 100644 --- a/framework/src/test/java/org/tron/common/crypto/ECKeyTest.java +++ b/framework/src/test/java/org/tron/common/crypto/ECKeyTest.java @@ -5,6 +5,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.tron.common.utils.client.utils.AbiUtil.generateOccupationConstantPrivateKey; @@ -67,6 +68,11 @@ public void testFromPrivateKey() { assertTrue(key.isPubKeyCanonical()); assertTrue(key.hasPrivKey()); assertArrayEquals(pubKey, key.getPubKey()); + + key = ECKey.fromPrivate((byte[]) null); + assertNull(key); + key = ECKey.fromPrivate(new byte[0]); + assertNull(key); } @Test(expected = IllegalArgumentException.class) diff --git a/framework/src/test/java/org/tron/common/crypto/SM2KeyTest.java b/framework/src/test/java/org/tron/common/crypto/SM2KeyTest.java index b84026d2085..87e4e14698c 100644 --- a/framework/src/test/java/org/tron/common/crypto/SM2KeyTest.java +++ b/framework/src/test/java/org/tron/common/crypto/SM2KeyTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.tron.common.utils.client.utils.AbiUtil.generateOccupationConstantPrivateKey; @@ -64,6 +65,11 @@ public void testFromPrivateKey() { assertTrue(key.isPubKeyCanonical()); assertTrue(key.hasPrivKey()); assertArrayEquals(pubKey, key.getPubKey()); + + key = SM2.fromPrivate((byte[]) null); + assertNull(key); + key = SM2.fromPrivate(new byte[0]); + assertNull(key); } @Test(expected = IllegalArgumentException.class) diff --git a/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java b/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java new file mode 100644 index 00000000000..7364b1f9b3a --- /dev/null +++ b/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java @@ -0,0 +1,268 @@ +package org.tron.core.config.args; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import org.bouncycastle.util.encoders.Hex; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockedStatic; +import org.tron.common.crypto.SignInterface; +import org.tron.common.parameter.CommonParameter; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.LocalWitnesses; +import org.tron.common.utils.PublicMethod; +import org.tron.common.utils.client.utils.Base58; +import org.tron.core.Constant; +import org.tron.core.exception.TronError; +import org.tron.core.exception.TronError.ErrCode; +import org.tron.keystore.Credentials; +import org.tron.keystore.WalletUtils; + +public class WitnessInitializerTest { + + private Config config; + private WitnessInitializer witnessInitializer; + + private static final String privateKey = PublicMethod.getRandomPrivateKey(); + private static final String address = Base58.encode58Check( + ByteArray.fromHexString(PublicMethod.getHexAddressByPrivateKey(privateKey))); + private static final String invalidAddress = "RJCzdnv88Hvqa2jB1C9dMmMYHr5DFdF2R3"; + + @Before + public void setUp() { + config = ConfigFactory.empty(); + witnessInitializer = new WitnessInitializer(config); + } + + @After + public void clear() { + Args.clearParam(); + } + + @Test + public void testInitLocalWitnessesEmpty() { + Args.PARAMETER.setWitness(false); + + LocalWitnesses result = witnessInitializer.initLocalWitnesses(); + assertNotNull(result); + assertTrue(result.getPrivateKeys().isEmpty()); + + Args.PARAMETER.setWitness(true); + LocalWitnesses localWitnesses = witnessInitializer.initLocalWitnesses(); + assertTrue(localWitnesses.getPrivateKeys().isEmpty()); + + String configString = "localwitness = [] \n localwitnesskeystore = []"; + config = ConfigFactory.parseString(configString); + witnessInitializer = new WitnessInitializer(config); + localWitnesses = witnessInitializer.initLocalWitnesses(); + assertTrue(localWitnesses.getPrivateKeys().isEmpty()); + } + + @Test + public void testTryInitFromCommandLine() + throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, + InvocationTargetException { + Field privateKeyField = CommonParameter.class.getDeclaredField("privateKey"); + privateKeyField.setAccessible(true); + privateKeyField.set(Args.getInstance(), ""); + + witnessInitializer = new WitnessInitializer(config); + Method method = WitnessInitializer.class.getDeclaredMethod( + "tryInitFromCommandLine"); + method.setAccessible(true); + boolean result = (boolean) method.invoke(witnessInitializer); + assertFalse(result); + + privateKeyField.set(Args.getInstance(), privateKey); + method.invoke(witnessInitializer); + result = (boolean) method.invoke(witnessInitializer); + assertTrue(result); + + Field witnessAddress = CommonParameter.class.getDeclaredField("witnessAddress"); + witnessAddress.setAccessible(true); + witnessAddress.set(Args.getInstance(), address); + result = (boolean) method.invoke(witnessInitializer); + assertTrue(result); + + witnessAddress.set(Args.getInstance(), invalidAddress); + InvocationTargetException thrown = assertThrows(InvocationTargetException.class, + () -> method.invoke(witnessInitializer)); + TronError targetException = (TronError) thrown.getTargetException(); + assertEquals(ErrCode.WITNESS_INIT, targetException.getErrCode()); + } + + @Test + public void testTryInitFromConfig() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + witnessInitializer = new WitnessInitializer(config); + Method method = WitnessInitializer.class.getDeclaredMethod( + "tryInitFromConfig"); + method.setAccessible(true); + boolean result = (boolean) method.invoke(witnessInitializer); + assertFalse(result); + + String configString = "localwitness = []"; + config = ConfigFactory.parseString(configString); + witnessInitializer = new WitnessInitializer(config); + result = (boolean) method.invoke(witnessInitializer); + assertFalse(result); + + configString = "localwitness = [" + privateKey + "]"; + config = ConfigFactory.parseString(configString); + witnessInitializer = new WitnessInitializer(config); + result = (boolean) method.invoke(witnessInitializer); + assertTrue(result); + + configString = "localWitnessAccountAddress = " + address + "\n" + + "localwitness = [\n" + privateKey + "]"; + config = ConfigFactory.parseString(configString); + witnessInitializer = new WitnessInitializer(config); + result = (boolean) method.invoke(witnessInitializer); + assertTrue(result); + + configString = "localwitness = [\n" + privateKey + "\n" + privateKey + "]"; + config = ConfigFactory.parseString(configString); + witnessInitializer = new WitnessInitializer(config); + result = (boolean) method.invoke(witnessInitializer); + assertTrue(result); + + configString = "localWitnessAccountAddress = " + invalidAddress + "\n" + + "localwitness = [\n" + privateKey + "]"; + config = ConfigFactory.parseString(configString); + witnessInitializer = new WitnessInitializer(config); + InvocationTargetException thrown = assertThrows(InvocationTargetException.class, + () -> method.invoke(witnessInitializer)); + TronError targetException = (TronError) thrown.getTargetException(); + assertEquals(ErrCode.WITNESS_INIT, targetException.getErrCode()); + + configString = "localWitnessAccountAddress = " + address + "\n" + + "localwitness = [\n" + privateKey + "\n" + privateKey + "]"; + config = ConfigFactory.parseString(configString); + witnessInitializer = new WitnessInitializer(config); + thrown = assertThrows(InvocationTargetException.class, + () -> method.invoke(witnessInitializer)); + targetException = (TronError) thrown.getTargetException(); + assertEquals(ErrCode.WITNESS_INIT, targetException.getErrCode()); + } + + @Test + public void testTryInitFromKeystore() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, + NoSuchFieldException { + witnessInitializer = new WitnessInitializer(config); + Method method = WitnessInitializer.class.getDeclaredMethod( + "tryInitFromKeystore"); + method.setAccessible(true); + method.invoke(witnessInitializer); + Field localWitnessField = WitnessInitializer.class.getDeclaredField("localWitnesses"); + localWitnessField.setAccessible(true); + LocalWitnesses localWitnesses = (LocalWitnesses) localWitnessField.get(witnessInitializer); + assertTrue(localWitnesses.getPrivateKeys().isEmpty()); + + String configString = "localwitnesskeystore = []"; + Config emptyListConfig = ConfigFactory.parseString(configString); + witnessInitializer = new WitnessInitializer(emptyListConfig); + method.invoke(witnessInitializer); + localWitnesses = (LocalWitnesses) localWitnessField.get(witnessInitializer); + assertTrue(localWitnesses.getPrivateKeys().isEmpty()); + } + + @Test + public void testTryInitFromKeyStore2() + throws NoSuchFieldException, IllegalAccessException { + Args.PARAMETER.setWitness(true); + Config mockConfig = mock(Config.class); + when(mockConfig.hasPath(Constant.LOCAL_WITNESS_KEYSTORE)).thenReturn(false); + witnessInitializer = new WitnessInitializer(mockConfig); + witnessInitializer.initLocalWitnesses(); + verify(mockConfig, never()).getStringList(anyString()); + + when(mockConfig.hasPath(Constant.LOCAL_WITNESS_KEYSTORE)).thenReturn(true); + when(mockConfig.getStringList(Constant.LOCAL_WITNESS_KEYSTORE)).thenReturn(new ArrayList<>()); + witnessInitializer = new WitnessInitializer(mockConfig); + witnessInitializer.initLocalWitnesses(); + verify(mockConfig, times(1)).getStringList(Constant.LOCAL_WITNESS_KEYSTORE); + + List keystores = new ArrayList<>(); + keystores.add("keystore1.json"); + keystores.add("keystore2.json"); + when(mockConfig.hasPath(Constant.LOCAL_WITNESS_KEYSTORE)).thenReturn(true); + when(mockConfig.getStringList(Constant.LOCAL_WITNESS_KEYSTORE)).thenReturn(keystores); + + Field password = CommonParameter.class.getDeclaredField("password"); + password.setAccessible(true); + password.set(Args.getInstance(), "password"); + + try (MockedStatic mockedWalletUtils = mockStatic(WalletUtils.class); + MockedStatic mockedByteArray = mockStatic(ByteArray.class)) { + // Mock WalletUtils.loadCredentials + Credentials credentials = mock(Credentials.class); + SignInterface signInterface = mock(SignInterface.class); + when(credentials.getSignInterface()).thenReturn(signInterface); + byte[] keyBytes = Hex.decode(privateKey); + when(signInterface.getPrivateKey()).thenReturn(keyBytes); + mockedWalletUtils.when(() -> WalletUtils.loadCredentials(anyString(), any(File.class))) + .thenReturn(credentials); + mockedByteArray.when(() -> ByteArray.toHexString(any())).thenReturn(privateKey); + mockedByteArray.when(() -> ByteArray.fromHexString(anyString())).thenReturn(keyBytes); + + witnessInitializer = new WitnessInitializer(mockConfig); + Field localWitnessField = WitnessInitializer.class.getDeclaredField("localWitnesses"); + localWitnessField.setAccessible(true); + localWitnessField.set(witnessInitializer, new LocalWitnesses(privateKey)); + LocalWitnesses localWitnesses = witnessInitializer.initLocalWitnesses(); + assertFalse(localWitnesses.getPrivateKeys().isEmpty()); + } + } + + @Test + public void testGetWitnessAddress() + throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, + NoSuchFieldException { + witnessInitializer = new WitnessInitializer(config); + Method method = WitnessInitializer.class.getDeclaredMethod( + "getWitnessAddress"); + method.setAccessible(true); + byte[] result = (byte[]) method.invoke(witnessInitializer); + assertNull(result); + + String configString = "localWitnessAccountAddress = " + address; + config = ConfigFactory.parseString(configString); + witnessInitializer = new WitnessInitializer(config); + Field localWitnessField = WitnessInitializer.class.getDeclaredField("localWitnesses"); + localWitnessField.setAccessible(true); + localWitnessField.set(witnessInitializer, new LocalWitnesses(privateKey)); + result = (byte[]) method.invoke(witnessInitializer); + assertNotNull(result); + + configString = "localWitnessAccountAddress = " + invalidAddress; + config = ConfigFactory.parseString(configString); + witnessInitializer = new WitnessInitializer(config); + InvocationTargetException thrown = assertThrows(InvocationTargetException.class, + () -> method.invoke(witnessInitializer)); + TronError targetException = (TronError) thrown.getTargetException(); + assertEquals(ErrCode.WITNESS_INIT, targetException.getErrCode()); + } +}