Skip to content

Commit bd3b5ef

Browse files
authored
feat(db,lite): add --exclude-historical-balance for lite snapshot (tronprotocol#6690)
* feat(toolkit): add --exclude-historical-balance for lite snapshot split Default behavior is unchanged: balance-trace and account-trace stay in the lite snapshot as before, so default operators (historyBalanceLookup=off) see no difference. Opt-in via `--exclude-historical-balance=true` on `split -t snapshot` excludes the two trace stores from the snapshot for size-conscious operators. A loud warning is printed at split time noting that this loss is permanent for nodes that had historyBalanceLookup=true (merge cannot restore the feature) and that operators who need historical balance lookup on the resulting lite node must NOT enable this flag. `split -t history` and `merge` ignore the flag and continue using the legacy 5-db archive set, so merge logic stays untouched. Includes: - DbLite: new CLI option, helper method, runtime warning. - README: parameter documentation and worked example. - DbLiteTest: 3-arg testTools overload and packaging-contract assertion. - DbLiteExcludeHistoricalBalanceRocksDbTest: opt-in path coverage. close tronprotocol#6597 * docs(toolkit): clarify lite snapshot trace exclusion
1 parent 6c56161 commit bd3b5ef

4 files changed

Lines changed: 115 additions & 9 deletions

File tree

plugins/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,20 @@ DB lite provides lite database, parameters are compatible with previous `LiteFul
7575
- `-fn | --fn-data-path`: The database path to be split or merged.
7676
- `-ds | --dataset-path`: When operation is `split`,`dataset-path` is the path that store the `snapshot` or `history`, when
7777
operation is `split`, `dataset-path` is the `history` data path.
78+
- `--exclude-historical-balance`: Only used with `operate=split -t snapshot`, default: false. When set to true, `balance-trace` and `account-trace` are excluded from the lite snapshot. The flag has functional impact only when the source full node ran with `historyBalanceLookup=true` (off by default; most operators are unaffected). **WARNING:** for nodes that had `historyBalanceLookup=true`, this loss is permanent — a lite node booted from such a snapshot cannot safely serve historical balance lookups (`getBlockBalance` may fail, and `getAccountBalance` may return `balance=0` when `account-trace` data is missing), and running `merge` afterwards will NOT restore the feature. If you need historical balance lookup on the resulting lite node, do **not** enable this flag. `split -t history` and `merge` ignore this flag.
7879
- `-h | --help`: Provide the help info.
7980

8081
### Examples:
8182

8283
```shell script
8384
# full command
84-
java -jar Toolkit.jar db lite [-h] -ds=<datasetPath> -fn=<fnDataPath> [-o=<operate>] [-t=<type>]
85+
java -jar Toolkit.jar db lite [-h] -ds=<datasetPath> -fn=<fnDataPath> [-o=<operate>] [-t=<type>] [--exclude-historical-balance]
8586
# examples
8687
#split and get a snapshot dataset
8788
java -jar Toolkit.jar db lite -o split -t snapshot --fn-data-path output-directory/database --dataset-path /tmp
89+
#split and get a snapshot dataset without balance-trace / account-trace (smaller snapshot;
90+
#historical balance lookup cannot be safely served on the resulting lite node)
91+
java -jar Toolkit.jar db lite -o split -t snapshot --fn-data-path output-directory/database --dataset-path /tmp --exclude-historical-balance
8892
#split and get a history dataset
8993
java -jar Toolkit.jar db lite -o split -t history --fn-data-path output-directory/database --dataset-path /tmp
9094
#merge history dataset and snapshot dataset

plugins/src/main/java/common/org/tron/plugins/DbLite.java

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.concurrent.Callable;
2121
import java.util.stream.Collectors;
2222
import java.util.stream.LongStream;
23+
import java.util.stream.Stream;
2324
import lombok.extern.slf4j.Slf4j;
2425
import me.tongfei.progressbar.ProgressBar;
2526
import org.rocksdb.RocksDBException;
@@ -57,6 +58,8 @@ public class DbLite implements Callable<Integer> {
5758
private static final String TRANSACTION_HISTORY_DB_NAME = "transactionHistoryStore";
5859
private static final String PROPERTIES_DB_NAME = "properties";
5960
private static final String TRANS_CACHE_DB_NAME = "trans-cache";
61+
private static final String BALANCE_TRACE_DB_NAME = "balance-trace";
62+
private static final String ACCOUNT_TRACE_DB_NAME = "account-trace";
6063

6164
private static final List<String> archiveDbs = Arrays.asList(
6265
BLOCK_DB_NAME,
@@ -65,6 +68,10 @@ public class DbLite implements Callable<Integer> {
6568
TRANSACTION_RET_DB_NAME,
6669
TRANSACTION_HISTORY_DB_NAME);
6770

71+
private static final List<String> traceDbs = Arrays.asList(
72+
BALANCE_TRACE_DB_NAME,
73+
ACCOUNT_TRACE_DB_NAME);
74+
6875
enum Operate { split, merge }
6976

7077
enum Type { snapshot, history }
@@ -105,8 +112,26 @@ enum Type { snapshot, history }
105112
private String datasetPath;
106113

107114
@CommandLine.Option(
108-
names = {"--help", "-h"},
115+
names = {"--exclude-historical-balance"},
116+
defaultValue = "false",
117+
description = "only used with `operate=split -t snapshot`: when true, balance-trace "
118+
+ "and account-trace are excluded from the lite snapshot. "
119+
+ "Default: ${DEFAULT-VALUE} (legacy behavior; trace stores stay in the snapshot). "
120+
+ "This flag only has a functional impact when the source full node ran with "
121+
+ "`historyBalanceLookup=true` (off by default; most operators are unaffected). "
122+
+ "WARNING: when historyBalanceLookup was enabled, this loss is permanent: a lite "
123+
+ "node booted from such a snapshot cannot safely serve historical balance lookups "
124+
+ "(getBlockBalance may fail, and getAccountBalance may return balance=0 when "
125+
+ "account-trace data is missing). Running merge afterwards will NOT restore the "
126+
+ "feature. If you need to keep historyBalanceLookup working on the resulting "
127+
+ "lite node, do NOT enable this flag. `split -t history` and `merge` ignore "
128+
+ "this flag.",
109129
order = 5)
130+
private boolean excludeHistoricalBalance;
131+
132+
@CommandLine.Option(
133+
names = {"--help", "-h"},
134+
order = 6)
110135
private boolean help;
111136

112137

@@ -120,6 +145,7 @@ public Integer call() {
120145
switch (this.operate) {
121146
case split:
122147
if (Type.snapshot == this.type) {
148+
warnIfExcludingHistoricalBalance();
123149
generateSnapshot(fnDataPath, datasetPath);
124150
} else if (Type.history == type) {
125151
generateHistory(fnDataPath, datasetPath);
@@ -253,12 +279,52 @@ public void completeHistoryData(String historyDir, String liteDir) {
253279
spec.commandLine().getOut().format("Merge history finished, take %d s.", during).println();
254280
}
255281

282+
/**
283+
* Compute the directories to exclude from the lite snapshot.
284+
* <p>
285+
* Default ({@code --exclude-historical-balance=false}): the legacy archive set
286+
* (5 dbs); {@link #BALANCE_TRACE_DB_NAME} / {@link #ACCOUNT_TRACE_DB_NAME}
287+
* stay with the snapshot as state-style stores.
288+
* <p>
289+
* Opt-in ({@code --exclude-historical-balance=true}): the trace stores are
290+
* additionally excluded, producing a smaller lite snapshot at the cost of
291+
* dropping historical balance lookup support on the resulting lite node.
292+
* Only {@code split -t snapshot} consults this. {@code split -t history}
293+
* and {@code merge} always use the legacy archive set.
294+
*/
295+
private List<String> snapshotExclusion() {
296+
if (!excludeHistoricalBalance) {
297+
return archiveDbs;
298+
}
299+
return Stream.concat(archiveDbs.stream(), traceDbs.stream())
300+
.collect(Collectors.toList());
301+
}
302+
303+
private void warnIfExcludingHistoricalBalance() {
304+
if (!excludeHistoricalBalance) {
305+
return;
306+
}
307+
String msg = "WARNING: --exclude-historical-balance is enabled. balance-trace / account-trace "
308+
+ "will be excluded from the lite snapshot. This only matters when the source full "
309+
+ "node ran with historyBalanceLookup=true (off by default; most operators are "
310+
+ "unaffected). When that switch was enabled, this loss is permanent: lite nodes "
311+
+ "booted from this snapshot cannot safely serve historical balance lookups "
312+
+ "(getBlockBalance may fail, and getAccountBalance may return balance=0 when "
313+
+ "account-trace data is missing). Running merge afterwards will NOT restore the "
314+
+ "feature. If you need to keep historyBalanceLookup working on the resulting "
315+
+ "lite node, do NOT use this flag.";
316+
logger.warn(msg);
317+
spec.commandLine().getErr().println(spec.commandLine().getColorScheme()
318+
.errorText(msg));
319+
}
320+
256321
private List<String> getSnapshotDbs(String sourceDir) {
257322
List<String> snapshotDbs = Lists.newArrayList();
258323
File basePath = new File(sourceDir);
324+
List<String> excluded = snapshotExclusion();
259325
Arrays.stream(Objects.requireNonNull(basePath.listFiles()))
260326
.filter(File::isDirectory)
261-
.filter(dir -> !archiveDbs.contains(dir.getName()))
327+
.filter(dir -> !excluded.contains(dir.getName()))
262328
.forEach(dir -> snapshotDbs.add(dir.getName()));
263329
return snapshotDbs;
264330
}
@@ -723,4 +789,3 @@ public long getSnapshotMaxNum() {
723789
}
724790

725791

726-

plugins/src/test/java/org/tron/plugins/DbLiteTest.java

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package org.tron.plugins;
22

3+
import static org.junit.Assert.assertFalse;
4+
import static org.junit.Assert.assertTrue;
35
import static org.tron.common.utils.PublicMethod.getRandomPrivateKey;
46

57
import io.grpc.ManagedChannel;
68
import io.grpc.ManagedChannelBuilder;
79
import java.io.File;
810
import java.io.IOException;
11+
import java.nio.file.Path;
912
import java.nio.file.Paths;
1013
import lombok.extern.slf4j.Slf4j;
1114
import org.junit.After;
@@ -68,7 +71,7 @@ public void shutdown() throws InterruptedException {
6871
context.close();
6972
}
7073

71-
public void init(String dbType) throws IOException {
74+
public void init(String dbType, boolean historyBalanceLookup) throws IOException {
7275
dbPath = folder.newFolder().toString();
7376
Args.setParam(new String[] {
7477
"-d", dbPath, "-w", "--p2p-disable", "true", "--storage-db-engine", dbType},
@@ -77,6 +80,7 @@ public void init(String dbType) throws IOException {
7780
Args.getInstance().setAllowAccountStateRoot(1);
7881
Args.getInstance().setRpcPort(PublicMethod.chooseRandomPort());
7982
Args.getInstance().setRpcEnable(true);
83+
Args.getInstance().setHistoryBalanceLookup(historyBalanceLookup);
8084
databaseDir = Args.getInstance().getStorage().getDbDirectory();
8185
// init dbBackupConfig to avoid NPE
8286
Args.getInstance().dbBackupConfig = DbBackupConfig.getInstance();
@@ -89,10 +93,20 @@ public void clear() {
8993

9094
public void testTools(String dbType, int checkpointVersion)
9195
throws InterruptedException, IOException {
92-
logger.info("dbType {}, checkpointVersion {}", dbType, checkpointVersion);
93-
init(dbType);
94-
final String[] argsForSnapshot =
95-
new String[] {"-o", "split", "-t", "snapshot", "--fn-data-path",
96+
testTools(dbType, checkpointVersion, false);
97+
}
98+
99+
public void testTools(String dbType, int checkpointVersion, boolean excludeHistoricalBalance)
100+
throws InterruptedException, IOException {
101+
logger.info("dbType {}, checkpointVersion {}, excludeHistoricalBalance {}",
102+
dbType, checkpointVersion, excludeHistoricalBalance);
103+
boolean historyBalanceLookup = excludeHistoricalBalance;
104+
init(dbType, historyBalanceLookup);
105+
final String[] argsForSnapshot = excludeHistoricalBalance
106+
? new String[] {"-o", "split", "-t", "snapshot", "--fn-data-path",
107+
dbPath + File.separator + databaseDir, "--dataset-path",
108+
dbPath, "--exclude-historical-balance"}
109+
: new String[] {"-o", "split", "-t", "snapshot", "--fn-data-path",
96110
dbPath + File.separator + databaseDir, "--dataset-path",
97111
dbPath};
98112
final String[] argsForHistory =
@@ -114,6 +128,16 @@ public void testTools(String dbType, int checkpointVersion)
114128
FileUtil.deleteDir(Paths.get(dbPath, databaseDir, "trans-cache").toFile());
115129
// generate snapshot
116130
cli.execute(argsForSnapshot);
131+
Path snapshotDir = Paths.get(dbPath, "snapshot");
132+
if (excludeHistoricalBalance) {
133+
// when --exclude-historical-balance=true, the lite snapshot must not ship
134+
// balance-trace / account-trace
135+
assertFalse(snapshotDir.resolve("balance-trace").toFile().exists());
136+
assertFalse(snapshotDir.resolve("account-trace").toFile().exists());
137+
} else {
138+
assertTrue(snapshotDir.resolve("balance-trace").toFile().exists());
139+
assertTrue(snapshotDir.resolve("account-trace").toFile().exists());
140+
}
117141
// start fullNode
118142
startApp();
119143
// produce transactions
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.tron.plugins.rocksdb;
2+
3+
import java.io.IOException;
4+
import org.junit.Test;
5+
import org.tron.plugins.DbLiteTest;
6+
7+
public class DbLiteExcludeHistoricalBalanceRocksDbTest extends DbLiteTest {
8+
9+
@Test
10+
public void testToolsWithExcludeHistoricalBalance() throws InterruptedException, IOException {
11+
testTools("ROCKSDB", 1, true);
12+
}
13+
}

0 commit comments

Comments
 (0)