Commit f3da73dd authored by Francis Li's avatar Francis Li Committed by GitHub

[op-conductor] Initial setup (#8642)

* Initial setup for op-conductor

* Rework based on feedback

* Update README

* Update README

* Rework flags structure

* Add tests

* Add CI configs

* Add dockerfile

* Remove TODO

---------
Co-authored-by: default avatarMatthew Slipper <me@matthewslipper.com>
parent 7e571097
...@@ -1493,6 +1493,10 @@ workflows: ...@@ -1493,6 +1493,10 @@ workflows:
name: op-challenger-tests name: op-challenger-tests
module: op-challenger module: op-challenger
requires: ["op-stack-go-lint"] requires: ["op-stack-go-lint"]
- go-test:
name: op-conductor-tests
module: op-conductor
requires: ["op-stack-go-lint"]
- go-test: - go-test:
name: op-program-tests name: op-program-tests
module: op-program module: op-program
...@@ -1547,6 +1551,7 @@ workflows: ...@@ -1547,6 +1551,7 @@ workflows:
- op-node-tests - op-node-tests
- op-proposer-tests - op-proposer-tests
- op-challenger-tests - op-challenger-tests
- op-conductor-tests
- op-program-tests - op-program-tests
- op-program-compat - op-program-compat
- op-service-tests - op-service-tests
...@@ -1589,6 +1594,12 @@ workflows: ...@@ -1589,6 +1594,12 @@ workflows:
docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>> docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
requires: ['op-stack-go-docker-build'] requires: ['op-stack-go-docker-build']
save_image_tag: <<pipeline.git.revision>> # for devnet later save_image_tag: <<pipeline.git.revision>> # for devnet later
- docker-build:
name: op-conductor-docker-build
docker_name: op-conductor
docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
requires: ['op-stack-go-docker-build']
save_image_tag: <<pipeline.git.revision>> # for devnet later
- docker-build: - docker-build:
name: op-heartbeat-docker-build name: op-heartbeat-docker-build
docker_name: op-heartbeat docker_name: op-heartbeat
...@@ -1717,6 +1728,21 @@ workflows: ...@@ -1717,6 +1728,21 @@ workflows:
release: true release: true
context: context:
- oplabs-gcr-release - oplabs-gcr-release
- docker-build:
name: op-conductor-docker-release
filters:
tags:
only: /^op-conductor\/v.*/
branches:
ignore: /.*/
docker_name: op-conductor
docker_tags: <<pipeline.git.revision>>
requires: ['op-stack-go-docker-build-release']
platforms: "linux/amd64,linux/arm64"
publish: true
release: true
context:
- oplabs-gcr-release
- docker-build: - docker-build:
name: op-ufm-docker-release name: op-ufm-docker-release
filters: filters:
...@@ -1897,6 +1923,16 @@ workflows: ...@@ -1897,6 +1923,16 @@ workflows:
context: context:
- oplabs-gcr - oplabs-gcr
- slack - slack
- docker-build:
name: op-conductor-docker-publish
docker_name: op-conductor
docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
requires: [ 'op-stack-go-docker-build-publish' ]
platforms: "linux/amd64,linux/arm64"
publish: true
context:
- oplabs-gcr
- slack
- docker-build: - docker-build:
name: op-heartbeat-docker-publish name: op-heartbeat-docker-publish
docker_name: op-heartbeat docker_name: op-heartbeat
......
...@@ -93,6 +93,19 @@ target "op-challenger" { ...@@ -93,6 +93,19 @@ target "op-challenger" {
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-challenger:${tag}"] tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-challenger:${tag}"]
} }
target "op-conductor" {
dockerfile = "Dockerfile"
context = "./op-conductor"
args = {
OP_STACK_GO_BUILDER = "op-stack-go"
}
contexts = {
op-stack-go: "target:op-stack-go"
}
platforms = split(",", PLATFORMS)
tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/op-conductor:${tag}"]
}
target "op-heartbeat" { target "op-heartbeat" {
dockerfile = "Dockerfile" dockerfile = "Dockerfile"
context = "./op-heartbeat" context = "./op-heartbeat"
......
package flags package flags
import ( import (
"fmt" "github.com/urfave/cli/v2"
"strings"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/flags" "github.com/ethereum-optimism/optimism/op-node/flags"
opservice "github.com/ethereum-optimism/optimism/op-service" opflags "github.com/ethereum-optimism/optimism/op-service/flags"
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
"github.com/urfave/cli/v2"
) )
const envVarPrefix = "OP_BOOTNODE" const envVarPrefix = "OP_BOOTNODE"
func prefixEnvVars(name string) []string {
return opservice.PrefixEnvVar(envVarPrefix, name)
}
var (
RollupConfig = &cli.StringFlag{
Name: flags.RollupConfig.Name,
Usage: "Rollup chain parameters",
EnvVars: prefixEnvVars("ROLLUP_CONFIG"),
}
Network = &cli.StringFlag{
Name: flags.Network.Name,
Usage: fmt.Sprintf("Predefined network selection. Available networks: %s", strings.Join(chaincfg.AvailableNetworks(), ", ")),
EnvVars: prefixEnvVars("NETWORK"),
}
)
var Flags = []cli.Flag{ var Flags = []cli.Flag{
RollupConfig, opflags.CLINetworkFlag(envVarPrefix),
Network, opflags.CLIRollupConfigFlag(envVarPrefix),
} }
func init() { func init() {
......
ARG OP_STACK_GO_BUILDER=us-docker.pkg.dev/oplabs-tools-artifacts/images/op-stack-go:latest
FROM $OP_STACK_GO_BUILDER as builder
# See "make golang-docker" and /ops/docker/op-stack-go
FROM alpine:3.18
COPY --from=builder /usr/local/bin/op-conductor /usr/local/bin/op-conductor
CMD ["op-conductor"]
GITCOMMIT ?= $(shell git rev-parse HEAD)
GITDATE ?= $(shell git show -s --format='%ct')
VERSION := v0.0.0
LDFLAGSSTRING +=-X main.GitCommit=$(GITCOMMIT)
LDFLAGSSTRING +=-X main.GitDate=$(GITDATE)
LDFLAGSSTRING +=-X main.Version=$(VERSION)
LDFLAGS := -ldflags "$(LDFLAGSSTRING)"
op-conductor:
env GO111MODULE=on GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -v $(LDFLAGS) -o ./bin/op-conductor ./cmd
clean:
rm bin/op-conductor
test:
go test -v ./...
.PHONY: \
clean \
op-conductor \
test
# op-conductor
op-conductor is an auxiliary service designed to enhance the reliability and availability of a sequencer in
high-availability setups, thereby minimizing the risks associated with single point of failure.
It is important to note, however, that this design does not incorporate Byzantine fault tolerance.
This means it operates under the assumption that all participating nodes are honest.
## Summary
The design will provide below guarantees:
1. No unsafe reorgs
2. No unsafe head stall during network partition
3. 100% uptime with no more than 1 node failure (for a standard 3 node setup)
## Design
![op-conductor architecture](./assets/op-conductor.svg)
On a high level, op-conductor serves the following functions:
1. serves as a (raft) consensus layer participant to determine
1. leader of the sequencers
2. store latest unsafe block within its state machine.
2. serves rpc requests for
1. admin rpc for manual recovery scenarios such as stop leadership vote, remove itself from cluster, etc
2. health rpc for op-node to determine if it should allow publish txs / unsafe blocks
3. monitor sequencer (op-node) health
4. control loop => control sequencer (op-node) status (start / stop) based on different scenarios
This is initial version of README, more details will be added later.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:lucid="lucid" width="1061" height="704.33"><g transform="translate(-399.4999999964151 -239.49999999812545)" lucid:page-tab-id="yaTR~mb8Jp3s"><path d="M400 246a6 6 0 0 1 6-6h1048a6 6 0 0 1 6 6v548a6 6 0 0 1-6 6H406a6 6 0 0 1-6-6z" fill="#fff" fill-opacity="0"/><path d="M403.7 240.47l.45-.18.9-.23.95-.07h2m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h4m4 0h2l.94.07.9.22.45.17m3.23 3.24l.18.45.23.9.07.95v2m0 3.96v3.97m0 3.97v3.97m0 3.97v3.97m0 3.98v3.97m0 3.98v3.97m0 3.97v3.97m0 3.97v3.98m0 3.97v3.97m0 3.97v3.96m0 3.98v3.97m0 3.98v3.97m0 3.97v3.97m0 3.96v3.97m0 3.97v3.97m0 3.97v3.98m0 3.97v3.96m0 3.97V383m0 3.97v3.97m0 3.97v3.98m0 3.98v3.97m0 3.97v3.97m0 3.97v3.97m0 3.98v3.97m0 3.97v3.97m0 3.96v3.98m0 3.97v3.98m0 3.97v3.97m0 3.97v3.96m0 3.97v3.97m0 3.97v3.98m0 3.97v3.97m0 3.96v3.97m0 3.97v3.97m0 3.97V518m0 4v3.96m0 3.97v3.97m0 3.97v3.97m0 3.97v3.98m0 3.97v3.98m0 3.97v3.97m0 3.97v3.97m0 3.98v3.97m0 3.97v3.97m0 3.96v3.97m0 3.98v3.98m0 3.97v3.97m0 3.97v3.96m0 3.97v3.97m0 3.97v3.98m0 3.97v3.97m0 3.96v3.97m0 3.97v3.97m0 3.97v3.97m0 3.98v3.98m0 3.97v3.97m0 3.97v3.97m0 3.97v3.98m0 3.97v3.97m0 3.97v3.97m0 3.97v3.97m0 3.98v3.97m0 3.97v3.97m0 3.96v3.97m0 3.97v3.98m0 3.97v3.97m0 3.97v3.96m0 3.97v3.97m0 3.97v3.97m0 3.97v2l-.07.94-.22.9-.17.45m-3.24 3.23l-.45.18-.9.23-.95.07h-2m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-4m-4 0h-2l-.94-.07-.9-.22-.45-.17m-3.23-3.24l-.18-.45-.23-.9-.07-.95v-2m0-3.96v-3.97m0-3.97v-3.97m0-3.97v-3.97m0-3.98v-3.97m0-3.98v-3.97m0-3.97v-3.97m0-3.97v-3.98m0-3.97v-3.97m0-3.97v-3.96m0-3.97v-3.98m0-3.98v-3.97m0-3.97v-3.97m0-3.96v-3.97m0-3.97v-3.97m0-3.98v-3.97m0-3.97v-3.96m0-3.97V657m0-3.97v-3.97m0-3.97v-3.98m0-3.98v-3.97m0-3.97v-3.97m0-3.97v-3.97m0-3.98v-3.97m0-3.97v-3.97m0-3.97v-3.97m0-3.97v-3.98m0-3.97v-3.97m0-3.97v-3.96m0-3.97v-3.97m0-3.98v-3.97m0-3.97v-3.97m0-3.96v-3.97m0-3.97v-3.97m0-3.97V522m0-4v-3.96m0-3.97v-3.97m0-3.97v-3.97m0-3.97v-3.98m0-3.97v-3.98m0-3.97v-3.97m0-3.97v-3.97m0-3.98v-3.97m0-3.97v-3.97m0-3.96v-3.98m0-3.97v-3.98m0-3.97v-3.97m0-3.97v-3.96m0-3.97v-3.97m0-3.97v-3.97m0-3.98v-3.97m0-3.96v-3.97m0-3.97v-3.97m0-3.97v-3.97m0-3.98v-3.98m0-3.97v-3.97m0-3.97v-3.97m0-3.97v-3.98m0-3.97v-3.97m0-3.97v-3.96m0-3.98v-3.97m0-3.98v-3.97m0-3.97v-3.97m0-3.96v-3.97m0-3.97v-3.97m0-3.98v-3.97m0-3.97v-3.96m0-3.97v-3.97m0-3.97v-3.97m0-3.97v-2l.07-.94.22-.9.17-.45" stroke="#5a6c86" fill="none"/><use xlink:href="#a" transform="matrix(1,0,0,1,400,260) translate(476.468 17.766)"/><path d="M721.67 866a6 6 0 0 1 6-6h224.66a6 6 0 0 1 6 6v71.33a6 6 0 0 1-6 6H727.67a6 6 0 0 1-6-6z" fill="#fff" fill-opacity="0"/><path d="M725.38 860.47l.43-.18.93-.23.94-.07h2m4 0h4.03m4 0h4.02m4 0h4.02m4.02 0h4m4.02 0h4m4.02 0h4.02m4 0h4.02m4 0h4.02m4 0h4.03m4 0h4m4.02 0h4m4.03 0h4m4.02 0h4m4.02 0h4m4.02 0h4m4.02 0h4m4.03 0h4m4.02 0h4m4 0h4.02m4.02 0h4m4.02 0h4m4.02 0h4.02m4 0h4.02m4 0h4.02m4.02 0h4m4.02 0h4m4.02 0h4.02m4 0h2l.95.07.92.22.42.17m3.24 3.24l.18.45.22.9.07.95v1.98m0 3.96v3.97m0 3.97v3.96m0 3.97v3.96m0 3.96v3.96m0 3.97v3.96m0 3.97v3.97m0 3.96v3.96m0 3.97v3.96m0 3.95v1.98l-.07.94-.22.92-.18.42m-3.24 3.24l-.43.18-.93.22-.94.07h-2m-4 0h-4.03m-4 0h-4.02m-4 0h-4.02m-4.02 0h-4m-4.02 0h-4m-4.02 0h-4.02m-4 0h-4.02m-4 0h-4.02m-4 0h-4.03m-4 0h-4m-4.02 0h-4m-4.03 0h-4m-4.02 0h-4m-4.02 0h-4m-4.02 0h-4m-4.02 0h-4m-4.03 0h-4m-4.02 0h-4m-4 0h-4.02m-4.02 0h-4m-4.02 0h-4m-4.02 0h-4.02m-4 0h-4.02m-4 0h-4.02m-4.02 0h-4m-4.02 0h-4m-4.02 0h-4.02m-4 0h-2l-.95-.07-.92-.22-.42-.18m-3.24-3.24l-.18-.43-.22-.93-.07-.94v-1.98m0-3.96v-3.97m0-3.97v-3.96m0-3.96v-3.97m0-3.96v-3.95m0-3.97v-3.96m0-3.96v-3.96m0-3.97v-3.96m0-3.96v-3.96m0-3.96V866l.07-.94.22-.9.18-.45" stroke="#5a6c86" fill="none"/><use xlink:href="#b" transform="matrix(1,0,0,1,721.6666666666667,880) translate(66.39522222222223 22.15266666666666)"/><path d="M760 326a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v88a6 6 0 0 1-6 6H766a6 6 0 0 1-6-6z" stroke="#3a414a" fill="#fff"/><use xlink:href="#c" transform="matrix(1,0,0,1,765,325.00000000000006) translate(16.33333333333333 52.87083333333334)"/><use xlink:href="#d" transform="matrix(1,0,0,1,765,325.00000000000006) translate(91 52.87083333333334)"/><path d="M1100 656.24a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v88a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6z" stroke="#3a414a" fill="#fff"/><use xlink:href="#e" transform="matrix(1,0,0,1,1105,655.2399605671899) translate(24.81111111111111 41.62083333333334)"/><use xlink:href="#f" transform="matrix(1,0,0,1,1105,655.2399605671899) translate(50.544444444444444 68.28750000000001)"/><path d="M460 656.24a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v88a6 6 0 0 1-6 6H466a6 6 0 0 1-6-6z" stroke="#3a414a" fill="#fff"/><use xlink:href="#g" transform="matrix(1,0,0,1,465,655.2399605671899) translate(11.62222222222222 41.62083333333334)"/><use xlink:href="#d" transform="matrix(1,0,0,1,465,655.2399605671899) translate(53.66666666666667 68.28750000000001)"/><path d="M1005.82 682.23l9.58 3.56 9.76 3.17 9.95 2.77 10.17 2.4 10.37 1.97 10.6 1.57 10.82 1.14 11.08.7 10.87.23-.02 1-10.88-.23-11.12-.7-10.87-1.14-10.63-1.57-10.4-2-10.2-2.4-10-2.78-9.8-3.18-9.62-3.58-9.42-3.96H996h2.58zM841.14 440.8l1.1 13.28 1.66 13.07 2.17 12.82 2.67 12.57 3.15 12.28 3.6 12 4.08 11.67 4.5 11.34 4.9 11 5.27 10.64 5.64 10.27 5.98 9.9 6.3 9.5 6.63 9.1 6.9 8.7 7.17 8.3 7.42 7.9 7.64 7.5 7.88 7.1 8.1 6.68 8.27 6.3 7.37 5.12h-1.75l-6.2-4.32-8.34-6.3-8.1-6.73-7.92-7.12-7.68-7.52-7.45-7.93-7.2-8.34-6.92-8.75-6.63-9.14-6.33-9.52-6-9.93-5.68-10.3-5.3-10.7-4.9-11.02-4.52-11.4-4.08-11.7-3.63-12.04-3.16-12.33-2.68-12.6-2.2-12.88-1.64-13.1-1.12-13.34-.17-3.96 1-.05z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1099.5 699.74v1h-.53l.02-1z" fill="#3a414a"/><path d="M1099.53 699.7v1.07l-.58-.02.02-1.05zm-.53 1h.47v-.94h-.45z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M845.1 436.24l-9.28.27 4.23-14.38z" fill="#3a414a"/><path d="M845.8 436.72l-10.65.3L840 420.5zm-9.3-.73l7.9-.24-4.3-12.02z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><use xlink:href="#h" transform="matrix(1,0,0,1,904.2594577496016,657.8534871292193) translate(0 17.546666666666667)"/><use xlink:href="#i" transform="matrix(1,0,0,1,904.2594577496016,657.8534871292193) translate(86.7022222222222 17.546666666666667)"/><path d="M678.5 692.4l-7.6 2.14-7.8 1.83-8 1.52-8.24 1.2-8.5.9-8.76.55-8.6.18v-1l8.55-.18 8.74-.55 8.43-.88 8.2-1.2 7.96-1.53 7.74-1.83 7.58-2.12.06-.02h3.24zm161.57-255.5l-.34 8.2-1.36 16.17-2 15.84-2.6 15.42-3.16 14.88-3.66 14.3-4.12 13.66-4.52 12.97-4.86 12.28-5.15 11.6-5.4 10.87-5.63 10.2-5.78 9.57-5.94 8.93-6.06 8.34-6.16 7.8-6.25 7.23-6.34 6.75-6.4 6.27-6.48 5.83-6.55 5.42-6.6 5.02-6.7 4.65-1.63 1.03h-1.87l2.95-1.87 6.65-4.62 6.58-5 6.52-5.38 6.45-5.8 6.37-6.24 6.3-6.72 6.23-7.2 6.13-7.75 6.03-8.3 5.9-8.9 5.78-9.52 5.6-10.17 5.38-10.84 5.14-11.54 4.84-12.24 4.5-12.93 4.1-13.62 3.67-14.25 3.15-14.85 2.6-15.37 2-15.8 1.35-16.12.34-8.2z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M621.03 700.73h-.53v-1h.5z" fill="#3a414a"/><path d="M621.05 700.75l-.57.02v-1.05l.55-.02zm-.52-1v.97h.47l-.02-.97z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M844.22 436.5l-9.27-.24 5-14.14z" fill="#3a414a"/><path d="M844.9 437.02l-10.65-.28L840 420.5zm-9.25-1.24l7.9.2-3.63-12.25z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><use xlink:href="#j" transform="matrix(1,0,0,1,651.610576381454,670.100648666295) translate(0 17.546666666666667)"/><use xlink:href="#k" transform="matrix(1,0,0,1,651.610576381454,670.100648666295) translate(54.15111111111112 17.546666666666667)"/><path d="M1230.68 649.24l.03-1.6.16-2.02.23-1.97.3-1.9.4-1.9.5-1.83.56-1.8.66-1.8.74-1.76.84-1.75.93-1.73 1.03-1.73 1.14-1.72 1.26-1.7 1.4-1.73 1.5-1.72 1.68-1.7 1.83-1.7 2-1.7 2.18-1.7 2.4-1.66 2.6-1.64 2.8-1.6 3.06-1.54 3.3-1.48 3.52-1.4 3.73-1.26 3.93-1.13 4.1-.98 4.2-.8 4.28-.62 4.28-.4 4.24-.2h4.13l4 .17 3.8.36 3.62.52 3.38.64 3.15.75 2.94.85 2.7.93 2.5.98 2.33 1.04 2.13 1.08 1.97 1.1 1.82 1.16 1.67 1.16.7.54 1.15.92 1.03.93.92.92.83.95.75.95.68.96.6 1 .56 1 .5 1.03.43 1.08.38 1.1.33 1.16.28 1.2.2 1.27.16 1.35.08 1.42v1.52l-.1 1.6-.2 1.77-.32 1.9-.47 2.06-.63 2.26-.87 2.47-1.12 2.73-1.43 3-1.82 3.3-2.25 3.63-2.77 3.94-3.32 4.22-3.92 4.42-4.48 4.54-4.96 4.5-5.33 4.3-5.52 4-5.54 3.53-5.42 3.05-5.2 2.56-4.9 2.1-4.57 1.66-4.25 1.28-.12.03" stroke="#3a414a" stroke-linejoin="round" fill="none"/><path d="M1231.18 649.24v.5h-1v-.53z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1262.1 700l13.48-6.56 1.3 9.18z" stroke="#3a414a" fill="#3a414a"/><use xlink:href="#l" transform="matrix(1,0,0,1,1205.1488398257522,602.3912985687056) translate(0 17.546666666666667)"/><use xlink:href="#m" transform="matrix(1,0,0,1,1205.1488398257522,602.3912985687056) translate(82.3111111111111 17.546666666666667)"/><use xlink:href="#n" transform="matrix(1,0,0,1,1205.1488398257522,602.3912985687056) translate(92.6222222222222 17.546666666666667)"/><use xlink:href="#o" transform="matrix(1,0,0,1,1205.1488398257522,602.3912985687056) translate(146.57777777777775 17.546666666666667)"/><use xlink:href="#p" transform="matrix(1,0,0,1,1205.1488398257522,602.3912985687056) translate(218.2222222222222 17.546666666666667)"/><path d="M1160 326a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v88a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6z" stroke="#3a414a" fill="#fff"/><use xlink:href="#q" transform="matrix(1,0,0,1,1165,325) translate(26.08888888888889 52.87083333333334)"/><use xlink:href="#r" transform="matrix(1,0,0,1,1165,325) translate(61.97777777777778 52.87083333333334)"/><path d="M1217.7 521.2l-19.7 39.22-3.52 8.38-2.83 7.6-2.4 7.4-2.08 7.43-1.8 7.73-1.57 8.2-1.32 8.92-1.03 9.84-.46 7.48-1-.06.46-7.5 1.03-9.9 1.3-8.93 1.58-8.25 1.82-7.77 2.1-7.48 2.4-7.42 2.85-7.65 3.55-8.43 19.7-39.22 1.54-3.23h1.1zm22.8-100.2l-.26 12.28-.7 11.13-1.03 9.9-1.3 8.93-1.58 8.26-.8 3.38h-1.02l.84-3.6 1.56-8.2 1.32-8.92 1.03-9.84.7-11.08.24-12.25z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1240.5 421.03l-1-.02v-.5h1z" fill="#3a414a"/><path d="M1240.5 421.05l-1.04-.02v-.55h1.07zm-.98-.53v.46l.94.02v-.48z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1185.1 634l-5.05 14.12-4.2-14.4z" fill="#3a414a"/><path d="M1185.8 633.52l-5.8 16.22-4.84-16.53zm-5.7 13l4.3-12.04-7.9-.23z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><use xlink:href="#s" transform="matrix(1,0,0,1,1083.3889193263144,474.8811451047337) translate(89.35166666666666 17.546666666666667)"/><use xlink:href="#t" transform="matrix(1,0,0,1,1083.3889193263144,474.8811451047337) translate(142.1161111111111 17.546666666666667)"/><use xlink:href="#u" transform="matrix(1,0,0,1,1083.3889193263144,474.8811451047337) translate(0.0049999999999954525 38.879999999999995)"/><use xlink:href="#v" transform="matrix(1,0,0,1,1083.3889193263144,474.8811451047337) translate(92.04055555555554 38.879999999999995)"/><use xlink:href="#w" transform="matrix(1,0,0,1,1083.3889193263144,474.8811451047337) translate(163.5338888888889 38.879999999999995)"/><use xlink:href="#x" transform="matrix(1,0,0,1,1083.3889193263144,474.8811451047337) translate(196.77833333333334 38.879999999999995)"/><use xlink:href="#y" transform="matrix(1,0,0,1,1083.3889193263144,474.8811451047337) translate(259.02722222222224 38.879999999999995)"/><path d="M1159 370H936.88" stroke="#3a414a" fill="none"/><path d="M1159.5 370.5h-.5v-1h.5z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M922.12 370l14.26-4.63v9.26z" stroke="#3a414a" fill="#3a414a"/><use xlink:href="#z" transform="matrix(1,0,0,1,940.8577777777778,323.33333333333337) translate(0 17.546666666666667)"/><use xlink:href="#t" transform="matrix(1,0,0,1,940.8577777777778,323.33333333333337) translate(57.626666666666665 17.546666666666667)"/><use xlink:href="#A" transform="matrix(1,0,0,1,940.8577777777778,323.33333333333337) translate(0 38.879999999999995)"/><use xlink:href="#B" transform="matrix(1,0,0,1,940.8577777777778,323.33333333333337) translate(41.528888888888886 38.879999999999995)"/><use xlink:href="#C" transform="matrix(1,0,0,1,940.8577777777778,323.33333333333337) translate(51.839999999999996 38.879999999999995)"/><use xlink:href="#D" transform="matrix(1,0,0,1,940.8577777777778,323.33333333333337) translate(102.00888888888889 38.879999999999995)"/><use xlink:href="#E" transform="matrix(1,0,0,1,940.8577777777778,323.33333333333337) translate(163.2 38.879999999999995)"/><path d="M840.5 843.12h-1v-85.8h1zm0-107.12h-1V421h1z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M840.5 421h-1v-.5h1z" fill="#3a414a"/><path d="M840.52 421.04h-1.04v-.56h1.04zm-1-.52v.47h.96v-.48z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M840 857.88l-4.63-14.26h9.26z" fill="#3a414a"/><path d="M840 859.5l-5.32-16.38h10.64zm-3.95-15.38l3.95 12.14 3.95-12.14z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><g><use xlink:href="#F" transform="matrix(1,0,0,1,796.6755555555555,736.0000000000001) translate(0 17.546666666666667)"/><use xlink:href="#m" transform="matrix(1,0,0,1,796.6755555555555,736.0000000000001) translate(41.528888888888886 17.546666666666667)"/><use xlink:href="#G" transform="matrix(1,0,0,1,796.6755555555555,736.0000000000001) translate(51.839999999999996 17.546666666666667)"/></g><path d="M704.78 901.17v1h-99.4v-1zM540.5 891h-1V751.24h1z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M540.5 751.25h-1v-.5h1z" fill="#3a414a"/><path d="M540.52 751.28h-1.04v-.56h1.04zm-1-.5v.45h.96v-.47z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M719.55 901.67l-14.27 4.63v-9.27z" fill="#3a414a"/><path d="M721.17 901.67l-16.4 5.32v-10.66zm-15.4 3.94l12.16-3.93-12.15-3.95z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><g><use xlink:href="#H" transform="matrix(1,0,0,1,504.8577580613727,891) translate(0 17.546666666666667)"/><use xlink:href="#I" transform="matrix(1,0,0,1,504.8577580613727,891) translate(49.80444444444444 17.546666666666667)"/></g><path d="M959.33 901.67H1174a6 6 0 0 0 6-6V767.12" stroke="#3a414a" fill="none"/><path d="M959.35 902.17h-.52v-1h.52z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1180 752.36l4.63 14.26h-9.27z" stroke="#3a414a" fill="#3a414a"/><g><use xlink:href="#J" transform="matrix(1,0,0,1,995.431111111111,905.6666666024425) translate(0 17.546666666666667)"/><use xlink:href="#K" transform="matrix(1,0,0,1,995.431111111111,905.6666666024425) translate(71.42222222222223 17.546666666666667)"/><use xlink:href="#L" transform="matrix(1,0,0,1,995.431111111111,905.6666666024425) translate(120.0088888888889 17.546666666666667)"/><use xlink:href="#M" transform="matrix(1,0,0,1,995.431111111111,905.6666666024425) translate(176.46222222222224 17.546666666666667)"/></g><defs><path fill="#5a6c86" d="M1038-507c0 321-164 521-482 521S72-187 72-507c0-248 107-410 284-485 60-25 126-37 200-37 317 0 482 201 482 522zm-782 1c0 225 80 381 300 381 213 0 298-159 298-381 0-223-84-383-298-383-221 0-300 158-300 383" id="N"/><path fill="#5a6c86" d="M602 14c-133 0-212-47-278-119v448H146v-1356c60 6 147-22 154 37l15 120c80-93 179-175 341-175 282 0 383 224 383 518 0 237-92 406-253 487-54 27-116 40-184 40zm253-527c-3-212-53-374-258-374-136 0-207 69-273 153v490c57 77 121 120 238 120 207 0 295-164 293-389" id="O"/><path fill="#5a6c86" d="M100-675h494v151H100v-151" id="P"/><path fill="#5a6c86" d="M895-142C799-8 539 62 344-21 173-94 74-262 74-507c0-317 160-522 477-522 151 0 254 54 333 132-21 26-39 58-63 81-42 20-68-19-100-34-42-20-91-42-160-40-219 6-304 160-304 383 0 220 82 376 295 383 106 4 169-38 223-84 22-19 53-21 70 1" id="Q"/><path fill="#5a6c86" d="M598-887c-125 2-207 68-274 141V0H146v-1013c60 6 147-22 154 37l14 110c82-87 177-163 336-163 232 0 339 151 339 384V0H811v-645c0-149-65-244-213-242" id="R"/><path fill="#5a6c86" d="M510-1031c133 0 210 49 277 120v-562h178V0c-60-6-146 21-154-37l-16-123C716-67 616 14 455 14 173 14 72-209 72-503c0-237 94-406 254-487 54-27 115-41 184-41zM256-503c2 212 53 373 258 373 136 0 207-69 273-153v-490c-57-77-121-119-237-119-208 0-296 164-294 389" id="S"/><path fill="#5a6c86" d="M461 16c-231 0-339-149-339-383v-646h178v646c0 148 67 243 213 241 125-2 207-66 274-140v-747h178V0c-60-6-146 22-154-37l-14-109C716-60 619 16 461 16" id="T"/><path fill="#5a6c86" d="M698-76c-54 52-145 92-245 92-162 1-249-96-249-260v-620c-58-9-160 26-160-39v-71l166-21 41-313c4-50 80-30 131-34v349h290v129H382v608c-2 78 40 125 111 126 60 2 88-33 128-48 9 0 18 6 25 17" id="U"/><path fill="#5a6c86" d="M584-856c-148 6-210 94-260 211V0H146v-1013c62 7 151-25 157 49l12 158c66-138 184-259 384-216 23 5 44 16 63 27l-23 133c-5 17-15 25-31 25-36 0-71-21-124-19" id="V"/><g id="a"><use transform="matrix(0.009,0,0,0.009,0,0)" xlink:href="#N"/><use transform="matrix(0.009,0,0,0.009,10.008,0)" xlink:href="#O"/><use transform="matrix(0.009,0,0,0.009,19.944,0)" xlink:href="#P"/><use transform="matrix(0.009,0,0,0.009,26.189999999999998,0)" xlink:href="#Q"/><use transform="matrix(0.009,0,0,0.009,34.596,0)" xlink:href="#N"/><use transform="matrix(0.009,0,0,0.009,44.604,0)" xlink:href="#R"/><use transform="matrix(0.009,0,0,0.009,54.611999999999995,0)" xlink:href="#S"/><use transform="matrix(0.009,0,0,0.009,64.67399999999999,0)" xlink:href="#T"/><use transform="matrix(0.009,0,0,0.009,74.68199999999999,0)" xlink:href="#Q"/><use transform="matrix(0.009,0,0,0.009,83.088,0)" xlink:href="#U"/><use transform="matrix(0.009,0,0,0.009,89.80199999999999,0)" xlink:href="#N"/><use transform="matrix(0.009,0,0,0.009,99.80999999999999,0)" xlink:href="#V"/></g><path fill="#5a6c86" d="M513-145c178-4 292-88 292-262 0-193-194-213-343-263-182-61-347-142-342-385 4-188 111-303 254-361 117-48 292-41 408 5 66 26 124 62 173 110-22 37-36 86-66 115-51 25-83-28-123-48-53-26-114-56-200-54-157 4-266 71-266 223 0 186 200 204 344 258 175 65 343 135 343 372 0 289-185 446-480 451-198 4-349-81-449-187 26-36 42-83 76-111 60-25 93 39 140 65 62 34 135 75 239 72" id="W"/><path fill="#5a6c86" d="M954-142C850-8 572 61 364-22 180-96 74-268 74-527c0-234 108-389 275-463 59-26 125-39 198-39 273 0 420 174 420 453 0 48-2 70-43 70H250c8 226 98 375 322 380 114 2 191-38 258-82 70-46 94 37 124 66zM807-617c-5-171-86-278-256-281-181-3-273 116-295 281h551" id="X"/><path fill="#5a6c86" d="M510-1031c142 0 220 55 289 134 10-46 3-116 60-116h106V343H787v-493C708-62 611 14 455 14 173 14 72-209 72-503c0-237 94-406 254-487 54-27 115-41 184-41zM256-503c2 212 53 373 258 373 136 0 207-69 273-153v-490c-56-74-122-119-237-119-208 0-296 164-294 389" id="Y"/><g id="b"><use transform="matrix(0.01122222222222222,0,0,0.01122222222222222,0,0)" xlink:href="#W"/><use transform="matrix(0.01122222222222222,0,0,0.01122222222222222,11.895555555555553,0)" xlink:href="#X"/><use transform="matrix(0.01122222222222222,0,0,0.01122222222222222,23.65644444444444,0)" xlink:href="#Y"/><use transform="matrix(0.01122222222222222,0,0,0.01122222222222222,36.20288888888888,0)" xlink:href="#T"/><use transform="matrix(0.01122222222222222,0,0,0.01122222222222222,48.68199999999999,0)" xlink:href="#X"/><use transform="matrix(0.01122222222222222,0,0,0.01122222222222222,60.44288888888888,0)" xlink:href="#R"/><use transform="matrix(0.01122222222222222,0,0,0.01122222222222222,72.92199999999998,0)" xlink:href="#Q"/><use transform="matrix(0.01122222222222222,0,0,0.01122222222222222,83.40355555555554,0)" xlink:href="#X"/><use transform="matrix(0.01122222222222222,0,0,0.01122222222222222,95.16444444444443,0)" xlink:href="#V"/></g><path fill="#3a414a" d="M895-142C799-8 539 62 344-21 173-94 74-262 74-507c0-317 160-522 477-522 151 0 254 54 333 132-21 26-39 58-63 81-42 20-68-19-100-34-42-20-91-42-160-40-219 6-304 160-304 383 0 220 82 376 295 383 106 4 169-38 223-84 22-19 53-21 70 1" id="Z"/><path fill="#3a414a" d="M1038-507c0 321-164 521-482 521S72-187 72-507c0-248 107-410 284-485 60-25 126-37 200-37 317 0 482 201 482 522zm-782 1c0 225 80 381 300 381 213 0 298-159 298-381 0-223-84-383-298-383-221 0-300 158-300 383" id="aa"/><path fill="#3a414a" d="M598-887c-125 2-207 68-274 141V0H146v-1013c60 6 147-22 154 37l14 110c82-87 177-163 336-163 232 0 339 151 339 384V0H811v-645c0-149-65-244-213-242" id="ab"/><path fill="#3a414a" d="M698-76c-54 52-145 92-245 92-162 1-249-96-249-260v-620c-58-9-160 26-160-39v-71l166-21 41-313c4-50 80-30 131-34v349h290v129H382v608c-2 78 40 125 111 126 60 2 88-33 128-48 9 0 18 6 25 17" id="ac"/><path fill="#3a414a" d="M584-856c-148 6-210 94-260 211V0H146v-1013c62 7 151-25 157 49l12 158c66-138 184-259 384-216 23 5 44 16 63 27l-23 133c-5 17-15 25-31 25-36 0-71-21-124-19" id="ad"/><path fill="#3a414a" d="M344-1473V0H166v-1473h178" id="ae"/><g id="c"><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,0,0)" xlink:href="#Z"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,10.377777777777778,0)" xlink:href="#aa"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,22.733333333333334,0)" xlink:href="#ab"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,35.08888888888889,0)" xlink:href="#ac"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,43.37777777777778,0)" xlink:href="#ad"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,52.333333333333336,0)" xlink:href="#aa"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,64.6888888888889,0)" xlink:href="#ae"/></g><path fill="#3a414a" d="M602 14c-133 0-212-47-278-119v448H146v-1356c60 6 147-22 154 37l15 120c80-93 179-175 341-175 282 0 383 224 383 518 0 237-92 406-253 487-54 27-116 40-184 40zm253-527c-3-212-53-374-258-374-136 0-207 69-273 153v490c57 77 121 120 238 120 207 0 295-164 293-389" id="af"/><g id="d"><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,0,0)" xlink:href="#ae"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,5.688888888888889,0)" xlink:href="#aa"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,18.044444444444444,0)" xlink:href="#aa"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,30.399999999999995,0)" xlink:href="#af"/></g><path fill="#3a414a" d="M409-112c121-3 207-52 207-167 0-134-157-142-264-181-133-48-263-98-263-275 0-197 153-290 360-294 139-3 243 49 317 118-26 35-46 114-111 76-53-31-114-63-202-61-108 3-195 44-195 147 0 129 158 136 262 175 128 48 263 93 263 264C783-89 627 12 400 16 255 19 139-39 62-107c27-41 57-128 128-81 57 38 118 78 219 76" id="ag"/><path fill="#3a414a" d="M954-142C850-8 572 61 364-22 180-96 74-268 74-527c0-234 108-389 275-463 59-26 125-39 198-39 273 0 420 174 420 453 0 48-2 70-43 70H250c8 226 98 375 322 380 114 2 191-38 258-82 70-46 94 37 124 66zM807-617c-5-171-86-278-256-281-181-3-273 116-295 281h551" id="ah"/><path fill="#3a414a" d="M461 16c-231 0-339-149-339-383v-646h178v646c0 148 67 243 213 241 125-2 207-66 274-140v-747h178V0c-60-6-146 22-154-37l-14-109C716-60 619 16 461 16" id="ai"/><g id="e"><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,0,0)" xlink:href="#Z"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,10.377777777777778,0)" xlink:href="#aa"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,22.733333333333334,0)" xlink:href="#ab"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,35.08888888888889,0)" xlink:href="#ag"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,44.733333333333334,0)" xlink:href="#ah"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,56.37777777777778,0)" xlink:href="#ab"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,68.73333333333333,0)" xlink:href="#ag"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,78.37777777777778,0)" xlink:href="#ai"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,90.73333333333333,0)" xlink:href="#ag"/></g><path fill="#3a414a" d="M409 293C214 8 88-383 149-866c35-276 133-488 260-685 32 22 70 38 97 65 12 17 8 37-3 57-126 218-214 479-214 800s87 582 214 800c15 26 10 65-15 74" id="aj"/><path fill="#3a414a" d="M537-1031c235 0 353 147 353 383V0c-58-5-129 17-142-42l-20-94C637-55 545 19 375 16 200 13 92-76 92-253c0-184 160-243 332-285 79-19 176-28 291-31 12-184-31-318-200-318-113 0-181 45-243 91-36 26-82 14-99-17l-32-57c101-96 215-161 396-161zM263-261c0 103 62 152 165 152 140 0 216-64 287-136v-211c-141 4-258 19-349 60-60 27-103 62-103 135" id="ak"/><path fill="#3a414a" d="M594-1317c-165 0-237 72-235 231v93h293v129H365V0H186v-861c-49-9-113-4-146-29-24-17-10-67-14-103h160v-98c5-229 120-363 348-363 45 0 87 7 126 20l-4 89c-2 31-28 28-62 28" id="al"/><path fill="#3a414a" d="M178-1551c194 286 322 675 260 1159-35 275-132 490-260 685-32-22-72-36-97-64-13-15-6-42 3-58C209-48 298-307 298-629c0-321-92-580-214-800-41-75 58-89 94-122" id="am"/><g id="f"><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,0,0)" xlink:href="#aj"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,6.666666666666667,0)" xlink:href="#ad"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,15.199999999999998,0)" xlink:href="#ak"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,26.46666666666667,0)" xlink:href="#al"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,33.955555555555556,0)" xlink:href="#ac"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,42.24444444444445,0)" xlink:href="#am"/></g><path fill="#3a414a" d="M598-887c-125 2-207 68-274 141V0H146v-1473h178v596c81-82 173-152 326-152 232 0 339 151 339 384V0H811v-645c0-149-65-244-213-242" id="an"/><path fill="#3a414a" d="M788 165v120H0V165h788" id="ao"/><path fill="#3a414a" d="M331-1473v867c49 0 82 0 108-28l320-343c20-19 33-36 70-36h162C858-871 723-729 590-586c-9 9-19 16-30 23 25 17 41 39 60 63L1016 0c-81-8-184 18-227-35L456-450c-21-27-31-33-75-34h-50V0H152v-1473h179" id="ap"/><g id="g"><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,0,0)" xlink:href="#an"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,12.355555555555556,0)" xlink:href="#ah"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,24,0)" xlink:href="#ak"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,35.266666666666666,0)" xlink:href="#ae"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,40.955555555555556,0)" xlink:href="#ac"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,49.24444444444445,0)" xlink:href="#an"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,61.6,0)" xlink:href="#ao"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,70.35555555555555,0)" xlink:href="#Z"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,80.73333333333333,0)" xlink:href="#an"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,93.08888888888889,0)" xlink:href="#ah"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,104.73333333333333,0)" xlink:href="#Z"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,115.11111111111111,0)" xlink:href="#ap"/></g><path fill="#333" d="M395-1486V0H148v-1486h247" id="aq"/><path fill="#333" d="M991-153C899-47 760 15 568 15 237 15 63-197 63-535c0-237 116-392 287-467 61-27 129-40 206-40 287 0 444 174 444 465 0 54-3 95-57 95H309c4 226 158 349 385 292 52-13 93-39 132-62 32-19 73-16 93 9zM778-631c-4-143-73-234-217-234-154 0-226 95-247 234h464" id="ar"/><path fill="#333" d="M556-1045c246 0 380 151 380 397V0c-79-6-181 23-196-53l-22-73C630-49 541 18 379 16 194 13 81-77 81-262c0-184 152-247 321-292 78-21 176-31 293-34 10-155-29-262-170-262-104 0-161 40-224 77-47 28-107 5-127-31l-45-79c118-108 260-162 427-162zM317-275c-3 86 56 121 139 121 117 0 179-51 239-111v-173c-122 6-219 17-297 53-49 22-79 51-81 110" id="as"/><path fill="#333" d="M502-1045c120-1 193 43 256 101v-542h247V0c-80-9-199 29-214-45l-20-99C693-58 601 15 441 15 163 15 61-217 61-510c0-241 98-411 259-494 54-27 115-41 182-41zM316-510c0 181 36 329 209 329 118 0 173-54 233-123v-460c-48-59-104-93-198-93-188 0-244 151-244 347" id="at"/><path fill="#333" d="M604-806c-122 5-180 74-225 167V0H132v-1026c83 11 206-35 218 62l15 124c63-106 147-205 295-205 51 0 93 12 126 35l-32 185c-4 23-15 33-40 33-33 0-65-16-110-14" id="au"/><path fill="#333" d="M254-198c95 60 334 64 323-83-9-119-156-122-253-159C192-490 72-550 72-729c0-214 163-309 387-313 145-3 264 55 338 127-26 36-45 82-77 111-69 21-111-33-176-48-103-23-247 0-238 102 11 114 156 118 251 155 126 49 251 100 251 270C808-59 575 48 294 6 192-9 106-54 42-110c28-39 43-95 83-120 49-31 96 11 129 32" id="av"/><path fill="#333" d="M605-850c-102 1-168 52-226 108V0H132v-1486h247v571c76-69 161-129 301-127 234 4 346 154 346 389V0H779v-653c0-121-55-198-174-197" id="aw"/><path fill="#333" d="M395-1026V0H148v-1026h247zm-123-457c96 0 160 62 160 158 0 94-65 155-160 155-93 0-156-62-156-155 0-95 61-158 156-158" id="ax"/><path fill="#333" d="M635 15C514 15 442-25 379-85v420H132v-1361c64 5 145-11 192 11 33 24 28 86 42 129 78-86 174-159 331-159 277 0 379 232 379 524 0 241-96 412-258 495-54 27-116 41-183 41zm186-536c0-181-37-329-209-329-117 0-175 55-233 124v460c48 60 104 93 198 93 188 0 244-152 244-348" id="ay"/><g id="h"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aq"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,4.817777777777778,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,14.32,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,23.626666666666665,0)" xlink:href="#at"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,33.76,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,43.26222222222222,0)" xlink:href="#au"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,50.52444444444444,0)" xlink:href="#av"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,58.29333333333334,0)" xlink:href="#aw"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,68.39999999999999,0)" xlink:href="#ax"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,73.21777777777775,0)" xlink:href="#ay"/></g><path fill="#333" d="M928-153C839-49 712 15 524 15c-227 0-358-131-424-305-47-123-49-306-4-434 67-190 213-318 465-318 165 0 270 58 357 143-29 37-52 81-86 112-71 26-104-41-170-55-24-5-52-12-86-12-192 5-260 143-260 339 0 194 67 336 254 342 98 3 148-38 200-79 26-20 67-17 87 9" id="az"/><path fill="#333" d="M605-850c-102 1-168 52-226 108V0H132v-1026c80 9 198-29 214 45l17 81c77-76 165-142 317-142 235 0 346 154 346 389V0H779v-653c0-121-55-198-174-197" id="aA"/><path fill="#333" d="M247-436C153-487 80-575 80-712c0-228 174-332 407-332 92 0 169 20 230 53h295c-4 63 19 133-53 146l-92 17c30 74 25 184-9 254-72 146-265 223-484 183-51 27-68 81-20 111 145 54 395 5 528 91 60 38 108 95 104 193-8 182-136 275-286 326-172 59-444 28-556-52C83 234 32 179 32 90c0-112 77-164 166-199-49-28-87-70-84-147 4-94 65-143 133-180zm247 621c132 0 252-20 264-139-10-98-129-93-228-102-63-6-132-5-191-13-47 27-93 62-93 127 0 112 123 127 248 127zM305-706c0 111 68 168 182 168s182-56 182-168c0-107-68-165-182-165s-182 58-182 165" id="aB"/><g id="i"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#az"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,8.48,0)" xlink:href="#aw"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,18.586666666666666,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,27.89333333333333,0)" xlink:href="#aA"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,38,0)" xlink:href="#aB"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,47.2,0)" xlink:href="#ar"/></g><path fill="#333" d="M738-75c-64 55-158 90-269 91-176 2-277-109-277-284v-573c-65-4-153 21-153-52v-98l165-27 52-280c10-66 115-35 183-42v323h270v176H439v556c-1 59 32 101 88 102 48 1 68-25 104-34 19 1 25 9 33 22" id="aC"/><g id="j"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aw"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,10.106666666666667,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,19.60888888888889,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,28.915555555555557,0)" xlink:href="#aq"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,33.733333333333334,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,40.61333333333334,0)" xlink:href="#aw"/></g><path fill="#333" d="M457 16c-234 0-346-155-346-390v-652h247v652c0 121 55 198 174 197 102-1 168-51 226-107v-742h247V0c-80-9-199 29-214-45l-17-82C697-50 608 16 457 16" id="aD"/><g id="k"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aD"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,10.106666666666667,0)" xlink:href="#ay"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,20.16,0)" xlink:href="#at"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,30.293333333333333,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,39.6,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,46.48,0)" xlink:href="#ar"/></g><path fill="#333" d="M638 15c-134 0-208-58-269-132-10 52-5 117-71 117H135v-1486h247v586c77-79 169-142 318-142 277 0 379 230 379 521 0 241-97 412-259 495-54 27-115 41-182 41zm186-536c0-181-37-329-209-329-117 0-175 55-233 124v460c48 61 104 93 199 93 187 0 243-152 243-348" id="aE"/><g id="l"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aw"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,10.106666666666667,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,19.60888888888889,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,28.915555555555557,0)" xlink:href="#au"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,36.17777777777778,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,43.05777777777778,0)" xlink:href="#aE"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,53.19111111111111,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,62.693333333333335,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,72,0)" xlink:href="#aC"/></g><path fill="#333" d="M218 3c-22 53-63 92-132 92H-18l584-1494c20-51 60-86 126-87h105" id="aF"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aF" id="m"/><g id="n"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aq"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,4.817777777777778,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,14.32,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,23.626666666666665,0)" xlink:href="#at"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,33.76,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,43.26222222222222,0)" xlink:href="#au"/></g><path fill="#333" d="M361-1005c121-49 297-49 417 0 184 74 298 236 298 490 0 330-178 530-506 530C241 15 61-185 61-515c0-254 115-416 300-490zm-45 492c0 201 65 338 254 338 188 0 251-137 251-338s-63-340-251-340c-189 0-254 139-254 340" id="aG"/><path fill="#333" d="M221-3C132-8 80-62 80-152c0-85 58-133 145-135 137-3 173 141 135 270-37 126-112 227-205 301-28-24-89-65-42-112 45-45 92-100 108-175" id="aH"/><g id="o"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,9.502222222222223,0)" xlink:href="#aq"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,14.32,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,23.822222222222223,0)" xlink:href="#az"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,32.30222222222223,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,39.18222222222223,0)" xlink:href="#ax"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,44.00000000000001,0)" xlink:href="#aG"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,54.106666666666676,0)" xlink:href="#aA"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,64.21333333333334,0)" xlink:href="#aH"/></g><g id="p"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,9.502222222222223,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,16.38222222222222,0)" xlink:href="#az"/></g><g id="q"><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,0,0)" xlink:href="#ad"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,8.955555555555556,0)" xlink:href="#af"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,21.22222222222222,0)" xlink:href="#Z"/></g><path fill="#3a414a" d="M18-1013h146c28-1 47 18 55 37l257 652c18 45 27 93 37 143 12-50 22-98 40-143l260-652c17-60 123-30 192-37L592 0H431" id="aI"/><g id="r"><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,0,0)" xlink:href="#ag"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,9.644444444444444,0)" xlink:href="#ah"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,21.28888888888889,0)" xlink:href="#ad"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,30.244444444444447,0)" xlink:href="#aI"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,41.333333333333336,0)" xlink:href="#ah"/><use transform="matrix(0.011111111111111112,0,0,0.011111111111111112,52.97777777777778,0)" xlink:href="#ad"/></g><path fill="#333" d="M565-850c-86 0-140 48-186 99V0H132v-1026c80 9 198-29 214 45l16 76c67-72 141-136 276-137 139-1 214 86 253 192 57-117 162-192 328-192 240 0 354 147 354 389V0h-247v-653c1-123-52-197-169-197s-180 76-180 197V0H729v-653c0-127-46-197-164-197" id="aJ"/><g id="s"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,9.306666666666667,0)" xlink:href="#at"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,19.439999999999994,0)" xlink:href="#aJ"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,34.40888888888889,0)" xlink:href="#ax"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,39.22666666666667,0)" xlink:href="#aA"/></g><g id="t"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#az"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,8.48,0)" xlink:href="#aG"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,18.586666666666666,0)" xlink:href="#aA"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,28.69333333333333,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,35.57333333333334,0)" xlink:href="#au"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,42.83555555555556,0)" xlink:href="#aG"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,52.94222222222223,0)" xlink:href="#aq"/></g><path fill="#333" d="M381 316C185 26 60-383 122-872c35-279 131-501 259-698 44 30 96 50 134 86 16 24 12 49-3 77-164 298-252 770-142 1185 35 132 78 259 143 374 20 35 10 87-22 97" id="aK"/><g id="u"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aK"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,5.333333333333333,0)" xlink:href="#aq"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,10.15111111111111,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,19.653333333333332,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,28.96,0)" xlink:href="#at"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,39.093333333333334,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,48.595555555555556,0)" xlink:href="#au"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,55.85777777777778,0)" xlink:href="#av"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,63.626666666666665,0)" xlink:href="#aw"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,73.73333333333333,0)" xlink:href="#ax"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,78.55111111111111,0)" xlink:href="#ay"/></g><path fill="#333" d="M601-1285c-158 0-198 102-186 268h267v176H423V0H176v-840c-61-14-153-3-153-76v-101h153c-17-292 113-454 383-454 47 0 91 6 132 19l-5 124c-1 41-44 43-85 43" id="aL"/><g id="v"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,6.88,0)" xlink:href="#au"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,13.884444444444444,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,23.191111111111113,0)" xlink:href="#aA"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,33.29777777777778,0)" xlink:href="#av"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,41.06666666666667,0)" xlink:href="#aL"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,47.297777777777775,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,56.80000000000001,0)" xlink:href="#au"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,64.06222222222223,0)" xlink:href="#aH"/></g><path fill="#333" d="M16 177c97 0 132-44 132-142v-1061h247V35c-4 210-111 324-327 325-50 0-86-6-126-19l8-133c7-33 23-31 66-31zm256-1660c96 0 160 62 160 158 0 94-65 155-160 155-93 0-156-62-156-155 0-95 61-158 156-158" id="aM"/><g id="w"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aM"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,4.782222222222222,0)" xlink:href="#aG"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,14.88888888888889,0)" xlink:href="#ax"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,19.706666666666667,0)" xlink:href="#aA"/></g><g id="x"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#az"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,8.48,0)" xlink:href="#aq"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,13.297777777777778,0)" xlink:href="#aD"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,23.404444444444444,0)" xlink:href="#av"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,31.173333333333332,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,38.053333333333335,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,47.55555555555556,0)" xlink:href="#au"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,54.81777777777778,0)" xlink:href="#aH"/></g><path fill="#333" d="M219-1570c196 289 321 700 259 1188-35 279-131 501-259 698-44-30-97-51-134-88-18-18-10-55 2-76 168-296 252-768 143-1184-35-133-78-260-142-375-22-41-9-79 21-97" id="aN"/><g id="y"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,9.502222222222223,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,16.38222222222222,0)" xlink:href="#az"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,24.862222222222222,0)" xlink:href="#aN"/></g><g id="z"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,9.306666666666667,0)" xlink:href="#at"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,19.439999999999994,0)" xlink:href="#aJ"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,34.40888888888889,0)" xlink:href="#ax"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,39.22666666666667,0)" xlink:href="#aJ"/></g><g id="A"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#av"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,7.768888888888889,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,14.648888888888889,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,23.955555555555556,0)" xlink:href="#au"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,31.217777777777776,0)" xlink:href="#aC"/></g><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aF" id="B"/><g id="C"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#ay"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,10.053333333333333,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,19.36,0)" xlink:href="#aD"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,29.466666666666665,0)" xlink:href="#av"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,37.23555555555556,0)" xlink:href="#ar"/></g><g id="D"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#az"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,8.48,0)" xlink:href="#aG"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,18.586666666666666,0)" xlink:href="#aA"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,28.69333333333333,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,35.57333333333334,0)" xlink:href="#au"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,42.83555555555556,0)" xlink:href="#aG"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,52.94222222222223,0)" xlink:href="#aq"/></g><g id="E"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aq"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,4.817777777777778,0)" xlink:href="#aG"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,14.924444444444445,0)" xlink:href="#aG"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,25.031111111111112,0)" xlink:href="#ay"/></g><g id="F"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#av"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,7.768888888888889,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,14.648888888888889,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,23.955555555555556,0)" xlink:href="#au"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,31.217777777777776,0)" xlink:href="#aC"/></g><g id="G"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#av"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,7.768888888888889,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,14.648888888888889,0)" xlink:href="#aG"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,24.755555555555556,0)" xlink:href="#ay"/></g><path fill="#333" d="M382-1486v851c54 1 89-1 115-33l255-315c22-25 41-43 86-43h226C946-887 832-742 710-606c-11 12-25 21-39 30 29 21 48 49 69 78L1082 0H859c-44-1-65-15-85-44L513-433c-20-29-30-36-75-37h-56V0H135v-1486h247" id="aO"/><g id="H"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#az"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,8.48,0)" xlink:href="#aw"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,18.586666666666666,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,28.08888888888889,0)" xlink:href="#az"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,36.568888888888885,0)" xlink:href="#aO"/></g><g id="I"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aw"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,10.106666666666667,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,19.60888888888889,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,28.915555555555557,0)" xlink:href="#aq"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,33.733333333333334,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,40.61333333333334,0)" xlink:href="#aw"/></g><g id="J"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#az"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,8.48,0)" xlink:href="#aG"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,18.586666666666666,0)" xlink:href="#aJ"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,33.55555555555556,0)" xlink:href="#aJ"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,48.52444444444444,0)" xlink:href="#ax"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,53.34222222222222,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,60.22222222222223,0)" xlink:href="#av"/></g><g id="K"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aq"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,4.817777777777778,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,14.124444444444444,0)" xlink:href="#aC"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,21.004444444444445,0)" xlink:href="#ar"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,30.506666666666668,0)" xlink:href="#av"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,38.275555555555556,0)" xlink:href="#aC"/></g><g id="L"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aD"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,10.106666666666667,0)" xlink:href="#aA"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,20.213333333333335,0)" xlink:href="#av"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,27.982222222222223,0)" xlink:href="#as"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,37.28888888888889,0)" xlink:href="#aL"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,43.52,0)" xlink:href="#ar"/></g><g id="M"><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,0,0)" xlink:href="#aE"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,10.133333333333333,0)" xlink:href="#aq"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,14.95111111111111,0)" xlink:href="#aG"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,25.057777777777776,0)" xlink:href="#az"/><use transform="matrix(0.008888888888888889,0,0,0.008888888888888889,33.53777777777778,0)" xlink:href="#aO"/></g></defs></g></svg>
\ No newline at end of file
package main
import (
"context"
"fmt"
"os"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/op-conductor/conductor"
"github.com/ethereum-optimism/optimism/op-conductor/flags"
opservice "github.com/ethereum-optimism/optimism/op-service"
"github.com/ethereum-optimism/optimism/op-service/cliapp"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum-optimism/optimism/op-service/opio"
)
var (
Version = "v0.0.1"
GitCommit = ""
GitDate = ""
)
func main() {
oplog.SetupDefaults()
app := cli.NewApp()
app.Flags = cliapp.ProtectFlags(flags.Flags)
app.Version = opservice.FormatVersion(Version, GitCommit, GitDate, "")
app.Name = "op-conductor"
app.Usage = "Optimism Sequencer Conductor Service"
app.Description = "op-conductor help sequencer to run in highly available mode"
app.Action = cliapp.LifecycleCmd(OpConductorMain)
app.Commands = []*cli.Command{}
ctx := opio.WithInterruptBlocker(context.Background())
err := app.RunContext(ctx, os.Args)
if err != nil {
log.Crit("Application failed", "message", err)
}
}
func OpConductorMain(ctx *cli.Context, closeApp context.CancelCauseFunc) (cliapp.Lifecycle, error) {
logCfg := oplog.ReadCLIConfig(ctx)
log := oplog.NewLogger(oplog.AppOut(ctx), logCfg)
oplog.SetGlobalLogHandler(log.GetHandler())
opservice.ValidateEnvVars(flags.EnvVarPrefix, flags.Flags, log)
cfg, err := conductor.NewConfig(ctx, log)
if err != nil {
return nil, fmt.Errorf("failed to read config: %w", err)
}
c, err := conductor.New(ctx.Context, cfg, log, Version)
if err != nil {
return nil, fmt.Errorf("failed to create conductor: %w", err)
}
return c, nil
}
package conductor
import (
"fmt"
"github.com/ethereum/go-ethereum/log"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/op-conductor/flags"
opnode "github.com/ethereum-optimism/optimism/op-node"
"github.com/ethereum-optimism/optimism/op-node/rollup"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
)
type Config struct {
// ConsensusAddr is the address to listen for consensus connections.
ConsensusAddr string
// ConsensusPort is the port to listen for consensus connections.
ConsensusPort int
// RaftServerID is the unique ID for this server used by raft consensus.
RaftServerID string
// RaftStorageDir is the directory to store raft data.
RaftStorageDir string
// RaftBootstrap is true if this node should bootstrap a new raft cluster.
RaftBootstrap bool
// NodeRPC is the HTTP provider URL for op-node.
NodeRPC string
RollupCfg rollup.Config
LogConfig oplog.CLIConfig
MetricsConfig opmetrics.CLIConfig
PprofConfig oppprof.CLIConfig
RPC oprpc.CLIConfig
}
// Check validates the CLIConfig.
func (c *Config) Check() error {
if c.ConsensusAddr == "" {
return fmt.Errorf("missing consensus address")
}
if c.ConsensusPort == 0 {
return fmt.Errorf("missing consensus port")
}
if c.RaftServerID == "" {
return fmt.Errorf("missing raft server ID")
}
if c.RaftStorageDir == "" {
return fmt.Errorf("missing raft storage directory")
}
if c.NodeRPC == "" {
return fmt.Errorf("missing node RPC")
}
if err := c.RollupCfg.Check(); err != nil {
return errors.Wrap(err, "invalid rollup config")
}
if err := c.MetricsConfig.Check(); err != nil {
return errors.Wrap(err, "invalid metrics config")
}
if err := c.PprofConfig.Check(); err != nil {
return errors.Wrap(err, "invalid pprof config")
}
if err := c.RPC.Check(); err != nil {
return errors.Wrap(err, "invalid rpc config")
}
return nil
}
// NewConfig parses the Config from the provided flags or environment variables.
func NewConfig(ctx *cli.Context, log log.Logger) (*Config, error) {
if err := flags.CheckRequired(ctx); err != nil {
return nil, errors.Wrap(err, "missing required flags")
}
rollupCfg, err := opnode.NewRollupConfig(log, ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to load rollup config")
}
return &Config{
ConsensusAddr: ctx.String(flags.ConsensusAddr.Name),
ConsensusPort: ctx.Int(flags.ConsensusPort.Name),
RaftServerID: ctx.String(flags.RaftServerID.Name),
RaftStorageDir: ctx.String(flags.RaftStorageDir.Name),
NodeRPC: ctx.String(flags.NodeRPC.Name),
RollupCfg: *rollupCfg,
LogConfig: oplog.ReadCLIConfig(ctx),
MetricsConfig: opmetrics.ReadCLIConfig(ctx),
PprofConfig: oppprof.ReadCLIConfig(ctx),
RPC: oprpc.ReadCLIConfig(ctx),
}, nil
}
package conductor
import (
"context"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-service/cliapp"
)
// New creates a new OpConductor instance.
func New(ctx context.Context, cfg *Config, log log.Logger, version string) (*OpConductor, error) {
panic("unimplemented")
}
// OpConductor represents a full conductor instance and its resources, it does:
// 1. performs health checks on sequencer
// 2. participate in consensus protocol for leader election
// 3. and control sequencer state based on leader and sequencer health status.
//
// OpConductor has three states:
// 1. running: it is running normally, which executes control loop and participates in leader election.
// 2. paused: control loop (sequencer start/stop) is paused, but it still participates in leader election.
// it is paused for disaster recovery situation
// 3. stopped: it is stopped, which means it is not participating in leader election and control loop. OpConductor cannot be started again from stopped mode.
type OpConductor struct{}
var _ cliapp.Lifecycle = (*OpConductor)(nil)
// Start implements cliapp.Lifecycle.
func (*OpConductor) Start(ctx context.Context) error {
panic("unimplemented")
}
// Stop implements cliapp.Lifecycle.
func (*OpConductor) Stop(ctx context.Context) error {
panic("unimplemented")
}
// Stopped implements cliapp.Lifecycle.
func (*OpConductor) Stopped() bool {
panic("unimplemented")
}
package flags
import (
"fmt"
"github.com/urfave/cli/v2"
opservice "github.com/ethereum-optimism/optimism/op-service"
opflags "github.com/ethereum-optimism/optimism/op-service/flags"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
)
const EnvVarPrefix = "OP_CONDUCTOR"
var (
ConsensusAddr = &cli.StringFlag{
Name: "consensus.addr",
Usage: "Address to listen for consensus connections",
EnvVars: opservice.PrefixEnvVar(EnvVarPrefix, "CONSENSUS_ADDR"),
Value: "127.0.0.1",
}
ConsensusPort = &cli.IntFlag{
Name: "consensus.port",
Usage: "Port to listen for consensus connections",
EnvVars: opservice.PrefixEnvVar(EnvVarPrefix, "CONSENSUS_PORT"),
Value: 50050,
}
RaftServerID = &cli.StringFlag{
Name: "raft.server.id",
Usage: "Unique ID for this server used by raft consensus",
EnvVars: opservice.PrefixEnvVar(EnvVarPrefix, "RAFT_SERVER_ID"),
}
RaftStorageDir = &cli.StringFlag{
Name: "raft.storage.dir",
Usage: "Directory to store raft data",
EnvVars: opservice.PrefixEnvVar(EnvVarPrefix, "RAFT_STORAGE_DIR"),
}
NodeRPC = &cli.StringFlag{
Name: "node.rpc",
Usage: "HTTP provider URL for op-node",
EnvVars: opservice.PrefixEnvVar(EnvVarPrefix, "NODE_RPC"),
}
)
var requiredFlags = []cli.Flag{
ConsensusAddr,
ConsensusPort,
RaftServerID,
RaftStorageDir,
NodeRPC,
}
var optionalFlags = []cli.Flag{}
func init() {
optionalFlags = append(optionalFlags, oprpc.CLIFlags(EnvVarPrefix)...)
optionalFlags = append(optionalFlags, oplog.CLIFlags(EnvVarPrefix)...)
optionalFlags = append(optionalFlags, opmetrics.CLIFlags(EnvVarPrefix)...)
optionalFlags = append(optionalFlags, oppprof.CLIFlags(EnvVarPrefix)...)
optionalFlags = append(optionalFlags, opflags.CLIFlags(EnvVarPrefix)...)
Flags = append(requiredFlags, optionalFlags...)
}
var Flags []cli.Flag
func CheckRequired(ctx *cli.Context) error {
for _, f := range requiredFlags {
if !ctx.IsSet(f.Names()[0]) {
return fmt.Errorf("flag %s is required", f.Names()[0])
}
}
return opflags.CheckRequiredXor(ctx)
}
package flags
import (
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/urfave/cli/v2"
opservice "github.com/ethereum-optimism/optimism/op-service"
)
// TestOptionalFlagsDontSetRequired asserts that all flags deemed optional set
// the Required field to false.
func TestOptionalFlagsDontSetRequired(t *testing.T) {
for _, flag := range optionalFlags {
reqFlag, ok := flag.(cli.RequiredFlag)
require.True(t, ok)
require.False(t, reqFlag.IsRequired())
}
}
// TestUniqueFlags asserts that all flag names are unique, to avoid accidental conflicts between the many flags.
func TestUniqueFlags(t *testing.T) {
seenCLI := make(map[string]struct{})
for _, flag := range Flags {
name := flag.Names()[0]
if _, ok := seenCLI[name]; ok {
t.Errorf("duplicate flag %s", name)
continue
}
seenCLI[name] = struct{}{}
}
}
// TestBetaFlags test that all flags starting with "beta." have "BETA_" in the env var, and vice versa.
func TestBetaFlags(t *testing.T) {
for _, flag := range Flags {
envFlag, ok := flag.(interface {
GetEnvVars() []string
})
if !ok || len(envFlag.GetEnvVars()) == 0 { // skip flags without env-var support
continue
}
name := flag.Names()[0]
envName := envFlag.GetEnvVars()[0]
if strings.HasPrefix(name, "beta.") {
require.Contains(t, envName, "BETA_", "%q flag must contain BETA in env var to match \"beta.\" flag name", name)
}
if strings.Contains(envName, "BETA_") {
require.True(t, strings.HasPrefix(name, "beta."), "%q flag must start with \"beta.\" in flag name to match \"BETA_\" env var", name)
}
}
}
func TestHasEnvVar(t *testing.T) {
for _, flag := range Flags {
flag := flag
flagName := flag.Names()[0]
t.Run(flagName, func(t *testing.T) {
envFlagGetter, ok := flag.(interface {
GetEnvVars() []string
})
envFlags := envFlagGetter.GetEnvVars()
require.True(t, ok, "must be able to cast the flag to an EnvVar interface")
require.Equal(t, 1, len(envFlags), "flags should have exactly one env var")
})
}
}
func TestEnvVarFormat(t *testing.T) {
for _, flag := range Flags {
flag := flag
flagName := flag.Names()[0]
t.Run(flagName, func(t *testing.T) {
envFlagGetter, ok := flag.(interface {
GetEnvVars() []string
})
envFlags := envFlagGetter.GetEnvVars()
require.True(t, ok, "must be able to cast the flag to an EnvVar interface")
require.Equal(t, 1, len(envFlags), "flags should have exactly one env var")
expectedEnvVar := opservice.FlagNameToEnvVarName(flagName, "OP_CONDUCTOR")
require.Equal(t, expectedEnvVar, envFlags[0])
})
}
}
...@@ -5,10 +5,12 @@ import ( ...@@ -5,10 +5,12 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/urfave/cli/v2"
opnode "github.com/ethereum-optimism/optimism/op-node" opnode "github.com/ethereum-optimism/optimism/op-node"
"github.com/ethereum-optimism/optimism/op-node/flags" "github.com/ethereum-optimism/optimism/op-node/flags"
opflags "github.com/ethereum-optimism/optimism/op-service/flags"
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/urfave/cli/v2"
) )
var Subcommands = []*cli.Command{ var Subcommands = []*cli.Command{
...@@ -16,13 +18,13 @@ var Subcommands = []*cli.Command{ ...@@ -16,13 +18,13 @@ var Subcommands = []*cli.Command{
Name: "dump-rollup-config", Name: "dump-rollup-config",
Usage: "Dumps network configs", Usage: "Dumps network configs",
Flags: []cli.Flag{ Flags: []cli.Flag{
flags.Network, opflags.CLINetworkFlag(flags.EnvVarPrefix),
}, },
Action: func(ctx *cli.Context) error { Action: func(ctx *cli.Context) error {
logCfg := oplog.ReadCLIConfig(ctx) logCfg := oplog.ReadCLIConfig(ctx)
logger := oplog.NewLogger(oplog.AppOut(ctx), logCfg) logger := oplog.NewLogger(oplog.AppOut(ctx), logCfg)
network := ctx.String(flags.Network.Name) network := ctx.String(opflags.NetworkFlagName)
if network == "" { if network == "" {
return errors.New("must specify a network name") return errors.New("must specify a network name")
} }
......
...@@ -2,16 +2,15 @@ package flags ...@@ -2,16 +2,15 @@ package flags
import ( import (
"fmt" "fmt"
"strings"
"time" "time"
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/op-node/rollup/sync" "github.com/ethereum-optimism/optimism/op-node/rollup/sync"
openum "github.com/ethereum-optimism/optimism/op-service/enum" openum "github.com/ethereum-optimism/optimism/op-service/enum"
opflags "github.com/ethereum-optimism/optimism/op-service/flags"
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/urfave/cli/v2"
) )
// Flags // Flags
...@@ -42,16 +41,6 @@ var ( ...@@ -42,16 +41,6 @@ var (
Value: "", Value: "",
Destination: new(string), Destination: new(string),
} }
RollupConfig = &cli.StringFlag{
Name: "rollup.config",
Usage: "Rollup chain parameters",
EnvVars: prefixEnvVars("ROLLUP_CONFIG"),
}
Network = &cli.StringFlag{
Name: "network",
Usage: fmt.Sprintf("Predefined network selection. Available networks: %s", strings.Join(chaincfg.AvailableNetworks(), ", ")),
EnvVars: prefixEnvVars("NETWORK"),
}
/* Optional Flags */ /* Optional Flags */
SyncModeFlag = &cli.GenericFlag{ SyncModeFlag = &cli.GenericFlag{
Name: "syncmode", Name: "syncmode",
...@@ -235,18 +224,6 @@ var ( ...@@ -235,18 +224,6 @@ var (
Usage: "Load protocol versions from the superchain L1 ProtocolVersions contract (if available), and report in logs and metrics", Usage: "Load protocol versions from the superchain L1 ProtocolVersions contract (if available), and report in logs and metrics",
EnvVars: prefixEnvVars("ROLLUP_LOAD_PROTOCOL_VERSIONS"), EnvVars: prefixEnvVars("ROLLUP_LOAD_PROTOCOL_VERSIONS"),
} }
CanyonOverrideFlag = &cli.Uint64Flag{
Name: "override.canyon",
Usage: "Manually specify the Canyon fork timestamp, overriding the bundled setting",
EnvVars: prefixEnvVars("OVERRIDE_CANYON"),
Hidden: false,
}
DeltaOverrideFlag = &cli.Uint64Flag{
Name: "override.delta",
Usage: "Manually specify the Delta fork timestamp, overriding the bundled setting",
EnvVars: prefixEnvVars("OVERRIDE_DELTA"),
Hidden: false,
}
/* Deprecated Flags */ /* Deprecated Flags */
L2EngineSyncEnabled = &cli.BoolFlag{ L2EngineSyncEnabled = &cli.BoolFlag{
Name: "l2.engine-sync", Name: "l2.engine-sync",
...@@ -294,8 +271,6 @@ var optionalFlags = []cli.Flag{ ...@@ -294,8 +271,6 @@ var optionalFlags = []cli.Flag{
SyncModeFlag, SyncModeFlag,
RPCListenAddr, RPCListenAddr,
RPCListenPort, RPCListenPort,
RollupConfig,
Network,
L1TrustRPC, L1TrustRPC,
L1RPCProviderKind, L1RPCProviderKind,
L1RPCRateLimit, L1RPCRateLimit,
...@@ -324,8 +299,6 @@ var optionalFlags = []cli.Flag{ ...@@ -324,8 +299,6 @@ var optionalFlags = []cli.Flag{
RollupHalt, RollupHalt,
RollupLoadProtocolVersions, RollupLoadProtocolVersions,
L1RethDBPath, L1RethDBPath,
CanyonOverrideFlag,
DeltaOverrideFlag,
} }
var DeprecatedFlags = []cli.Flag{ var DeprecatedFlags = []cli.Flag{
...@@ -345,34 +318,15 @@ func init() { ...@@ -345,34 +318,15 @@ func init() {
optionalFlags = append(optionalFlags, P2PFlags(EnvVarPrefix)...) optionalFlags = append(optionalFlags, P2PFlags(EnvVarPrefix)...)
optionalFlags = append(optionalFlags, oplog.CLIFlags(EnvVarPrefix)...) optionalFlags = append(optionalFlags, oplog.CLIFlags(EnvVarPrefix)...)
optionalFlags = append(optionalFlags, DeprecatedFlags...) optionalFlags = append(optionalFlags, DeprecatedFlags...)
optionalFlags = append(optionalFlags, opflags.CLIFlags(EnvVarPrefix)...)
Flags = append(requiredFlags, optionalFlags...) Flags = append(requiredFlags, optionalFlags...)
} }
// This checks flags that are exclusive & required. Specifically for each
// set of flags, exactly one flag must be set.
var requiredXorFlags = [][]string{
{
RollupConfig.Name,
Network.Name,
},
}
func CheckRequired(ctx *cli.Context) error { func CheckRequired(ctx *cli.Context) error {
for _, f := range requiredFlags { for _, f := range requiredFlags {
if !ctx.IsSet(f.Names()[0]) { if !ctx.IsSet(f.Names()[0]) {
return fmt.Errorf("flag %s is required", f.Names()[0]) return fmt.Errorf("flag %s is required", f.Names()[0])
} }
} }
for _, flagNames := range requiredXorFlags { return opflags.CheckRequiredXor(ctx)
setCount := 0
for _, f := range flagNames {
if ctx.IsSet(f) {
setCount += 1
}
}
if setCount != 1 {
return fmt.Errorf("exactly one of the flags %v is required", flagNames)
}
}
return nil
} }
...@@ -9,21 +9,21 @@ import ( ...@@ -9,21 +9,21 @@ import (
"os" "os"
"strings" "strings"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/flags" "github.com/ethereum-optimism/optimism/op-node/flags"
"github.com/ethereum-optimism/optimism/op-node/node" "github.com/ethereum-optimism/optimism/op-node/node"
p2pcli "github.com/ethereum-optimism/optimism/op-node/p2p/cli" p2pcli "github.com/ethereum-optimism/optimism/op-node/p2p/cli"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/driver" "github.com/ethereum-optimism/optimism/op-node/rollup/driver"
"github.com/ethereum-optimism/optimism/op-node/rollup/sync" "github.com/ethereum-optimism/optimism/op-node/rollup/sync"
opflags "github.com/ethereum-optimism/optimism/op-service/flags"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/ethereum-optimism/optimism/op-service/sources"
) )
// NewConfig creates a Config from the provided flags or environment variables. // NewConfig creates a Config from the provided flags or environment variables.
...@@ -149,7 +149,7 @@ func NewL2EndpointConfig(ctx *cli.Context, log log.Logger) (*node.L2EndpointConf ...@@ -149,7 +149,7 @@ func NewL2EndpointConfig(ctx *cli.Context, log log.Logger) (*node.L2EndpointConf
if _, err := io.ReadFull(rand.Reader, secret[:]); err != nil { if _, err := io.ReadFull(rand.Reader, secret[:]); err != nil {
return nil, fmt.Errorf("failed to generate jwt secret: %w", err) return nil, fmt.Errorf("failed to generate jwt secret: %w", err)
} }
if err := os.WriteFile(fileName, []byte(hexutil.Encode(secret[:])), 0600); err != nil { if err := os.WriteFile(fileName, []byte(hexutil.Encode(secret[:])), 0o600); err != nil {
return nil, err return nil, err
} }
} }
...@@ -179,8 +179,8 @@ func NewDriverConfig(ctx *cli.Context) *driver.Config { ...@@ -179,8 +179,8 @@ func NewDriverConfig(ctx *cli.Context) *driver.Config {
} }
func NewRollupConfig(log log.Logger, ctx *cli.Context) (*rollup.Config, error) { func NewRollupConfig(log log.Logger, ctx *cli.Context) (*rollup.Config, error) {
network := ctx.String(flags.Network.Name) network := ctx.String(opflags.NetworkFlagName)
rollupConfigPath := ctx.String(flags.RollupConfig.Name) rollupConfigPath := ctx.String(opflags.RollupConfigFlagName)
if ctx.Bool(flags.BetaExtraNetworks.Name) { if ctx.Bool(flags.BetaExtraNetworks.Name) {
log.Warn("The beta.extra-networks flag is deprecated and can be omitted safely.") log.Warn("The beta.extra-networks flag is deprecated and can be omitted safely.")
} }
...@@ -214,12 +214,12 @@ Conflicting configuration is deprecated, and will stop the op-node from starting ...@@ -214,12 +214,12 @@ Conflicting configuration is deprecated, and will stop the op-node from starting
} }
func applyOverrides(ctx *cli.Context, rollupConfig *rollup.Config) { func applyOverrides(ctx *cli.Context, rollupConfig *rollup.Config) {
if ctx.IsSet(flags.CanyonOverrideFlag.Name) { if ctx.IsSet(opflags.CanyonOverrideFlagName) {
canyon := ctx.Uint64(flags.CanyonOverrideFlag.Name) canyon := ctx.Uint64(opflags.CanyonOverrideFlagName)
rollupConfig.CanyonTime = &canyon rollupConfig.CanyonTime = &canyon
} }
if ctx.IsSet(flags.DeltaOverrideFlag.Name) { if ctx.IsSet(opflags.DeltaOverrideFlagName) {
delta := ctx.Uint64(flags.DeltaOverrideFlag.Name) delta := ctx.Uint64(opflags.DeltaOverrideFlagName)
rollupConfig.DeltaTime = &delta rollupConfig.DeltaTime = &delta
} }
} }
......
package flags
import (
"fmt"
"strings"
"github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
opservice "github.com/ethereum-optimism/optimism/op-service"
)
const (
RollupConfigFlagName = "rollup.config"
NetworkFlagName = "network"
CanyonOverrideFlagName = "override.canyon"
DeltaOverrideFlagName = "override.delta"
)
func CLIFlags(envPrefix string) []cli.Flag {
return []cli.Flag{
&cli.Uint64Flag{
Name: CanyonOverrideFlagName,
Usage: "Manually specify the Canyon fork timestamp, overriding the bundled setting",
EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_CANYON"),
Hidden: false,
},
&cli.Uint64Flag{
Name: DeltaOverrideFlagName,
Usage: "Manually specify the Delta fork timestamp, overriding the bundled setting",
EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_DELTA"),
Hidden: false,
},
CLINetworkFlag(envPrefix),
CLIRollupConfigFlag(envPrefix),
}
}
func CLINetworkFlag(envPrefix string) cli.Flag {
return &cli.StringFlag{
Name: NetworkFlagName,
Usage: fmt.Sprintf("Predefined network selection. Available networks: %s", strings.Join(chaincfg.AvailableNetworks(), ", ")),
EnvVars: opservice.PrefixEnvVar(envPrefix, "NETWORK"),
}
}
func CLIRollupConfigFlag(envPrefix string) cli.Flag {
return &cli.StringFlag{
Name: RollupConfigFlagName,
Usage: "Rollup chain parameters",
EnvVars: opservice.PrefixEnvVar(envPrefix, "ROLLUP_CONFIG"),
}
}
// This checks flags that are exclusive & required. Specifically for each
// set of flags, exactly one flag must be set.
var requiredXorFlags = [][]string{
{
RollupConfigFlagName,
NetworkFlagName,
},
}
func CheckRequiredXor(ctx *cli.Context) error {
for _, flagSet := range requiredXorFlags {
var setCount int
for _, flagName := range flagSet {
if ctx.IsSet(flagName) {
setCount++
}
}
if setCount != 1 {
return fmt.Errorf("exactly one of the following flags must be set: %s", strings.Join(flagSet, ", "))
}
}
return nil
}
...@@ -33,6 +33,7 @@ ARG OP_NODE_VERSION=v0.0.0 ...@@ -33,6 +33,7 @@ ARG OP_NODE_VERSION=v0.0.0
ARG OP_CHALLENGER_VERSION=v0.0.0 ARG OP_CHALLENGER_VERSION=v0.0.0
ARG OP_BATCHER_VERSION=v0.0.0 ARG OP_BATCHER_VERSION=v0.0.0
ARG OP_PROPOSER_VERSION=v0.0.0 ARG OP_PROPOSER_VERSION=v0.0.0
ARG OP_CONDUCTOR_VERSION=v0.0.0
# separate docker-builds: # separate docker-builds:
...@@ -66,6 +67,8 @@ RUN --mount=type=cache,target=/root/.cache/go-build cd op-batcher && make op-bat ...@@ -66,6 +67,8 @@ RUN --mount=type=cache,target=/root/.cache/go-build cd op-batcher && make op-bat
GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_BATCHER_VERSION" GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_BATCHER_VERSION"
RUN --mount=type=cache,target=/root/.cache/go-build cd op-proposer && make op-proposer \ RUN --mount=type=cache,target=/root/.cache/go-build cd op-proposer && make op-proposer \
GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_PROPOSER_VERSION" GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_PROPOSER_VERSION"
RUN --mount=type=cache,target=/root/.cache/go-build cd op-conductor && make op-conductor \
GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_CONDUCTOR_VERSION"
FROM alpine:3.18 FROM alpine:3.18
...@@ -80,5 +83,6 @@ COPY --from=builder /app/op-node/bin/op-node /usr/local/bin/ ...@@ -80,5 +83,6 @@ COPY --from=builder /app/op-node/bin/op-node /usr/local/bin/
COPY --from=builder /app/op-challenger/bin/op-challenger /usr/local/bin/ COPY --from=builder /app/op-challenger/bin/op-challenger /usr/local/bin/
COPY --from=builder /app/op-batcher/bin/op-batcher /usr/local/bin/ COPY --from=builder /app/op-batcher/bin/op-batcher /usr/local/bin/
COPY --from=builder /app/op-proposer/bin/op-proposer /usr/local/bin/ COPY --from=builder /app/op-proposer/bin/op-proposer /usr/local/bin/
COPY --from=builder /app/op-conductor/bin/op-conductor /usr/local/bin/
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
!/op-bootnode !/op-bootnode
!/op-chain-ops !/op-chain-ops
!/op-challenger !/op-challenger
!/op-conductor
!/op-heartbeat !/op-heartbeat
!/op-node !/op-node
!/op-preimage !/op-preimage
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment