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:
type: approval
filters:
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:
ignore: /.*/
- docker-build: # just to warm up the cache (other jobs run in parallel)
name: op-stack-go-docker-build-release
filters:
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:
ignore: /.*/
docker_name: op-stack-go
......@@ -1661,6 +1661,22 @@ workflows:
- oplabs-gcr-release
requires:
- 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:
name: ci-builder-docker-release
filters:
......
......@@ -15,11 +15,12 @@ jobs:
runs-on: ubuntu-latest
# map the step outputs to job outputs
outputs:
fault-mon: ${{ steps.packages.outputs.fault-mon }}
balance-mon: ${{ steps.packages.outputs.balance-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 }}
wd-mon: ${{ steps.packages.outputs.wd-mon }}
canary-docker-tag: ${{ steps.docker-image-name.outputs.canary-docker-tag }}
op-exporter: ${{ steps.packages.outputs.op-exporter }}
endpoint-monitor: ${{ steps.packages.outputs.endpoint-monitor }}
......@@ -97,6 +98,33 @@ jobs:
push: true
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:
name: Publish Drippie Monitor Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
needs: canary-publish
......
......@@ -16,11 +16,12 @@ jobs:
if: github.repository == 'ethereum-optimism/optimism'
# map the step outputs to job outputs
outputs:
fault-mon: ${{ steps.packages.outputs.fault-mon }}
balance-mon: ${{ steps.packages.outputs.drippie-mon }}
balance-mon: ${{ steps.packages.outputs.balance-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 }}
wd-mon: ${{ steps.packages.outputs.wd-mon }}
op-exporter: ${{ steps.packages.outputs.op-exporter }}
endpoint-monitor: ${{ steps.packages.outputs.endpoint-monitor }}
# Permissions necessary for Changesets to push a new branch and open PRs
......@@ -186,6 +187,33 @@ jobs:
push: true
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:
name: Publish Drippie Monitor Version ${{ needs.release.outputs.drippie-mon }}
needs: release
......
......@@ -12,6 +12,7 @@ import (
opnode "github.com/ethereum-optimism/optimism/op-node"
"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/networks"
"github.com/ethereum-optimism/optimism/op-node/cmd/p2p"
"github.com/ethereum-optimism/optimism/op-node/flags"
"github.com/ethereum-optimism/optimism/op-node/metrics"
......@@ -57,6 +58,10 @@ func main() {
Name: "doc",
Subcommands: doc.NewSubcommands(metrics.NewMetrics("default")),
},
{
Name: "networks",
Subcommands: networks.Subcommands,
},
}
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
# 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
FROM base as replica-mon
WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:replica-mon"]
FROM base as balance-mon
WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:balance-mon"]
......@@ -98,14 +94,24 @@ FROM base as drippie-mon
WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:drippie-mon"]
FROM base as wd-mon
from base as fault-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
WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:wallet-mon"]
from base as fault-mon
FROM base as wd-mon
WORKDIR /opt/optimism/packages/chain-mon
CMD ["start:fault-mon"]
CMD ["start:wd-mon"]
......@@ -6,7 +6,7 @@ DOCKER_REPO=$1
GIT_TAG=$2
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
echo "image name could not be parsed from git tag '$GIT_TAG'"
exit 1
......
......@@ -8,6 +8,18 @@ BALANCE_MON__RPC=
# JSON array in the format [{ "address": <address>, "nickname": <nickname> }, ... ]
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 ↓ #
###############################################################################
......
......@@ -10,17 +10,21 @@
],
"scripts": {
"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:wd-mon": "tsx watch ./src/wd-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: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:wallet-mon": "tsx ./src/wallet-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:multisig-mon": "tsx ./src/multisig-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:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json",
"build": "tsc -p ./tsconfig.json",
......
......@@ -6,9 +6,7 @@ import {
validators,
} from '@eth-optimism/common-ts'
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'
type BalanceMonOptions = {
......@@ -18,12 +16,11 @@ type BalanceMonOptions = {
type BalanceMonMetrics = {
balances: Gauge
safeNonces: Gauge
unexpectedRpcErrors: Counter
}
type BalanceMonState = {
accounts: Array<{ address: string; nickname: string; safe: boolean }>
accounts: Array<{ address: string; nickname: string }>
}
export class BalanceMonService extends BaseServiceV2<
......@@ -57,11 +54,6 @@ export class BalanceMonService extends BaseServiceV2<
desc: 'Balances of addresses',
labels: ['address', 'nickname'],
},
safeNonces: {
type: Gauge,
desc: 'Safe nonce',
labels: ['address', 'nickname'],
},
unexpectedRpcErrors: {
type: Counter,
desc: 'Number of unexpected RPC errors',
......@@ -103,38 +95,6 @@ export class BalanceMonService extends BaseServiceV2<
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 './drippie-mon/service'
export * from './fault-mon/index'
export * from './multisig-mon/service'
export * from './wd-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