pessimism
Because you can't always be optimistic
Pessimism is a public good monitoring service that allows for OP Stack and EVM compatible blockchains to be continuously assessed for real-time threats using custom defined user heuristic rule sets. To learn about Pessimism's architecture, please advise the documentation.
Warning: Pessimism is currently experimental and very much in development. It means Pessimism is currently unstable, so code will change and builds can break over the coming months. If you come across problems, it would help greatly to open issues so that we can fix them as quickly as possible.
Setup
To use the template, run the following command(s):
-
Create local config file (
config.env
) to store all necessary environmental variables. There's already an exampleconfig.env.template
in the repo that stores default env vars. -
Download or upgrade to
golang 1.19
. -
Install all project golang dependencies by running
go mod download
.
To Run
-
Compile pessimism to machine binary by running the following project level command(s):
- Using Make:
make build-app
- Using Make:
-
To run the compiled binary, you can use the following project level command(s):
- Using Make:
make run-app
- Direct Call:
./bin/pessimism
- Using Make:
Docker
-
Ensure docker is installed on your machine
-
Pull the latest image from Github container registry (ghcr) via
docker pull ghcr.io/base-org/pessimism:latest
-
Make sure you have followed the above instructions to create a local config file (config.env) using the config.env.template
-
Run the following:
- Without genesis.json:
docker run -p 8080:8080 -p 7300:7300 --env-file=config.env -it ghcr.io/base-org/pessimism:latest
- With genesis.json:
docker run -p 8080:8080 -p 7300:7300 --env-file=config.env -it -v ${PWD}/genesis.json:/app/genesis.json ghcr.io/base-org/pessimism:latest
Note: If you want to bootstrap the application and run specific heuristics/pipelines upon start, update config.env BOOTSTRAP_PATH
value to the location of your genesis.json file then run
Building and Running New Images
-
Run
make docker-build
at the root of the repository to build a new docker image. -
Run
make docker-run
at the root of the repository to run the new docker image.
Linting
golangci-lint is used to perform code linting. Configurations are defined in .golangci.yml It can be ran using the following project level command(s):
- Using Make:
make lint
- Direct Call:
golangci-lint run
Testing
Unit Tests
Unit tests are written using the native go test library with test mocks generated using the golang native mock library. These tests live throughout the project's /internal
directory and are named with the suffix _test.go
.
Unit tests can run using the following project level command(s):
- Using Make:
make test
- Direct Call:
go test ./...
Integration Tests
Integration tests are written that leverage the existing op-e2e testing framework for spinning up pieces of the bedrock system. Additionally, the httptest library is used to mock downstream alerting services (e.g. Slack's webhook API). These tests live in the project's /e2e
directory.
Integration tests can run using the following project level command(s):
- Using Make:
make e2e-test
- Direct Call:
go test ./e2e/...
Bootstrap Config
A bootstrap config file is used to define the initial state of the pessimism service. The file must be json
formatted with its directive defined in the BOOTSTRAP_PATH
env var. (e.g. BOOTSTRAP_PATH=./genesis.json
)
Example File
[
{
"network": "layer1",
"pipeline_type": "live",
"type": "contract_event",
"start_height": null,
"alerting_params": {
"message": "",
"destination": "slack"
},
"heuristic_params": {
"address": "0xfC0157aA4F5DB7177830ACddB3D5a9BB5BE9cc5e",
"args": ["Transfer(address, address, uint256)"]
}
},
{
"network": "layer1",
"pipeline_type": "live",
"type": "balance_enforcement",
"start_height": null,
"alerting_params": {
"message": "",
"destination": "slack"
},
"heuristic_params": {
"address": "0xfC0157aA4F5DB7177830ACddB3D5a9BB5BE9cc5e",
"lower": 1,
"upper": 2
}
}
]
Spawning a heuristic session
To learn about the currently supported heuristics and how to spawn them, please advise the heuristics' documentation.
Import testify/mock replaced with gomock
Closes #26
Hi, I have replaced testify/mock with gomock. EthClient is autogenerated with mockgen. Please let me know if the tests are rewritten correctly.
State Key Representation is Insecure
Problem
The current state key representation is very insecure given that a struct is used with no pointer references by the respective stateful component definitions. Currently this results in data loss of the state keys that are held in the component's structure once higher level callers garbage collect the value. Because of this, active components fail to lookup necessary stateful values for secure operation
This bug is currently only prevalent in the current
account_balance
oracle implementation, consequently resulting in the existingbalance_enforcement
invariant to not work.There are some bandaid fixes that we could easily apply to remediate this in the short-term: I. Make the
balance_oracle
store a reference to the stateKey type instead of a direct valueHowever, the fundamental representation of the key itself is flawed as by nature it should be a low-memory primitive type. Additionally, a lower level representation would ensure that there'd be need to no have a string representation in memory.
Problem Solution - 1 (32 byte array)
Update state key representation to be adherent with existing ID representations that are already used across the application. A byte slice representation would be ideal that encodes the necessary metadata for stateful lookups using the following 256 bit representation:
With a byte encoding schema like:
This would avoid the need for pointers when referencing keys. Additionally, chars in go occupy
4 bytes
, meaning that this rep stored as a string would be128
bytes versus32
.Problem Solution - 2 (57 byte struct)
Store references to state keys in the oracle metadata. This would require keeping the existing state key struct types as is; ie:
NOTE: We should probably update the struct definition to store the PUUID instead of doing a string concatenation inside a clone method
Versus solution - 1
In comparison to solution - 1, 2 will occupy more space as the
Nested
value would be a boolean; occupying 4 bytes instead of 1 and would require holding 25 bytes for the entirePUUID
. However, other data fields(ie. nested, prefix, registerType, address)
would occupy the same space as they do in solution - 1. It's important to note that this solution is more intuitive for developers and readability purposes.Bump github.com/urfave/cli from 1.22.9 to 1.22.14
Bumps github.com/urfave/cli from 1.22.9 to 1.22.14.
Release notes
Sourced from github.com/urfave/cli's releases.
Commits
f5ca62f
Merge pull request #1748 from urfave/v1-update-deps8b495cc
Update dependencies for v1ed683a7
Merge pull request #1712 from urfave/v1-update-deps3133e8d
Update dependencies forv1-maint
f0d71d7
Merge pull request #1693 from urfave/v1-bump-go-versionse44ce3a
Shift tested Go versions in v1-maint49f9838
Merge pull request #1654 from urfave/v1-ci-updatesa5c98d3
Do not run the toc command on windows9b65c47
Update toc command for windows compatd391605
Compare file contents ignoring Windows-specific line endingsDependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase
.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebase
will rebase this PR@dependabot recreate
will recreate this PR, overwriting any edits that have been made to it@dependabot merge
will merge this PR after your CI passes on it@dependabot squash and merge
will squash and merge this PR after your CI passes on it@dependabot cancel merge
will cancel a previously requested merge and block automerging@dependabot reopen
will reopen this PR if it is closed@dependabot close
will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot ignore this major version
will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor version
will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependency
will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)`Pipeline` Lacks Introspective Capabilities into its Components
Problem
Existing
Pipeline
struct receiver logic has no support for an event loop routine that can read existing component states to understand when: I. A component crashes or stops II. An oracle component finishes backfilling:syncing --> live
III. (STRETCH) Inter-component communication latency is below some thresholdThis logic is critical for the
etlManager
abstraction to be able to: I. Perform merging operations when asyncing
pipeline has becomelive
; with there existing >1 identical pipelines with the same ID andlive
state II. Understand when pipelines have successfully shutdown IV. Understand when pipelines have crashed in real-timeProposed Solution
Two current possible solution paths, both of which are open for discussion:
Solution 1: Higher Order Event Polling
This event loop should run in the following fashion to understand when key changes to component (consequently pipeline) state occur using some interval based polling algorithm like this:
This issues with this approach are: I. Polling increases computational load II. Increased latency given time discrepancies between when a component state change happens versus when the poller performs a pipeline read
Solution 2: Event Based
Otherwise, a more event (listener/subscriber) based model could be leveraged where the pipeline is actively listening for components to emit activationState events. This
The issues with this approach are: I. (abstraction leak) Components need to have higher order knowledge (i.e, go channel) of the greater Pipeline. II. Increased concurrency management.
NOTE
These proposed solutions don't take failure management into considerations For example, in the instance of a failed pipeline, we could enact some retry procedure to re-attempt running it
N
times. These fail safe or recovery procedures should be explored in a subsequent issue.Execution Timing Metric & Code Comments
Fixes Issue
Fixes #
Changes proposed
Screenshots (Optional)
Note to reviewers
Bump github.com/go-chi/chi from 1.5.4 to 4.1.2+incompatible
Bumps github.com/go-chi/chi from 1.5.4 to 4.1.2+incompatible.
Release notes
Sourced from github.com/go-chi/chi's releases.
... (truncated)
Changelog
Sourced from github.com/go-chi/chi's changelog.
... (truncated)
Commits
86f9a6e
Release v4.1.2fdba45d
cosmetic, move public methods to top of source file234035e
README, add note on go-chi/httprate middlewaree7728c6
Replace wildcards correctly in RoutePattern (#515)5704d7e
fix: handle methodnotallowed with path variables (#512)ccb4c33
README2333c5c
Trying Github sponsor thing1fafc30
Release v4.1.199ad97f
Route recursive-search regexp patterns (#506)23b8ec2
middleware.RouteHeaders: new middleware to allow header based routing flows (...Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase
.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebase
will rebase this PR@dependabot recreate
will recreate this PR, overwriting any edits that have been made to it@dependabot merge
will merge this PR after your CI passes on it@dependabot squash and merge
will squash and merge this PR after your CI passes on it@dependabot cancel merge
will cancel a previously requested merge and block automerging@dependabot reopen
will reopen this PR if it is closed@dependabot close
will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot ignore this major version
will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor version
will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependency
will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)DoS vector w/ Infinite Go Routines
Risk Vector
Currently, the
/v0/invariant
endpoint can be exploited by an attacker to create infinite go routines on an application instance of Pessimism. While deduplication policies do exist within the ETL implementation, an attacker could meticulously request invariant deployments where deduplication would not occur for some time (eg. backfill from L1 genesis block). Eventually the machine running the Pessimism app would exhaust computation resources (ie. cpu, ram) to the point where the app could no longer function.Mitigation(s)
MAX_GO_ROUTINES
) ORMAX_PIPELINES
)ETL DAG & Pipeline Support
Fixes Issue
Closes https://github.com/base-org/pessimism/issues/7
Changes proposed
Added higher level component management abstractions for handling component connectivity, routing, and introspection:
manager
- Used for managing ETL pipelines and pipeline DAG for deploying new pipelines provided some higher order config.graph
- Used to for managing and representing ETL pipeline components as graph nodes.pipeline
- Used for storing pipeline metadata; i,e. components, ids, internal activity states.conduit
toetl
; seems more intuitive that way ;)Extended existing component level logic with constructs to better support component modularity and seamless inter-connectivity:
metaData
struct that's inherited by all component types to store component agnostic field dataingress
struct that tracks all component entrypoint(register_type-->channel)
information. Useful for algorithmic connectivity in pipeline DAG and supporting future multi-data source imports per a component. (i,e. https://github.com/base-org/pessimism/issues/12)Moved away from common
models
data package to more generalizedcore
module that stores subsystem (ETL, Risk Engine, API) agnostic constructs.Screenshots (Optional)
Next Steps
Changed `invariant` Abstraction to `Heuristic`
Fixes Issue
Fixes #
Changes proposed
The term
invariant
is rather unorthodox and difficult for people to reason about; especially provided that its a more formal mathematical term. Because of this, we have opted to use a more clean/concise abstraction. Internal conversations polled for the termHeuristic
to be used.Screenshots (Optional)
Note to reviewers
Refactored Invariant Registry & Added Fault Detector Implementation
Fixes Issues
Fixes #
Changes proposed
Screenshots (Optional)
Note to reviewers
Bump github.com/stretchr/testify from 1.8.2 to 1.8.4
Bumps github.com/stretchr/testify from 1.8.2 to 1.8.4.
Commits
f97607b
Create GitHub release when new release tag is pushed (#1354)4c93d8f
EqualExportedValues: Handle nested pointer, slice and map fields (#1379)4b2f4d2
add EventuallyWithT assertion (#1264)b3106d7
allow testing for functional options (#1023)437071b
assert: fix error message formatting for NotContains (#1362)c5fc9d6
Compare public elements of struct (#1309)Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase
.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebase
will rebase this PR@dependabot recreate
will recreate this PR, overwriting any edits that have been made to it@dependabot merge
will merge this PR after your CI passes on it@dependabot squash and merge
will squash and merge this PR after your CI passes on it@dependabot cancel merge
will cancel a previously requested merge and block automerging@dependabot reopen
will reopen this PR if it is closed@dependabot close
will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot ignore this major version
will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor version
will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependency
will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)[RFC] Native Bridge Supply Monitoring
Heuristic Description
A heuristic should exist that monitors for discrepancies between the locked ETH amount on the L1
OptimismPortal
and the unlocked amount on L2. This allows for deep introspection into the safety of the native bridge and allows chain operators to detect real-time anomalies.Consideration(s)
0x000
blackhole address or immobilizing it viaSELFDESTRUCT
operations that specify the calling contract as the beneficiary. This could result in potential discrepancies between the circulating supply on L2 and the locked supply on L1. Burns can also be trigged by anyone on theL2ToL1MessagePasser
contract to delete initiated withdrawal funds.Pseudocode
The following pseudocode demonstrates a high level implementation for how to compute different native bridge supplies on both L1 and L2. Additionally, it showcases a lightweight heuristic analysis example.
[RFC] Event/Transaction Frequency Heuristic
Heuristic Description
NOTE - Some the provided use cases could be redundant with existing telemetry that's already leveraged by OP Stack chain operators
Context
Some system contract events that emit from OP Stack contracts occur on semi-deterministic time intervals. The same applies to some protocol transactions as well. For example, proposer submission to the
L2OutputOracle
typically occur around every hour on Base (see Etherscan). If this event were to not occur on its expected interval and be missed, it could be indicative of potential sequencer/protocol liveness failures.Example Use Cases
Some further examples of other potential liveness failures that could be caught via this heuristic:
BatchInbox
is not being posted to by theop-batcher
OutputProposal
events fail to post to theL2OutputOracle
contract via theop-proposer
Technical Details
There should exist some calculation policies for how an event/transaction delta is computed that is configurable via the
heurisitc_params
; e.g:static
: Keep track of the last time a specific event(address,sig)
or transaction(to,from)
was emitted/executed. If the time delta from the last event goes above a user defined threshold, then alert. This is useful for monitoring frequencies that are expected to be constant (e.g, sequencer/batcher l1 submission times).dynamic
: Compute the moving average (MA
) ofn
prior time deltas for some(address,event)
or(to,from)
pair. After computingMA
, calculate thepercent_diff
betweenMA
and the most recent time delta. Ifpercent_diff
falls above some user defined threshold, then alert. This could be useful for monitoring repetitive events with differing frequencies based on entropic factors like user usage (e.g, bridging deposits, withdrawals).Additionally a
type
enum should supported that assumes eithertransaction
orcontract_event
.Bump github.com/libp2p/go-libp2p from 0.25.1 to 0.27.8
Bumps github.com/libp2p/go-libp2p from 0.25.1 to 0.27.8.
Release notes
Sourced from github.com/libp2p/go-libp2p's releases.
... (truncated)
Changelog
Sourced from github.com/libp2p/go-libp2p's changelog.
... (truncated)
Commits
8506ab2
release v0.27.869acf8b
swarm: don't open new streams over transient connections (#2450)b7ebfaa
manually bump qtls dependencies to fix RSA key size vulnerability0cce607
core/crypto: restrict RSA keys to <= 8192 bits (#2454)68ad5ea
Release v0.27.7 (#2374)2df518f
Release v0.27.6 (#2359)6dffa1a
Release v0.27.5 (#2324)fc89448
Bump version to v0.27.445d3c6f
identify: reject signed peer records on peer ID mismatch40978ee
swarm: change maps with multiaddress keys to use strings (#2284)Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase
.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebase
will rebase this PR@dependabot recreate
will recreate this PR, overwriting any edits that have been made to it@dependabot merge
will merge this PR after your CI passes on it@dependabot squash and merge
will squash and merge this PR after your CI passes on it@dependabot cancel merge
will cancel a previously requested merge and block automerging@dependabot reopen
will reopen this PR if it is closed@dependabot close
will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot show <dependency name> ignore conditions
will show all of the ignore conditions of the specified dependency@dependabot ignore this major version
will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor version
will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependency
will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the Security Alerts page.Configurable Alerting Definition
Problem
Currently, the severity routing configuration is hardcoded. While this works for some opinionated use cases, it fails to be generalized to many unique use cases. Additionally the service only supports integration with a single slack webhook and two pagerduty integration keys. Ideally, a user could have up to many slack webhooks and pager-duty services to alert.
Problem Solution
Support some alerting definition JSON that allows for severity routing definitions of multiple downstream dependencies for a severity. This will be a global definition that the application ingests and uses to understand where to alert.
This would look something like: