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 304ced33698..e43120edd66 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 @@ -100,108 +100,116 @@ public static void initVmHardFork(boolean pass) { // The init* setters below mutate the global (HEAD) config in place. They are kept for tests and // legacy callers; production config loading goes through ConfigLoader -> setGlobalSnapshot, which // publishes a fresh Snapshot wholesale via the volatile field. + // + // Drop any leftover thread-local view first. Getters use current() (local if present), so writing + // only globalSnapshot would leave a stale local snapshot shadowing the value just set. + private static Snapshot forInit() { + localSnapshot.remove(); + return globalSnapshot; + } + public static void initAllowMultiSign(long allow) { - globalSnapshot.allowMultiSign = allow == 1; + forInit().allowMultiSign = allow == 1; } public static void initAllowTvmTransferTrc10(long allow) { - globalSnapshot.allowTvmTransferTrc10 = allow == 1; + forInit().allowTvmTransferTrc10 = allow == 1; } public static void initAllowTvmConstantinople(long allow) { - globalSnapshot.allowTvmConstantinople = allow == 1; + forInit().allowTvmConstantinople = allow == 1; } public static void initAllowTvmSolidity059(long allow) { - globalSnapshot.allowTvmSolidity059 = allow == 1; + forInit().allowTvmSolidity059 = allow == 1; } public static void initAllowShieldedTRC20Transaction(long allow) { - globalSnapshot.allowShieldedTRC20Transaction = allow == 1; + forInit().allowShieldedTRC20Transaction = allow == 1; } public static void initAllowTvmIstanbul(long allow) { - globalSnapshot.allowTvmIstanbul = allow == 1; + forInit().allowTvmIstanbul = allow == 1; } public static void initAllowTvmFreeze(long allow) { - globalSnapshot.allowTvmFreeze = allow == 1; + forInit().allowTvmFreeze = allow == 1; } public static void initAllowTvmVote(long allow) { - globalSnapshot.allowTvmVote = allow == 1; + forInit().allowTvmVote = allow == 1; } public static void initAllowTvmLondon(long allow) { - globalSnapshot.allowTvmLondon = allow == 1; + forInit().allowTvmLondon = allow == 1; } public static void initAllowTvmCompatibleEvm(long allow) { - globalSnapshot.allowTvmCompatibleEvm = allow == 1; + forInit().allowTvmCompatibleEvm = allow == 1; } public static void initAllowHigherLimitForMaxCpuTimeOfOneTx(long allow) { - globalSnapshot.allowHigherLimitForMaxCpuTimeOfOneTx = allow == 1; + forInit().allowHigherLimitForMaxCpuTimeOfOneTx = allow == 1; } public static void initAllowTvmFreezeV2(long allow) { - globalSnapshot.allowTvmFreezeV2 = allow == 1; + forInit().allowTvmFreezeV2 = allow == 1; } public static void initAllowOptimizedReturnValueOfChainId(long allow) { - globalSnapshot.allowOptimizedReturnValueOfChainId = allow == 1; + forInit().allowOptimizedReturnValueOfChainId = allow == 1; } public static void initAllowDynamicEnergy(long allow) { - globalSnapshot.allowDynamicEnergy = allow == 1; + forInit().allowDynamicEnergy = allow == 1; } public static void initDynamicEnergyThreshold(long threshold) { - globalSnapshot.dynamicEnergyThreshold = threshold; + forInit().dynamicEnergyThreshold = threshold; } public static void initDynamicEnergyIncreaseFactor(long increaseFactor) { - globalSnapshot.dynamicEnergyIncreaseFactor = increaseFactor; + forInit().dynamicEnergyIncreaseFactor = increaseFactor; } public static void initDynamicEnergyMaxFactor(long maxFactor) { - globalSnapshot.dynamicEnergyMaxFactor = maxFactor; + forInit().dynamicEnergyMaxFactor = maxFactor; } public static void initAllowTvmShangHai(long allow) { - globalSnapshot.allowTvmShanghai = allow == 1; + forInit().allowTvmShanghai = allow == 1; } public static void initAllowEnergyAdjustment(long allow) { - globalSnapshot.allowEnergyAdjustment = allow == 1; + forInit().allowEnergyAdjustment = allow == 1; } public static void initAllowStrictMath(long allow) { - globalSnapshot.allowStrictMath = allow == 1; + forInit().allowStrictMath = allow == 1; } public static void initAllowTvmCancun(long allow) { - globalSnapshot.allowTvmCancun = allow == 1; + forInit().allowTvmCancun = allow == 1; } public static void initDisableJavaLangMath(long allow) { - globalSnapshot.disableJavaLangMath = allow == 1; + forInit().disableJavaLangMath = allow == 1; } public static void initAllowTvmBlob(long allow) { - globalSnapshot.allowTvmBlob = allow == 1; + forInit().allowTvmBlob = allow == 1; } public static void initAllowTvmSelfdestructRestriction(long allow) { - globalSnapshot.allowTvmSelfdestructRestriction = allow == 1; + forInit().allowTvmSelfdestructRestriction = allow == 1; } public static void initAllowTvmOsaka(long allow) { - globalSnapshot.allowTvmOsaka = allow == 1; + forInit().allowTvmOsaka = allow == 1; } public static void initAllowHardenResourceCalculation(long allow) { - globalSnapshot.allowHardenResourceCalculation = allow == 1; + forInit().allowHardenResourceCalculation = allow == 1; } public static boolean getEnergyLimitHardFork() { diff --git a/framework/src/test/java/org/tron/common/runtime/vm/VMConfigIsolationTest.java b/framework/src/test/java/org/tron/common/runtime/vm/VMConfigIsolationTest.java index 845db6dd6af..ebc6ba98d97 100644 --- a/framework/src/test/java/org/tron/common/runtime/vm/VMConfigIsolationTest.java +++ b/framework/src/test/java/org/tron/common/runtime/vm/VMConfigIsolationTest.java @@ -73,6 +73,13 @@ public void testSetGlobalConfigDropsLocalView() { assertFalse("setGlobalSnapshot must drop the thread-local view", VMConfig.allowTvmOsaka()); } + @Test + public void testInitIsVisibleWhenLocalSnapshotExists() { + VMConfig.setLocalSnapshot(new VMConfig.Snapshot()); + VMConfig.initAllowTvmLondon(1); + assertTrue("init* must not be shadowed by a stale local view", VMConfig.allowTvmLondon()); + } + // Deep-copy the current global config through the public getters (no thread-local set here, so // the getters read the global) so @After can restore the exact prior state. private static VMConfig.Snapshot snapshotGlobal() { diff --git a/framework/src/test/java/org/tron/core/net/messagehandler/TransactionsMsgHandlerTest.java b/framework/src/test/java/org/tron/core/net/messagehandler/TransactionsMsgHandlerTest.java index ed2121d360f..8a7cd876e2c 100644 --- a/framework/src/test/java/org/tron/core/net/messagehandler/TransactionsMsgHandlerTest.java +++ b/framework/src/test/java/org/tron/core/net/messagehandler/TransactionsMsgHandlerTest.java @@ -51,7 +51,6 @@ public void testProcessMessage() { try { transactionsMsgHandler.init(); - PeerConnection peer = Mockito.mock(PeerConnection.class); TronNetDelegate tronNetDelegate = Mockito.mock(TronNetDelegate.class); AdvService advService = Mockito.mock(AdvService.class); @@ -76,11 +75,12 @@ public void testProcessMessage() { .setType(Protocol.Transaction.Contract.ContractType.TransferContract) .setParameter(Any.pack(transferContract)).build()).build()) .build(); + PeerConnection peer = Mockito.mock(PeerConnection.class); Map advInvRequest = new ConcurrentHashMap<>(); Item item = new Item(new TransactionMessage(trx).getMessageId(), Protocol.Inventory.InventoryType.TRX); advInvRequest.put(item, 0L); - Mockito.when(peer.getAdvInvRequest()).thenReturn(advInvRequest); + Mockito.doReturn(advInvRequest).when(peer).getAdvInvRequest(); List transactionList = new ArrayList<>(); transactionList.add(trx); @@ -99,14 +99,15 @@ public void testProcessMessage() { ByteArray.fromHexString("121212a9cf"), ByteArray.fromHexString("123456"), 100, 100000000, 0, 0); + PeerConnection peer1 = Mockito.mock(PeerConnection.class); Map advInvRequest1 = new ConcurrentHashMap<>(); Item item1 = new Item(new TransactionMessage(trx1).getMessageId(), Protocol.Inventory.InventoryType.TRX); advInvRequest1.put(item1, 0L); - Mockito.when(peer.getAdvInvRequest()).thenReturn(advInvRequest1); + Mockito.doReturn(advInvRequest1).when(peer1).getAdvInvRequest(); List transactionList1 = new ArrayList<>(); transactionList1.add(trx1); - transactionsMsgHandler.processMessage(peer, new TransactionsMessage(transactionList1)); + transactionsMsgHandler.processMessage(peer1, new TransactionsMessage(transactionList1)); Assert.assertNull(advInvRequest.get(item1)); // test 0 contract @@ -116,18 +117,20 @@ public void testProcessMessage() { .build(); List transactionList2 = new ArrayList<>(); transactionList2.add(trx2); + PeerConnection peer2 = Mockito.mock(PeerConnection.class); try { - transactionsMsgHandler.processMessage(peer, new TransactionsMessage(transactionList2)); + transactionsMsgHandler.processMessage(peer2, new TransactionsMessage(transactionList2)); } catch (Exception ep) { Assert.assertTrue(true); } + PeerConnection peer3 = Mockito.mock(PeerConnection.class); Map advInvRequest2 = new ConcurrentHashMap<>(); Item item2 = new Item(new TransactionMessage(trx2).getMessageId(), Protocol.Inventory.InventoryType.TRX); advInvRequest2.put(item2, 0L); - Mockito.when(peer.getAdvInvRequest()).thenReturn(advInvRequest2); + Mockito.doReturn(advInvRequest2).when(peer3).getAdvInvRequest(); try { - transactionsMsgHandler.processMessage(peer, new TransactionsMessage(transactionList2)); + transactionsMsgHandler.processMessage(peer3, new TransactionsMessage(transactionList2)); } catch (Exception ep) { Assert.assertTrue(true); } @@ -231,7 +234,7 @@ private void stubAdvInvRequest(PeerConnection peer, TransactionsMessage msg) { Protocol.Inventory.InventoryType.TRX); advInvRequest.put(item, 0L); } - Mockito.when(peer.getAdvInvRequest()).thenReturn(advInvRequest); + Mockito.doReturn(advInvRequest).when(peer).getAdvInvRequest(); } @Test @@ -324,7 +327,7 @@ public void testDuplicateTransactionRejected() throws Exception { Item item = new Item(trxMsg.getMessageId(), Protocol.Inventory.InventoryType.TRX); Map advInvRequest = new ConcurrentHashMap<>(); advInvRequest.put(item, System.currentTimeMillis()); - Mockito.when(peer.getAdvInvRequest()).thenReturn(advInvRequest); + Mockito.doReturn(advInvRequest).when(peer).getAdvInvRequest(); try { handler.processMessage(peer, msg); @@ -342,8 +345,6 @@ public void testInvalidSigLength() throws Exception { TransactionsMsgHandler handler = new TransactionsMsgHandler(); handler.init(); try { - PeerConnection peer = Mockito.mock(PeerConnection.class); - BalanceContract.TransferContract transferContract = BalanceContract.TransferContract .newBuilder() .setAmount(10) @@ -363,9 +364,10 @@ public void testInvalidSigLength() throws Exception { List shortList = new ArrayList<>(); shortList.add(shortSigTrx); - stubAdvInvRequest(peer, new TransactionsMessage(shortList)); + PeerConnection shortPeer = Mockito.mock(PeerConnection.class); + stubAdvInvRequest(shortPeer, new TransactionsMessage(shortList)); P2pException shortEx = Assert.assertThrows(P2pException.class, - () -> handler.processMessage(peer, new TransactionsMessage(shortList))); + () -> handler.processMessage(shortPeer, new TransactionsMessage(shortList))); Assert.assertEquals(TypeEnum.BAD_TRX, shortEx.getType()); // signature longer than 68 bytes → BAD_TRX @@ -381,9 +383,10 @@ public void testInvalidSigLength() throws Exception { List longList = new ArrayList<>(); longList.add(longSigTrx); - stubAdvInvRequest(peer, new TransactionsMessage(longList)); + PeerConnection longPeer = Mockito.mock(PeerConnection.class); + stubAdvInvRequest(longPeer, new TransactionsMessage(longList)); P2pException longEx = Assert.assertThrows(P2pException.class, - () -> handler.processMessage(peer, new TransactionsMessage(longList))); + () -> handler.processMessage(longPeer, new TransactionsMessage(longList))); Assert.assertEquals(TypeEnum.BAD_TRX, longEx.getType()); // exactly 65 bytes → passes the length check (no P2pException from check) @@ -399,8 +402,9 @@ public void testInvalidSigLength() throws Exception { List validList = new ArrayList<>(); validList.add(validSigTrx); - stubAdvInvRequest(peer, new TransactionsMessage(validList)); - handler.processMessage(peer, new TransactionsMessage(validList)); + PeerConnection validPeer = Mockito.mock(PeerConnection.class); + stubAdvInvRequest(validPeer, new TransactionsMessage(validList)); + handler.processMessage(validPeer, new TransactionsMessage(validList)); // 68 bytes (upper bound) also passes the length check Protocol.Transaction paddedSigTrx = Protocol.Transaction.newBuilder() @@ -415,8 +419,9 @@ public void testInvalidSigLength() throws Exception { List paddedList = new ArrayList<>(); paddedList.add(paddedSigTrx); - stubAdvInvRequest(peer, new TransactionsMessage(paddedList)); - handler.processMessage(peer, new TransactionsMessage(paddedList)); + PeerConnection paddedPeer = Mockito.mock(PeerConnection.class); + stubAdvInvRequest(paddedPeer, new TransactionsMessage(paddedList)); + handler.processMessage(paddedPeer, new TransactionsMessage(paddedList)); } finally { handler.close(); }