diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java index cad4270c2e0..7a30f7e0270 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -199,7 +199,13 @@ public class CommonParameter { //If you are running a solidity node for java tron, this flag is set to true @Getter @Setter + @Parameter(names = {"--solidity"}, description = "running a solidity node for java tron") public boolean solidityNode = false; + //If you are running KeystoreFactory, this flag is set to true + @Getter + @Setter + @Parameter(names = {"--keystore"}, description = "running KeystoreFactory") + public boolean keystore = false; @Getter @Setter public int rpcPort; diff --git a/framework/build.gradle b/framework/build.gradle index d3dc308db03..82ee117dd26 100644 --- a/framework/build.gradle +++ b/framework/build.gradle @@ -217,37 +217,13 @@ startScripts.enabled = false run.enabled = false tasks.distTar.enabled = false -createScript(project, 'org.tron.program.SolidityNode', 'SolidityNode') createScript(project, 'org.tron.program.FullNode', 'FullNode') -createScript(project, 'org.tron.program.KeystoreFactory', 'KeystoreFactory') -createScript(project, 'org.tron.program.DBConvert', 'DBConvert') - -def releaseBinary = hasProperty('binaryRelease') ? getProperty('binaryRelease') : 'true' -def skipSolidity = hasProperty('skipSolidity') ? true : false -def skipKeystore = hasProperty('skipKeystore') ? true : false -def skipConvert = hasProperty('skipConvert') ? true : false -def skipAll = hasProperty('skipAll') ? true : false -if (releaseBinary == 'true') { - artifacts { - archives(binaryRelease('buildFullNodeJar', 'FullNode', 'org.tron.program.FullNode')) - } - if (!skipAll) { - if (!skipSolidity) { - artifacts { - archives(binaryRelease('buildSolidityNodeJar', 'SolidityNode', 'org.tron.program.SolidityNode'))} - } - if (!skipKeystore) { - artifacts { - archives(binaryRelease('buildKeystoreFactoryJar', 'KeystoreFactory', 'org.tron.program.KeystoreFactory'))} - } - if (!skipConvert) { - artifacts { - archives(binaryRelease('buildDBConvertJar', 'DBConvert', 'org.tron.program.DBConvert'))} - } - } +artifacts { + archives(binaryRelease('buildFullNodeJar', 'FullNode', 'org.tron.program.FullNode')) } + task copyToParent(type: Copy) { into "../build/distributions" from "$buildDir/distributions" diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index 58fa58f962b..c2b5f94cfbb 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -167,6 +167,7 @@ public static void clearParam() { PARAMETER.tcpNettyWorkThreadNum = 0; PARAMETER.udpNettyWorkThreadNum = 0; PARAMETER.solidityNode = false; + PARAMETER.keystore = false; PARAMETER.trustNodeAddr = ""; PARAMETER.walletExtensionApi = false; PARAMETER.estimateEnergy = false; @@ -238,7 +239,7 @@ public static void clearParam() { PARAMETER.maxUnsolidifiedBlocks = 54; PARAMETER.allowOldRewardOpt = 0; PARAMETER.allowEnergyAdjustment = 0; - GlobalContext.removeHeader(); + GlobalContext.clear(); } /** diff --git a/framework/src/main/java/org/tron/program/SolidityNode.java b/framework/src/main/java/org/tron/core/services/SolidityService.java similarity index 63% rename from framework/src/main/java/org/tron/program/SolidityNode.java rename to framework/src/main/java/org/tron/core/services/SolidityService.java index ee0f740b768..641ffb3257c 100644 --- a/framework/src/main/java/org/tron/program/SolidityNode.java +++ b/framework/src/main/java/org/tron/core/services/SolidityService.java @@ -1,240 +1,196 @@ -package org.tron.program; - -import static org.tron.core.config.Parameter.ChainConstant.BLOCK_PRODUCED_INTERVAL; - -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.joran.JoranConfigurator; -import java.io.File; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.atomic.AtomicLong; -import lombok.extern.slf4j.Slf4j; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.util.ObjectUtils; -import org.tron.common.application.Application; -import org.tron.common.application.ApplicationFactory; -import org.tron.common.application.TronApplicationContext; -import org.tron.common.client.DatabaseGrpcClient; -import org.tron.common.parameter.CommonParameter; -import org.tron.common.prometheus.Metrics; -import org.tron.core.ChainBaseManager; -import org.tron.core.Constant; -import org.tron.core.capsule.BlockCapsule; -import org.tron.core.config.DefaultConfig; -import org.tron.core.config.args.Args; -import org.tron.core.db.Manager; -import org.tron.core.net.TronNetDelegate; -import org.tron.protos.Protocol.Block; - -@Slf4j(topic = "app") -public class SolidityNode { - - private Manager dbManager; - - private ChainBaseManager chainBaseManager; - - private DatabaseGrpcClient databaseGrpcClient; - - private final TronNetDelegate tronNetDelegate; - - private AtomicLong ID = new AtomicLong(); - - private AtomicLong remoteBlockNum = new AtomicLong(); - - private LinkedBlockingDeque blockQueue = new LinkedBlockingDeque<>(100); - - private int exceptionSleepTime = 1000; - - private volatile boolean flag = true; - - public SolidityNode(Manager dbManager, TronNetDelegate tronNetDelegate) { - this.dbManager = dbManager; - this.chainBaseManager = dbManager.getChainBaseManager(); - this.tronNetDelegate = tronNetDelegate; - resolveCompatibilityIssueIfUsingFullNodeDatabase(); - ID.set(chainBaseManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum()); - databaseGrpcClient = new DatabaseGrpcClient(CommonParameter.getInstance().getTrustNodeAddr()); - remoteBlockNum.set(getLastSolidityBlockNum()); - } - - private static void load(String path) { - try { - File file = new File(path); - if (!file.exists() || !file.isFile() || !file.canRead()) { - return; - } - LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); - JoranConfigurator configurator = new JoranConfigurator(); - configurator.setContext(lc); - lc.reset(); - configurator.doConfigure(file); - logger.info("load logback configure file success"); - } catch (Exception e) { - logger.error(e.getMessage()); - } - } - - /** - * Start the SolidityNode. - */ - public static void main(String[] args) { - logger.info("Solidity node is running."); - Args.setParam(args, Constant.TESTNET_CONF); - CommonParameter parameter = CommonParameter.getInstance(); - load(parameter.getLogbackPath()); - - if (ObjectUtils.isEmpty(parameter.getTrustNodeAddr())) { - logger.error("Trust node is not set."); - return; - } - parameter.setSolidityNode(true); - - if (parameter.isHelp()) { - logger.info("Here is the help message."); - return; - } - // init metrics first - Metrics.init(); - - DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); - beanFactory.setAllowCircularReferences(false); - TronApplicationContext context = - new TronApplicationContext(beanFactory); - context.register(DefaultConfig.class); - context.refresh(); - Application appT = ApplicationFactory.create(context); - context.registerShutdownHook(); - appT.startup(); - SolidityNode node = new SolidityNode(appT.getDbManager(), - context.getBean(TronNetDelegate.class)); - node.start(); - appT.blockUntilShutdown(); - } - - private void start() { - try { - new Thread(this::getBlock).start(); - new Thread(this::processBlock).start(); - logger.info("Success to start solid node, ID: {}, remoteBlockNum: {}.", ID.get(), - remoteBlockNum); - } catch (Exception e) { - logger.error("Failed to start solid node, address: {}.", - CommonParameter.getInstance().getTrustNodeAddr()); - System.exit(0); - } - } - - private void getBlock() { - long blockNum = ID.incrementAndGet(); - while (flag) { - try { - if (blockNum > remoteBlockNum.get()) { - sleep(BLOCK_PRODUCED_INTERVAL); - remoteBlockNum.set(getLastSolidityBlockNum()); - continue; - } - Block block = getBlockByNum(blockNum); - blockQueue.put(block); - blockNum = ID.incrementAndGet(); - } catch (Exception e) { - logger.error("Failed to get block {}, reason: {}.", blockNum, e.getMessage()); - sleep(exceptionSleepTime); - } - } - } - - private void processBlock() { - while (flag) { - try { - Block block = blockQueue.take(); - loopProcessBlock(block); - flag = dbManager.getLatestSolidityNumShutDown() != dbManager.getDynamicPropertiesStore() - .getLatestBlockHeaderNumberFromDB(); - } catch (Exception e) { - logger.error(e.getMessage()); - sleep(exceptionSleepTime); - } - } - logger.info("Begin shutdown, currentBlockNum:{}, DbBlockNum:{}, solidifiedBlockNum:{}", - dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber(), - dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumberFromDB(), - dbManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum()); - tronNetDelegate.markHitDown(); - tronNetDelegate.unparkHitThread(); - } - - private void loopProcessBlock(Block block) { - while (flag) { - long blockNum = block.getBlockHeader().getRawData().getNumber(); - try { - dbManager.pushVerifiedBlock(new BlockCapsule(block)); - chainBaseManager.getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(blockNum); - logger - .info("Success to process block: {}, blockQueueSize: {}.", blockNum, blockQueue.size()); - return; - } catch (Exception e) { - logger.error("Failed to process block {}.", new BlockCapsule(block), e); - sleep(exceptionSleepTime); - block = getBlockByNum(blockNum); - } - } - } - - private Block getBlockByNum(long blockNum) { - while (true) { - try { - long time = System.currentTimeMillis(); - Block block = databaseGrpcClient.getBlock(blockNum); - long num = block.getBlockHeader().getRawData().getNumber(); - if (num == blockNum) { - logger.info("Success to get block: {}, cost: {}ms.", - blockNum, System.currentTimeMillis() - time); - return block; - } else { - logger.warn("Get block id not the same , {}, {}.", num, blockNum); - sleep(exceptionSleepTime); - } - } catch (Exception e) { - logger.error("Failed to get block: {}, reason: {}.", blockNum, e.getMessage()); - sleep(exceptionSleepTime); - } - } - } - - private long getLastSolidityBlockNum() { - while (true) { - try { - long time = System.currentTimeMillis(); - long blockNum = databaseGrpcClient.getDynamicProperties().getLastSolidityBlockNum(); - logger.info("Get last remote solid blockNum: {}, remoteBlockNum: {}, cost: {}.", - blockNum, remoteBlockNum, System.currentTimeMillis() - time); - return blockNum; - } catch (Exception e) { - logger.error("Failed to get last solid blockNum: {}, reason: {}.", remoteBlockNum.get(), - e.getMessage()); - sleep(exceptionSleepTime); - } - } - } - - public void sleep(long time) { - try { - Thread.sleep(time); - } catch (Exception e1) { - logger.error(e1.getMessage()); - } - } - - private void resolveCompatibilityIssueIfUsingFullNodeDatabase() { - long lastSolidityBlockNum = - chainBaseManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum(); - long headBlockNum = chainBaseManager.getHeadBlockNum(); - logger.info("headBlockNum:{}, solidityBlockNum:{}, diff:{}", - headBlockNum, lastSolidityBlockNum, headBlockNum - lastSolidityBlockNum); - if (lastSolidityBlockNum < headBlockNum) { - logger.info("use fullNode database, headBlockNum:{}, solidityBlockNum:{}, diff:{}", - headBlockNum, lastSolidityBlockNum, headBlockNum - lastSolidityBlockNum); - chainBaseManager.getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(headBlockNum); - } - } +package org.tron.core.services; + +import static org.tron.core.config.Parameter.ChainConstant.BLOCK_PRODUCED_INTERVAL; + +import java.util.Optional; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.atomic.AtomicLong; +import javax.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import org.tron.common.client.DatabaseGrpcClient; +import org.tron.common.parameter.CommonParameter; +import org.tron.core.ChainBaseManager; +import org.tron.core.capsule.BlockCapsule; +import org.tron.core.db.Manager; +import org.tron.core.net.TronNetDelegate; +import org.tron.protos.Protocol.Block; + +@Slf4j(topic = "app") +@Component +public class SolidityService { + + @Autowired + private Manager dbManager; + + @Autowired + private ChainBaseManager chainBaseManager; + + private DatabaseGrpcClient databaseGrpcClient; + + @Autowired + private TronNetDelegate tronNetDelegate; + + private AtomicLong ID; + + private AtomicLong remoteBlockNum; + + private LinkedBlockingDeque blockQueue; + + private int exceptionSleepTime; + + private volatile boolean flag = true; + + private static Optional INSTANCE = Optional.empty(); + + @PostConstruct + private void init() { + if (!CommonParameter.getInstance().isSolidityNode()) { + return; + } + if (ObjectUtils.isEmpty(CommonParameter.getInstance().getTrustNodeAddr())) { + throw new IllegalArgumentException("Trust node is not set."); + } + resolveCompatibilityIssueIfUsingFullNodeDatabase(); + ID = new AtomicLong(chainBaseManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum()); + databaseGrpcClient = new DatabaseGrpcClient(CommonParameter.getInstance().getTrustNodeAddr()); + remoteBlockNum = new AtomicLong(0); + blockQueue = new LinkedBlockingDeque<>(100); + exceptionSleepTime = 1000; + INSTANCE = Optional.of(this); + } + + public static void runIfNeed() { + INSTANCE.ifPresent(SolidityService::start); + } + + private void start() { + try { + remoteBlockNum.set(getLastSolidityBlockNum()); + new Thread(this::getBlock).start(); + new Thread(this::processBlock).start(); + logger.info("Success to start solid node, ID: {}, remoteBlockNum: {}.", ID.get(), + remoteBlockNum); + } catch (Exception e) { + logger.error("Failed to start solid node, address: {}.", + CommonParameter.getInstance().getTrustNodeAddr()); + System.exit(0); + } + } + + private void getBlock() { + long blockNum = ID.incrementAndGet(); + while (flag) { + try { + if (blockNum > remoteBlockNum.get()) { + sleep(BLOCK_PRODUCED_INTERVAL); + remoteBlockNum.set(getLastSolidityBlockNum()); + continue; + } + Block block = getBlockByNum(blockNum); + blockQueue.put(block); + blockNum = ID.incrementAndGet(); + } catch (Exception e) { + logger.error("Failed to get block {}, reason: {}.", blockNum, e.getMessage()); + sleep(exceptionSleepTime); + } + } + } + + private void processBlock() { + while (flag) { + try { + Block block = blockQueue.take(); + loopProcessBlock(block); + flag = dbManager.getLatestSolidityNumShutDown() != dbManager.getDynamicPropertiesStore() + .getLatestBlockHeaderNumberFromDB(); + } catch (Exception e) { + logger.error(e.getMessage()); + sleep(exceptionSleepTime); + } + } + logger.info("Begin shutdown, currentBlockNum:{}, DbBlockNum:{}, solidifiedBlockNum:{}", + dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber(), + dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumberFromDB(), + dbManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum()); + tronNetDelegate.markHitDown(); + tronNetDelegate.unparkHitThread(); + } + + private void loopProcessBlock(Block block) { + while (flag) { + long blockNum = block.getBlockHeader().getRawData().getNumber(); + try { + dbManager.pushVerifiedBlock(new BlockCapsule(block)); + chainBaseManager.getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(blockNum); + logger + .info("Success to process block: {}, blockQueueSize: {}.", blockNum, blockQueue.size()); + return; + } catch (Exception e) { + logger.error("Failed to process block {}.", new BlockCapsule(block), e); + sleep(exceptionSleepTime); + block = getBlockByNum(blockNum); + } + } + } + + private Block getBlockByNum(long blockNum) { + while (true) { + try { + long time = System.currentTimeMillis(); + Block block = databaseGrpcClient.getBlock(blockNum); + long num = block.getBlockHeader().getRawData().getNumber(); + if (num == blockNum) { + logger.info("Success to get block: {}, cost: {}ms.", + blockNum, System.currentTimeMillis() - time); + return block; + } else { + logger.warn("Get block id not the same , {}, {}.", num, blockNum); + sleep(exceptionSleepTime); + } + } catch (Exception e) { + logger.error("Failed to get block: {}, reason: {}.", blockNum, e.getMessage()); + sleep(exceptionSleepTime); + } + } + } + + private long getLastSolidityBlockNum() { + while (true) { + try { + long time = System.currentTimeMillis(); + long blockNum = databaseGrpcClient.getDynamicProperties().getLastSolidityBlockNum(); + logger.info("Get last remote solid blockNum: {}, remoteBlockNum: {}, cost: {}.", + blockNum, remoteBlockNum, System.currentTimeMillis() - time); + return blockNum; + } catch (Exception e) { + logger.error("Failed to get last solid blockNum: {}, reason: {}.", remoteBlockNum.get(), + e.getMessage()); + sleep(exceptionSleepTime); + } + } + } + + private void sleep(long time) { + try { + Thread.sleep(time); + } catch (Exception e1) { + logger.error(e1.getMessage()); + } + } + + private void resolveCompatibilityIssueIfUsingFullNodeDatabase() { + long lastSolidityBlockNum = + chainBaseManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum(); + long headBlockNum = chainBaseManager.getHeadBlockNum(); + logger.info("headBlockNum:{}, solidityBlockNum:{}, diff:{}", + headBlockNum, lastSolidityBlockNum, headBlockNum - lastSolidityBlockNum); + if (lastSolidityBlockNum < headBlockNum) { + logger.info("use fullNode database, headBlockNum:{}, solidityBlockNum:{}, diff:{}", + headBlockNum, lastSolidityBlockNum, headBlockNum - lastSolidityBlockNum); + chainBaseManager.getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(headBlockNum); + } + } } \ No newline at end of file diff --git a/framework/src/main/java/org/tron/program/FullNode.java b/framework/src/main/java/org/tron/program/FullNode.java index b7adf0ffe1a..cc0a8b98ee5 100644 --- a/framework/src/main/java/org/tron/program/FullNode.java +++ b/framework/src/main/java/org/tron/program/FullNode.java @@ -15,6 +15,7 @@ import org.tron.core.Constant; import org.tron.core.config.DefaultConfig; import org.tron.core.config.args.Args; +import org.tron.core.services.SolidityService; @Slf4j(topic = "app") public class FullNode { @@ -40,7 +41,6 @@ public static void load(String path) { * Start the FullNode. */ public static void main(String[] args) { - logger.info("Full node running."); Args.setParam(args, Constant.TESTNET_CONF); CommonParameter parameter = Args.getInstance(); @@ -53,6 +53,16 @@ public static void main(String[] args) { return; } + if (parameter.isKeystore()) { + KeystoreFactory.exec(); + return; + } + if (parameter.isSolidityNode()) { + logger.info("Solidity node is running."); + } else { + logger.info("Full node running."); + } + if (Args.getInstance().isDebug()) { logger.info("in debug mode, it won't check energy time"); } else { @@ -71,6 +81,7 @@ public static void main(String[] args) { Application appT = ApplicationFactory.create(context); context.registerShutdownHook(); appT.startup(); + SolidityService.runIfNeed(); appT.blockUntilShutdown(); } } diff --git a/framework/src/main/java/org/tron/program/KeystoreFactory.java b/framework/src/main/java/org/tron/program/KeystoreFactory.java index bfd2df22856..2df7c420fa7 100755 --- a/framework/src/main/java/org/tron/program/KeystoreFactory.java +++ b/framework/src/main/java/org/tron/program/KeystoreFactory.java @@ -1,6 +1,5 @@ package org.tron.program; -import com.beust.jcommander.JCommander; import java.io.File; import java.io.IOException; import java.util.Scanner; @@ -11,8 +10,6 @@ import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.ByteArray; import org.tron.common.utils.Utils; -import org.tron.core.Constant; -import org.tron.core.config.args.Args; import org.tron.core.exception.CipherException; import org.tron.keystore.Credentials; import org.tron.keystore.WalletUtils; @@ -22,15 +19,8 @@ public class KeystoreFactory { private static final String FilePath = "Wallet"; - public static void main(String[] args) { - Args.setParam(args, Constant.TESTNET_CONF); + public static void exec() { KeystoreFactory cli = new KeystoreFactory(); - - JCommander.newBuilder() - .addObject(cli) - .build() - .parse(args); - cli.run(); } diff --git a/framework/src/test/java/org/tron/core/db/api/AssetUpdateHelperTest.java b/framework/src/test/java/org/tron/core/db/api/AssetUpdateHelperTest.java index ed18b1be97d..96b6ac2c816 100644 --- a/framework/src/test/java/org/tron/core/db/api/AssetUpdateHelperTest.java +++ b/framework/src/test/java/org/tron/core/db/api/AssetUpdateHelperTest.java @@ -28,7 +28,6 @@ public class AssetUpdateHelperTest extends BaseTest { static { Args.setParam(new String[]{"-d", dbPath(), "-w"}, "config-test-index.conf"); - Args.getInstance().setSolidityNode(true); } @Before diff --git a/plugins/build.gradle b/plugins/build.gradle index bfa5c8a6893..7987c2629d5 100644 --- a/plugins/build.gradle +++ b/plugins/build.gradle @@ -11,7 +11,7 @@ jacoco { def versions = [ checkstyle: '8.7', ] -mainClassName = 'org.tron.plugins.ArchiveManifest' +mainClassName = 'org.tron.plugins.Toolkit' group 'org.tron' version '1.0.0' @@ -133,23 +133,10 @@ def createScript(project, mainClass, name) { applicationDistribution.from("../gradle/java-tron.vmoptions") { into "bin" } -createScript(project, 'org.tron.plugins.ArchiveManifest', 'ArchiveManifest') createScript(project, 'org.tron.plugins.Toolkit', 'Toolkit') -def releaseBinary = hasProperty('binaryRelease') ? getProperty('binaryRelease') : 'true' -def skipArchive = hasProperty('skipArchive') ? true : false -def skipAll = hasProperty('skipAll') ? true : false -if (releaseBinary == 'true') { - artifacts { - archives(binaryRelease('buildToolkitJar', 'Toolkit', 'org.tron.plugins.Toolkit')) - } - if (!skipAll) { - if (!skipArchive) { - artifacts { - archives(binaryRelease('buildArchiveManifestJar', 'ArchiveManifest', 'org.tron.plugins.ArchiveManifest')) - } - } - } +artifacts { + archives(binaryRelease('buildToolkitJar', 'Toolkit', 'org.tron.plugins.Toolkit')) } task copyToParent(type: Copy) { diff --git a/start.sh b/start.sh index 89f13cf25a7..64bbed26273 100644 --- a/start.sh +++ b/start.sh @@ -377,7 +377,7 @@ rebuildManifest() { return fi - ARCHIVE_JAR='ArchiveManifest.jar' + ARCHIVE_JAR='Toolkit.jar' if [[ -f $ARCHIVE_JAR ]]; then echo 'info: execute rebuild manifest.' $JAVACMD -jar $ARCHIVE_JAR -d $REBUILD_DIR -m $REBUILD_MANIFEST_SIZE -b $REBUILD_BATCH_SIZE