diff --git a/rolling-shutter/cmd/command.go b/rolling-shutter/cmd/command.go index 8d40c8b28..1b66d53ad 100644 --- a/rolling-shutter/cmd/command.go +++ b/rolling-shutter/cmd/command.go @@ -10,6 +10,7 @@ import ( "github.com/shutter-network/rolling-shutter/rolling-shutter/cmd/gnosiskeyper" "github.com/shutter-network/rolling-shutter/rolling-shutter/cmd/optimism" "github.com/shutter-network/rolling-shutter/rolling-shutter/cmd/p2pnode" + "github.com/shutter-network/rolling-shutter/rolling-shutter/cmd/primevkeyper" "github.com/shutter-network/rolling-shutter/rolling-shutter/cmd/shutterservicekeyper" "github.com/shutter-network/rolling-shutter/rolling-shutter/cmd/snapshot" "github.com/shutter-network/rolling-shutter/rolling-shutter/cmd/snapshotkeyper" @@ -29,6 +30,7 @@ func Subcommands() []*cobra.Command { cryptocmd.Cmd(), p2pnode.Cmd(), shutterservicekeyper.Cmd(), + primevkeyper.Cmd(), } } diff --git a/rolling-shutter/cmd/primevkeyper/keyper.go b/rolling-shutter/cmd/primevkeyper/keyper.go new file mode 100644 index 000000000..eea90084d --- /dev/null +++ b/rolling-shutter/cmd/primevkeyper/keyper.go @@ -0,0 +1,53 @@ +package primevkeyper + +import ( + "context" + + "github.com/jackc/pgx/v4/pgxpool" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" + "github.com/spf13/cobra" + + "github.com/shutter-network/rolling-shutter/rolling-shutter/cmd/shversion" + keyper "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/primev" + "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/primev/database" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/configuration/command" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/db" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/service" +) + +func Cmd() *cobra.Command { + builder := command.Build( + main, + command.Usage( + "Run a Shutter keyper for PrimeV POC", + `This command runs a keyper node. It will connect to both a PrimeV and a +Shuttermint node which have to be started separately in advance.`, + ), + command.WithGenerateConfigSubcommand(), + command.WithDumpConfigSubcommand(), + ) + builder.AddInitDBCommand(initDB) + return builder.Command() +} + +func main(config *keyper.Config) error { + log.Info(). + Str("version", shversion.Version()). + Str("address", config.GetAddress().Hex()). + Str("shuttermint", config.Shuttermint.ShuttermintURL). + Msg("starting primev keyper") + + kpr := keyper.New(config) + return service.RunWithSighandler(context.Background(), kpr) +} + +func initDB(cfg *keyper.Config) error { + ctx := context.Background() + dbpool, err := pgxpool.Connect(ctx, cfg.DatabaseURL) + if err != nil { + return errors.Wrap(err, "failed to connect to database") + } + defer dbpool.Close() + return db.InitDB(ctx, dbpool, database.Definition.Name(), database.Definition) +} diff --git a/rolling-shutter/docs/rolling-shutter.md b/rolling-shutter/docs/rolling-shutter.md index 4f7fd30f6..1f1a4d858 100644 --- a/rolling-shutter/docs/rolling-shutter.md +++ b/rolling-shutter/docs/rolling-shutter.md @@ -21,6 +21,7 @@ A collection of commands to run and interact with Rolling Shutter nodes * [rolling-shutter op-bootstrap](rolling-shutter_op-bootstrap.md) - Bootstrap validator utility functions for a shuttermint chain * [rolling-shutter op-keyper](rolling-shutter_op-keyper.md) - Run a Shutter optimism keyper node * [rolling-shutter p2pnode](rolling-shutter_p2pnode.md) - Run a Shutter p2p bootstrap node +* [rolling-shutter primevkeyper](rolling-shutter_primevkeyper.md) - Run a Shutter keyper for PrimeV POC * [rolling-shutter shutterservicekeyper](rolling-shutter_shutterservicekeyper.md) - Run a Shutter keyper for Shutter Service * [rolling-shutter snapshot](rolling-shutter_snapshot.md) - Run the Snapshot Hub communication module * [rolling-shutter snapshotkeyper](rolling-shutter_snapshotkeyper.md) - Run a Shutter snapshotkeyper node diff --git a/rolling-shutter/docs/rolling-shutter_primevkeyper.md b/rolling-shutter/docs/rolling-shutter_primevkeyper.md new file mode 100644 index 000000000..ab30b4ded --- /dev/null +++ b/rolling-shutter/docs/rolling-shutter_primevkeyper.md @@ -0,0 +1,35 @@ +## rolling-shutter primevkeyper + +Run a Shutter keyper for PrimeV POC + +### Synopsis + +This command runs a keyper node. It will connect to both a PrimeV and a +Shuttermint node which have to be started separately in advance. + +``` +rolling-shutter primevkeyper [flags] +``` + +### Options + +``` + --config string config file + -h, --help help for primevkeyper +``` + +### Options inherited from parent commands + +``` + --logformat string set log format, possible values: min, short, long, max (default "long") + --loglevel string set log level, possible values: warn, info, debug (default "info") + --no-color do not write colored logs +``` + +### SEE ALSO + +* [rolling-shutter](rolling-shutter.md) - A collection of commands to run and interact with Rolling Shutter nodes +* [rolling-shutter primevkeyper dump-config](rolling-shutter_primevkeyper_dump-config.md) - Dump a 'primevkeyper' configuration file, based on given config and env vars +* [rolling-shutter primevkeyper generate-config](rolling-shutter_primevkeyper_generate-config.md) - Generate a 'primevkeyper' configuration file +* [rolling-shutter primevkeyper initdb](rolling-shutter_primevkeyper_initdb.md) - Initialize the database of the 'primevkeyper' + diff --git a/rolling-shutter/docs/rolling-shutter_primevkeyper_dump-config.md b/rolling-shutter/docs/rolling-shutter_primevkeyper_dump-config.md new file mode 100644 index 000000000..b9253f446 --- /dev/null +++ b/rolling-shutter/docs/rolling-shutter_primevkeyper_dump-config.md @@ -0,0 +1,29 @@ +## rolling-shutter primevkeyper dump-config + +Dump a 'primevkeyper' configuration file, based on given config and env vars + +``` +rolling-shutter primevkeyper dump-config [flags] +``` + +### Options + +``` + --config string config file + -f, --force overwrite existing file + -h, --help help for dump-config + --output string output file +``` + +### Options inherited from parent commands + +``` + --logformat string set log format, possible values: min, short, long, max (default "long") + --loglevel string set log level, possible values: warn, info, debug (default "info") + --no-color do not write colored logs +``` + +### SEE ALSO + +* [rolling-shutter primevkeyper](rolling-shutter_primevkeyper.md) - Run a Shutter keyper for PrimeV POC + diff --git a/rolling-shutter/docs/rolling-shutter_primevkeyper_generate-config.md b/rolling-shutter/docs/rolling-shutter_primevkeyper_generate-config.md new file mode 100644 index 000000000..f52b9a1b1 --- /dev/null +++ b/rolling-shutter/docs/rolling-shutter_primevkeyper_generate-config.md @@ -0,0 +1,29 @@ +## rolling-shutter primevkeyper generate-config + +Generate a 'primevkeyper' configuration file + +``` +rolling-shutter primevkeyper generate-config [flags] +``` + +### Options + +``` + -f, --force overwrite existing file + -h, --help help for generate-config + --output string output file +``` + +### Options inherited from parent commands + +``` + --config string config file + --logformat string set log format, possible values: min, short, long, max (default "long") + --loglevel string set log level, possible values: warn, info, debug (default "info") + --no-color do not write colored logs +``` + +### SEE ALSO + +* [rolling-shutter primevkeyper](rolling-shutter_primevkeyper.md) - Run a Shutter keyper for PrimeV POC + diff --git a/rolling-shutter/docs/rolling-shutter_primevkeyper_initdb.md b/rolling-shutter/docs/rolling-shutter_primevkeyper_initdb.md new file mode 100644 index 000000000..50907a265 --- /dev/null +++ b/rolling-shutter/docs/rolling-shutter_primevkeyper_initdb.md @@ -0,0 +1,27 @@ +## rolling-shutter primevkeyper initdb + +Initialize the database of the 'primevkeyper' + +``` +rolling-shutter primevkeyper initdb [flags] +``` + +### Options + +``` + -h, --help help for initdb +``` + +### Options inherited from parent commands + +``` + --config string config file + --logformat string set log format, possible values: min, short, long, max (default "long") + --loglevel string set log level, possible values: warn, info, debug (default "info") + --no-color do not write colored logs +``` + +### SEE ALSO + +* [rolling-shutter primevkeyper](rolling-shutter_primevkeyper.md) - Run a Shutter keyper for PrimeV POC + diff --git a/rolling-shutter/go.mod b/rolling-shutter/go.mod index 2291b98c4..eb34adb6d 100644 --- a/rolling-shutter/go.mod +++ b/rolling-shutter/go.mod @@ -10,7 +10,7 @@ require ( github.com/bitwurx/jrpc2 v0.0.0-20220302204700-52c6dbbeb536 github.com/deckarep/golang-set/v2 v2.6.0 github.com/deepmap/oapi-codegen v1.9.1 - github.com/ethereum/go-ethereum v1.15.7 + github.com/ethereum/go-ethereum v1.15.11 github.com/ferranbt/fastssz v0.1.3 github.com/getkin/kin-openapi v0.87.0 github.com/go-chi/chi/v5 v5.0.10 @@ -30,6 +30,7 @@ require ( github.com/oapi-codegen/runtime v1.1.1 github.com/pelletier/go-toml/v2 v2.1.0 github.com/pkg/errors v0.9.1 + github.com/primev/mev-commit/contracts-abi v0.0.0-20250922193515-6d402958637d github.com/prometheus/client_golang v1.22.0 github.com/rs/zerolog v1.28.0 github.com/shutter-network/contracts/v2 v2.0.0-beta.2.0.20250908105003-7e53b1579b04 @@ -59,25 +60,24 @@ require ( ) require ( - github.com/DataDog/zstd v1.5.2 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.17.0 // indirect + github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/consensys/bavard v0.1.22 // indirect - github.com/consensys/gnark-crypto v0.14.0 // indirect + github.com/consensys/bavard v0.1.27 // indirect + github.com/consensys/gnark-crypto v0.16.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/gogoproto v1.4.1 // indirect github.com/cosmos/gorocksdb v1.2.0 // indirect + github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect - github.com/crate-crypto/go-kzg-4844 v1.1.0 // indirect github.com/creachadair/taskgroup v0.3.2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect @@ -86,7 +86,7 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/elastic/gosigar v0.14.3 // indirect - github.com/ethereum/c-kzg-4844 v1.0.0 // indirect + github.com/ethereum/c-kzg-4844/v2 v2.1.0 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect @@ -158,7 +158,6 @@ require ( github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect github.com/miekg/dns v1.1.66 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect @@ -201,7 +200,7 @@ require ( github.com/pion/transport/v3 v3.0.7 // indirect github.com/pion/turn/v4 v4.0.0 // indirect github.com/pion/webrtc/v4 v4.0.10 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polydawn/refmt v0.89.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.63.0 // indirect @@ -211,7 +210,6 @@ require ( github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect - github.com/rivo/uniseg v0.4.3 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/rs/cors v1.9.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect @@ -222,8 +220,8 @@ require ( github.com/subosito/gotenv v1.4.2 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect github.com/tendermint/tm-db v0.6.7 // indirect - github.com/tklauser/go-sysconf v0.3.12 // indirect - github.com/tklauser/numcpus v0.6.1 // indirect + github.com/tklauser/go-sysconf v0.3.13 // indirect + github.com/tklauser/numcpus v0.7.0 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/wlynxg/anet v0.0.5 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect diff --git a/rolling-shutter/go.sum b/rolling-shutter/go.sum index aef9d6b10..d32151b08 100644 --- a/rolling-shutter/go.sum +++ b/rolling-shutter/go.sum @@ -51,8 +51,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= -github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= -github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= @@ -77,8 +77,8 @@ github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.17.0 h1:1X2TS7aHz1ELcC0yU1y2stUs/0ig5oMU6STFZGrhvHI= -github.com/bits-and-blooms/bitset v1.17.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= +github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= @@ -110,8 +110,8 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a h1:f52TdbU4D5nozMAhO9TvTJ2ZMCXtN4VIAmfrrZ0JXQ4= +github.com/cockroachdb/fifo v0.0.0-20240616162244-4768e80dfb9a/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= @@ -120,10 +120,10 @@ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwP github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= -github.com/consensys/bavard v0.1.22 h1:Uw2CGvbXSZWhqK59X0VG/zOjpTFuOMcPLStrp1ihI0A= -github.com/consensys/bavard v0.1.22/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= -github.com/consensys/gnark-crypto v0.14.0 h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E= -github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCeWHHrb1li/n1XoU0= +github.com/consensys/bavard v0.1.27 h1:j6hKUrGAy/H+gpNrpLU3I26n1yc+VMGmd6ID5+gAhOs= +github.com/consensys/bavard v0.1.27/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= +github.com/consensys/gnark-crypto v0.16.0 h1:8Dl4eYmUWK9WmlP1Bj6je688gBRJCJbT8Mw4KoTAawo= +github.com/consensys/gnark-crypto v0.16.0/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= @@ -152,6 +152,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-eth-kzg v1.3.0 h1:05GrhASN9kDAidaFJOda6A4BEvgvuXbazXg/0E3OOdI= +github.com/crate-crypto/go-eth-kzg v1.3.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= @@ -162,8 +164,9 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= @@ -201,10 +204,10 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= -github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.15.7 h1:vm1XXruZVnqtODBgqFaTclzP0xAvCvQIDKyFNUA1JpY= -github.com/ethereum/go-ethereum v1.15.7/go.mod h1:+S9k+jFzlyVTNcYGvqFhzN/SFhI6vA+aOY4T5tLSPL0= +github.com/ethereum/c-kzg-4844/v2 v2.1.0 h1:gQropX9YFBhl3g4HYhwE70zq3IHFRgbbNPw0Shwzf5w= +github.com/ethereum/c-kzg-4844/v2 v2.1.0/go.mod h1:TC48kOKjJKPbN7C++qIgt0TJzZ70QznYR7Ob+WXl57E= +github.com/ethereum/go-ethereum v1.15.11 h1:JK73WKeu0WC0O1eyX+mdQAVHUV+UR1a9VB/domDngBU= +github.com/ethereum/go-ethereum v1.15.11/go.mod h1:mf8YiHIb0GR4x4TipcvBUPxJLw1mFdmxzoDi11sDRoI= github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= @@ -233,8 +236,8 @@ github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8x github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.87.0 h1:eeb0WBIgRiXra7ZY0Vo+jWloqvaF2kNEaxAyb+39N+E= github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= -github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k= +github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -630,8 +633,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= @@ -792,10 +795,13 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4= github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw= +github.com/primev/mev-commit/contracts-abi v0.0.0-20250922193515-6d402958637d h1:41CGwNFiG8IIwviQoVu4mMUMDbkE/q3C07vakBACxzg= +github.com/primev/mev-commit/contracts-abi v0.0.0-20250922193515-6d402958637d/go.mod h1:m1vHlJXZuPOja6j93QBz28T9HvjFAefG7QBPuXQLTcU= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= @@ -819,9 +825,8 @@ github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtB github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= -github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= @@ -948,10 +953,10 @@ github.com/tendermint/tendermint v0.37.0-rc2 h1:2n1em+jfbhSv6QnBj8F6KHCpbIzZCB8K github.com/tendermint/tendermint v0.37.0-rc2/go.mod h1:uYQO9DRNPeZROa9X3hJOZpYcVREDC2/HST+EiU5g2+A= github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8= github.com/tendermint/tm-db v0.6.7/go.mod h1:byQDzFkZV1syXr/ReXS808NxA2xvyuuVgXOJ/088L6I= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= +github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= +github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= +github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= diff --git a/rolling-shutter/keyper/kprtopics/kprtopics.go b/rolling-shutter/keyper/kprtopics/kprtopics.go index bfe3c6296..93ed0f1e6 100644 --- a/rolling-shutter/keyper/kprtopics/kprtopics.go +++ b/rolling-shutter/keyper/kprtopics/kprtopics.go @@ -5,4 +5,5 @@ const ( DecryptionKeys = "decryptionKeys" DecryptionKeyShares = "decryptionKeyShares" EonPublicKey = "EonPublicKey" + PrimevCommitment = "primevCommitment" ) diff --git a/rolling-shutter/keyperimpl/primev/config.go b/rolling-shutter/keyperimpl/primev/config.go new file mode 100644 index 000000000..ce322d788 --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/config.go @@ -0,0 +1,190 @@ +package primev + +import ( + "io" + + "github.com/ethereum/go-ethereum/common" + + "github.com/shutter-network/rolling-shutter/rolling-shutter/keyper/kprconfig" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/configuration" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/metricsserver" + "github.com/shutter-network/rolling-shutter/rolling-shutter/p2p" +) + +type Config struct { + InstanceID uint64 `shconfig:",required"` + DatabaseURL string `shconfig:",required" comment:"If it's empty, we use the standard PG_ environment variables"` + + HTTPListenAddress string + + Primev *PrimevConfig + + Chain *ChainConfig + P2P *p2p.Config + Shuttermint *kprconfig.ShuttermintConfig + Metrics *metricsserver.MetricsConfig + + MaxNumKeysPerMessage uint64 +} + +func NewConfig() *Config { + c := &Config{} + c.Init() + return c +} + +func (c *Config) Init() { + c.P2P = p2p.NewConfig() + c.Primev = NewPrimevConfig() + c.Shuttermint = kprconfig.NewShuttermintConfig() + c.Chain = NewChainConfig() + c.Metrics = metricsserver.NewConfig() +} + +func (c *Config) Validate() error { + // TODO: needs to be implemented + return nil +} + +func (c *Config) Name() string { + return "primevkeyper" +} + +func (c *Config) SetDefaultValues() error { + c.MaxNumKeysPerMessage = 500 + c.HTTPListenAddress = ":3000" + return nil +} + +func (c *Config) SetExampleValues() error { + err := c.SetDefaultValues() + if err != nil { + return err + } + c.InstanceID = 42 + c.DatabaseURL = "postgres://pguser:pgpassword@localhost:5432/shutter" + return nil +} + +func (c Config) TOMLWriteHeader(_ io.Writer) (int, error) { + return 0, nil +} + +func (c *Config) GetAddress() common.Address { + return c.Chain.Node.PrivateKey.EthereumAddress() +} + +type PrimevConfig struct { + SyncStartBlockNumber uint64 `shconfig:",required"` + SyncMonitorCheckInterval uint64 `shconfig:",required"` + PrimevRPC string `shconfig:",required"` + ProviderRegistryContract common.Address `shconfig:",required"` +} + +func NewPrimevConfig() *PrimevConfig { + c := &PrimevConfig{} + c.Init() + return c +} + +func (c *PrimevConfig) Init() { + c.SyncStartBlockNumber = 0 + c.SyncMonitorCheckInterval = 30 + c.ProviderRegistryContract = common.Address{} +} + +func (c *PrimevConfig) Name() string { + return "primev" +} + +func (c *PrimevConfig) Validate() error { + return nil +} + +func (c *PrimevConfig) SetDefaultValues() error { //nolint:unparam + c.SyncMonitorCheckInterval = 30 + c.ProviderRegistryContract = common.Address{} + c.SyncStartBlockNumber = 0 + return nil +} + +func (c *PrimevConfig) SetExampleValues() error { //nolint:unparam + c.SyncMonitorCheckInterval = 30 + c.PrimevRPC = "wss://chainrpc-wss.testnet.mev-commit.xyz" + c.ProviderRegistryContract = common.Address{} + c.SyncStartBlockNumber = 0 + return nil +} + +type ChainConfig struct { + Node *configuration.EthnodeConfig `shconfig:",required"` + Contracts *ContractsConfig `shconfig:",required"` +} + +func NewChainConfig() *ChainConfig { + c := &ChainConfig{ + Node: configuration.NewEthnodeConfig(), + Contracts: NewContractsConfig(), + } + c.Init() + return c +} + +func (c *ChainConfig) Init() { + c.Node.Init() + c.Contracts.Init() +} + +func (c *ChainConfig) Name() string { + return "chain" +} + +func (c *ChainConfig) Validate() error { + return nil +} + +func (c *ChainConfig) SetDefaultValues() error { + return c.Contracts.SetDefaultValues() +} + +func (c *ChainConfig) SetExampleValues() error { + return nil +} + +func (c *ChainConfig) TOMLWriteHeader(_ io.Writer) (int, error) { + return 0, nil +} + +type ContractsConfig struct { + KeyperSetManager common.Address `shconfig:",required"` + KeyBroadcastContract common.Address `shconfig:",required"` +} + +func NewContractsConfig() *ContractsConfig { + return &ContractsConfig{ + KeyperSetManager: common.Address{}, + KeyBroadcastContract: common.Address{}, + } +} + +func (c *ContractsConfig) Init() {} + +func (c *ContractsConfig) Name() string { + return "contracts" +} + +func (c *ContractsConfig) Validate() error { + return nil +} + +func (c *ContractsConfig) SetDefaultValues() error { + return nil +} + +func (c *ContractsConfig) SetExampleValues() error { + return nil +} + +func (c *ContractsConfig) TOMLWriteHeader(_ io.Writer) (int, error) { + return 0, nil +} diff --git a/rolling-shutter/keyperimpl/primev/database/db.sqlc.gen.go b/rolling-shutter/keyperimpl/primev/database/db.sqlc.gen.go new file mode 100644 index 000000000..4aa2bf022 --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/database/db.sqlc.gen.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.28.0 + +package database + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/rolling-shutter/keyperimpl/primev/database/definition.go b/rolling-shutter/keyperimpl/primev/database/definition.go new file mode 100644 index 000000000..d6c9516f2 --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/database/definition.go @@ -0,0 +1,29 @@ +package database + +import ( + "embed" + + "github.com/rs/zerolog/log" + + "github.com/shutter-network/rolling-shutter/rolling-shutter/keyper/database" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/db" +) + +//go:generate sqlc generate --file sql/sqlc.yaml + +//go:embed sql +var files embed.FS + +var Definition db.Definition + +func init() { + def, err := db.NewSQLCDefinition(files, "sql/", "primevkeyper") + if err != nil { + log.Fatal().Err(err).Msg("failed to initialize DB metadata") + } + Definition = db.NewAggregateDefinition( + "primevkeyper", + def, + database.Definition, + ) +} diff --git a/rolling-shutter/keyperimpl/primev/database/models.sqlc.gen.go b/rolling-shutter/keyperimpl/primev/database/models.sqlc.gen.go new file mode 100644 index 000000000..5f06346bb --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/database/models.sqlc.gen.go @@ -0,0 +1,41 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.28.0 + +package database + +type Commitment struct { + TxHashes []string + ProviderAddress string + CommitmentSignature string + CommitmentDigest string + BlockNumber int64 + ReceivedBidDigest string + ReceivedBidSignature string + BidderNodeAddress string +} + +type CommittedTransaction struct { + Eon int64 + IdentityPrefix string + IdentityPreimage string + BlockNumber int64 + TxHash string + CommitmentDigest string + ProviderAddress string +} + +type ProviderRegistryEvent struct { + BlockNumber int64 + BlockHash []byte + TxIndex int64 + LogIndex int64 + ProviderAddress string + BlsKeys [][]byte +} + +type ProviderRegistryEventsSyncedUntil struct { + EnforceOneRow bool + BlockHash []byte + BlockNumber int64 +} diff --git a/rolling-shutter/keyperimpl/primev/database/primev.sqlc.gen.go b/rolling-shutter/keyperimpl/primev/database/primev.sqlc.gen.go new file mode 100644 index 000000000..4d4e8b41e --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/database/primev.sqlc.gen.go @@ -0,0 +1,193 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.28.0 +// source: primev.sql + +package database + +import ( + "context" + + "github.com/jackc/pgconn" +) + +const deleteProviderRegistryEventsFromBlockNumber = `-- name: DeleteProviderRegistryEventsFromBlockNumber :exec +DELETE FROM provider_registry_events WHERE block_number >= $1 +` + +func (q *Queries) DeleteProviderRegistryEventsFromBlockNumber(ctx context.Context, blockNumber int64) error { + _, err := q.db.Exec(ctx, deleteProviderRegistryEventsFromBlockNumber, blockNumber) + return err +} + +const getCommitmentByTxHash = `-- name: GetCommitmentByTxHash :many +SELECT + c.tx_hashes, + c.provider_address, + c.commitment_signature, + c.commitment_digest, + c.block_number, + c.received_bid_digest, + c.received_bid_signature, + c.bidder_node_address +FROM commitment c +WHERE $1 = ANY(c.tx_hashes) +` + +func (q *Queries) GetCommitmentByTxHash(ctx context.Context, txHashes []string) ([]Commitment, error) { + rows, err := q.db.Query(ctx, getCommitmentByTxHash, txHashes) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Commitment + for rows.Next() { + var i Commitment + if err := rows.Scan( + &i.TxHashes, + &i.ProviderAddress, + &i.CommitmentSignature, + &i.CommitmentDigest, + &i.BlockNumber, + &i.ReceivedBidDigest, + &i.ReceivedBidSignature, + &i.BidderNodeAddress, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getProviderRegistryEventsSyncedUntil = `-- name: GetProviderRegistryEventsSyncedUntil :one +SELECT enforce_one_row, block_hash, block_number FROM provider_registry_events_synced_until LIMIT 1 +` + +func (q *Queries) GetProviderRegistryEventsSyncedUntil(ctx context.Context) (ProviderRegistryEventsSyncedUntil, error) { + row := q.db.QueryRow(ctx, getProviderRegistryEventsSyncedUntil) + var i ProviderRegistryEventsSyncedUntil + err := row.Scan(&i.EnforceOneRow, &i.BlockHash, &i.BlockNumber) + return i, err +} + +const insertMultipleTransactionsAndUpsertCommitment = `-- name: InsertMultipleTransactionsAndUpsertCommitment :exec +WITH inserted_transactions AS ( + INSERT INTO committed_transactions (eon, identity_preimage, identity_prefix, block_number, tx_hash, commitment_digest, provider_address) + SELECT + unnest($1::bigint[]) as eon, + unnest($2::text[]) as identity_preimage, + unnest($3::text[]) as identity_prefix, + unnest($4::bigint[]) as block_number, + unnest($5::text[]) as tx_hash, + $6, + $7 + ON CONFLICT (eon, identity_preimage, tx_hash, block_number) + DO NOTHING + RETURNING tx_hash as hashes +), +upserted_commitment AS ( + INSERT INTO commitment (tx_hashes, provider_address, commitment_signature, commitment_digest, block_number, received_bid_digest, received_bid_signature, bidder_node_address) + SELECT + ARRAY_AGG(hashes), + $7, + $8, + $6, + $9, + $10, + $11, + $12 + FROM inserted_transactions + ON CONFLICT (provider_address, commitment_digest) + DO UPDATE SET + tx_hashes = commitment.tx_hashes || EXCLUDED.tx_hashes, + received_bid_digest = EXCLUDED.received_bid_digest, + received_bid_signature = EXCLUDED.received_bid_signature, + bidder_node_address = EXCLUDED.bidder_node_address + RETURNING tx_hashes, provider_address +) +SELECT tx_hashes, provider_address FROM upserted_commitment +` + +type InsertMultipleTransactionsAndUpsertCommitmentParams struct { + Eons []int64 + IdentityPreimages []string + IdentityPrefixes []string + BlockNumbers []int64 + TxHashes []string + CommitmentDigest string + ProviderAddress string + CommitmentSignature string + BlockNumber int64 + ReceivedBidDigest string + ReceivedBidSignature string + BidderNodeAddress string +} + +func (q *Queries) InsertMultipleTransactionsAndUpsertCommitment(ctx context.Context, arg InsertMultipleTransactionsAndUpsertCommitmentParams) error { + _, err := q.db.Exec(ctx, insertMultipleTransactionsAndUpsertCommitment, + arg.Eons, + arg.IdentityPreimages, + arg.IdentityPrefixes, + arg.BlockNumbers, + arg.TxHashes, + arg.CommitmentDigest, + arg.ProviderAddress, + arg.CommitmentSignature, + arg.BlockNumber, + arg.ReceivedBidDigest, + arg.ReceivedBidSignature, + arg.BidderNodeAddress, + ) + return err +} + +const insertProviderRegistryEvent = `-- name: InsertProviderRegistryEvent :execresult +INSERT INTO provider_registry_events (block_number, block_hash, tx_index, log_index, provider_address, bls_keys) +VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (block_number, tx_index, log_index) DO UPDATE SET +block_number = $1, +block_hash = $2, +tx_index = $3, +log_index = $4, +bls_keys = $6 +` + +type InsertProviderRegistryEventParams struct { + BlockNumber int64 + BlockHash []byte + TxIndex int64 + LogIndex int64 + ProviderAddress string + BlsKeys [][]byte +} + +func (q *Queries) InsertProviderRegistryEvent(ctx context.Context, arg InsertProviderRegistryEventParams) (pgconn.CommandTag, error) { + return q.db.Exec(ctx, insertProviderRegistryEvent, + arg.BlockNumber, + arg.BlockHash, + arg.TxIndex, + arg.LogIndex, + arg.ProviderAddress, + arg.BlsKeys, + ) +} + +const setProviderRegistryEventsSyncedUntil = `-- name: SetProviderRegistryEventsSyncedUntil :exec +INSERT INTO provider_registry_events_synced_until (block_hash, block_number) VALUES ($1, $2) +ON CONFLICT (enforce_one_row) DO UPDATE +SET block_hash = $1, block_number = $2 +` + +type SetProviderRegistryEventsSyncedUntilParams struct { + BlockHash []byte + BlockNumber int64 +} + +func (q *Queries) SetProviderRegistryEventsSyncedUntil(ctx context.Context, arg SetProviderRegistryEventsSyncedUntilParams) error { + _, err := q.db.Exec(ctx, setProviderRegistryEventsSyncedUntil, arg.BlockHash, arg.BlockNumber) + return err +} diff --git a/rolling-shutter/keyperimpl/primev/database/sql/queries/primev.sql b/rolling-shutter/keyperimpl/primev/database/sql/queries/primev.sql new file mode 100644 index 000000000..00dbfe61e --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/database/sql/queries/primev.sql @@ -0,0 +1,70 @@ +-- name: GetCommitmentByTxHash :many +SELECT + c.tx_hashes, + c.provider_address, + c.commitment_signature, + c.commitment_digest, + c.block_number, + c.received_bid_digest, + c.received_bid_signature, + c.bidder_node_address +FROM commitment c +WHERE $1 = ANY(c.tx_hashes); + +-- name: InsertMultipleTransactionsAndUpsertCommitment :exec +WITH inserted_transactions AS ( + INSERT INTO committed_transactions (eon, identity_preimage, identity_prefix, block_number, tx_hash, commitment_digest, provider_address) + SELECT + unnest(sqlc.arg('eons')::bigint[]) as eon, + unnest(sqlc.arg('identity_preimages')::text[]) as identity_preimage, + unnest(sqlc.arg('identity_prefixes')::text[]) as identity_prefix, + unnest(sqlc.arg('block_numbers')::bigint[]) as block_number, + unnest(sqlc.arg('tx_hashes')::text[]) as tx_hash, + sqlc.arg('commitment_digest'), + sqlc.arg('provider_address') + ON CONFLICT (eon, identity_preimage, tx_hash, block_number) + DO NOTHING + RETURNING tx_hash as hashes +), +upserted_commitment AS ( + INSERT INTO commitment (tx_hashes, provider_address, commitment_signature, commitment_digest, block_number, received_bid_digest, received_bid_signature, bidder_node_address) + SELECT + ARRAY_AGG(hashes), + sqlc.arg('provider_address'), + sqlc.arg('commitment_signature'), + sqlc.arg('commitment_digest'), + sqlc.arg('block_number'), + sqlc.arg('received_bid_digest'), + sqlc.arg('received_bid_signature'), + sqlc.arg('bidder_node_address') + FROM inserted_transactions + ON CONFLICT (provider_address, commitment_digest) + DO UPDATE SET + tx_hashes = commitment.tx_hashes || EXCLUDED.tx_hashes, + received_bid_digest = EXCLUDED.received_bid_digest, + received_bid_signature = EXCLUDED.received_bid_signature, + bidder_node_address = EXCLUDED.bidder_node_address + RETURNING tx_hashes, provider_address +) +SELECT tx_hashes, provider_address FROM upserted_commitment; + +-- name: GetProviderRegistryEventsSyncedUntil :one +SELECT * FROM provider_registry_events_synced_until LIMIT 1; + +-- name: SetProviderRegistryEventsSyncedUntil :exec +INSERT INTO provider_registry_events_synced_until (block_hash, block_number) VALUES ($1, $2) +ON CONFLICT (enforce_one_row) DO UPDATE +SET block_hash = $1, block_number = $2; + +-- name: InsertProviderRegistryEvent :execresult +INSERT INTO provider_registry_events (block_number, block_hash, tx_index, log_index, provider_address, bls_keys) +VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (block_number, tx_index, log_index) DO UPDATE SET +block_number = $1, +block_hash = $2, +tx_index = $3, +log_index = $4, +bls_keys = $6; + +-- name: DeleteProviderRegistryEventsFromBlockNumber :exec +DELETE FROM provider_registry_events WHERE block_number >= $1; \ No newline at end of file diff --git a/rolling-shutter/keyperimpl/primev/database/sql/schemas/primev.sql b/rolling-shutter/keyperimpl/primev/database/sql/schemas/primev.sql new file mode 100644 index 000000000..e72038243 --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/database/sql/schemas/primev.sql @@ -0,0 +1,43 @@ +-- schema-version: primev-1 -- +-- Please change the version above if you make incompatible changes to +-- the schema. We'll use this to check we're using the right schema. + +CREATE TABLE commitment( + tx_hashes text[] NOT NULL, + provider_address text NOT NULL, + commitment_signature text NOT NULL, + commitment_digest text NOT NULL, + block_number bigint NOT NULL CHECK (block_number >= 0), + received_bid_digest text NOT NULL, + received_bid_signature text NOT NULL, + bidder_node_address text NOT NULL, + PRIMARY KEY (commitment_digest, provider_address) +); + +CREATE TABLE committed_transactions( + eon bigint NOT NULL CHECK (eon >= 0), + identity_prefix text NOT NULL, + identity_preimage text NOT NULL, + block_number bigint NOT NULL CHECK (block_number >= 0), + tx_hash text NOT NULL, + commitment_digest text NOT NULL, + provider_address text NOT NULL, + PRIMARY KEY (eon, identity_preimage, tx_hash, block_number), + FOREIGN KEY (commitment_digest, provider_address) REFERENCES commitment(commitment_digest, provider_address) +); + +CREATE TABLE provider_registry_events_synced_until( + enforce_one_row bool PRIMARY KEY DEFAULT true, + block_hash bytea NOT NULL, + block_number bigint NOT NULL CHECK (block_number >= 0) +); + +CREATE TABLE provider_registry_events( + block_number bigint NOT NULL CHECK (block_number >= 0), + block_hash bytea NOT NULL, + tx_index bigint NOT NULL CHECK (tx_index >= 0), + log_index bigint NOT NULL CHECK (log_index >= 0), + provider_address text NOT NULL, + bls_keys bytea[] NOT NULL, + PRIMARY KEY (block_number, tx_index, log_index) +); \ No newline at end of file diff --git a/rolling-shutter/keyperimpl/primev/database/sql/sqlc.yaml b/rolling-shutter/keyperimpl/primev/database/sql/sqlc.yaml new file mode 100644 index 000000000..63efe1093 --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/database/sql/sqlc.yaml @@ -0,0 +1,13 @@ +version: "2" +sql: + - schema: "schemas" + queries: "queries" + engine: "postgresql" + gen: + go: + package: "database" + out: "../" + sql_package: "pgx/v4" + output_db_file_name: "db.sqlc.gen.go" + output_models_file_name: "models.sqlc.gen.go" + output_files_suffix: "c.gen" diff --git a/rolling-shutter/keyperimpl/primev/handler.go b/rolling-shutter/keyperimpl/primev/handler.go new file mode 100644 index 000000000..5c2bc22f8 --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/handler.go @@ -0,0 +1,161 @@ +package primev + +import ( + "bytes" + "context" + "encoding/hex" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/jackc/pgx/v4/pgxpool" + pubsub "github.com/libp2p/go-libp2p-pubsub" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" + + corekeyperdatabase "github.com/shutter-network/rolling-shutter/rolling-shutter/keyper/database" + "github.com/shutter-network/rolling-shutter/rolling-shutter/keyper/epochkghandler" + "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/primev/database" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/broker" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/identitypreimage" + "github.com/shutter-network/rolling-shutter/rolling-shutter/p2pmsg" +) + +type PrimevCommitmentHandler struct { + config *Config + decryptionTriggerChannel chan *broker.Event[*epochkghandler.DecryptionTrigger] + dbpool *pgxpool.Pool +} + +func (h *PrimevCommitmentHandler) MessagePrototypes() []p2pmsg.Message { + return []p2pmsg.Message{&p2pmsg.Commitment{}} +} + +func (h *PrimevCommitmentHandler) ValidateMessage(_ context.Context, msg p2pmsg.Message) (pubsub.ValidationResult, error) { + commitment, ok := msg.(*p2pmsg.Commitment) + if !ok { + return pubsub.ValidationReject, errors.Errorf("received message of unexpected type %s", msg.ProtoReflect().Descriptor().FullName()) + } + if len(commitment.Identities) != len(commitment.TxHashes) { + return pubsub.ValidationReject, errors.Errorf("number of identities (%d) does not match number of tx hashes (%d)", + len(commitment.Identities), len(commitment.TxHashes)) + } + if commitment.GetInstanceId() != h.config.InstanceID { + return pubsub.ValidationReject, errors.Errorf("instance ID mismatch (want=%d, have=%d)", + h.config.InstanceID, commitment.GetInstanceId()) + } + return pubsub.ValidationAccept, nil + // TODO: more validations need to be done here +} + +func (h *PrimevCommitmentHandler) HandleMessage(ctx context.Context, msg p2pmsg.Message) ([]p2pmsg.Message, error) { + log.Info().Msg("received commitment") + commitment, ok := msg.(*p2pmsg.Commitment) + if !ok { + return nil, errors.Errorf("received message of unexpected type %s", msg.ProtoReflect().Descriptor().FullName()) + } + + hLog := log.With(). + Str("provider_address", commitment.ProviderAddress). + Strs("identities_prefixes", commitment.Identities). + Logger() + + bidderNodeAddress, err := getBidderNodeAddress(commitment.ReceivedBidDigest, commitment.ReceivedBidSignature) + if err != nil { + hLog.Error().Err(err).Msg("failed to get bidder node address") + return nil, err + } + + identityPreimages := make([]identitypreimage.IdentityPreimage, 0, len(commitment.Identities)) + identityPreimagesHex := make([]string, 0, len(commitment.Identities)) + for _, identityPrefix := range commitment.Identities { + identityPrefixBytes, err := hex.DecodeString(identityPrefix) + if err != nil { + hLog.Error().Err(err).Msg("failed to decode identity prefix") + return nil, err + } + identityPreimage := computeIdentity(identityPrefixBytes, bidderNodeAddress.Bytes()) + identityPreimageTyped := identitypreimage.IdentityPreimage(identityPreimage) + identityPreimages = append(identityPreimages, identityPreimageTyped) + identityPreimagesHex = append(identityPreimagesHex, identityPreimageTyped.Hex()) + } + + blockNumbers := make([]int64, 0, len(commitment.Identities)) + eons := make([]int64, 0, len(commitment.Identities)) + + obsKeyperDB := corekeyperdatabase.New(h.dbpool) + eon, err := obsKeyperDB.GetEonForBlockNumber(ctx, commitment.BlockNumber) + if err != nil { + hLog.Error().Err(err).Msg("failed to get eon for block number") + return nil, err + } + for range commitment.Identities { + blockNumbers = append(blockNumbers, commitment.BlockNumber) + eons = append(eons, eon.Eon) + } + db := database.New(h.dbpool) + err = db.InsertMultipleTransactionsAndUpsertCommitment(ctx, database.InsertMultipleTransactionsAndUpsertCommitmentParams{ + Eons: eons, + IdentityPreimages: identityPreimagesHex, + BlockNumbers: blockNumbers, + TxHashes: commitment.TxHashes, + IdentityPrefixes: commitment.Identities, + ProviderAddress: commitment.ProviderAddress, + CommitmentSignature: commitment.CommitmentSignature, + CommitmentDigest: commitment.CommitmentDigest, + BlockNumber: commitment.BlockNumber, + ReceivedBidDigest: commitment.ReceivedBidDigest, + ReceivedBidSignature: commitment.ReceivedBidSignature, + BidderNodeAddress: bidderNodeAddress.Hex(), + }) + if err != nil { + hLog.Error().Err(err).Msg("failed to insert multiple transactions and upsert commitment") + return nil, err + } + + blockNumberUint64, err := medley.Int64ToUint64Safe(commitment.BlockNumber) + if err != nil { + hLog.Error().Err(err).Msg("failed to convert block number to uint64") + return nil, err + } + + // TODO: before sending the dec trigger, we need to check if majority of providers have generated commitments + + decryptionTrigger := &epochkghandler.DecryptionTrigger{ + BlockNumber: blockNumberUint64, + IdentityPreimages: identityPreimages, + } + + select { + case h.decryptionTriggerChannel <- broker.NewEvent(decryptionTrigger): + case <-ctx.Done(): + return nil, ctx.Err() + } + + hLog.Info().Msg("sent decryption trigger") + + return nil, nil +} + +func getBidderNodeAddress(digest, signature string) (*common.Address, error) { + digestBytes := common.FromHex(digest) + signatureBytes := common.FromHex(signature) + + if signatureBytes[64] == 27 || signatureBytes[64] == 28 { + signatureBytes[64] -= 27 // Transform V from 27/28 to 0/1 + } + + pubKey, err := crypto.SigToPub(digestBytes, signatureBytes) + if err != nil { + return nil, err + } + bidderNodeAddress := crypto.PubkeyToAddress(*pubKey) + return &bidderNodeAddress, nil +} + +func computeIdentity(identityPrefix, sender []byte) []byte { + var buf bytes.Buffer + buf.Write(identityPrefix) + buf.Write(sender) + return crypto.Keccak256(buf.Bytes()) +} diff --git a/rolling-shutter/keyperimpl/primev/keyper.go b/rolling-shutter/keyperimpl/primev/keyper.go new file mode 100644 index 000000000..609a35672 --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/keyper.go @@ -0,0 +1,208 @@ +package primev + +import ( + "context" + "log/slog" + + "github.com/ethereum/go-ethereum/ethclient" + gethLog "github.com/ethereum/go-ethereum/log" + "github.com/jackc/pgx/v4/pgxpool" + "github.com/pkg/errors" + providerregistry "github.com/primev/mev-commit/contracts-abi/clients/ProviderRegistry" + "github.com/rs/zerolog/log" + + "github.com/shutter-network/rolling-shutter/rolling-shutter/eonkeypublisher" + "github.com/shutter-network/rolling-shutter/rolling-shutter/keyper" + "github.com/shutter-network/rolling-shutter/rolling-shutter/keyper/epochkghandler" + "github.com/shutter-network/rolling-shutter/rolling-shutter/keyper/kprconfig" + "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/primev/database" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/broker" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/chainsync" + syncevent "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/chainsync/event" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/db" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/service" + "github.com/shutter-network/rolling-shutter/rolling-shutter/p2p" +) + +var ErrParseKeyperSet = errors.New("cannot parse KeyperSet") + +type Keyper struct { + core *keyper.KeyperCore + config *Config + dbpool *pgxpool.Pool + + chainSyncClient *chainsync.Client + providerRegistrySyncer *ProviderRegistrySyncer + eonKeyPublisher *eonkeypublisher.EonKeyPublisher + newKeyperSets chan *syncevent.KeyperSet + newEonPublicKeys chan keyper.EonPublicKey + newBlocks chan *syncevent.LatestBlock + + // outputs + decryptionTriggerChannel chan *broker.Event[*epochkghandler.DecryptionTrigger] +} + +func New(c *Config) *Keyper { + return &Keyper{ + config: c, + } +} + +func (k *Keyper) Start(ctx context.Context, runner service.Runner) error { + var err error + + k.newKeyperSets = make(chan *syncevent.KeyperSet) + k.newEonPublicKeys = make(chan keyper.EonPublicKey) + k.newBlocks = make(chan *syncevent.LatestBlock) + k.decryptionTriggerChannel = make(chan *broker.Event[*epochkghandler.DecryptionTrigger]) + + k.dbpool, err = db.Connect(ctx, runner, k.config.DatabaseURL, database.Definition.Name()) + if err != nil { + return errors.Wrap(err, "failed to connect to database") + } + + messageSender, err := p2p.New(k.config.P2P) + if err != nil { + return errors.Wrap(err, "failed to initialize p2p messaging") + } + + messageSender.AddMessageHandler(&PrimevCommitmentHandler{ + config: k.config, + decryptionTriggerChannel: k.decryptionTriggerChannel, + dbpool: k.dbpool, + }) + + k.core, err = NewKeyper(k, messageSender) + if err != nil { + return errors.Wrap(err, "can't instantiate keyper core") + } + + k.chainSyncClient, err = chainsync.NewClient( + ctx, + chainsync.WithClientURL(k.config.Chain.Node.EthereumURL), + chainsync.WithKeyperSetManager(k.config.Chain.Contracts.KeyperSetManager), + chainsync.WithKeyBroadcastContract(k.config.Chain.Contracts.KeyBroadcastContract), + chainsync.WithSyncNewKeyperSet(k.channelNewKeyperSet), + chainsync.WithSyncNewBlock(k.channelNewBlock), + chainsync.WithPrivateKey(k.config.Chain.Node.PrivateKey.Key), + chainsync.WithLogger(gethLog.NewLogger(slog.Default().Handler())), + ) + if err != nil { + return err + } + + eonKeyPublisherClient, err := ethclient.DialContext(ctx, k.config.Chain.Node.EthereumURL) + if err != nil { + return errors.Wrapf(err, "failed to dial ethereum node at %s", k.config.Chain.Node.EthereumURL) + } + k.eonKeyPublisher, err = eonkeypublisher.NewEonKeyPublisher( + k.dbpool, + eonKeyPublisherClient, + k.config.Chain.Contracts.KeyperSetManager, + k.config.Chain.Node.PrivateKey.Key, + ) + if err != nil { + return errors.Wrap(err, "failed to initialize eon key publisher") + } + + err = k.initRegistrySyncer(ctx) + if err != nil { + return err + } + + runner.Go(func() error { return k.processInputs(ctx) }) + return runner.StartService(k.core, k.chainSyncClient, k.eonKeyPublisher) +} + +func NewKeyper(kpr *Keyper, messagingMiddleware p2p.Messaging) (*keyper.KeyperCore, error) { + return keyper.New( + &kprconfig.Config{ + InstanceID: kpr.config.InstanceID, + DatabaseURL: kpr.config.DatabaseURL, + HTTPEnabled: false, + HTTPReadOnly: true, + HTTPListenAddress: kpr.config.HTTPListenAddress, + P2P: kpr.config.P2P, + Ethereum: kpr.config.Chain.Node, + Shuttermint: kpr.config.Shuttermint, + Metrics: kpr.config.Metrics, + MaxNumKeysPerMessage: kpr.config.MaxNumKeysPerMessage, + }, + kpr.decryptionTriggerChannel, + keyper.WithDBPool(kpr.dbpool), + keyper.NoBroadcastEonPublicKey(), + keyper.WithEonPublicKeyHandler(kpr.channelNewEonPublicKey), + keyper.WithMessaging(messagingMiddleware), + ) +} + +// initRegistrySyncer initializes the registry syncer. +func (k *Keyper) initRegistrySyncer(ctx context.Context) error { + client, err := ethclient.DialContext(ctx, k.config.Primev.PrimevRPC) + if err != nil { + return errors.Wrap(err, "failed to dial Ethereum execution node") + } + + log.Info(). + Str("contract-address", k.config.Chain.Contracts.KeyperSetManager.Hex()). + Msg("initializing registry syncer") + + contract, err := providerregistry.NewProviderregistry(k.config.Primev.ProviderRegistryContract, client) + if err != nil { + return err + } + + k.providerRegistrySyncer = &ProviderRegistrySyncer{ + Contract: contract, + DBPool: k.dbpool, + ExecutionClient: client, + SyncStartBlockNumber: k.config.Primev.SyncStartBlockNumber, + } + + // Perform an initial sync now because it might take some time and doing so during regular + // slot processing might hold up things + err = k.providerRegistrySyncer.Sync(ctx) + if err != nil { + return err + } + + return nil +} + +func (k *Keyper) processInputs(ctx context.Context) error { + var err error + for { + select { + case ev := <-k.newBlocks: + err = k.processNewBlock(ctx, ev) + case ev := <-k.newKeyperSets: + err = k.processNewKeyperSet(ctx, ev) + case ev := <-k.newEonPublicKeys: + err = k.processNewEonPublicKey(ctx, ev) + case <-ctx.Done(): + return ctx.Err() + } + if err != nil { + // TODO: Check if it's safe to drop those events. If not, we should store the + // ones that remain on the channel in the db and process them when we restart. + // TODO: also, should we stop the keyper or just log the error and continue? + // return err + log.Error().Err(err).Msg("error processing event") + } + } +} + +func (k *Keyper) channelNewEonPublicKey(_ context.Context, key keyper.EonPublicKey) error { + k.newEonPublicKeys <- key + return nil +} + +func (k *Keyper) channelNewKeyperSet(_ context.Context, ev *syncevent.KeyperSet) error { + k.newKeyperSets <- ev + return nil +} + +func (k *Keyper) channelNewBlock(_ context.Context, ev *syncevent.LatestBlock) error { + k.newBlocks <- ev + return nil +} diff --git a/rolling-shutter/keyperimpl/primev/newblock.go b/rolling-shutter/keyperimpl/primev/newblock.go new file mode 100644 index 000000000..54380de4b --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/newblock.go @@ -0,0 +1,19 @@ +package primev + +import ( + "context" + + syncevent "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/chainsync/event" +) + +// TODO: the syncing logic for provider registry to be stripped out of here. +// +// As it uses different chain. Adding it here, just for convenience of development of POC. +func (k *Keyper) processNewBlock(ctx context.Context, _ *syncevent.LatestBlock) error { + if k.providerRegistrySyncer != nil { + if err := k.providerRegistrySyncer.Sync(ctx); err != nil { + return err + } + } + return nil +} diff --git a/rolling-shutter/keyperimpl/primev/neweonpublickey.go b/rolling-shutter/keyperimpl/primev/neweonpublickey.go new file mode 100644 index 000000000..4dc145e9c --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/neweonpublickey.go @@ -0,0 +1,12 @@ +package primev + +import ( + "context" + + "github.com/shutter-network/rolling-shutter/rolling-shutter/keyper" +) + +func (k *Keyper) processNewEonPublicKey(_ context.Context, key keyper.EonPublicKey) error { //nolint: unparam + k.eonKeyPublisher.Publish(key) + return nil +} diff --git a/rolling-shutter/keyperimpl/primev/newkeyperset.go b/rolling-shutter/keyperimpl/primev/newkeyperset.go new file mode 100644 index 000000000..fbc299173 --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/newkeyperset.go @@ -0,0 +1,56 @@ +package primev + +import ( + "context" + + "github.com/jackc/pgx/v4" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" + + obskeyper "github.com/shutter-network/rolling-shutter/rolling-shutter/chainobserver/db/keyper" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley" + syncevent "github.com/shutter-network/rolling-shutter/rolling-shutter/medley/chainsync/event" + "github.com/shutter-network/rolling-shutter/rolling-shutter/shdb" +) + +func (k *Keyper) processNewKeyperSet(ctx context.Context, ev *syncevent.KeyperSet) error { + isMember := false + for _, m := range ev.Members { + if m.Cmp(k.config.GetAddress()) == 0 { + isMember = true + break + } + } + + log.Info(). + Uint64("activation-block", ev.ActivationBlock). + Uint64("eon", ev.Eon). + Int("num-members", len(ev.Members)). + Uint64("threshold", ev.Threshold). + Bool("is-member", isMember). + Msg("new keyper set added") + + return k.dbpool.BeginFunc(ctx, func(tx pgx.Tx) error { + obskeyperdb := obskeyper.New(tx) + + keyperConfigIndex, err := medley.Uint64ToInt64Safe(ev.Eon) + if err != nil { + return errors.Wrap(err, ErrParseKeyperSet.Error()) + } + activationBlockNumber, err := medley.Uint64ToInt64Safe(ev.ActivationBlock) + if err != nil { + return errors.Wrap(err, ErrParseKeyperSet.Error()) + } + threshold, err := medley.Uint64ToInt64Safe(ev.Threshold) + if err != nil { + return errors.Wrap(err, ErrParseKeyperSet.Error()) + } + + return obskeyperdb.InsertKeyperSet(ctx, obskeyper.InsertKeyperSetParams{ + KeyperConfigIndex: keyperConfigIndex, + ActivationBlockNumber: activationBlockNumber, + Keypers: shdb.EncodeAddresses(ev.Members), + Threshold: int32(threshold), //nolint:gosec + }) + }) +} diff --git a/rolling-shutter/keyperimpl/primev/providerregistrysyncer.go b/rolling-shutter/keyperimpl/primev/providerregistrysyncer.go new file mode 100644 index 000000000..9e2ff79bd --- /dev/null +++ b/rolling-shutter/keyperimpl/primev/providerregistrysyncer.go @@ -0,0 +1,286 @@ +package primev + +import ( + "bytes" + "context" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/jackc/pgx/v4" + "github.com/jackc/pgx/v4/pgxpool" + "github.com/pkg/errors" + providerregistry "github.com/primev/mev-commit/contracts-abi/clients/ProviderRegistry" + "github.com/rs/zerolog/log" + + "github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/primev/database" + "github.com/shutter-network/rolling-shutter/rolling-shutter/medley" +) + +const ( + AssumedReorgDepth = 10 + maxRequestBlockRange = 10_000 +) + +type ProviderRegistrySyncer struct { + Contract *providerregistry.Providerregistry + DBPool *pgxpool.Pool + ExecutionClient *ethclient.Client + SyncStartBlockNumber uint64 +} + +// getNumReorgedBlocks returns the number of blocks that have already been synced, but are no +// longer in the chain. +func getNumReorgedBlocks(syncedUntil *database.ProviderRegistryEventsSyncedUntil, header *types.Header) int { + shouldBeParent := header.Number.Int64() == syncedUntil.BlockNumber+1 + isParent := bytes.Equal(header.ParentHash.Bytes(), syncedUntil.BlockHash) + isReorg := shouldBeParent && !isParent + if !isReorg { + return 0 + } + // We don't know how deep the reorg is, so we make a conservative guess. Assuming higher depths + // is safer because it means we resync a little bit more. + depth := AssumedReorgDepth + if syncedUntil.BlockNumber < int64(depth) { + return int(syncedUntil.BlockNumber) + } + return depth +} + +// resetSyncStatus clears the db from its recent history after a reorg of given depth. +func (s *ProviderRegistrySyncer) resetSyncStatus(ctx context.Context, numReorgedBlocks int) error { + if numReorgedBlocks == 0 { + return nil + } + return s.DBPool.BeginFunc(ctx, func(tx pgx.Tx) error { + queries := database.New(tx) + + syncStatus, err := queries.GetProviderRegistryEventsSyncedUntil(ctx) + if err != nil { + return errors.Wrap(err, "failed to query sync status from db in order to reset it") + } + if syncStatus.BlockNumber < int64(numReorgedBlocks) { + return errors.Wrapf(err, "detected reorg deeper (%d) than blocks synced (%d)", syncStatus.BlockNumber, numReorgedBlocks) + } + + deleteFromInclusive := syncStatus.BlockNumber - int64(numReorgedBlocks) + 1 + + err = queries.DeleteProviderRegistryEventsFromBlockNumber(ctx, deleteFromInclusive) + if err != nil { + return errors.Wrap(err, "failed to delete provider registered events from db") + } + // Currently, we don't have enough information in the db to populate block hash. + // However, using default values here is fine since the syncer is expected to resync + // immediately after this function call which will set the correct values. When we do proper + // reorg handling, we should store the full block data of the previous blocks so that we can + // avoid this. + + newSyncedUntilBlockNumber := deleteFromInclusive - 1 + + err = queries.SetProviderRegistryEventsSyncedUntil(ctx, database.SetProviderRegistryEventsSyncedUntilParams{ + BlockHash: []byte{}, + BlockNumber: newSyncedUntilBlockNumber, + }) + if err != nil { + return errors.Wrap(err, "failed to reset provider registered event sync status in db") + } + log.Info(). + Int("depth", numReorgedBlocks). + Int64("previous-synced-until", syncStatus.BlockNumber). + Int64("new-synced-until", newSyncedUntilBlockNumber). + Msg("sync status reset due to reorg") + return nil + }) +} + +func (s *ProviderRegistrySyncer) handlePotentialReorg(ctx context.Context, header *types.Header) error { + queries := database.New(s.DBPool) + syncedUntil, err := queries.GetProviderRegistryEventsSyncedUntil(ctx) + if err == pgx.ErrNoRows { + return nil + } + if err != nil { + return errors.Wrap(err, "failed to query registration events sync status") + } + + numReorgedBlocks := getNumReorgedBlocks(&syncedUntil, header) + if numReorgedBlocks > 0 { + return s.resetSyncStatus(ctx, numReorgedBlocks) + } + return nil +} + +// Sync fetches IdentityRegistered events from the registry contract and inserts them into the +// database. It starts at the end point of the previous call to sync (or 0 if it is the first call) +// and ends at the given block number. +func (s *ProviderRegistrySyncer) Sync(ctx context.Context) error { + header, err := s.ExecutionClient.HeaderByNumber(ctx, nil) + if err != nil { + return errors.Wrap(err, "failed to get latest block number") + } + + if err := s.handlePotentialReorg(ctx, header); err != nil { + return err + } + + queries := database.New(s.DBPool) + syncedUntil, err := queries.GetProviderRegistryEventsSyncedUntil(ctx) + if err != nil && err != pgx.ErrNoRows { + return errors.Wrap(err, "failed to query provider registered events sync status") + } + var start uint64 + if err == pgx.ErrNoRows { + start = s.SyncStartBlockNumber + } else { + start = uint64(syncedUntil.BlockNumber + 1) //nolint:gosec + } + endBlock := header.Number.Uint64() + log.Debug(). + Uint64("start-block", start). + Uint64("end-block", endBlock). + Msg("syncing registry contract") + syncRanges := medley.GetSyncRanges(start, endBlock, maxRequestBlockRange) + for _, r := range syncRanges { + err = s.syncRange(ctx, r[0], r[1]) + if err != nil { + return err + } + } + return nil +} + +func (s *ProviderRegistrySyncer) syncRange( + ctx context.Context, + start, + end uint64, +) error { + events, err := s.fetchEvents(ctx, start, end) + if err != nil { + return err + } + filteredEvents, blsKeys := s.filterEvents(ctx, events) + + header, err := s.ExecutionClient.HeaderByNumber(ctx, new(big.Int).SetUint64(end)) + if err != nil { + return errors.Wrap(err, "failed to get execution block header by number") + } + err = s.DBPool.BeginFunc(ctx, func(tx pgx.Tx) error { + err = s.insertProviderRegistryEvents(ctx, tx, filteredEvents, blsKeys) + if err != nil { + return err + } + return database.New(tx).SetProviderRegistryEventsSyncedUntil(ctx, database.SetProviderRegistryEventsSyncedUntilParams{ + BlockNumber: int64(end), //nolint:gosec + BlockHash: header.Hash().Bytes(), + }) + }) + if err != nil { + log.Warn().AnErr("error adding provider registered event into db", err) + } + log.Info(). + Uint64("start-block", start). + Uint64("end-block", end). + Int("num-inserted-events", len(filteredEvents)). + Int("num-discarded-events", len(events)-len(filteredEvents)). + Msg("synced provider registry contract") + + return nil +} + +func (s *ProviderRegistrySyncer) fetchEvents( + ctx context.Context, + start, + end uint64, +) ([]*providerregistry.ProviderregistryProviderRegistered, error) { + opts := bind.FilterOpts{ + Start: start, + End: &end, + Context: ctx, + } + + // TODO: need to test if this fetches all provider registered events regardless of the provider address + it, err := s.Contract.ProviderregistryFilterer.FilterProviderRegistered(&opts, nil) + if err != nil { + return nil, errors.Wrap(err, "failed to query provider registered events") + } + events := []*providerregistry.ProviderregistryProviderRegistered{} + for it.Next() { + events = append(events, it.Event) + } + if it.Error() != nil { + return nil, errors.Wrap(it.Error(), "failed to iterate provider registered events") + } + return events, nil +} + +func (s *ProviderRegistrySyncer) filterEvents( + ctx context.Context, + events []*providerregistry.ProviderregistryProviderRegistered, +) ([]*providerregistry.ProviderregistryProviderRegistered, [][][]byte) { + filteredEvents := []*providerregistry.ProviderregistryProviderRegistered{} + blsKeys := [][][]byte{} + for _, event := range events { + err := s.Contract.IsProviderValid(&bind.CallOpts{ + Context: ctx, + BlockNumber: big.NewInt(int64(event.Raw.BlockNumber)), //nolint:gosec + }, event.Provider) + if err != nil { + log.Warn(). + Uint64("block-number", event.Raw.BlockNumber). + Str("block-hash", event.Raw.BlockHash.Hex()). + Uint("tx-index", event.Raw.TxIndex). + Uint("log-index", event.Raw.Index). + Str("provider", event.Provider.Hex()). + Msg("ignoring provider registered event with invalid provider") + continue + } + + blsKey, err := s.Contract.GetBLSKeys(&bind.CallOpts{ + Context: ctx, + BlockNumber: big.NewInt(int64(event.Raw.BlockNumber)), //nolint:gosec + }, event.Provider) + if err != nil { + log.Warn(). + Uint64("block-number", event.Raw.BlockNumber). + Str("block-hash", event.Raw.BlockHash.Hex()). + Uint("tx-index", event.Raw.TxIndex). + Uint("log-index", event.Raw.Index). + Str("provider", event.Provider.Hex()). + Msg("ignoring provider registered event with invalid provider") + continue + } + + filteredEvents = append(filteredEvents, event) + blsKeys = append(blsKeys, blsKey) + } + return filteredEvents, blsKeys +} + +// insertProviderRegistryEvents inserts the given events into the database. +func (s *ProviderRegistrySyncer) insertProviderRegistryEvents( + ctx context.Context, + tx pgx.Tx, + events []*providerregistry.ProviderregistryProviderRegistered, + blsKeys [][][]byte, +) error { + queries := database.New(tx) + for i, event := range events { + _, err := queries.InsertProviderRegistryEvent(ctx, database.InsertProviderRegistryEventParams{ + BlockNumber: int64(event.Raw.BlockNumber), //nolint:gosec + BlockHash: event.Raw.BlockHash.Bytes(), + TxIndex: int64(event.Raw.TxIndex), //nolint:gosec + LogIndex: int64(event.Raw.Index), //nolint:gosec + ProviderAddress: event.Provider.Hex(), + BlsKeys: blsKeys[i], + }) + if err != nil { + return errors.Wrap(err, "failed to insert provider registered event into db") + } + log.Debug(). + Uint64("block", event.Raw.BlockNumber). + Str("provider", event.Provider.Hex()). + Msg("synced new provider registered event") + } + return nil +} diff --git a/rolling-shutter/p2pmsg/gossip.pb.go b/rolling-shutter/p2pmsg/gossip.pb.go index 42b788457..0fc0f065b 100644 --- a/rolling-shutter/p2pmsg/gossip.pb.go +++ b/rolling-shutter/p2pmsg/gossip.pb.go @@ -965,6 +965,162 @@ func (x *Envelope) GetTrace() *TraceContext { return nil } +type Commitment struct { + state protoimpl.MessageState `protogen:"open.v1"` + InstanceId uint64 `protobuf:"varint,1,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` + TxHashes []string `protobuf:"bytes,2,rep,name=tx_hashes,json=txHashes,proto3" json:"tx_hashes,omitempty"` + BidAmount string `protobuf:"bytes,3,opt,name=bid_amount,json=bidAmount,proto3" json:"bid_amount,omitempty"` + BlockNumber int64 `protobuf:"varint,4,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + ReceivedBidDigest string `protobuf:"bytes,5,opt,name=received_bid_digest,json=receivedBidDigest,proto3" json:"received_bid_digest,omitempty"` + ReceivedBidSignature string `protobuf:"bytes,6,opt,name=received_bid_signature,json=receivedBidSignature,proto3" json:"received_bid_signature,omitempty"` + CommitmentDigest string `protobuf:"bytes,7,opt,name=commitment_digest,json=commitmentDigest,proto3" json:"commitment_digest,omitempty"` + CommitmentSignature string `protobuf:"bytes,8,opt,name=commitment_signature,json=commitmentSignature,proto3" json:"commitment_signature,omitempty"` + ProviderAddress string `protobuf:"bytes,9,opt,name=provider_address,json=providerAddress,proto3" json:"provider_address,omitempty"` + DecayStartTimestamp int64 `protobuf:"varint,10,opt,name=decay_start_timestamp,json=decayStartTimestamp,proto3" json:"decay_start_timestamp,omitempty"` + DecayEndTimestamp int64 `protobuf:"varint,11,opt,name=decay_end_timestamp,json=decayEndTimestamp,proto3" json:"decay_end_timestamp,omitempty"` + DispatchTimestamp int64 `protobuf:"varint,12,opt,name=dispatch_timestamp,json=dispatchTimestamp,proto3" json:"dispatch_timestamp,omitempty"` + RevertingTxHashes []string `protobuf:"bytes,13,rep,name=reverting_tx_hashes,json=revertingTxHashes,proto3" json:"reverting_tx_hashes,omitempty"` + SlashAmount string `protobuf:"bytes,14,opt,name=slash_amount,json=slashAmount,proto3" json:"slash_amount,omitempty"` + Identities []string `protobuf:"bytes,15,rep,name=identities,proto3" json:"identities,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Commitment) Reset() { + *x = Commitment{} + mi := &file_gossip_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Commitment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Commitment) ProtoMessage() {} + +func (x *Commitment) ProtoReflect() protoreflect.Message { + mi := &file_gossip_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Commitment.ProtoReflect.Descriptor instead. +func (*Commitment) Descriptor() ([]byte, []int) { + return file_gossip_proto_rawDescGZIP(), []int{14} +} + +func (x *Commitment) GetInstanceId() uint64 { + if x != nil { + return x.InstanceId + } + return 0 +} + +func (x *Commitment) GetTxHashes() []string { + if x != nil { + return x.TxHashes + } + return nil +} + +func (x *Commitment) GetBidAmount() string { + if x != nil { + return x.BidAmount + } + return "" +} + +func (x *Commitment) GetBlockNumber() int64 { + if x != nil { + return x.BlockNumber + } + return 0 +} + +func (x *Commitment) GetReceivedBidDigest() string { + if x != nil { + return x.ReceivedBidDigest + } + return "" +} + +func (x *Commitment) GetReceivedBidSignature() string { + if x != nil { + return x.ReceivedBidSignature + } + return "" +} + +func (x *Commitment) GetCommitmentDigest() string { + if x != nil { + return x.CommitmentDigest + } + return "" +} + +func (x *Commitment) GetCommitmentSignature() string { + if x != nil { + return x.CommitmentSignature + } + return "" +} + +func (x *Commitment) GetProviderAddress() string { + if x != nil { + return x.ProviderAddress + } + return "" +} + +func (x *Commitment) GetDecayStartTimestamp() int64 { + if x != nil { + return x.DecayStartTimestamp + } + return 0 +} + +func (x *Commitment) GetDecayEndTimestamp() int64 { + if x != nil { + return x.DecayEndTimestamp + } + return 0 +} + +func (x *Commitment) GetDispatchTimestamp() int64 { + if x != nil { + return x.DispatchTimestamp + } + return 0 +} + +func (x *Commitment) GetRevertingTxHashes() []string { + if x != nil { + return x.RevertingTxHashes + } + return nil +} + +func (x *Commitment) GetSlashAmount() string { + if x != nil { + return x.SlashAmount + } + return "" +} + +func (x *Commitment) GetIdentities() []string { + if x != nil { + return x.Identities + } + return nil +} + var File_gossip_proto protoreflect.FileDescriptor var file_gossip_proto_rawDesc = string([]byte{ @@ -1099,8 +1255,49 @@ var file_gossip_proto_rawDesc = string([]byte{ 0x12, 0x2f, 0x0a, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x32, 0x70, 0x6d, 0x73, 0x67, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x48, 0x00, 0x52, 0x05, 0x74, 0x72, 0x61, 0x63, 0x65, 0x88, 0x01, - 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x42, 0x0b, 0x5a, 0x09, 0x2e, - 0x2f, 0x3b, 0x70, 0x32, 0x70, 0x6d, 0x73, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x22, 0x83, 0x05, 0x0a, 0x0a, + 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74, + 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, + 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x69, 0x64, 0x5f, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x69, + 0x64, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x13, 0x72, 0x65, + 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0x42, 0x69, 0x64, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, + 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x62, 0x69, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x72, 0x65, 0x63, 0x65, + 0x69, 0x76, 0x65, 0x64, 0x42, 0x69, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x64, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, + 0x14, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x12, 0x29, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x64, + 0x65, 0x63, 0x61, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x64, 0x65, 0x63, 0x61, + 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x2e, 0x0a, 0x13, 0x64, 0x65, 0x63, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x64, 0x65, + 0x63, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x2d, 0x0a, 0x12, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x64, 0x69, 0x73, + 0x70, 0x61, 0x74, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, + 0x0a, 0x13, 0x72, 0x65, 0x76, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x5f, 0x68, + 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x76, + 0x65, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x21, + 0x0a, 0x0c, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0e, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x41, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, + 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, + 0x73, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x3b, 0x70, 0x32, 0x70, 0x6d, 0x73, 0x67, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -1115,7 +1312,7 @@ func file_gossip_proto_rawDescGZIP() []byte { return file_gossip_proto_rawDescData } -var file_gossip_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_gossip_proto_msgTypes = make([]protoimpl.MessageInfo, 15) var file_gossip_proto_goTypes = []any{ (*DecryptionTrigger)(nil), // 0: p2pmsg.DecryptionTrigger (*KeyShare)(nil), // 1: p2pmsg.KeyShare @@ -1131,7 +1328,8 @@ var file_gossip_proto_goTypes = []any{ (*EonPublicKey)(nil), // 11: p2pmsg.EonPublicKey (*TraceContext)(nil), // 12: p2pmsg.TraceContext (*Envelope)(nil), // 13: p2pmsg.Envelope - (*anypb.Any)(nil), // 14: google.protobuf.Any + (*Commitment)(nil), // 14: p2pmsg.Commitment + (*anypb.Any)(nil), // 15: google.protobuf.Any } var file_gossip_proto_depIdxs = []int32{ 1, // 0: p2pmsg.DecryptionKeyShares.shares:type_name -> p2pmsg.KeyShare @@ -1142,7 +1340,7 @@ var file_gossip_proto_depIdxs = []int32{ 7, // 5: p2pmsg.DecryptionKeys.gnosis:type_name -> p2pmsg.GnosisDecryptionKeysExtra 8, // 6: p2pmsg.DecryptionKeys.optimism:type_name -> p2pmsg.OptimismDecryptionKeysExtra 9, // 7: p2pmsg.DecryptionKeys.service:type_name -> p2pmsg.ShutterServiceDecryptionKeysExtra - 14, // 8: p2pmsg.Envelope.message:type_name -> google.protobuf.Any + 15, // 8: p2pmsg.Envelope.message:type_name -> google.protobuf.Any 12, // 9: p2pmsg.Envelope.trace:type_name -> p2pmsg.TraceContext 10, // [10:10] is the sub-list for method output_type 10, // [10:10] is the sub-list for method input_type @@ -1173,7 +1371,7 @@ func file_gossip_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_gossip_proto_rawDesc), len(file_gossip_proto_rawDesc)), NumEnums: 0, - NumMessages: 14, + NumMessages: 15, NumExtensions: 0, NumServices: 0, }, diff --git a/rolling-shutter/p2pmsg/gossip.proto b/rolling-shutter/p2pmsg/gossip.proto index 6253c27bc..5fc7d61ea 100644 --- a/rolling-shutter/p2pmsg/gossip.proto +++ b/rolling-shutter/p2pmsg/gossip.proto @@ -98,3 +98,21 @@ message Envelope { google.protobuf.Any message = 2; optional TraceContext trace = 3; } + +message Commitment { + uint64 instance_id = 1; + repeated string tx_hashes = 2; + string bid_amount = 3; + int64 block_number = 4; + string received_bid_digest = 5; + string received_bid_signature = 6; + string commitment_digest = 7; + string commitment_signature = 8; + string provider_address = 9; + int64 decay_start_timestamp = 10; + int64 decay_end_timestamp = 11; + int64 dispatch_timestamp = 12; + repeated string reverting_tx_hashes = 13; + string slash_amount = 14; + repeated string identities = 15; +}; \ No newline at end of file diff --git a/rolling-shutter/p2pmsg/messages.go b/rolling-shutter/p2pmsg/messages.go index 237f768fe..8fd1d4b9b 100644 --- a/rolling-shutter/p2pmsg/messages.go +++ b/rolling-shutter/p2pmsg/messages.go @@ -164,3 +164,15 @@ func (*EonPublicKey) Topic() string { func (*EonPublicKey) Validate() error { return nil } + +func (c *Commitment) LogInfo() string { + return fmt.Sprintf("Commitment{commitment_digest=%s}", c.CommitmentDigest) +} + +func (c *Commitment) Topic() string { + return kprtopics.PrimevCommitment +} + +func (c *Commitment) Validate() error { + return nil +} diff --git a/rolling-shutter/p2pnode/host.go b/rolling-shutter/p2pnode/host.go index 68094b51c..6559609b0 100644 --- a/rolling-shutter/p2pnode/host.go +++ b/rolling-shutter/p2pnode/host.go @@ -34,6 +34,7 @@ func (dummyMessageHandler) MessagePrototypes() []p2pmsg.Message { &p2pmsg.DecryptionKeys{}, &p2pmsg.DecryptionTrigger{}, &p2pmsg.EonPublicKey{}, + &p2pmsg.Commitment{}, } }