Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 42 additions & 38 deletions actuator/src/main/java/org/tron/core/vm/config/ConfigLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,48 @@ public class ConfigLoader {
// snapshot into a thread-local view instead of the process-wide global, so it cannot pollute
// the flags the block-processing path reads concurrently.
public static void load(StoreFactory storeFactory, boolean isolate) {
if (!disable) {
DynamicPropertiesStore ds = storeFactory.getChainBaseManager().getDynamicPropertiesStore();
VMConfig.setVmTrace(CommonParameter.getInstance().isVmTrace());
if (ds != null) {
VMConfig.initVmHardFork(checkForEnergyLimit(ds));
VMConfig.Snapshot snapshot = new VMConfig.Snapshot();
snapshot.allowMultiSign = ds.getAllowMultiSign() == 1;
snapshot.allowTvmTransferTrc10 = ds.getAllowTvmTransferTrc10() == 1;
snapshot.allowTvmConstantinople = ds.getAllowTvmConstantinople() == 1;
snapshot.allowTvmSolidity059 = ds.getAllowTvmSolidity059() == 1;
snapshot.allowShieldedTRC20Transaction = ds.getAllowShieldedTRC20Transaction() == 1;
snapshot.allowTvmIstanbul = ds.getAllowTvmIstanbul() == 1;
snapshot.allowTvmFreeze = ds.getAllowTvmFreeze() == 1;
snapshot.allowTvmVote = ds.getAllowTvmVote() == 1;
snapshot.allowTvmLondon = ds.getAllowTvmLondon() == 1;
snapshot.allowTvmCompatibleEvm = ds.getAllowTvmCompatibleEvm() == 1;
snapshot.allowHigherLimitForMaxCpuTimeOfOneTx =
ds.getAllowHigherLimitForMaxCpuTimeOfOneTx() == 1;
snapshot.allowTvmFreezeV2 = ds.supportUnfreezeDelay();
snapshot.allowOptimizedReturnValueOfChainId = ds.getAllowOptimizedReturnValueOfChainId() == 1;
snapshot.allowDynamicEnergy = ds.getAllowDynamicEnergy() == 1;
snapshot.dynamicEnergyThreshold = ds.getDynamicEnergyThreshold();
snapshot.dynamicEnergyIncreaseFactor = ds.getDynamicEnergyIncreaseFactor();
snapshot.dynamicEnergyMaxFactor = ds.getDynamicEnergyMaxFactor();
snapshot.allowTvmShanghai = ds.getAllowTvmShangHai() == 1;
snapshot.allowEnergyAdjustment = ds.getAllowEnergyAdjustment() == 1;
snapshot.allowStrictMath = ds.getAllowStrictMath() == 1;
snapshot.allowTvmCancun = ds.getAllowTvmCancun() == 1;
snapshot.disableJavaLangMath = ds.getConsensusLogicOptimization() == 1;
snapshot.allowTvmBlob = ds.getAllowTvmBlob() == 1;
snapshot.allowTvmSelfdestructRestriction = ds.getAllowTvmSelfdestructRestriction() == 1;
snapshot.allowTvmOsaka = ds.getAllowTvmOsaka() == 1;
snapshot.allowHardenResourceCalculation = ds.getAllowHardenResourceCalculation() == 1;
if (isolate) {
VMConfig.setLocalSnapshot(snapshot);
} else {
VMConfig.setGlobalSnapshot(snapshot);
}
if (disable) {
// Tests freeze flags via VMConfig.init*(). A leftover thread-local snapshot from a
// prior constant-call would otherwise keep shadowing those flags (London/Osaka flakes).
VMConfig.clearLocalSnapshot();
return;
}
DynamicPropertiesStore ds = storeFactory.getChainBaseManager().getDynamicPropertiesStore();
VMConfig.setVmTrace(CommonParameter.getInstance().isVmTrace());
if (ds != null) {
VMConfig.initVmHardFork(checkForEnergyLimit(ds));
VMConfig.Snapshot snapshot = new VMConfig.Snapshot();
snapshot.allowMultiSign = ds.getAllowMultiSign() == 1;
snapshot.allowTvmTransferTrc10 = ds.getAllowTvmTransferTrc10() == 1;
snapshot.allowTvmConstantinople = ds.getAllowTvmConstantinople() == 1;
snapshot.allowTvmSolidity059 = ds.getAllowTvmSolidity059() == 1;
snapshot.allowShieldedTRC20Transaction = ds.getAllowShieldedTRC20Transaction() == 1;
snapshot.allowTvmIstanbul = ds.getAllowTvmIstanbul() == 1;
snapshot.allowTvmFreeze = ds.getAllowTvmFreeze() == 1;
snapshot.allowTvmVote = ds.getAllowTvmVote() == 1;
snapshot.allowTvmLondon = ds.getAllowTvmLondon() == 1;
snapshot.allowTvmCompatibleEvm = ds.getAllowTvmCompatibleEvm() == 1;
snapshot.allowHigherLimitForMaxCpuTimeOfOneTx =
ds.getAllowHigherLimitForMaxCpuTimeOfOneTx() == 1;
snapshot.allowTvmFreezeV2 = ds.supportUnfreezeDelay();
snapshot.allowOptimizedReturnValueOfChainId = ds.getAllowOptimizedReturnValueOfChainId() == 1;
snapshot.allowDynamicEnergy = ds.getAllowDynamicEnergy() == 1;
snapshot.dynamicEnergyThreshold = ds.getDynamicEnergyThreshold();
snapshot.dynamicEnergyIncreaseFactor = ds.getDynamicEnergyIncreaseFactor();
snapshot.dynamicEnergyMaxFactor = ds.getDynamicEnergyMaxFactor();
snapshot.allowTvmShanghai = ds.getAllowTvmShangHai() == 1;
snapshot.allowEnergyAdjustment = ds.getAllowEnergyAdjustment() == 1;
snapshot.allowStrictMath = ds.getAllowStrictMath() == 1;
snapshot.allowTvmCancun = ds.getAllowTvmCancun() == 1;
snapshot.disableJavaLangMath = ds.getConsensusLogicOptimization() == 1;
snapshot.allowTvmBlob = ds.getAllowTvmBlob() == 1;
snapshot.allowTvmSelfdestructRestriction = ds.getAllowTvmSelfdestructRestriction() == 1;
snapshot.allowTvmOsaka = ds.getAllowTvmOsaka() == 1;
snapshot.allowHardenResourceCalculation = ds.getAllowHardenResourceCalculation() == 1;
if (isolate) {
VMConfig.setLocalSnapshot(snapshot);
} else {
VMConfig.setGlobalSnapshot(snapshot);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class BackupServer implements AutoCloseable {

private BackupManager backupManager;

private Channel channel;
private volatile Channel channel;

private volatile boolean shutdown = false;

Expand All @@ -52,6 +52,11 @@ public void initServer() {
}
}

public boolean isBound() {
Channel ch = channel;
return ch != null && ch.isActive();
}

private void start() throws Exception {
NioEventLoopGroup group = new NioEventLoopGroup(1);
try {
Expand All @@ -77,6 +82,12 @@ public void initChannel(NioDatagramChannel ch)

logger.info("Backup server started, bind port {}", port);

// close() may have raced the bind: without this, closeFuture.sync() waits forever
// because close() saw a still-null channel and skipped channel.close().
if (shutdown) {
channel.close();
}

channel.closeFuture().sync();
if (shutdown) {
logger.info("Shutdown backup BackupServer");
Expand All @@ -95,14 +106,17 @@ public void initChannel(NioDatagramChannel ch)
public void close() {
logger.info("Closing backup server...");
shutdown = true;
backupManager.stop();
// Close the datagram channel first so start() can leave closeFuture.sync().
// BackupManager.stop() awaits its scheduler for up to 60s; doing that first
// ate the JUnit 60s timeout on slow Rocky Linux CI before the channel closed.
if (channel != null) {
try {
channel.close().await(10, TimeUnit.SECONDS);
} catch (Exception e) {
logger.warn("Closing backup server failed.", e);
}
}
backupManager.stop();
ExecutorServiceManager.shutdownAndAwaitTermination(executor, name);
logger.info("Backup server closed.");
}
Expand Down
6 changes: 6 additions & 0 deletions framework/src/test/java/org/tron/common/BaseMethodTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import org.tron.core.config.DefaultConfig;
import org.tron.core.config.args.Args;
import org.tron.core.db.Manager;
import org.tron.core.vm.config.ConfigLoader;
import org.tron.core.vm.config.VMConfig;

/**
* Base class for tests that need a fresh Spring context per test method.
Expand Down Expand Up @@ -82,6 +84,10 @@ public final void destroyContext() {
context.close(); // triggers appT.shutdown() via TronApplicationContext
}
Args.clearParam();
// forkEvery=100 reuses this JVM/thread: drop leftover TVM flags so the next
// class does not see ConfigLoader.disable=true or a stale local snapshot.
VMConfig.clearLocalSnapshot();
ConfigLoader.disable = false;
}

protected void beforeDestroy() {
Expand Down
10 changes: 10 additions & 0 deletions framework/src/test/java/org/tron/common/BaseTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.ClassRule;
Expand All @@ -28,6 +29,8 @@
import org.tron.core.net.peer.PeerConnection;
import org.tron.core.net.peer.PeerManager;
import org.tron.core.store.AccountStore;
import org.tron.core.vm.config.ConfigLoader;
import org.tron.core.vm.config.VMConfig;
import org.tron.protos.Protocol;

/**
Expand Down Expand Up @@ -89,10 +92,17 @@ public static String dbPath() {
return null;
}

@After
public void clearVmThreadLocal() {
VMConfig.clearLocalSnapshot();
}

@AfterClass
public static void destroy() {
appT1.shutdown();
Args.clearParam();
VMConfig.clearLocalSnapshot();
ConfigLoader.disable = false;
}

public void closePeer() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.ArrayList;
import java.util.List;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
Expand Down Expand Up @@ -46,7 +47,12 @@ public void tearDown() {
@Test(timeout = 60_000)
public void test() throws InterruptedException {
backupServer.initServer();
// wait for the server to start so channel is assigned before close() is called
Thread.sleep(1000);
// Wait until the NioDatagramChannel is actually bound. A fixed 1s sleep is
// not enough on a loaded Rocky Linux CI worker, and close() then races bind.
long deadline = System.currentTimeMillis() + 15_000L;
while (!backupServer.isBound() && System.currentTimeMillis() < deadline) {
Thread.sleep(50);
}
Assert.assertTrue("BackupServer UDP channel did not bind", backupServer.isBound());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.Collections;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.encoders.Hex;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.tron.common.runtime.TVMTestResult;
Expand All @@ -30,16 +31,31 @@ function getbasefee() public returns(uint) {

}*/

@Test
public void testBaseFee() throws ContractExeException, ReceiptCheckErrException,
VMIllegalException, ContractValidateException {
private void enableLondon() {
// Drop a leftover thread-local snapshot from a prior constant-call in this JVM
// (forkEvery=100). initAllowTvmLondon() only mutates globalSnapshot.
VMConfig.clearLocalSnapshot();
ConfigLoader.disable = true;
VMConfig.initAllowTvmTransferTrc10(1);
VMConfig.initAllowTvmConstantinople(1);
VMConfig.initAllowTvmSolidity059(1);
VMConfig.initAllowTvmIstanbul(1);
VMConfig.initAllowTvmLondon(1);
manager.getDynamicPropertiesStore().saveAllowTvmLondon(1);
manager.getDynamicPropertiesStore().saveChangeDelegation(1);
}

@After
public void resetVmFlags() {
VMConfig.clearLocalSnapshot();
ConfigLoader.disable = false;
VMConfig.initAllowTvmLondon(0);
}

@Test
public void testBaseFee() throws ContractExeException, ReceiptCheckErrException,
VMIllegalException, ContractValidateException {
enableLondon();

String contractName = "testBaseFee";
byte[] address = Hex.decode(OWNER_ADDRESS);
Expand Down Expand Up @@ -81,13 +97,7 @@ public void testBaseFee() throws ContractExeException, ReceiptCheckErrException,
@Test
public void testStartWithEF() throws ContractExeException, ReceiptCheckErrException,
VMIllegalException, ContractValidateException {
ConfigLoader.disable = true;
VMConfig.initAllowTvmTransferTrc10(1);
VMConfig.initAllowTvmConstantinople(1);
VMConfig.initAllowTvmSolidity059(1);
VMConfig.initAllowTvmIstanbul(1);
VMConfig.initAllowTvmLondon(1);
manager.getDynamicPropertiesStore().saveChangeDelegation(1);
enableLondon();

String contractName = "testStartWithEF";
byte[] address = Hex.decode(OWNER_ADDRESS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ public void before() {
dbManager.getDynamicPropertiesStore().saveTotalSignNum(5);
}

private void setAllowTvmOsaka(long allow) {
// initAllowTvmOsaka mutates globalSnapshot only. A leftover thread-local view
// from a prior constant-call would hide the Osaka guard (TIP-854 flake).
VMConfig.clearLocalSnapshot();
VMConfig.initAllowTvmOsaka(allow);
dbManager.getDynamicPropertiesStore().saveAllowTvmOsaka(allow);
}

@Test
public void testAddressNonExist() {
byte[] hash = Hash.sha3(longData);
Expand Down Expand Up @@ -160,7 +168,7 @@ public void testDifferentCase() {
// energy formula already assumes, returning (false, empty).
@Test
public void testTip854RejectsMalformedCalldata() {
VMConfig.initAllowTvmOsaka(1);
setAllowTvmOsaka(1);
try {
// Bucket 1: 32-aligned head + sub-word trailing bytes (r=1, r=31).
for (int r : new int[]{1, 31}) {
Expand All @@ -187,7 +195,7 @@ public void testTip854RejectsMalformedCalldata() {
Assert.assertFalse("null calldata", ret.getLeft());
Assert.assertSame(ByteUtil.EMPTY_BYTE_ARRAY, ret.getRight());
} finally {
VMConfig.initAllowTvmOsaka(0);
setAllowTvmOsaka(0);
}
}

Expand Down Expand Up @@ -226,18 +234,18 @@ public void testTip854CanonicalInputUnchanged() {
signs.add(Hex.toHexString(key1.sign(toSign).toByteArray()));
signs.add(Hex.toHexString(key2.sign(toSign).toByteArray()));

VMConfig.initAllowTvmOsaka(0);
setAllowTvmOsaka(0);
Pair<Boolean, byte[]> pre =
validateMultiSign(StringUtil.encode58Check(key.getAddress()), 2, data, signs);
VMConfig.initAllowTvmOsaka(1);
setAllowTvmOsaka(1);
try {
Pair<Boolean, byte[]> post =
validateMultiSign(StringUtil.encode58Check(key.getAddress()), 2, data, signs);
Assert.assertEquals(pre.getLeft(), post.getLeft());
Assert.assertArrayEquals(pre.getValue(), post.getValue());
Assert.assertArrayEquals(DataWord.ONE().getData(), post.getValue());
} finally {
VMConfig.initAllowTvmOsaka(0);
setAllowTvmOsaka(0);
}
}

Expand All @@ -247,7 +255,7 @@ public void testTip854CanonicalInputUnchanged() {
// pre-activation failure mode the TIP explicitly preserves.
@Test
public void testTip854PreActivationNoOp() {
VMConfig.initAllowTvmOsaka(0);
setAllowTvmOsaka(0);
contract.setRepository(RepositoryImpl.createRoot(StoreFactory.getInstance()));
try {
Pair<Boolean, byte[]> ret = contract.execute(new byte[(5 + 1) * 32]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
import com.google.protobuf.ByteString;
import java.io.IOException;
import java.math.BigInteger;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Objects;
import java.util.Random;
Expand Down Expand Up @@ -343,8 +345,12 @@ public static int chooseRandomPort(int min, int max) {
}

private static boolean checkPortAvailable(int port) throws IOException {
try (java.net.ServerSocket ss = new java.net.ServerSocket(port)) {
// BackupServer binds UDP; a TCP-only probe can return a port that is still
// held by another maxParallelForks worker's NioDatagramChannel.
try (ServerSocket ss = new ServerSocket(port);
DatagramSocket ds = new DatagramSocket(port)) {
ss.setReuseAddress(true);
ds.setReuseAddress(true);
return true;
} catch (IOException e) {
return false;
Expand Down
Loading
Loading