Skip to content
Open
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ The TRON network is mainly divided into:
- **Private Networks**
Customized TRON networks set up by private entities for testing, development, or specific use cases.

Network selection is performed by specifying the appropriate configuration file upon full-node startup. Mainnet configuration: [config.conf](framework/src/main/resources/config.conf); Nile testnet configuration: [config-nile.conf](https://github.com/tron-nile-testnet/nile-testnet/blob/master/framework/src/main/resources/config-nile.conf)
Network selection is performed by specifying the appropriate configuration file upon full-node startup. Built-in configuration template: [reference.conf](common/src/main/resources/reference.conf); Mainnet configuration: [config.conf](framework/src/main/resources/config.conf); Nile testnet configuration: [config-nile.conf](https://github.com/tron-nile-testnet/nile-testnet/blob/master/framework/src/main/resources/config-nile.conf)

### 1. Join the TRON main network
Launch a main-network full node with the built-in default configuration:
Expand Down
11 changes: 0 additions & 11 deletions common/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,6 @@
# Key naming rules (required for ConfigBeanFactory auto-binding):
# - Use standard camelCase: maxConnections, syncFetchBatchNum, etc.
#
# Keys that cannot auto-bind (handled via normalizeNonStandardKeys() or manual reads):
#
# 1. committee.pBFTExpireNum / committee.allowPBFT — normalized to camelCase in
# CommitteeConfig.normalizeNonStandardKeys() before ConfigBeanFactory binding.
#
# 2. node.isOpenFullTcpDisconnect — normalized to "openFullTcpDisconnect" in
# NodeConfig.normalizeNonStandardKeys() before ConfigBeanFactory binding.
#
# 3. node.shutdown.BlockTime/BlockHeight/BlockCount — optional PascalCase nested keys;
# read manually in NodeConfig.fromConfig() after ConfigBeanFactory binding.
#
# =============================================================================

net {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ public class TronNetDelegate {
@PostConstruct
public void init() {
hitThread = new Thread(() -> {
LockSupport.park();
while (!hitDown && !Thread.currentThread().isInterrupted()) {
LockSupport.park();
}
// to Guarantee Some other thread invokes unpark with the current thread as the target
if (hitDown && exit) {
System.exit(0);
Expand Down
4 changes: 4 additions & 0 deletions framework/src/main/java/org/tron/program/SolidityNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@ private Block getBlockByNum(long blockNum) {
sleep(exceptionSleepTime);
}
} catch (Exception e) {
if (!flag || tronNetDelegate.isHitDown()) {
logger.info("getBlockByNum stopped during shutdown, block: {}.", blockNum);
break;
}
logger.error("Failed to get block: {}, reason: {}.", blockNum, e.getMessage());
sleep(exceptionSleepTime);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.tron.common.zksnark.LibrustzcashParam.IvkToPkdParams;
import org.tron.common.zksnark.LibrustzcashParam.OutputProofParams;
import org.tron.common.zksnark.LibrustzcashParam.SpendSigParams;
import org.tron.consensus.dpos.DposSlot;
import org.tron.core.Wallet;
import org.tron.core.actuator.Actuator;
import org.tron.core.actuator.ActuatorCreator;
Expand Down Expand Up @@ -143,11 +144,13 @@ public class ShieldedReceiveTest extends BaseTest {
private Wallet wallet;
@Resource
private TransactionUtil transactionUtil;
@Resource
private DposSlot dposSlot;

private static boolean init;

static {
Args.setParam(new String[]{"--output-directory", dbPath(), "-w"}, SHIELD_CONF);
Args.setParam(new String[] {"--output-directory", dbPath(), "-w"}, SHIELD_CONF);
ADDRESS_ONE_PRIVATE_KEY = getRandomPrivateKey();
FROM_ADDRESS = getHexAddressByPrivateKey(ADDRESS_ONE_PRIVATE_KEY);
}
Expand Down Expand Up @@ -331,7 +334,7 @@ public void testBroadcastBeforeAllowZksnark()

//Add public address sign
transactionCap = TransactionUtils.addTransactionSign(transactionCap.getInstance(),
ADDRESS_ONE_PRIVATE_KEY, chainBaseManager.getAccountStore());
ADDRESS_ONE_PRIVATE_KEY, chainBaseManager.getAccountStore());
try {
dbManager.pushTransaction(transactionCap);
} catch (Exception e) {
Expand Down Expand Up @@ -433,7 +436,7 @@ public String[] generateSpendAndOutputParams() throws ZksnarkException, BadItemE
boolean ok2 = JLibrustzcash.librustzcashSaplingCheckOutput(checkOutputParams);
Assert.assertTrue(ok2);

return new String[]{ByteArray.toHexString(checkSpendParamsData),
return new String[] {ByteArray.toHexString(checkSpendParamsData),
ByteArray.toHexString(dataToBeSigned),
ByteArray.toHexString(checkOutputParams.encode())};
}
Expand Down Expand Up @@ -2402,10 +2405,13 @@ public void pushSameSkAndScanAndSpend() throws Exception {
assert ecKey != null;
byte[] witnessAddress = ecKey.getAddress();
WitnessCapsule witnessCapsule = new WitnessCapsule(ByteString.copyFrom(witnessAddress));
// Stop the consensus task before modifying the witness schedule: DposTask uses the same
// localwitness key and would otherwise race to produce blocks at the same slot,
// triggering fork resolution and making the test slow.
consensusService.stop();
chainBaseManager.addWitness(ByteString.copyFrom(witnessAddress));

//sometimes generate block failed, try several times.
long time = System.currentTimeMillis();
long time = nextScheduledTime(witnessCapsule.getAddress());
Block block = getSignedBlock(witnessCapsule.getAddress(), time, privateKey);
dbManager.pushBlock(new BlockCapsule(block));

Expand Down Expand Up @@ -2451,15 +2457,16 @@ public void pushSameSkAndScanAndSpend() throws Exception {
boolean ok = dbManager.pushTransaction(transactionCap);
Assert.assertTrue(ok);

Thread.sleep(500);
//package transaction to block
block = getSignedBlock(witnessCapsule.getAddress(), time + 3000, privateKey);
block = getSignedBlock(witnessCapsule.getAddress(),
nextScheduledTime(witnessCapsule.getAddress()), privateKey);
dbManager.pushBlock(new BlockCapsule(block));

BlockCapsule blockCapsule3 = new BlockCapsule(wallet.getNowBlock());
Assert.assertEquals("blocknum != 2", 2, blockCapsule3.getNum());
Assert.assertEquals("blocknum != 3", 3, blockCapsule3.getNum());

block = getSignedBlock(witnessCapsule.getAddress(), time + 6000, privateKey);
block = getSignedBlock(witnessCapsule.getAddress(),
nextScheduledTime(witnessCapsule.getAddress()), privateKey);
dbManager.pushBlock(new BlockCapsule(block));

// scan note by ivk
Expand Down Expand Up @@ -2526,6 +2533,20 @@ public void pushSameSkAndScanAndSpend() throws Exception {
Assert.assertTrue(ok2);
}

// Returns the earliest timestamp at which witnessAddr is the DPoS-scheduled producer,
// relative to the current chain head. Using this avoids relying on the genesis-only
// bypass in validBlock() (latestBlockHeaderNumber == 0) when prior tests have pushed blocks.
private long nextScheduledTime(ByteString witnessAddr) {
int size = chainBaseManager.getWitnessScheduleStore().getActiveWitnesses().size();
for (long slot = 1; slot <= size; slot++) {
if (dposSlot.getScheduledWitness(slot).equals(witnessAddr)) {
return dposSlot.getTime(slot);
}
}
throw new IllegalStateException("No scheduled slot for witness within "
+ size + " slots: " + ByteArray.toHexString(witnessAddr.toByteArray()));
}

@Test
public void decodePaymentAddressIgnoreCase() {
String addressLower =
Expand Down
41 changes: 41 additions & 0 deletions framework/src/test/java/org/tron/program/SolidityNodeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;

Expand Down Expand Up @@ -329,6 +330,46 @@ public void testGetBlockByNumWhenClosed() throws Exception {
}
}

/**
* getBlockByNum() must break immediately — without a 1-second sleep — when a
* gRPC exception is thrown while flag races to false (the P3 shutdown-race fix).
* The invocation time is measured directly so the assertion is independent of
* Spring-context startup overhead.
*/
@Test(timeout = 5000)
public void testGetBlockByNumNoErrorOnExceptionDuringShutdown() throws Exception {
Method m = SolidityNode.class.getDeclaredMethod("getBlockByNum", long.class);
m.setAccessible(true);
Field clientField = getField("databaseGrpcClient");
Object origClient = clientField.get(solidityNode);
try {
DatabaseGrpcClient mockClient = mock(DatabaseGrpcClient.class);
// flag races to false inside the gRPC call — exact close() race
Mockito.when(mockClient.getBlock(42L)).thenAnswer(inv -> {
setFlag(false);
throw new RuntimeException("channel closed during shutdown");
});
clientField.set(solidityNode, mockClient);

long start = System.currentTimeMillis();
InvocationTargetException t = assertThrows(InvocationTargetException.class, () -> {
m.invoke(solidityNode, 42L);
});
assertTrue(t.getCause() instanceof RuntimeException);
assertEquals("SolidityNode is closing.", t.getCause().getMessage());
long elapsed = System.currentTimeMillis() - start;
// Without the fix the catch sleeps exceptionSleepTime (1000 ms) before
// re-checking the while condition. With the fix it breaks immediately.
assertTrue("Expected break without sleep (<500 ms), got " + elapsed + " ms",
elapsed < 500);
// No retry: exactly one gRPC call must be made.
Mockito.verify(mockClient, Mockito.times(1)).getBlock(42L);
} finally {
setFlag(true);
clientField.set(solidityNode, origClient);
}
}

// ── getLastSolidityBlockNum() ─────────────────────────────────────────────────

/**
Expand Down
Loading