Skip to content

Commit

Permalink
Sinner (#1380)
Browse files Browse the repository at this point in the history
* init

* stashing at prev checkpoint to resolve build issues

* updating graphql

* live filling updates

* stash prev changes before tests

* update queries w/tests

* update api and cli

* stash before deploy

* api tests

* lint

* lint

* lint + gen

* code cov

* gen

* adding code cov

* lint + test + coderabbit suggestions

* symlink

* edits

* hold

* Update go.mod

* sinner docker + main.go

* sinner test flake, bytes -> hex string update, update assert use, lint

* update logging

* deprecate port flag

* updating fetch ceil

* adding concurrency during parse store

* add comments

* gen (stringer)

* add build to .goreleaser.yml

* build

* Revert "build" [goreleaser]

This reverts commit 8c61076.

* fix goreleaser [goreleaser]

* fix replacement issue

* [sinner] add start readme (#1499)

* add start readme

* fix https://github.com/synapsecns/sanguine/pull/1380/files#r1371810612

---------

Co-authored-by: Trajan0x <[email protected]>

* sinner strings for contract_type (#1498)

Co-authored-by: Trajan0x <[email protected]>

* trajan edits

* nits

* explorer update

* Sinner: resolvers and updating db read functions (#1514)

* init staging

* add more db read functions

* update model to where

* update filters

* hash

* Revert "hash"

This reverts commit 9b159df.

* remove unused db mocks

* handle invalid port

---------

Co-authored-by: Trajan0x <[email protected]>

* type fix

* simplify w generics

* add go error group to unified command + updated read.go

* code rabbit nit

* logger fix

* Parser, API, and config updates

* tests, sinner/indexer updates, db updates

* lint + refactor graphql + db

* Add log range asc to API

* [goreleaser]

* Update README.md

* refactor indexer

* exit 1 on fail

* update scribe fetcher and pagination behavior

* mysql context

* mysql + refresh rate

* update config and readme + [goreleaser]

* update tests

* typo + [goreleaser]

* prom exporter gen

* revert abi - [goreleaser]

* [goreleaser]

* specify varchar length for indexing [goreleaser]

* update 64 to 66 to account for 0x [goreleaser]

* update api

* [goreleaser]

* gen

* update comment

* [goreleaser]

* add asc flag

* [goroutine]

* [goreleaser]

---------

Co-authored-by: Trajan0x <[email protected]>
Co-authored-by: trajan0x <[email protected]>
  • Loading branch information
3 people authored Nov 2, 2023
1 parent 523dcbb commit 060df78
Show file tree
Hide file tree
Showing 97 changed files with 33,830 additions and 3 deletions.
4 changes: 4 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ flags:
paths:
- services/scribe/
carryforward: true
sinner:
paths:
- services/sinner/
carryforward: true
solidity:
paths:
- packages/contracts-core/
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ jobs:
fi
done
# Check if max retries is exceeded for this package.
if [ $retries -eq $max_num_retries ]; then
echo "Max retries exceeded for $pkg"
exit 1
fi
if [ -f profile.cov ]; then
tail -n +2 profile.cov >> coverage.txt
rm profile.cov
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,12 @@ root
│ ├── <a href="./packages/explorer-ui">explorer-ui</a>: Explorer UI
│ ├── <a href="./packages/sdk-router">sdk-router</a>: SDK router
│ ├── <a href="./packages/sdk-router">synapse-interface</a>: Synapse frontend code
├── <a href="./tools">services</a>
├── <a href="./services">services</a>
│ ├── <a href="./services/cctp-relayer">CCTP Relayer</a>: CCTP message relayer
│ ├── <a href="./services/explorer">explorer</a>: Bridge/messaging explorer backend
│ ├── <a href="./services/omnirpc">omnirpc</a>: Latency aware RPC Client used across multiple-chains at once
│ ├── <a href="./services/scribe">scribe</a>: Generalized ethereum event logger
│ ├── <a href="./services/omnirpc">omnirpc</a>: Latency aware RPC Client used across multiple-chains at once
│ ├── <a href="./services/sinner">sinner</a>: [Synapse Interchain Network](https://interchain.synapseprotocol.com/) indexer & query interface
├── <a href="./tools">tools</a>
│ ├── <a href="./tools/abigen">abigen</a>: Used to generate abigen bindings for go
│ ├── <a href="./tools/bundle">bundle</a>: Modified version of <a href="https://pkg.go.dev/golang.org/x/[email protected]/cmd/bundle"> go bundler </a> with improved shadowing support
Expand Down
15 changes: 15 additions & 0 deletions docker/sinner.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM gcr.io/distroless/static:latest

LABEL org.label-schema.description="Sinner Docker file"
LABEL org.label-schema.name="ghcr.io/synapsecns/sanguine/sinner"
LABEL org.label-schema.schema-version="1.0.0"
LABEL org.label-schema.vcs-url="https://github.com/synapsecns/sanguine"
LABEL org.opencontainers.image.source="https://github.com/synapsecns/sanguine"
LABEL org.opencontainers.image.description="Sinner Docker image"

USER nonroot:nonroot

WORKDIR /app
COPY --chown=nonroot:nonroot sinner /app/sinner

ENTRYPOINT ["/app/sinner"]
1 change: 1 addition & 0 deletions go.work
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ use (
./services/explorer
./services/omnirpc
./services/scribe
./services/sinner
./tools
)
1 change: 0 additions & 1 deletion services/scribe/db/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ func NewEventDBSuite(tb testing.TB) *DBSuite {

func (t *DBSuite) SetupTest() {
t.TestSuite.SetupTest()

t.logIndex.Store(0)

sqliteStore, err := sqlite.NewSqliteStore(t.GetTestContext(), filet.TmpDir(t.T(), ""), t.scribeMetrics, false)
Expand Down
87 changes: 87 additions & 0 deletions services/sinner/.goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
project_name: sinner

monorepo:
tag_prefix: services/sinner/
dir: services/sinner/

# for now, this is a library release
builds:
# Linux AMD64
- id: sinner
binary: sinner
ldflags:
# We need to build a static binary because we are building in a glibc based system and running in a musl container
- -s -w -extldflags "-static"
# required workaround for https://github.com/Shopify/sarama/issues/2206
# See: https://github.com/golang/go/issues/35067#issuecomment-544805311 because we're statically compiling,
# without forcing netgo, we use the cgo resolver which will not work for .local (a canonical tld in kubernetes)
# the other way to resolve this would be to modify the nsswitch.conf in the container, but that's a bit less clean.
# osusergo was included as a recommendation here: https://github.com/kubernetes/kubernetes/pull/114225#issuecomment-1348920040
tags:
- netgo
- osusergo
env:
- CC=gcc
- CXX=g++
main: main.go
goos:
- linux
goarch:
- amd64

# add a source archive at release time
source:
enabled: true

# Archives
archives:
- format: tar.gz
wrap_in_directory: true
format_overrides:
- goos: windows
format: zip
name_template: '{{.ProjectName}}-{{.Version}}_{{.Os}}_{{.Arch}}'
files:
- README.md

checksum:
name_template: checksums.txt

# Add a changelog
changelog:
sort: asc



dockers:
# Docker AMD64
- goos: linux
goarch: amd64
image_templates:
- 'ghcr.io/synapsecns/sanguine/sinner:latest'
- 'ghcr.io/synapsecns/sanguine/sinner:{{ .FullCommit }}'
- 'ghcr.io/synapsecns/sanguine/sinner:{{ .Tag }}'
build_flag_templates:
- '--label=org.opencontainers.image.created={{.Date}}'
- '--label=org.opencontainers.image.name={{.ProjectName}}'
- '--label=org.opencontainers.image.revision={{.FullCommit}}'
- '--label=org.opencontainers.image.version={{.Version}}'
- '--label=org.opencontainers.image.source={{.GitURL}}'
dockerfile: ../../docker/sinner.Dockerfile
ids:
- sinner

# track sizes
report_sizes: true

# modified timestamps
metadata:
# Set the modified timestamp on the metadata files.
#
# Templates: allowed.
mod_timestamp: '{{ .CommitTimestamp }}'

# produce software bill of lading
sboms:
- artifacts: archive

1 change: 1 addition & 0 deletions services/sinner/Makefile
109 changes: 109 additions & 0 deletions services/sinner/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Sinner
[![Go Reference](https://pkg.go.dev/badge/github.com/synapsecns/sanguine/services/sinner.svg)](https://pkg.go.dev/github.com/synapsecns/sanguine/services/sinner)
[![Go Report Card](https://goreportcard.com/badge/github.com/synapsecns/sanguine/services/sinner)](https://goreportcard.com/report/github.com/synapsecns/sanguine/services/sinner)

Sinner tracks the message lifecycle for the synapse interchain network.

## Scope

While this applications goal is to encompass the full range of events sent through SIN, the initial scope is much smaller & pragmatically focused on developers building on SIN & the developent of the off-chain protocols itself. To that end, at a high level the goal of the application is to track the message through the following stages. Completed types are contained in the table below:

## Config:

Example Indexer Config:

```yaml
default_refresh_rate: 1
scribe_url: "http://scribe.com/graphql"
db_path: "/tmp/a.db"
db_type: sqlite
skip_migrations: false
chains:
- chain_id: 444
contracts:
- address: "0x537ab51470984D6D9aDF8953C0D2ed8eDA4050ED"
start_block: 1
contract_type: origin
- address: "0xA944636Ac279e0346AF96Ef7e236025C6cBFE609"
start_block: 1
contract_type: execution_hub
- chain_id: 421614
contracts:
- address: "0x537ab51470984D6D9aDF8953C0D2ed8eDA4050ED"
start_block: 1
contract_type: origin
- address: "0xA944636Ac279e0346AF96Ef7e236025C6cBFE609"
start_block: 1
contract_type: execution_hub
- chain_id: 11155111
contracts:
- address: "0x537ab51470984D6D9aDF8953C0D2ed8eDA4050ED"
start_block: 1
contract_type: origin
- address: "0xA944636Ac279e0346AF96Ef7e236025C6cBFE609"
start_block: 1
contract_type: execution_hub
```
Example Server Config
```yaml
http_port: 8080
db_path: "/tmp/a.db"
db_type: sqlite
skip_migrations: true
```
If running the `unified` command, the config will be a combination of the above two configs (simply add the `http_port` to the top of your indexer config).
### **Message Stages**

1. [x] Message sent on origin chain.
2. [ ] At least one Guard submitted the snapshot for the origin chain taken after the message was sent.
3. [ ] At least one Notary submitted the snapshot for the origin chain taken after the message was sent.
4. [ ] Attestation created from any of the (3) snapshots was submitted to the destination chain.
5. [ ] Optimistic period for the message has passed (awaiting the execution).
6. [ ] An Executor tried to execute the message, but the destination app reverted (awaiting the retry).
7. [x] An Executor successfully executed the message.


### **Tracked Events & States**

_Note: the above only reflects progress in tracking message states in Sinner, not the agents_

1. [x] `Origin` on origin chain emits an event for every sent message.
* `event Sent(bytes32 indexed messageHash, uint32 indexed nonce, uint32 indexed destination, bytes message);`
2. [ ] `Summit` on Synapse Chain emits an event for every state in the Guard snapshot that was submitted.
* `event StateSaved(bytes state);`
* We are interested in the states that have:
* Origin domain matching the origin domain of the message.
* Nonce higher or equal as the nonce of the message.
3. [ ] `Inbox` on Synapse Chain emits an event for every snapshot that was submitted (both Guard and Notary).
* `event SnapshotAccepted(uint32 indexed domain, address indexed agent, bytes snapPayload, bytes snapSignature)`
* We are only interested in Notary snapshots, so `domain != 0`.
* Notary domain could be different from the origin domain of the message, that's fine.
* [ ] `snapPayload` is a concatenation of encoded states. We are interested in the states that have:
* Origin domain matching the origin domain of the message.
* Nonce higher or equal as the nonce of the message.
* [ ] In the same transaction <code>Summit</code> emits an event with the created attestation: - <code>event AttestationSaved(bytes attestation);</code>

In other words, the submitted Guard/Notary snapshot "enables" messages coming from the set of origin domains (matching the domains of the states) with nonce less or equal to the nonce of the submitted state for the origin domain.

4. `LightInbox` on the destination chain emits an event for every submitted attestation.
* [ ] `event AttestationAccepted(uint32 domain, address notary, bytes attPayload, bytes attSignature);`
* [ ] We are only interested in the attestation with payload matching any of the attestations from (3).
* [ ] Optimistic period for the message starts when the first suitable attestation is submitted.
5. This could be tracked by checking the timestamp of the last mined destination block, no events needed.
6. `Destination` emits the event whenever an Executor tries to execute the message.
* [ ] `event Executed(uint32 indexed remoteDomain, bytes32 indexed messageHash, bool success);`
* [ ] We are only interested in the events that have:
* `remoteDomain` matching the origin domain of the message.
* `messageHash` matching the hash of the message (emitted in (1)).
* `success` equal to `false`.
* [ ] These "failed" messages could be later retried by any Executor.
7. [x] `Destination` emits the event whenever an Executor successfully executes the message.
* `event Executed(uint32 indexed remoteDomain, bytes32 indexed messageHash, bool success);`
* We are only interested in the events that have:
* `remoteDomain` matching the origin domain of the message.
* `messageHash` matching the hash of the message (emitted in (1)).
* `success` equal to `true`.
* [ ] The executed message could not be retried anymore.
2 changes: 2 additions & 0 deletions services/sinner/api/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package api contains the api used by sinner
package api
110 changes: 110 additions & 0 deletions services/sinner/api/resolver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package api_test

import (
"github.com/brianvoe/gofakeit/v6"
"github.com/ethereum/go-ethereum/common"
. "github.com/stretchr/testify/assert"
"github.com/synapsecns/sanguine/core"
"github.com/synapsecns/sanguine/services/sinner/db/model"
graphqlModel "github.com/synapsecns/sanguine/services/sinner/graphql/server/graph/model"
"github.com/synapsecns/sanguine/services/sinner/types"
"math/big"
)

//nolint:cyclop
func (t *APISuite) TestGetOrigin() {
chainID := gofakeit.Uint32()
txHash := common.BigToHash(big.NewInt(gofakeit.Int64())).String()
messageHash := common.BigToHash(big.NewInt(gofakeit.Int64())).String()

originSent := &model.OriginSent{
ContractAddress: common.BigToAddress(big.NewInt(gofakeit.Int64())).String(),
BlockNumber: gofakeit.Uint64(),
TxHash: txHash,
MessageHash: messageHash,
ChainID: chainID,
}

err := t.db.StoreOriginSent(t.GetTestContext(), originSent)
Nil(t.T(), err)

result, err := t.sinnerAPI.GetOriginInfo(t.GetTestContext(), core.PtrTo(messageHash), nil, nil)
Nil(t.T(), err)
NotNil(t.T(), result)
Equal(t.T(), txHash, *result.Response[0].OriginTxHash)

results, err := t.sinnerAPI.GetOriginInfo(t.GetTestContext(), nil, core.PtrTo(int(chainID)), core.PtrTo(txHash))
Nil(t.T(), err)
NotNil(t.T(), results)
Equal(t.T(), txHash, *results.Response[0].OriginTxHash)
}

func (t *APISuite) TestGetExecuted() {
chainID := gofakeit.Uint32()
txHash := common.BigToHash(big.NewInt(gofakeit.Int64())).String()
messageHash := common.BigToHash(big.NewInt(gofakeit.Int64())).String()

executed := &model.Executed{
ContractAddress: common.BigToAddress(big.NewInt(gofakeit.Int64())).String(),
BlockNumber: gofakeit.Uint64(),
TxHash: txHash,
MessageHash: messageHash,
ChainID: chainID,
RemoteDomain: gofakeit.Uint32(),
Success: gofakeit.Bool(),
}

err := t.db.StoreExecuted(t.GetTestContext(), executed)
Nil(t.T(), err)

result, err := t.sinnerAPI.GetDestinationInfo(t.GetTestContext(), core.PtrTo(messageHash), nil, nil)
Nil(t.T(), err)
NotNil(t.T(), result)
Equal(t.T(), txHash, *result.Response[0].TxHash)

results, err := t.sinnerAPI.GetDestinationInfo(t.GetTestContext(), nil, core.PtrTo(int(chainID)), core.PtrTo(txHash))
Nil(t.T(), err)
NotNil(t.T(), results)
Equal(t.T(), txHash, *results.Response[0].TxHash)
}

func (t *APISuite) TestMessageStatus() {
txHash := common.BigToHash(big.NewInt(gofakeit.Int64())).String()
desTxHash := common.BigToHash(big.NewInt(gofakeit.Int64())).String()
messageHash := common.BigToHash(big.NewInt(gofakeit.Int64())).String()

err := t.db.StoreOrUpdateMessageStatus(t.GetTestContext(), txHash, messageHash, types.Origin)
Nil(t.T(), err)

result, err := t.sinnerAPI.GetMessageStatus(t.GetTestContext(), core.PtrTo(messageHash), nil, nil)
Nil(t.T(), err)
NotNil(t.T(), result)
Equal(t.T(), txHash, *result.Response.OriginTxHash)
Equal(t.T(), graphqlModel.MessageStateLastSeenOrigin, *result.Response.LastSeen)

// Add destination
err = t.db.StoreOrUpdateMessageStatus(t.GetTestContext(), desTxHash, messageHash, types.Destination)
Nil(t.T(), err)

desResult, err := t.sinnerAPI.GetMessageStatus(t.GetTestContext(), core.PtrTo(messageHash), nil, nil)
Nil(t.T(), err)
NotNil(t.T(), desResult)
Equal(t.T(), desTxHash, *desResult.Response.DestinationTxHash)
Equal(t.T(), graphqlModel.MessageStateLastSeenDestination, *desResult.Response.LastSeen)

// Test query by origin tx hash
originSent := &model.OriginSent{
ContractAddress: common.BigToAddress(big.NewInt(gofakeit.Int64())).String(),
BlockNumber: gofakeit.Uint64(),
TxHash: txHash,
MessageHash: messageHash,
ChainID: gofakeit.Uint32(),
}
err = t.db.StoreOriginSent(t.GetTestContext(), originSent)
Nil(t.T(), err)
desResult, err = t.sinnerAPI.GetMessageStatus(t.GetTestContext(), nil, core.PtrTo(int(originSent.ChainID)), core.PtrTo(originSent.TxHash))
Nil(t.T(), err)
NotNil(t.T(), desResult)
Equal(t.T(), desTxHash, *desResult.Response.DestinationTxHash)
Equal(t.T(), graphqlModel.MessageStateLastSeenDestination, *desResult.Response.LastSeen)
}
Loading

0 comments on commit 060df78

Please sign in to comment.