diff --git a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java index d7e2f1c0949..cd42d7a9010 100644 --- a/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java +++ b/actuator/src/main/java/org/tron/core/utils/ProposalUtil.java @@ -871,6 +871,21 @@ public static void validator(DynamicPropertiesStore dynamicPropertiesStore, } break; } + case ALLOW_TVM_OSAKA: { + if (!forkController.pass(ForkBlockVersionEnum.VERSION_4_8_2)) { + throw new ContractValidateException( + "Bad chain parameter id [ALLOW_TVM_OSAKA]"); + } + if (dynamicPropertiesStore.getAllowTvmOsaka() == 1) { + throw new ContractValidateException( + "[ALLOW_TVM_OSAKA] has been valid, no need to propose again"); + } + if (value != 1) { + throw new ContractValidateException( + "This value[ALLOW_TVM_OSAKA] is only allowed to be 1"); + } + break; + } default: break; } @@ -955,7 +970,8 @@ public enum ProposalType { // current value, value range CONSENSUS_LOGIC_OPTIMIZATION(88), // 0, 1 ALLOW_TVM_BLOB(89), // 0, 1 PROPOSAL_EXPIRE_TIME(92), // (0, 31536003000) - ALLOW_TVM_SELFDESTRUCT_RESTRICTION(94); // 0, 1 + ALLOW_TVM_SELFDESTRUCT_RESTRICTION(94), // 0, 1 + ALLOW_TVM_OSAKA(96); // 0, 1 private long code; diff --git a/actuator/src/main/java/org/tron/core/utils/TransactionRegister.java b/actuator/src/main/java/org/tron/core/utils/TransactionRegister.java index 867ea06bfe2..14746211045 100644 --- a/actuator/src/main/java/org/tron/core/utils/TransactionRegister.java +++ b/actuator/src/main/java/org/tron/core/utils/TransactionRegister.java @@ -1,24 +1,58 @@ package org.tron.core.utils; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import lombok.extern.slf4j.Slf4j; import org.reflections.Reflections; import org.tron.core.actuator.AbstractActuator; +import org.tron.core.exception.TronError; @Slf4j(topic = "TransactionRegister") public class TransactionRegister { + private static final AtomicBoolean REGISTERED = new AtomicBoolean(false); + private static final String PACKAGE_NAME = "org.tron.core.actuator"; + public static void registerActuator() { - Reflections reflections = new Reflections("org.tron"); - Set> subTypes = reflections - .getSubTypesOf(AbstractActuator.class); - for (Class _class : subTypes) { - try { - _class.newInstance(); - } catch (Exception e) { - logger.error("{} contract actuator register fail!", _class, e); + if (REGISTERED.get()) { + logger.debug("Actuator already registered."); + return; + } + + synchronized (TransactionRegister.class) { + if (REGISTERED.get()) { + logger.debug("Actuator already registered."); + return; + } + logger.debug("Register actuator start."); + Reflections reflections = new Reflections(PACKAGE_NAME); + Set> subTypes = reflections + .getSubTypesOf(AbstractActuator.class); + + for (Class clazz : subTypes) { + try { + logger.debug("Registering actuator: {} start", clazz.getName()); + clazz.getDeclaredConstructor().newInstance(); + logger.debug("Registering actuator: {} done", clazz.getName()); + } catch (Exception e) { + Throwable cause = e.getCause() != null ? e.getCause() : e; + String detail = cause.getMessage() != null ? cause.getMessage() : cause.toString(); + throw new TronError(clazz.getName() + ": " + detail, + e, TronError.ErrCode.ACTUATOR_REGISTER); + } } + + REGISTERED.set(true); + logger.debug("Register actuator done, total {}.", subTypes.size()); } } + static boolean isRegistered() { + return REGISTERED.get(); + } + + // For testing only — resets registration state between tests. + static void resetForTesting() { + REGISTERED.set(false); + } } 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 654a76db33b..634f7f2d3d1 100644 --- a/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java +++ b/actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java @@ -622,6 +622,8 @@ public static class ModExp extends PrecompiledContract { private static final int ARGS_OFFSET = 32 * 3; // addresses length part + private static final int UPPER_BOUND = 1024; + @Override public long getEnergyForData(byte[] data) { @@ -660,6 +662,11 @@ public Pair execute(byte[] data) { int expLen = parseLen(data, 1); int modLen = parseLen(data, 2); + if (VMConfig.allowTvmOsaka() + && (baseLen > UPPER_BOUND || expLen > UPPER_BOUND || modLen > UPPER_BOUND)) { + return Pair.of(false, EMPTY_BYTE_ARRAY); + } + BigInteger base = parseArg(data, ARGS_OFFSET, baseLen); BigInteger exp = parseArg(data, addSafely(ARGS_OFFSET, baseLen), expLen); BigInteger mod = parseArg(data, addSafely(addSafely(ARGS_OFFSET, baseLen), expLen), modLen); diff --git a/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java b/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java index e0ebca329cd..e099101912b 100644 --- a/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java +++ b/actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java @@ -45,6 +45,7 @@ public static void load(StoreFactory storeFactory) { VMConfig.initDisableJavaLangMath(ds.getConsensusLogicOptimization()); VMConfig.initAllowTvmBlob(ds.getAllowTvmBlob()); VMConfig.initAllowTvmSelfdestructRestriction(ds.getAllowTvmSelfdestructRestriction()); + VMConfig.initAllowTvmOsaka(ds.getAllowTvmOsaka()); } } } 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 89c5ba18e59..e0adb0d444a 100644 --- a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java +++ b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java @@ -238,6 +238,8 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking private static final byte[] ALLOW_TVM_SELFDESTRUCT_RESTRICTION = "ALLOW_TVM_SELFDESTRUCT_RESTRICTION".getBytes(); + private static final byte[] ALLOW_TVM_OSAKA = "ALLOW_TVM_OSAKA".getBytes(); + @Autowired private DynamicPropertiesStore(@Value("properties") String dbName) { super(dbName); @@ -2980,6 +2982,17 @@ public long getProposalExpireTime() { .orElse(CommonParameter.getInstance().getProposalExpireTime()); } + public long getAllowTvmOsaka() { + return Optional.ofNullable(getUnchecked(ALLOW_TVM_OSAKA)) + .map(BytesCapsule::getData) + .map(ByteArray::toLong) + .orElse(CommonParameter.getInstance().getAllowTvmOsaka()); + } + + public void saveAllowTvmOsaka(long value) { + this.put(ALLOW_TVM_OSAKA, new BytesCapsule(ByteArray.fromLong(value))); + } + private static class DynamicResourceProperties { private static final byte[] ONE_DAY_NET_LIMIT = "ONE_DAY_NET_LIMIT".getBytes(); diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java index fbb39a13288..a73158a718a 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -633,6 +633,10 @@ public class CommonParameter { @Setter public long allowTvmBlob; + @Getter + @Setter + public long allowTvmOsaka; + private static double calcMaxTimeRatio() { return 5.0; } 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 8ec27ed3eb5..db88ab5e047 100644 --- a/common/src/main/java/org/tron/core/config/Parameter.java +++ b/common/src/main/java/org/tron/core/config/Parameter.java @@ -28,7 +28,8 @@ public enum ForkBlockVersionEnum { VERSION_4_7_7(31, 1596780000000L, 80), VERSION_4_8_0(32, 1596780000000L, 80), VERSION_4_8_0_1(33, 1596780000000L, 70), - VERSION_4_8_1(34, 1596780000000L, 80); + VERSION_4_8_1(34, 1596780000000L, 80), + VERSION_4_8_2(35, 1596780000000L, 80); // if add a version, modify BLOCK_VERSION simultaneously @Getter @@ -77,7 +78,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 = 34; + public static final int BLOCK_VERSION = 35; 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/exception/TronError.java b/common/src/main/java/org/tron/core/exception/TronError.java index f407c6dfe3c..4ee7cdae916 100644 --- a/common/src/main/java/org/tron/core/exception/TronError.java +++ b/common/src/main/java/org/tron/core/exception/TronError.java @@ -49,6 +49,7 @@ public enum ErrCode { RATE_LIMITER_INIT(1), SOLID_NODE_INIT(0), PARAMETER_INIT(1), + ACTUATOR_REGISTER(1), JDK_VERSION(1); private final int code; diff --git a/common/src/main/java/org/tron/core/vm/config/VMConfig.java b/common/src/main/java/org/tron/core/vm/config/VMConfig.java index 578827b2f8c..1a7f0c058a4 100644 --- a/common/src/main/java/org/tron/core/vm/config/VMConfig.java +++ b/common/src/main/java/org/tron/core/vm/config/VMConfig.java @@ -61,6 +61,8 @@ public class VMConfig { private static boolean ALLOW_TVM_SELFDESTRUCT_RESTRICTION = false; + private static boolean ALLOW_TVM_OSAKA = false; + private VMConfig() { } @@ -172,6 +174,10 @@ public static void initAllowTvmSelfdestructRestriction(long allow) { ALLOW_TVM_SELFDESTRUCT_RESTRICTION = allow == 1; } + public static void initAllowTvmOsaka(long allow) { + ALLOW_TVM_OSAKA = allow == 1; + } + public static boolean getEnergyLimitHardFork() { return CommonParameter.ENERGY_LIMIT_HARD_FORK; } @@ -271,4 +277,8 @@ public static boolean allowTvmBlob() { public static boolean allowTvmSelfdestructRestriction() { return ALLOW_TVM_SELFDESTRUCT_RESTRICTION; } + + public static boolean allowTvmOsaka() { + return ALLOW_TVM_OSAKA; + } } diff --git a/framework/build.gradle b/framework/build.gradle index 9b287fdeb27..d884b6a7c49 100644 --- a/framework/build.gradle +++ b/framework/build.gradle @@ -30,7 +30,7 @@ static def isWindows() { return org.gradle.internal.os.OperatingSystem.current().isWindows() } -task version(type: Exec) { +tasks.register('version', Exec) { commandLine 'bash', '-c', '../ver.sh' } @@ -78,7 +78,7 @@ checkstyleMain { source = 'src/main/java' } -task lint(type: Checkstyle) { +tasks.register('lint', Checkstyle) { // Cleaning the old log because of the creation of the new ones (not sure if totaly needed) delete fileTree(dir: "${project.rootDir}/app/build/reports") source 'src' @@ -123,10 +123,10 @@ def configureTestTask = { Task t -> t.exclude 'org/tron/core/ShieldedTRC20BuilderTest.class' t.exclude 'org/tron/common/runtime/vm/WithdrawRewardTest.class' } - t.maxHeapSize = "1024m" + t.maxHeapSize = "512m" + t.maxParallelForks = Math.max(1, Math.min(4, Runtime.runtime.availableProcessors())) t.doFirst { t.forkEvery = 100 - t.jvmArgs "-XX:MetaspaceSize=128m", "-XX:MaxMetaspaceSize=256m", "-XX:+UseG1GC" } } @@ -150,7 +150,7 @@ test { } } -task testWithRocksDb(type: Test) { +tasks.register('testWithRocksDb', Test) { description = 'Run tests with RocksDB engine' group = 'verification' configureTestTask(it) @@ -197,7 +197,9 @@ def binaryRelease(taskName, jarName, mainClass) { exclude "META-INF/*.SF" exclude "META-INF/*.DSA" exclude "META-INF/*.RSA" - + // for service SPI loader for dnsjava + // see https://issues.apache.org/jira/browse/HADOOP-19288 + exclude "META-INF/services/java.net.spi.InetAddressResolverProvider" manifest { attributes "Main-Class": "${mainClass}" } diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index 8c86f2f66ac..39e8f06c281 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -1509,6 +1509,11 @@ public Protocol.ChainParameters getChainParameters() { .setValue(dbManager.getDynamicPropertiesStore().getProposalExpireTime()) .build()); + builder.addChainParameter(Protocol.ChainParameters.ChainParameter.newBuilder() + .setKey("getAllowTvmOsaka") + .setValue(dbManager.getDynamicPropertiesStore().getAllowTvmOsaka()) + .build()); + return builder.build(); } diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index dd8fd3422de..83d7fd2c63d 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 @@ -1037,6 +1037,10 @@ public static void applyConfigParams( config.hasPath(ConfigKey.COMMITTEE_ALLOW_TVM_BLOB) ? config .getInt(ConfigKey.COMMITTEE_ALLOW_TVM_BLOB) : 0; + PARAMETER.allowTvmOsaka = + config.hasPath(ConfigKey.COMMITTEE_ALLOW_TVM_OSAKA) ? config + .getInt(ConfigKey.COMMITTEE_ALLOW_TVM_OSAKA) : 0; + logConfig(); } diff --git a/framework/src/main/java/org/tron/core/config/args/ConfigKey.java b/framework/src/main/java/org/tron/core/config/args/ConfigKey.java index 06dd7d9d57a..b21c9c440a4 100644 --- a/framework/src/main/java/org/tron/core/config/args/ConfigKey.java +++ b/framework/src/main/java/org/tron/core/config/args/ConfigKey.java @@ -247,6 +247,7 @@ private ConfigKey() { 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"; + public static final String COMMITTEE_ALLOW_TVM_OSAKA = "committee.allowTvmOsaka"; public static final String ALLOW_ACCOUNT_ASSET_OPTIMIZATION = "committee.allowAccountAssetOptimization"; public static final String ALLOW_ASSET_OPTIMIZATION = "committee.allowAssetOptimization"; 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 51d53f6a59e..1bec0c2bda3 100644 --- a/framework/src/main/java/org/tron/core/consensus/ProposalService.java +++ b/framework/src/main/java/org/tron/core/consensus/ProposalService.java @@ -392,6 +392,10 @@ public static boolean process(Manager manager, ProposalCapsule proposalCapsule) manager.getDynamicPropertiesStore().saveProposalExpireTime(entry.getValue()); break; } + case ALLOW_TVM_OSAKA: { + manager.getDynamicPropertiesStore().saveAllowTvmOsaka(entry.getValue()); + break; + } default: find = false; break; diff --git a/framework/src/main/resources/config.conf b/framework/src/main/resources/config.conf index 069b51286d9..369924074bc 100644 --- a/framework/src/main/resources/config.conf +++ b/framework/src/main/resources/config.conf @@ -759,6 +759,7 @@ committee = { # allowTvmBlob = 0 # consensusLogicOptimization = 0 # allowOptimizedReturnValueOfChainId = 0 + # allowTvmOsaka = 0 } event.subscribe = { diff --git a/framework/src/test/java/org/tron/common/runtime/vm/AllowTvmOsakaTest.java b/framework/src/test/java/org/tron/common/runtime/vm/AllowTvmOsakaTest.java new file mode 100644 index 00000000000..897ec43e24a --- /dev/null +++ b/framework/src/test/java/org/tron/common/runtime/vm/AllowTvmOsakaTest.java @@ -0,0 +1,77 @@ +package org.tron.common.runtime.vm; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.Assert; +import org.junit.Test; +import org.tron.common.utils.ByteUtil; +import org.tron.core.vm.PrecompiledContracts; +import org.tron.core.vm.config.ConfigLoader; +import org.tron.core.vm.config.VMConfig; + +@Slf4j +public class AllowTvmOsakaTest extends VMTestBase { + + private static final PrecompiledContracts.PrecompiledContract modExp = + new PrecompiledContracts.ModExp(); + + private static byte[] toLenBytes(int value) { + byte[] b = new byte[32]; + b[28] = (byte) ((value >> 24) & 0xFF); + b[29] = (byte) ((value >> 16) & 0xFF); + b[30] = (byte) ((value >> 8) & 0xFF); + b[31] = (byte) (value & 0xFF); + return b; + } + + @Test + public void testEIP7823() { + ConfigLoader.disable = true; + VMConfig.initAllowTvmOsaka(1); + + try { + // all-zero lengths: should succeed + Pair result = modExp.execute( + ByteUtil.merge(toLenBytes(0), toLenBytes(0), toLenBytes(0))); + Assert.assertTrue(result.getLeft()); + + // baseLen == 1024: boundary, should succeed + result = modExp.execute( + ByteUtil.merge(toLenBytes(1024), toLenBytes(0), toLenBytes(0))); + Assert.assertTrue(result.getLeft()); + + // baseLen == 1025: just over the limit, should fail + result = modExp.execute( + ByteUtil.merge(toLenBytes(1025), toLenBytes(0), toLenBytes(0))); + Assert.assertFalse(result.getLeft()); + + // oversized expLen only: should fail + result = modExp.execute( + ByteUtil.merge(toLenBytes(0), toLenBytes(1025), toLenBytes(0))); + Assert.assertFalse(result.getLeft()); + + // oversized modLen only: should fail + result = modExp.execute( + ByteUtil.merge(toLenBytes(0), toLenBytes(0), toLenBytes(1025))); + Assert.assertFalse(result.getLeft()); + } finally { + VMConfig.initAllowTvmOsaka(0); + ConfigLoader.disable = false; + } + } + + @Test + public void testEIP7823DisabledShouldPass() { + ConfigLoader.disable = true; + VMConfig.initAllowTvmOsaka(0); + + try { + // all limits exceeded while osaka is disabled: should succeed (no restriction) + Pair result = modExp.execute( + ByteUtil.merge(toLenBytes(2048), toLenBytes(2048), toLenBytes(2048))); + Assert.assertTrue(result.getLeft()); + } finally { + ConfigLoader.disable = false; + } + } +} diff --git a/framework/src/test/java/org/tron/core/utils/TransactionRegisterTest.java b/framework/src/test/java/org/tron/core/utils/TransactionRegisterTest.java new file mode 100644 index 00000000000..ea622213f45 --- /dev/null +++ b/framework/src/test/java/org/tron/core/utils/TransactionRegisterTest.java @@ -0,0 +1,137 @@ +package org.tron.core.utils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.HashSet; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockedConstruction; +import org.mockito.junit.MockitoJUnitRunner; +import org.reflections.Reflections; +import org.tron.core.actuator.AbstractActuator; +import org.tron.core.actuator.TransferActuator; +import org.tron.core.config.args.Args; +import org.tron.core.exception.TronError; + +@RunWith(MockitoJUnitRunner.class) +public class TransactionRegisterTest { + + @Before + public void init() { + Args.getInstance().setActuatorSet(new HashSet<>()); + TransactionRegister.resetForTesting(); + } + + @After + public void destroy() { + Args.clearParam(); + } + + @Test + public void testAlreadyRegisteredSkipRegistration() { + TransactionRegister.registerActuator(); + assertTrue("First registration should be completed", TransactionRegister.isRegistered()); + + TransactionRegister.registerActuator(); + assertTrue("Registration should still be true", TransactionRegister.isRegistered()); + } + + @Test + public void testConcurrentAccessThreadSafe() throws InterruptedException { + final int threadCount = 5; + Thread[] threads = new Thread[threadCount]; + final AtomicBoolean testPassed = new AtomicBoolean(true); + + for (int i = 0; i < threadCount; i++) { + threads[i] = new Thread(() -> { + try { + TransactionRegister.registerActuator(); + } catch (Throwable e) { + testPassed.set(false); + } + }); + } + + for (Thread thread : threads) { + thread.start(); + } + + for (Thread thread : threads) { + thread.join(); + } + + assertTrue("All threads should complete without exceptions", testPassed.get()); + assertTrue("Registration should be completed", TransactionRegister.isRegistered()); + } + + @Test + public void testDoubleCheckLockingAtomicBoolean() { + assertFalse("Initial registration state should be false", TransactionRegister.isRegistered()); + + TransactionRegister.registerActuator(); + assertTrue("After first call, should be registered", TransactionRegister.isRegistered()); + + TransactionRegister.registerActuator(); + assertTrue("After second call, should still be registered", TransactionRegister.isRegistered()); + } + + @Test + public void testRegistrationRunsExactlyOnce() { + final AtomicInteger constructorCallCount = new AtomicInteger(0); + + try (MockedConstruction ignored = mockConstruction(Reflections.class, + (mock, context) -> { + constructorCallCount.incrementAndGet(); + when(mock.getSubTypesOf(AbstractActuator.class)).thenReturn(Collections.emptySet()); + })) { + + // Call multiple times; Reflections should only be constructed once + for (int i = 0; i < 5; i++) { + TransactionRegister.registerActuator(); + } + + assertEquals("Reflections should be constructed exactly once regardless of call count", + 1, constructorCallCount.get()); + assertTrue(TransactionRegister.isRegistered()); + } + } + + @Test + public void testMultipleCallsConsistency() { + assertFalse("Should start unregistered", TransactionRegister.isRegistered()); + + TransactionRegister.registerActuator(); + assertTrue("Should be registered after first call", TransactionRegister.isRegistered()); + + for (int i = 0; i < 5; i++) { + TransactionRegister.registerActuator(); + assertTrue("Should remain registered after call " + (i + 2), + TransactionRegister.isRegistered()); + } + } + + @Test + public void testThrowsTronError() { + try (MockedConstruction ignored = mockConstruction(Reflections.class, + (mock, context) -> when(mock.getSubTypesOf(AbstractActuator.class)) + .thenReturn(Collections.singleton(TransferActuator.class))); + MockedConstruction ignored1 = mockConstruction(TransferActuator.class, + (mock, context) -> { + throw new RuntimeException("boom"); + })) { + TronError error = assertThrows(TronError.class, TransactionRegister::registerActuator); + assertEquals(TronError.ErrCode.ACTUATOR_REGISTER, error.getErrCode()); + assertTrue(error.getMessage().contains("TransferActuator")); + } + } +} \ No newline at end of file diff --git a/framework/src/test/resources/logback-test.xml b/framework/src/test/resources/logback-test.xml index 9cf4a04062f..cc8c84e831f 100644 --- a/framework/src/test/resources/logback-test.xml +++ b/framework/src/test/resources/logback-test.xml @@ -1,40 +1,42 @@ - - - - - - - %d{HH:mm:ss.SSS} %p [%c{1}] %m%n - - - INFO - - - - - ./logs/tron-test.log - - - ./logs/tron-test-%d{yyyy-MM-dd}.%i.log.zip - - - 100MB - 60 - 20GB - - - %d{HH:mm:ss.SSS} %p [%c{1}] %m%n - - - - - - - - - - - - + + + + + + + %d{HH:mm:ss.SSS} %p [%c{1}] %m%n + + + ${console.log.level:-ERROR} + + + + + ./logs/tron-test.log + 8192 + true + + + ./logs/tron-test-%d{yyyy-MM-dd}.%i.log.zip + + + 100MB + 60 + 20GB + + + %d{HH:mm:ss.SSS} %p [%c{1}] %m%n + + + + + + + + + + + +