diff --git a/docker/.env.default b/docker/.env.default index 8a8492d6..efc96ec2 100644 --- a/docker/.env.default +++ b/docker/.env.default @@ -10,11 +10,26 @@ L1_WS_RPC_URL=wss://eth-mainnet.g.alchemy.com/v2/ # The beacon chain RPC endpoint L1_BEACON_RPC_URL= +# The L1 signer private key +L1_SIGNER= + +# The batch inbox contract address deployed on l1 +BATCH_INBOX_ADDRESS= + # JWT secret for the engine API JWT_SECRET=bf549f5188556ce0951048ef467ec93067bc4ea21acebe46ef675cd4e8e015ff -# Hildr's external rpc service port -RPC_PORT=9545 +# Execution client chain ID +L2_CHAIN_ID= + +# Execution client signer private key +L2_SIGNER= + +# Deployed l2 output oracle contract address +L2OO_ADDRESS= + +# Deployed l2 dispute game factory contract address +L2DGF_ADDRESS= # Execution client: can be either `op-geth` or `op-erigon` EXECUTION_CLIENT=op-geth @@ -28,6 +43,15 @@ EXECUTION_CLIENT_RPC_PORT=8545 # The execution client WebSocket port. EXECUTION_CLIENT_WS_PORT=8546 +# The Roll up client. +ROLLUP_CLIENT=hildr-node + +# The Roll up client RPC port. +ROLLUP_RPC_PORT=11545 + +# Hildr's external rpc service port +ROLLUP_RPC_PORT=9545 + # Sync mode: can be either `full` or `checkpoint` SYNC_MODE=full diff --git a/docker/batcher.dock b/docker/batcher.dock new file mode 100644 index 00000000..0b58df51 --- /dev/null +++ b/docker/batcher.dock @@ -0,0 +1,14 @@ +FROM ghcr.io/graalvm/graalvm-community:21 as builder + +WORKDIR /root/hildr +COPY . . +RUN ./gradlew clean hildr-batcher:buildJarForDocker + +FROM ghcr.io/graalvm/graalvm-community:21 + +WORKDIR /usr/local/bin +COPY --from=builder /root/hildr/hildr-batcher/build/docker/hildr-batcher.jar . +ENV HILDR_BATCHER_JAR /usr/local/bin/hildr-batcher.jar +ENV HILDR_BATCHER_MAIN_CLASS io.optimism.batcher.HildrBatcher + +ENTRYPOINT ["java", "--enable-preview", "-cp" , "/usr/local/bin/hildr-batcher.jar", "io.optimism.batcher.HildrBatcher"] \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index f8d63312..244ac896 100755 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -25,7 +25,7 @@ services: - .env ports: - "9200:9200" - - "${RPC_PORT}:${RPC_PORT}" + - "${ROLLUP_RPC_PORT}:${ROLLUP_RPC_PORT}" volumes: - ./:/scripts - data:/data @@ -49,13 +49,53 @@ services: - .env ports: - "9200:9200" - - "${RPC_PORT}:${RPC_PORT}" + - "${ROLLUP_RPC_PORT}:${ROLLUP_RPC_PORT}" volumes: - ./:/scripts - data:/data - ${OP_ROLLUP_JSON_FILEPATH:-.}:/rollup.json <<: *logging + hildr-batcher: + container_name: hildr-batcher + build: + dockerfile: ./docker/batcher.dock + context: ../ + profiles: + - hildr-batcher + restart: unless-stopped + stop_grace_period: 3m + entrypoint: /scripts/start-hildr-batcher-java.sh + depends_on: + - op-geth + env_file: + - .env + ports: + - "9201:9201" + volumes: + - ./:/scripts + <<: *logging + + hildr-proposer: + container_name: hildr-proposer + build: + dockerfile: ./docker/proposer.dock + context: ../ + profiles: + - hildr-proposer + restart: unless-stopped + stop_grace_period: 3m + entrypoint: /scripts/start-hildr-batcher-java.sh + depends_on: + - op-geth + env_file: + - .env + ports: + - "9203:9203" + volumes: + - ./:/scripts + <<: *logging + op-geth: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:v1.101304.2 container_name: op-geth diff --git a/docker/proposer.dock b/docker/proposer.dock new file mode 100644 index 00000000..004e72ab --- /dev/null +++ b/docker/proposer.dock @@ -0,0 +1,14 @@ +FROM ghcr.io/graalvm/graalvm-community:21 as builder + +WORKDIR /root/hildr +COPY . . +RUN ./gradlew clean hildr-batcher:buildJarForDocker + +FROM ghcr.io/graalvm/graalvm-community:21 + +WORKDIR /usr/local/bin +COPY --from=builder /root/hildr/hildr-batcher/build/docker/hildr-proposer.jar . +ENV HILDR_PROPOSER_JAR /usr/local/bin/hildr-proposer.jar +ENV HILDR_PROPOSER_MAIN_CLASS io.optimism.proposer.HildrProposer + +ENTRYPOINT ["java", "--enable-preview", "-cp" , "/usr/local/bin/hildr-proposer.jar", "io.optimism.proposer.HildrProposer"] \ No newline at end of file diff --git a/docker/start-hildr-batcher-java.sh b/docker/start-hildr-batcher-java.sh new file mode 100644 index 00000000..aa2e1332 --- /dev/null +++ b/docker/start-hildr-batcher-java.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +exec java --enable-preview \ + -cp $HILDR_BATCHER_JAR $HILDR_BATCHER_MAIN_CLASS \ + --l1-rpc-url $L1_RPC_URL \ + --l1-signer $L1_SIGNER \ + --batch-inbox-address $BATCH_INBOX_ADDRESS \ + --l2-rpc-url http://${EXECUTION_CLIENT}:${EXECUTION_CLIENT_RPC_PORT} \ + --rollup-rpc-url http://${ROLLUP_CLIENT}:${ROLLUP_RPC_PORT} \ + --log-level $LOG_LEVEL \ No newline at end of file diff --git a/docker/start-hildr-proposer-java.sh b/docker/start-hildr-proposer-java.sh new file mode 100644 index 00000000..6b2751fb --- /dev/null +++ b/docker/start-hildr-proposer-java.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -e + +exec java --enable-preview \ + -cp $HILDR_PROPOSER_JAR $HILDR_PROPOSER_MAIN_CLASS \ + --l1-rpc-url $L1_RPC_URL \ + --l2-rpc-url http://${EXECUTION_CLIENT}:${EXECUTION_CLIENT_RPC_PORT} \ + --l2-chain-id $L2_CHAIN_ID \ + --l2-signer $L2_SIGNER \ + --l2oo-address $L2OO_ADDRESS \ + --l2dgf-address $L2DGF_ADDRESS \ + --rollup-rpc-url http://${ROLLUP_CLIENT}:${ROLLUP_RPC_PORT} \ + --log-level $LOG_LEVEL \ No newline at end of file diff --git a/hildr-batcher/build.gradle b/hildr-batcher/build.gradle index e7ae0b35..589b8743 100644 --- a/hildr-batcher/build.gradle +++ b/hildr-batcher/build.gradle @@ -258,6 +258,21 @@ shadowJar { archiveFileName = "${project.name}-${project.version}.jar" } +task buildJarForDocker { + dependsOn jar + def buildImageDir = "build/docker" + def out = new ByteArrayOutputStream() + doFirst { + new File(buildImageDir).mkdirs() + copy { + from "build/libs/${project.name}-${project.version}.jar" + into buildImageDir + rename "${project.name}-${project.version}.jar", "${project.name}.jar" + } + } + println(out.toString()) +} + nativeCompile { enabled = false } diff --git a/hildr-batcher/src/main/java/io/optimism/batcher/cli/Cli.java b/hildr-batcher/src/main/java/io/optimism/batcher/cli/Cli.java index eaa5e5d1..eb0653e9 100644 --- a/hildr-batcher/src/main/java/io/optimism/batcher/cli/Cli.java +++ b/hildr-batcher/src/main/java/io/optimism/batcher/cli/Cli.java @@ -1,11 +1,13 @@ package io.optimism.batcher.cli; +import ch.qos.logback.classic.Level; import io.micrometer.tracing.Tracer; import io.optimism.batcher.BatcherSubmitter; import io.optimism.batcher.config.Config; import io.optimism.batcher.exception.BatcherExecutionException; import io.optimism.batcher.telemetry.BatcherMetricsServer; import io.optimism.batcher.telemetry.BatcherPrometheusMetrics; +import io.optimism.cli.typeconverter.LogLevelConverter; import io.optimism.utilities.telemetry.Logging; import io.optimism.utilities.telemetry.TracerTaskWrapper; import org.slf4j.Logger; @@ -43,7 +45,7 @@ public class Cli implements Runnable { @Option(names = "--sub-safety-margin", required = true, description = "") Long subSafetyMargin; - @Option(names = "--pull-interval", required = true, description = "") + @Option(names = "--poll-interval", required = true, description = "") Long pollInterval; @Option(names = "--max-l1-tx-size", required = true, description = "") @@ -61,18 +63,26 @@ public class Cli implements Runnable { @Option(names = "--enable-metrics", description = "If not contains this option, will not open metrics server") boolean enableMetrics; - @Option( - names = "--metrics-port", - defaultValue = "9200", - required = true, - description = "The port of metrics server ") + @Option(names = "--metrics-port", defaultValue = "9200", description = "The port of metrics server ") Integer metricsPort; + @Option( + names = "--log-level", + defaultValue = "DEBUG", + converter = LogLevelConverter.class, + description = "Log level") + Level logLevel; + /** the Cli constructor. */ public Cli() {} @Override public void run() { + var logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + if (logger instanceof ch.qos.logback.classic.Logger) { + var logbackLogger = (ch.qos.logback.classic.Logger) logger; + logbackLogger.setLevel(logLevel); + } TracerTaskWrapper.setTracerSupplier(Logging.INSTANCE::getTracer); // listen close signal diff --git a/hildr-node/src/main/java/io/optimism/cli/Cli.java b/hildr-node/src/main/java/io/optimism/cli/Cli.java index 4d41bdde..c09d4e12 100644 --- a/hildr-node/src/main/java/io/optimism/cli/Cli.java +++ b/hildr-node/src/main/java/io/optimism/cli/Cli.java @@ -106,6 +106,13 @@ public class Cli implements Runnable { @Option(names = "--devnet", description = "Dev net flag") Boolean devnet; + @Option( + names = "--sequencer-enable", + defaultValue = "false", + description = + "Enable sequencing of new L2 blocks. A separate batch submitter has to be deployed to publish the data for verifiers.") + Boolean sequencerEnable; + @Option( names = "--log-level", defaultValue = "DEBUG", @@ -118,8 +125,11 @@ public Cli() {} @Override public void run() { - var logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); - logger.setLevel(logLevel); + var logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + if (logger instanceof ch.qos.logback.classic.Logger) { + var logbackLogger = (ch.qos.logback.classic.Logger) logger; + logbackLogger.setLevel(logLevel); + } TracerTaskWrapper.setTracerSupplier(Logging.INSTANCE::getTracer); if (Boolean.TRUE.equals(metricsEnable)) { var metricsPort = this.metricsPort; @@ -211,6 +221,7 @@ private Config.CliConfig from(Cli cli) { cli.checkpointSyncUrl, cli.rpcPort, cli.syncMode, + cli.sequencerEnable, cli.devnet); } } diff --git a/hildr-node/src/main/java/io/optimism/cli/typeconverter/LogLevelConverter.java b/hildr-node/src/main/java/io/optimism/cli/typeconverter/LogLevelConverter.java deleted file mode 100644 index 7f3cfaa3..00000000 --- a/hildr-node/src/main/java/io/optimism/cli/typeconverter/LogLevelConverter.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.optimism.cli.typeconverter; - -import ch.qos.logback.classic.Level; -import picocli.CommandLine; - -/** - * the Log Level converter, used for picocli parse args. - * - * @author thinkAfCod - * @since 0.2.0 - */ -public class LogLevelConverter implements CommandLine.ITypeConverter { - - /** the LogLevelConverter constructor. */ - public LogLevelConverter() {} - - @Override - public Level convert(String value) throws Exception { - return Level.valueOf(value); - } -} diff --git a/hildr-node/src/main/java/io/optimism/config/Config.java b/hildr-node/src/main/java/io/optimism/config/Config.java index 4dc932ba..e6161612 100644 --- a/hildr-node/src/main/java/io/optimism/config/Config.java +++ b/hildr-node/src/main/java/io/optimism/config/Config.java @@ -43,6 +43,7 @@ * @param checkpointSyncUrl The checkpoint sync url. * @param rpcPort The rpc port. * @param devnet The flag of devnet. + * @param sequencerEnable The flag of sequencerEnable. * @param syncMode The sync mode * @param chainConfig The chain config. * @author grapebaba @@ -59,6 +60,7 @@ public record Config( String checkpointSyncUrl, Integer rpcPort, Boolean devnet, + Boolean sequencerEnable, SyncMode syncMode, ChainConfig chainConfig) { @@ -144,7 +146,8 @@ private static MapConfigSource getMapConfigSource() { * @param jwtSecret L2 engine API jwt secret. * @param checkpointSyncUrl The checkpoint sync url. * @param rpcPort The rpc port. - * @param syncMode The sync mode. + * @param syncMode The sync mode. + * @param sequencerEnable The sequencer enable flag. * @param devnet The devnet flag. */ public record CliConfig( @@ -158,6 +161,7 @@ public record CliConfig( String checkpointSyncUrl, Integer rpcPort, SyncMode syncMode, + Boolean sequencerEnable, Boolean devnet) { /** @@ -197,6 +201,7 @@ public Map toConfigMap() { if (syncMode != null) { map.put("config.syncMode", syncMode.toString()); } + map.put("config.sequencerEnable", String.valueOf(sequencerEnable != null && sequencerEnable)); map.put("config.devnet", String.valueOf(devnet != null && devnet)); return map; } diff --git a/hildr-node/src/main/java/io/optimism/driver/Driver.java b/hildr-node/src/main/java/io/optimism/driver/Driver.java index ba8c7e7a..b42d509f 100644 --- a/hildr-node/src/main/java/io/optimism/driver/Driver.java +++ b/hildr-node/src/main/java/io/optimism/driver/Driver.java @@ -77,6 +77,8 @@ public class Driver extends AbstractExecutionThreadService { private final EngineDriver engineDriver; + private final ISequencer sequencer; + private final RpcServer rpcServer; private List unfinalizedBlocks; @@ -115,6 +117,7 @@ public class Driver extends AbstractExecutionThreadService { * Instantiates a new Driver. * * @param engineDriver the engine driver + * @param sequencer the sequencer * @param pipeline the pipeline * @param l2Fetcher the L2 HeadInfo fetcher * @param state the state @@ -128,6 +131,7 @@ public class Driver extends AbstractExecutionThreadService { @SuppressWarnings("preview") public Driver( EngineDriver engineDriver, + ISequencer sequencer, Pipeline pipeline, BiFunction> l2Fetcher, AtomicReference state, @@ -138,6 +142,7 @@ public Driver( Config config, OpStackNetwork opStackNetwork) { this.engineDriver = engineDriver; + this.sequencer = sequencer; this.rpcServer = rpcServer; this.pipeline = pipeline; this.l2Fetcher = l2Fetcher; @@ -240,10 +245,15 @@ public static Driver from(Config config, CountDownLatch latch) MpscUnboundedXaddArrayQueue unsafeBlockQueue = new MpscUnboundedXaddArrayQueue<>(1024 * 64); OpStackNetwork opStackNetwork = new OpStackNetwork(config.chainConfig(), unsafeBlockQueue); + ISequencer sequencer = null; + if (config.sequencerEnable()) { + sequencer = new Sequencer(); + } l2Provider.shutdown(); return new Driver<>( engineDriver, + sequencer, pipeline, l2Fetcher, state, @@ -346,6 +356,7 @@ protected void run() { while (isRunning() && !isShutdownTriggered) { try { this.advance(); + this.sequencerAction(); } catch (InterruptedException e) { LOGGER.error("driver run interrupted", e); this.latch.countDown(); @@ -410,6 +421,21 @@ private void awaitEngineReady() throws InterruptedException { } } + private void sequencerAction() throws InterruptedException, ExecutionException { + if (!this.isP2PNetworkStarted.get()) { + return; + } + try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { + var task = scope.fork(TracerTaskWrapper.wrap((Callable) () -> { + Driver.this.sequencer.runNextSequencerAction(); + return null; + })); + scope.join(); + scope.throwIfFailed(); + task.get(); + } + } + @SuppressWarnings("VariableDeclarationUsageDistance") private void advance() throws InterruptedException, ExecutionException { try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { diff --git a/hildr-node/src/main/java/io/optimism/driver/ISequencer.java b/hildr-node/src/main/java/io/optimism/driver/ISequencer.java new file mode 100644 index 00000000..9b0221e5 --- /dev/null +++ b/hildr-node/src/main/java/io/optimism/driver/ISequencer.java @@ -0,0 +1,67 @@ +/* + * Copyright 2023 q315xia@163.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package io.optimism.driver; + +import io.optimism.network.ExecutionPayloadEnvelop; +import io.optimism.type.L2BlockRef; +import java.time.Duration; + +/** + * The sequencer Interface. + * @author thinkAfCod + * @since 0.4.1 + */ +public interface ISequencer { + /** + * Initiates a block building job on top of the given L2 head, safe and finalized blocks, and using the provided l1Origin. + */ + void startBuildingBlock(); + + /** + * Takes the current block that is being built, and asks the engine to complete the building, seal the block, and persist it as canonical. + * Warning: the safe and finalized L2 blocks as viewed during the initiation of the block building are reused for completion of the block building. + * The Execution engine should not change the safe and finalized blocks between start and completion of block building. + * @return the newest execution payload envelop + */ + ExecutionPayloadEnvelop completeBuildingBlock(); + + /** + * Returns a desired delay till the RunNextSequencerAction call. + * @return the next start sequencer action duration + */ + Duration planNextSequencerAction(); + + /** + * Starts new block building work, or seals existing work, + * and is best timed by first awaiting the delay returned by PlanNextSequencerAction. + * If a new block is successfully sealed, it will be returned for publishing, null otherwise. + * @return the execution payload envelop + */ + ExecutionPayloadEnvelop runNextSequencerAction(); + + /** + * Returns the L2 head reference that the latest block is or was being built on top of. + * @return the L2 head reference + */ + L2BlockRef buildingOnto(); + + /** + * Cancels the current open block building job. + * The sequencer only maintains one block building job at a time. + */ + void cancelBuildingBlock(); +} diff --git a/hildr-node/src/main/java/io/optimism/driver/Sequencer.java b/hildr-node/src/main/java/io/optimism/driver/Sequencer.java new file mode 100644 index 00000000..8a3f546b --- /dev/null +++ b/hildr-node/src/main/java/io/optimism/driver/Sequencer.java @@ -0,0 +1,60 @@ +/* + * Copyright 2023 q315xia@163.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package io.optimism.driver; + +import io.optimism.network.ExecutionPayloadEnvelop; +import io.optimism.type.L2BlockRef; +import java.time.Duration; + +/** + * The sequencer class. + * @author thinkAfCod + * @since 0.4.1 + */ +public class Sequencer implements ISequencer { + + /** + * Instantiates a new Sequencer. + */ + public Sequencer() {} + + @Override + public void startBuildingBlock() {} + + @Override + public ExecutionPayloadEnvelop completeBuildingBlock() { + return null; + } + + @Override + public Duration planNextSequencerAction() { + return null; + } + + @Override + public ExecutionPayloadEnvelop runNextSequencerAction() { + return null; + } + + @Override + public L2BlockRef buildingOnto() { + return null; + } + + @Override + public void cancelBuildingBlock() {} +} diff --git a/hildr-node/src/test/java/io/optimism/HildrTest.java b/hildr-node/src/test/java/io/optimism/HildrTest.java index 195110e4..d5dfa846 100644 --- a/hildr-node/src/test/java/io/optimism/HildrTest.java +++ b/hildr-node/src/test/java/io/optimism/HildrTest.java @@ -25,7 +25,7 @@ class HildrTest { @Test void appHasGreeting() throws JsonProcessingException { CliConfig cliConfig = new CliConfig( - "test", "test", "test", "test", "test", "test", "test", null, null, Config.SyncMode.Full, false); + "test", "test", "test", "test", "test", "test", "test", null, null, Config.SyncMode.Full, false, false); TomlMapper mapper = new TomlMapper(); String cliConfigStr = mapper.writerFor(CliConfig.class).writeValueAsString(cliConfig); diff --git a/hildr-node/src/test/java/io/optimism/TestConstants.java b/hildr-node/src/test/java/io/optimism/TestConstants.java index 34c46e92..34b62e6b 100644 --- a/hildr-node/src/test/java/io/optimism/TestConstants.java +++ b/hildr-node/src/test/java/io/optimism/TestConstants.java @@ -57,6 +57,7 @@ public static Config createConfig() { null, null, Config.SyncMode.Full, + false, false); return Config.create(null, cliConfig, Config.ChainConfig.optimismGoerli()); } diff --git a/hildr-node/src/test/java/io/optimism/config/ConfigTest.java b/hildr-node/src/test/java/io/optimism/config/ConfigTest.java index cd180703..0c813e84 100644 --- a/hildr-node/src/test/java/io/optimism/config/ConfigTest.java +++ b/hildr-node/src/test/java/io/optimism/config/ConfigTest.java @@ -26,8 +26,8 @@ class ConfigTest { */ @Test void create() { - CliConfig cliConfig = - new CliConfig(null, null, null, null, null, null, "testjwt", null, null, Config.SyncMode.Full, false); + CliConfig cliConfig = new CliConfig( + null, null, null, null, null, null, "testjwt", null, null, Config.SyncMode.Full, false, false); Config config = Config.create( Paths.get("src", "test", "resources", "test.toml"), cliConfig, ChainConfig.optimismGoerli()); assertEquals("https://example2.com", config.l2RpcUrl()); diff --git a/hildr-node/src/test/java/io/optimism/derive/stages/ChannelsTest.java b/hildr-node/src/test/java/io/optimism/derive/stages/ChannelsTest.java index e7950dc1..df745c1c 100644 --- a/hildr-node/src/test/java/io/optimism/derive/stages/ChannelsTest.java +++ b/hildr-node/src/test/java/io/optimism/derive/stages/ChannelsTest.java @@ -117,7 +117,19 @@ void testReadChannelData() { private Tuple2, MessagePassingQueue> createStage() { Config config = new Config( - "", "", "", "", "", "", null, null, 9545, false, Config.SyncMode.Full, ChainConfig.optimismGoerli()); + "", + "", + "", + "", + "", + "", + null, + null, + 9545, + false, + false, + Config.SyncMode.Full, + ChainConfig.optimismGoerli()); MessagePassingQueue transactionMessageMessagePassingQueue = new MpscGrowableArrayQueue<>(4096); Channels channels = diff --git a/hildr-node/src/test/java/io/optimism/driver/DriverTest.java b/hildr-node/src/test/java/io/optimism/driver/DriverTest.java index e9c26077..097f2e02 100644 --- a/hildr-node/src/test/java/io/optimism/driver/DriverTest.java +++ b/hildr-node/src/test/java/io/optimism/driver/DriverTest.java @@ -37,6 +37,7 @@ void testNewDriverFromFinalizedHead() throws IOException, ExecutionException, In l2rpc, null, Config.SyncMode.Full, + false, false); Config config = Config.create(null, cliConfig, ChainConfig.optimismGoerli()); diff --git a/hildr-node/src/test/java/io/optimism/rpc/RpcServerTest.java b/hildr-node/src/test/java/io/optimism/rpc/RpcServerTest.java index c0554d2e..23b0ace0 100644 --- a/hildr-node/src/test/java/io/optimism/rpc/RpcServerTest.java +++ b/hildr-node/src/test/java/io/optimism/rpc/RpcServerTest.java @@ -115,6 +115,7 @@ void testRpcServerRegister() throws IOException, InterruptedException { null, 9545, false, + false, Config.SyncMode.Full, Config.ChainConfig.optimism())); rpcServer.start(); diff --git a/hildr-proposer/build.gradle b/hildr-proposer/build.gradle index efb6da71..741fbdc3 100644 --- a/hildr-proposer/build.gradle +++ b/hildr-proposer/build.gradle @@ -241,6 +241,21 @@ shadowJar { transform(com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer) } +task buildJarForDocker { + dependsOn jar + def buildImageDir = "build/docker" + def out = new ByteArrayOutputStream() + doFirst { + new File(buildImageDir).mkdirs() + copy { + from "build/libs/${project.name}-${project.version}.jar" + into buildImageDir + rename "${project.name}-${project.version}.jar", "${project.name}.jar" + } + } + println(out.toString()) +} + nativeCompile { enabled = false } diff --git a/hildr-proposer/src/main/java/io/optimism/proposer/cli/Cli.java b/hildr-proposer/src/main/java/io/optimism/proposer/cli/Cli.java index 7b5b35f3..96173448 100644 --- a/hildr-proposer/src/main/java/io/optimism/proposer/cli/Cli.java +++ b/hildr-proposer/src/main/java/io/optimism/proposer/cli/Cli.java @@ -1,8 +1,11 @@ package io.optimism.proposer.cli; +import ch.qos.logback.classic.Level; +import io.optimism.cli.typeconverter.LogLevelConverter; import io.optimism.proposer.L2OutputSubmitter; import io.optimism.proposer.config.Config; import io.optimism.utilities.telemetry.Logging; +import io.optimism.utilities.telemetry.TracerTaskWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import picocli.CommandLine; @@ -30,7 +33,7 @@ public class Cli implements Runnable { @CommandLine.Option(names = "--rollup-rpc-url", required = true, description = "The rollup node RPC URL") String rollupRpcUrl; - @CommandLine.Option(names = "--l2-chainId", required = true, description = "The L2 chain ID") + @CommandLine.Option(names = "--l2-chain-id", required = true, description = "The L2 chain ID") Long l2ChainId; @CommandLine.Option(names = "--l2-signer", required = true, description = "The L2 chain private key") @@ -42,7 +45,10 @@ public class Cli implements Runnable { @CommandLine.Option(names = "--l2dgf-address", description = "The L2 dispute game factory contract address") String dgfContractAddr; - @CommandLine.Option(names = "--poll-interval", description = "How frequently to poll L2 for new blocks") + @CommandLine.Option( + names = "--poll-interval", + defaultValue = "300", + description = "How frequently to poll L2 for new blocks") Long pollInterval; @CommandLine.Option( @@ -57,6 +63,13 @@ public class Cli implements Runnable { description = "Allow the proposer to submit proposals for L2 blocks derived from non-finalized L1 blocks") boolean allowNonFinalized; + @CommandLine.Option( + names = "--log-level", + defaultValue = "DEBUG", + converter = LogLevelConverter.class, + description = "Log level") + Level logLevel; + /** * The proposer CLI constructor. */ @@ -64,6 +77,12 @@ public Cli() {} @Override public void run() { + var logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + if (logger instanceof ch.qos.logback.classic.Logger) { + var logbackLogger = (ch.qos.logback.classic.Logger) logger; + logbackLogger.setLevel(logLevel); + } + TracerTaskWrapper.setTracerSupplier(Logging.INSTANCE::getTracer); // listen close signal Signal.handle(new Signal("INT"), sig -> System.exit(0)); diff --git a/hildr-utilities/build.gradle b/hildr-utilities/build.gradle index 3e8cd2e9..59d961a6 100644 --- a/hildr-utilities/build.gradle +++ b/hildr-utilities/build.gradle @@ -6,7 +6,7 @@ plugins { id "net.ltgt.errorprone" version "3.1.0" } -group = 'me.grapebaba' +group = 'io.optimism' version = '0.4.0' repositories { @@ -77,6 +77,7 @@ dependencies { api 'io.opentelemetry:opentelemetry-sdk' api 'io.opentelemetry:opentelemetry-sdk-logs' + implementation 'info.picocli:picocli:4.7.3' implementation 'com.fasterxml.jackson:jackson-bom:2.15.2' implementation 'com.fasterxml.jackson.core:jackson-core' diff --git a/hildr-utilities/src/main/java/io/optimism/cli/typeconverter/LogLevelConverter.java b/hildr-utilities/src/main/java/io/optimism/cli/typeconverter/LogLevelConverter.java new file mode 100644 index 00000000..7127e850 --- /dev/null +++ b/hildr-utilities/src/main/java/io/optimism/cli/typeconverter/LogLevelConverter.java @@ -0,0 +1,38 @@ +/* + * Copyright 2023 q315xia@163.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package io.optimism.cli.typeconverter; + +import ch.qos.logback.classic.Level; +import org.apache.commons.lang3.StringUtils; +import picocli.CommandLine; + +/** + * the Log Level converter, used for picocli parse args. + * + * @author thinkAfCod + * @since 0.2.0 + */ +public class LogLevelConverter implements CommandLine.ITypeConverter { + + /** the LogLevelConverter constructor. */ + public LogLevelConverter() {} + + @Override + public Level convert(String value) throws Exception { + return StringUtils.isEmpty(value) ? Level.DEBUG : Level.valueOf(value); + } +}