Commit adaf2387 authored by Adrian Sutton's avatar Adrian Sutton

Merge remote-tracking branch 'origin/develop' into aj/split-providers

parents 18e9d9fd 91805fc9
...@@ -1526,14 +1526,14 @@ workflows: ...@@ -1526,14 +1526,14 @@ workflows:
type: approval type: approval
filters: filters:
tags: tags:
only: /^(proxyd|indexer|ci-builder|ufm-[a-z0-9\-]*|op-[a-z0-9\-]*)\/v.*/ only: /^(proxyd|chain-mon|indexer|ci-builder|ufm-[a-z0-9\-]*|op-[a-z0-9\-]*)\/v.*/
branches: branches:
ignore: /.*/ ignore: /.*/
- docker-build: # just to warm up the cache (other jobs run in parallel) - docker-build: # just to warm up the cache (other jobs run in parallel)
name: op-stack-go-docker-build-release name: op-stack-go-docker-build-release
filters: filters:
tags: tags:
only: /^(proxyd|indexer|ci-builder|ufm-[a-z0-9\-]*|op-[a-z0-9\-]*)\/v.*/ only: /^(proxyd|chain-mon|indexer|ci-builder|ufm-[a-z0-9\-]*|op-[a-z0-9\-]*)\/v.*/
branches: branches:
ignore: /.*/ ignore: /.*/
docker_name: op-stack-go docker_name: op-stack-go
...@@ -1661,6 +1661,22 @@ workflows: ...@@ -1661,6 +1661,22 @@ workflows:
- oplabs-gcr-release - oplabs-gcr-release
requires: requires:
- hold - hold
- docker-build:
name: chain-mon-docker-release
filters:
tags:
only: /^chain-mon\/v.*/
branches:
ignore: /.*/
docker_name: chain-mon
docker_tags: <<pipeline.git.revision>>,latest
publish: true
release: true
resource_class: xlarge
context:
- oplabs-gcr-release
requires:
- hold
- docker-build: - docker-build:
name: ci-builder-docker-release name: ci-builder-docker-release
filters: filters:
......
...@@ -15,11 +15,12 @@ jobs: ...@@ -15,11 +15,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
# map the step outputs to job outputs # map the step outputs to job outputs
outputs: outputs:
fault-mon: ${{ steps.packages.outputs.fault-mon }}
balance-mon: ${{ steps.packages.outputs.balance-mon }} balance-mon: ${{ steps.packages.outputs.balance-mon }}
drippie-mon: ${{ steps.packages.outputs.drippie-mon }} drippie-mon: ${{ steps.packages.outputs.drippie-mon }}
wd-mon: ${{ steps.packages.outputs.wd-mon }} fault-mon: ${{ steps.packages.outputs.fault-mon }}
multisig-mon: ${{ steps.packages.outputs.multisig-mon }}
replica-mon: ${{ steps.packages.outputs.replica-mon }} replica-mon: ${{ steps.packages.outputs.replica-mon }}
wd-mon: ${{ steps.packages.outputs.wd-mon }}
canary-docker-tag: ${{ steps.docker-image-name.outputs.canary-docker-tag }} canary-docker-tag: ${{ steps.docker-image-name.outputs.canary-docker-tag }}
op-exporter: ${{ steps.packages.outputs.op-exporter }} op-exporter: ${{ steps.packages.outputs.op-exporter }}
endpoint-monitor: ${{ steps.packages.outputs.endpoint-monitor }} endpoint-monitor: ${{ steps.packages.outputs.endpoint-monitor }}
...@@ -97,6 +98,33 @@ jobs: ...@@ -97,6 +98,33 @@ jobs:
push: true push: true
tags: ethereumoptimism/balance-mon:${{ needs.canary-publish.outputs.canary-docker-tag }} tags: ethereumoptimism/balance-mon:${{ needs.canary-publish.outputs.canary-docker-tag }}
multisig-mon:
name: Publish Multisig Monitor Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
needs: canary-publish
if: needs.canary-publish.outputs.multisig-mon != ''
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.packages
target: multisig-mon
push: true
tags: ethereumoptimism/multisig-mon:${{ needs.canary-publish.outputs.canary-docker-tag }}
drippie-mon: drippie-mon:
name: Publish Drippie Monitor Version ${{ needs.canary-publish.outputs.canary-docker-tag }} name: Publish Drippie Monitor Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
needs: canary-publish needs: canary-publish
......
...@@ -16,11 +16,12 @@ jobs: ...@@ -16,11 +16,12 @@ jobs:
if: github.repository == 'ethereum-optimism/optimism' if: github.repository == 'ethereum-optimism/optimism'
# map the step outputs to job outputs # map the step outputs to job outputs
outputs: outputs:
fault-mon: ${{ steps.packages.outputs.fault-mon }} balance-mon: ${{ steps.packages.outputs.balance-mon }}
balance-mon: ${{ steps.packages.outputs.drippie-mon }}
drippie-mon: ${{ steps.packages.outputs.drippie-mon }} drippie-mon: ${{ steps.packages.outputs.drippie-mon }}
wd-mon: ${{ steps.packages.outputs.wd-mon }} fault-mon: ${{ steps.packages.outputs.fault-mon }}
multisig-mon: ${{ steps.packages.outputs.multisig-mon }}
replica-mon: ${{ steps.packages.outputs.replica-mon }} replica-mon: ${{ steps.packages.outputs.replica-mon }}
wd-mon: ${{ steps.packages.outputs.wd-mon }}
op-exporter: ${{ steps.packages.outputs.op-exporter }} op-exporter: ${{ steps.packages.outputs.op-exporter }}
endpoint-monitor: ${{ steps.packages.outputs.endpoint-monitor }} endpoint-monitor: ${{ steps.packages.outputs.endpoint-monitor }}
# Permissions necessary for Changesets to push a new branch and open PRs # Permissions necessary for Changesets to push a new branch and open PRs
...@@ -186,6 +187,33 @@ jobs: ...@@ -186,6 +187,33 @@ jobs:
push: true push: true
tags: ethereumoptimism/balance-mon:${{ needs.release.outputs.balance-mon }},ethereumoptimism/balance-mon:latest tags: ethereumoptimism/balance-mon:${{ needs.release.outputs.balance-mon }},ethereumoptimism/balance-mon:latest
multisig-mon:
name: Publish Multisig Monitor Version ${{ needs.release.outputs.multisig-mon }}
needs: release
if: needs.release.outputs.multisig-mon != ''
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.packages
target: multisig-mon
push: true
tags: ethereumoptimism/multisig-mon:${{ needs.release.outputs.multisig-mon }},ethereumoptimism/multisig-mon:latest
drippie-mon: drippie-mon:
name: Publish Drippie Monitor Version ${{ needs.release.outputs.drippie-mon }} name: Publish Drippie Monitor Version ${{ needs.release.outputs.drippie-mon }}
needs: release needs: release
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
opnode "github.com/ethereum-optimism/optimism/op-node" opnode "github.com/ethereum-optimism/optimism/op-node"
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/cmd/genesis" "github.com/ethereum-optimism/optimism/op-node/cmd/genesis"
"github.com/ethereum-optimism/optimism/op-node/cmd/networks"
"github.com/ethereum-optimism/optimism/op-node/cmd/p2p" "github.com/ethereum-optimism/optimism/op-node/cmd/p2p"
"github.com/ethereum-optimism/optimism/op-node/flags" "github.com/ethereum-optimism/optimism/op-node/flags"
"github.com/ethereum-optimism/optimism/op-node/metrics" "github.com/ethereum-optimism/optimism/op-node/metrics"
...@@ -57,6 +58,10 @@ func main() { ...@@ -57,6 +58,10 @@ func main() {
Name: "doc", Name: "doc",
Subcommands: doc.NewSubcommands(metrics.NewMetrics("default")), Subcommands: doc.NewSubcommands(metrics.NewMetrics("default")),
}, },
{
Name: "networks",
Subcommands: networks.Subcommands,
},
} }
ctx := opio.WithInterruptBlocker(context.Background()) ctx := opio.WithInterruptBlocker(context.Background())
......
package networks
import (
"encoding/json"
"errors"
"fmt"
opnode "github.com/ethereum-optimism/optimism/op-node"
"github.com/ethereum-optimism/optimism/op-node/flags"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/urfave/cli/v2"
)
var Subcommands = []*cli.Command{
{
Name: "dump-rollup-config",
Usage: "Dumps network configs",
Flags: []cli.Flag{
flags.Network,
},
Action: func(ctx *cli.Context) error {
logCfg := oplog.ReadCLIConfig(ctx)
logger := oplog.NewLogger(oplog.AppOut(ctx), logCfg)
network := ctx.String(flags.Network.Name)
if network == "" {
return errors.New("must specify a network name")
}
rCfg, err := opnode.NewRollupConfig(logger, ctx)
if err != nil {
return err
}
out, err := json.MarshalIndent(rCfg, "", " ")
if err != nil {
return err
}
fmt.Println(string(out))
return nil
},
},
}
...@@ -86,10 +86,6 @@ WORKDIR /opt/optimism/packages/chain-mon ...@@ -86,10 +86,6 @@ WORKDIR /opt/optimism/packages/chain-mon
# TODO keeping the rest of these here for now because they are being used # TODO keeping the rest of these here for now because they are being used
# but we should really delete them we only need one image # but we should really delete them we only need one image
FROM base as replica-mon
WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:replica-mon"]
FROM base as balance-mon FROM base as balance-mon
WORKDIR /opt/optimism/packages/chain-mon WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:balance-mon"] CMD ["start:balance-mon"]
...@@ -98,14 +94,24 @@ FROM base as drippie-mon ...@@ -98,14 +94,24 @@ FROM base as drippie-mon
WORKDIR /opt/optimism/packages/chain-mon WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:drippie-mon"] CMD ["start:drippie-mon"]
FROM base as wd-mon from base as fault-mon
WORKDIR /opt/optimism/packages/chain-mon WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:wd-mon"] CMD ["start:fault-mon"]
from base as multisig-mon
WORKDIR /opt/optimism/packages/multisig-mon
CMD ["start:multisig-mon"]
FROM base as replica-mon
WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:replica-mon"]
FROM base as wallet-mon FROM base as wallet-mon
WORKDIR /opt/optimism/packages/chain-mon WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:wallet-mon"] CMD ["start:wallet-mon"]
from base as fault-mon FROM base as wd-mon
WORKDIR /opt/optimism/packages/chain-mon WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:fault-mon"] CMD ["start:wd-mon"]
...@@ -6,7 +6,7 @@ DOCKER_REPO=$1 ...@@ -6,7 +6,7 @@ DOCKER_REPO=$1
GIT_TAG=$2 GIT_TAG=$2
GIT_SHA=$3 GIT_SHA=$3
IMAGE_NAME=$(echo "$GIT_TAG" | grep -Eow '^(ci-builder|proxyd|indexer|ufm-[a-z0-9\-]*|op-[a-z0-9\-]*)' || true) IMAGE_NAME=$(echo "$GIT_TAG" | grep -Eow '^(ci-builder|chain-mon|proxyd|indexer|ufm-[a-z0-9\-]*|op-[a-z0-9\-]*)' || true)
if [ -z "$IMAGE_NAME" ]; then if [ -z "$IMAGE_NAME" ]; then
echo "image name could not be parsed from git tag '$GIT_TAG'" echo "image name could not be parsed from git tag '$GIT_TAG'"
exit 1 exit 1
......
...@@ -8,6 +8,18 @@ BALANCE_MON__RPC= ...@@ -8,6 +8,18 @@ BALANCE_MON__RPC=
# JSON array in the format [{ "address": <address>, "nickname": <nickname> }, ... ] # JSON array in the format [{ "address": <address>, "nickname": <nickname> }, ... ]
BALANCE_MON__ACCOUNTS= BALANCE_MON__ACCOUNTS=
###############################################################################
# ↓ multisig-mon ↓ #
###############################################################################
# RPC pointing to network to monitor safe nonces on
MULTISIG_MON__RPC=
# JSON array in the format [{ "address": <address>, "nickname": <nickname> }, ... ]
MULTISIG_MON__ACCOUNTS=
############################################################################### ###############################################################################
# ↓ wallet-mon ↓ # # ↓ wallet-mon ↓ #
############################################################################### ###############################################################################
......
...@@ -10,17 +10,21 @@ ...@@ -10,17 +10,21 @@
], ],
"scripts": { "scripts": {
"dev:balance-mon": "tsx watch ./src/balance-mon/service.ts", "dev:balance-mon": "tsx watch ./src/balance-mon/service.ts",
"dev:wallet-mon": "tsx watch ./src/wallet-mon/service.ts",
"dev:drippie-mon": "tsx watch ./src/drippie-mon/service.ts", "dev:drippie-mon": "tsx watch ./src/drippie-mon/service.ts",
"dev:wd-mon": "tsx watch ./src/wd-mon/service.ts",
"dev:fault-mon": "tsx watch ./src/fault-mon/service.ts", "dev:fault-mon": "tsx watch ./src/fault-mon/service.ts",
"dev:multisig-mon": "tsx watch ./src/multisig-mon/service.ts",
"dev:replica-mon": "tsx watch ./src/replica-mon/service.ts", "dev:replica-mon": "tsx watch ./src/replica-mon/service.ts",
"dev:wallet-mon": "tsx watch ./src/wallet-mon/service.ts",
"dev:wd-mon": "tsx watch ./src/wd-mon/service.ts",
"start:balance-mon": "tsx ./src/balance-mon/service.ts", "start:balance-mon": "tsx ./src/balance-mon/service.ts",
"start:wallet-mon": "tsx ./src/wallet-mon/service.ts",
"start:drippie-mon": "tsx ./src/drippie-mon/service.ts", "start:drippie-mon": "tsx ./src/drippie-mon/service.ts",
"start:wd-mon": "tsx ./src/wd-mon/service.ts",
"start:fault-mon": "tsx ./src/fault-mon/service.ts", "start:fault-mon": "tsx ./src/fault-mon/service.ts",
"start:multisig-mon": "tsx ./src/multisig-mon/service.ts",
"start:replica-mon": "tsx ./src/replica-mon/service.ts", "start:replica-mon": "tsx ./src/replica-mon/service.ts",
"start:wallet-mon": "tsx ./src/wallet-mon/service.ts",
"start:wd-mon": "tsx ./src/wd-mon/service.ts",
"test": "hardhat test", "test": "hardhat test",
"test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json", "test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json",
"build": "tsc -p ./tsconfig.json", "build": "tsc -p ./tsconfig.json",
......
...@@ -6,9 +6,7 @@ import { ...@@ -6,9 +6,7 @@ import {
validators, validators,
} from '@eth-optimism/common-ts' } from '@eth-optimism/common-ts'
import { Provider } from '@ethersproject/abstract-provider' import { Provider } from '@ethersproject/abstract-provider'
import { BigNumber, ethers } from 'ethers'
import Safe from '../abi/IGnosisSafe.0.8.19.json'
import { version } from '../../package.json' import { version } from '../../package.json'
type BalanceMonOptions = { type BalanceMonOptions = {
...@@ -18,12 +16,11 @@ type BalanceMonOptions = { ...@@ -18,12 +16,11 @@ type BalanceMonOptions = {
type BalanceMonMetrics = { type BalanceMonMetrics = {
balances: Gauge balances: Gauge
safeNonces: Gauge
unexpectedRpcErrors: Counter unexpectedRpcErrors: Counter
} }
type BalanceMonState = { type BalanceMonState = {
accounts: Array<{ address: string; nickname: string; safe: boolean }> accounts: Array<{ address: string; nickname: string }>
} }
export class BalanceMonService extends BaseServiceV2< export class BalanceMonService extends BaseServiceV2<
...@@ -57,11 +54,6 @@ export class BalanceMonService extends BaseServiceV2< ...@@ -57,11 +54,6 @@ export class BalanceMonService extends BaseServiceV2<
desc: 'Balances of addresses', desc: 'Balances of addresses',
labels: ['address', 'nickname'], labels: ['address', 'nickname'],
}, },
safeNonces: {
type: Gauge,
desc: 'Safe nonce',
labels: ['address', 'nickname'],
},
unexpectedRpcErrors: { unexpectedRpcErrors: {
type: Counter, type: Counter,
desc: 'Number of unexpected RPC errors', desc: 'Number of unexpected RPC errors',
...@@ -103,38 +95,6 @@ export class BalanceMonService extends BaseServiceV2< ...@@ -103,38 +95,6 @@ export class BalanceMonService extends BaseServiceV2<
name: 'getBalance', name: 'getBalance',
}) })
} }
// Get the safe nonce to report
if (account.safe) {
try {
const safeContract = new ethers.Contract(
account.address,
Safe.abi,
this.options.rpc
)
const safeNonce = BigNumber.from(await safeContract.nonce())
this.logger.info(`got nonce`, {
address: account.address,
nickname: account.nickname,
nonce: safeNonce.toString(),
})
this.metrics.safeNonces.set(
{ address: account.address, nickname: account.nickname },
parseInt(safeNonce.toString(), 10)
)
} catch (err) {
this.logger.info(`got unexpected RPC error`, {
section: 'safeNonce',
name: 'getSafeNonce',
err,
})
this.metrics.unexpectedRpcErrors.inc({
section: 'safeNonce',
name: 'getSafeNonce',
})
}
}
} }
} }
} }
......
export * from './balance-mon/service' export * from './balance-mon/service'
export * from './drippie-mon/service' export * from './drippie-mon/service'
export * from './fault-mon/index'
export * from './multisig-mon/service'
export * from './wd-mon/service' export * from './wd-mon/service'
export * from './wallet-mon/service' export * from './wallet-mon/service'
export * from './fault-mon/index'
import {
BaseServiceV2,
StandardOptions,
Gauge,
Counter,
validators,
} from '@eth-optimism/common-ts'
import { Provider } from '@ethersproject/abstract-provider'
import { ethers } from 'ethers'
import Safe from '../abi/IGnosisSafe.0.8.19.json'
import { version } from '../../package.json'
type MultisigMonOptions = {
rpc: Provider
accounts: string
}
type MultisigMonMetrics = {
safeNonce: Gauge
unexpectedRpcErrors: Counter
}
type MultisigMonState = {
accounts: Array<{ address: string; nickname: string }>
}
export class MultisigMonService extends BaseServiceV2<
MultisigMonOptions,
MultisigMonMetrics,
MultisigMonState
> {
constructor(options?: Partial<MultisigMonOptions & StandardOptions>) {
super({
version,
name: 'multisig-mon',
loop: true,
options: {
loopIntervalMs: 60_000,
...options,
},
optionsSpec: {
rpc: {
validator: validators.provider,
desc: 'Provider for network to monitor balances on',
},
accounts: {
validator: validators.str,
desc: 'JSON array of [{ address, nickname, safe }] to monitor balances and nonces of',
public: true,
},
},
metricsSpec: {
safeNonce: {
type: Gauge,
desc: 'Safe nonce',
labels: ['address', 'nickname'],
},
unexpectedRpcErrors: {
type: Counter,
desc: 'Number of unexpected RPC errors',
labels: ['section', 'name'],
},
},
})
}
protected async init(): Promise<void> {
this.state.accounts = JSON.parse(this.options.accounts)
}
protected async main(): Promise<void> {
for (const account of this.state.accounts) {
try {
const safeContract = new ethers.Contract(
account.address,
Safe.abi,
this.options.rpc
)
const safeNonce = await safeContract.nonce()
this.logger.info(`got nonce`, {
address: account.address,
nickname: account.nickname,
nonce: safeNonce.toString(),
})
this.metrics.safeNonce.set(
{ address: account.address, nickname: account.nickname },
parseInt(safeNonce.toString(), 10)
)
} catch (err) {
this.logger.error(`got unexpected RPC error`, {
section: 'safeNonce',
name: 'getSafeNonce',
err,
})
this.metrics.unexpectedRpcErrors.inc({
section: 'safeNonce',
name: 'getSafeNonce',
})
}
}
}
}
if (require.main === module) {
const service = new MultisigMonService()
service.run()
}
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