From d371a5289c4231e8d65583e2eeaacb351bccfb9e Mon Sep 17 00:00:00 2001 From: halibobo1205 Date: Mon, 11 May 2026 13:35:40 +0800 Subject: [PATCH] fix(event): reject incompatible event-plugin versions below 3.0.0 Pre-3.0.0(The previous event-plugin public release is 2.2.0) event-plugin builds still link against com.alibaba.fastjson, which was removed from java-tron in #6701. When such a plugin is loaded, the NoClassDefFoundError surfaces inside the plugin's own worker thread and is swallowed by its catch(Throwable) handler. The node keeps running while silently dropping every trigger, leaving operators with no signal that the event subscription is broken. Enforce a minimum Plugin-Version at startup in EventPluginLoader.startPlugin using pf4j's VersionManager (semver). When the descriptor version is below 3.0.0, log a clear upgrade hint and return false; the existing call chain in Manager.startEventSubscribing wraps that into TronError(EVENT_SUBSCRIBE_INIT) and aborts node startup instead of silently degrading. --- .../common/logsfilter/EventPluginLoader.java | 32 +++++++++++++++++++ .../common/logsfilter/EventLoaderTest.java | 31 ++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java b/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java index 7061b2e9d57..c0b7afd6779 100644 --- a/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java +++ b/framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java @@ -3,6 +3,7 @@ import com.beust.jcommander.internal.Sets; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Strings; import java.io.File; import java.util.HashSet; import java.util.List; @@ -14,8 +15,10 @@ import org.bouncycastle.util.encoders.Hex; import org.pf4j.CompoundPluginDescriptorFinder; import org.pf4j.DefaultPluginManager; +import org.pf4j.DefaultVersionManager; import org.pf4j.ManifestPluginDescriptorFinder; import org.pf4j.PluginManager; +import org.pf4j.VersionManager; import org.springframework.util.StringUtils; import org.tron.common.logsfilter.nativequeue.NativeMessageQueue; import org.tron.common.logsfilter.trigger.BlockLogTrigger; @@ -29,6 +32,16 @@ @Slf4j public class EventPluginLoader { + /** + * Minimum event-plugin Plugin-Version compatible with this node. Bumped to 3.0.0 to + * reject pre-fastjson-removal builds whose worker threads would fail with + * NoClassDefFoundError on com.alibaba.fastjson at runtime. The previous event-plugin + * release is 2.2.0, so 3.0.0 is the first version that ships the Jackson replacement. + */ + static final String MIN_PLUGIN_VERSION = "3.0.0"; + + private static final VersionManager VERSION_MANAGER = new DefaultVersionManager(); + private static EventPluginLoader instance; private long MAX_PENDING_SIZE = 50000; @@ -457,6 +470,10 @@ protected CompoundPluginDescriptorFinder createPluginDescriptorFinder() { return false; } + if (!isPluginVersionSupported(pluginManager, pluginId)) { + return false; + } + pluginManager.startPlugins(); eventListeners = pluginManager.getExtensions(IPluginEventListener.class); @@ -471,6 +488,21 @@ protected CompoundPluginDescriptorFinder createPluginDescriptorFinder() { return true; } + static boolean isPluginVersionSupported(PluginManager pm, String pluginId) { + String pluginVersion = pm.getPlugin(pluginId).getDescriptor().getVersion(); + if (Strings.isNullOrEmpty(pluginVersion)) { + return false; + } + boolean isSupported = VERSION_MANAGER.compareVersions(pluginVersion, MIN_PLUGIN_VERSION) >= 0; + + if (!isSupported) { + logger.error( + "event-plugin '{}' version {} is older than required {}, please upgrade event-plugin", + pluginId, pluginVersion, MIN_PLUGIN_VERSION); + } + return isSupported; + } + public void stopPlugin() { if (Objects.nonNull(pluginManager)) { pluginManager.stopPlugins(); diff --git a/framework/src/test/java/org/tron/common/logsfilter/EventLoaderTest.java b/framework/src/test/java/org/tron/common/logsfilter/EventLoaderTest.java index 1e5268ddeb6..958af4f7b7b 100644 --- a/framework/src/test/java/org/tron/common/logsfilter/EventLoaderTest.java +++ b/framework/src/test/java/org/tron/common/logsfilter/EventLoaderTest.java @@ -3,11 +3,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.List; import org.junit.Assert; import org.junit.Test; +import org.pf4j.PluginDescriptor; +import org.pf4j.PluginManager; +import org.pf4j.PluginWrapper; import org.tron.common.logsfilter.trigger.BlockLogTrigger; import org.tron.common.logsfilter.trigger.TransactionLogTrigger; @@ -48,6 +53,32 @@ public void launchNativeQueue() { EventPluginLoader.getInstance().stopPlugin(); } + @Test + public void testIsPluginVersionSupported() { + assertEquals("3.0.0", EventPluginLoader.MIN_PLUGIN_VERSION); + // last releases before fastjson removal — must be rejected + assertFalse(checkVersion("1.0.0")); + assertFalse(checkVersion("2.2.0")); + assertFalse(checkVersion("2.9.9")); + // 3.0.0 onward — must be accepted + assertTrue(checkVersion("3.0.0")); + assertTrue(checkVersion("3.1.5")); + assertTrue(checkVersion("10.0.0")); + // empty/null version — reject + assertFalse(checkVersion("")); + assertFalse(checkVersion(null)); + } + + private static boolean checkVersion(String version) { + PluginManager pm = mock(PluginManager.class); + PluginWrapper wrapper = mock(PluginWrapper.class); + PluginDescriptor desc = mock(PluginDescriptor.class); + when(pm.getPlugin("test")).thenReturn(wrapper); + when(wrapper.getDescriptor()).thenReturn(desc); + when(desc.getVersion()).thenReturn(version); + return EventPluginLoader.isPluginVersionSupported(pm, "test"); + } + @Test public void testBlockLogTrigger() { BlockLogTrigger blt = new BlockLogTrigger();