From e6d4a3b5714218a0d64ba04e3bd2b88a85ca8547 Mon Sep 17 00:00:00 2001 From: Jinsuk Park Date: Thu, 22 Aug 2024 23:51:14 +0900 Subject: [PATCH 1/6] verify signature from builder submission --- go.mod | 7 ++--- go.sum | 14 +++++----- op-node/node/builder.go | 58 ++++++++++++++++++++++++++++++++++------- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 1e49d0ec5f6d..54f89632b2b0 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/DataDog/zstd v1.5.2 github.com/andybalholm/brotli v1.1.0 github.com/attestantio/go-builder-client v0.4.6 + github.com/attestantio/go-eth2-client v0.21.1 github.com/btcsuite/btcd v0.24.0 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 github.com/cockroachdb/pebble v0.0.0-20231018212520-f6cde3fc2fa4 @@ -16,6 +17,7 @@ require ( github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240603085035-9c8f6081266e github.com/ethereum/go-ethereum v1.13.15 + github.com/flashbots/go-boost-utils v1.8.1 github.com/fsnotify/fsnotify v1.7.0 github.com/go-chi/chi/v5 v5.0.12 github.com/go-chi/docgen v1.2.0 @@ -23,7 +25,6 @@ require ( github.com/google/go-cmp v0.6.0 github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8 github.com/google/uuid v1.6.0 - github.com/gorilla/websocket v1.5.1 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/hashicorp/raft v1.6.1 @@ -64,7 +65,6 @@ require ( github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/allegro/bigcache v1.2.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/attestantio/go-eth2-client v0.21.1 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect @@ -107,7 +107,7 @@ require ( github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/goccy/go-yaml v1.9.2 // indirect + github.com/goccy/go-yaml v1.11.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -115,6 +115,7 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/graph-gophers/graphql-go v1.3.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-bexpr v0.1.11 // indirect diff --git a/go.sum b/go.sum index ad9a61c1c7de..5b9cbd3456cf 100644 --- a/go.sum +++ b/go.sum @@ -185,7 +185,6 @@ github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-2024060308503 github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240603085035-9c8f6081266e/go.mod h1:7xh2awFQqsiZxFrHKTgEd+InVfDRrkKVUIuK8SAFHp0= github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= @@ -195,6 +194,8 @@ github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16M github.com/ferranbt/fastssz v0.1.3/go.mod h1:0Y9TEd/9XuFlh7mskMPfXiI2Dkw4Ddg9EyXt1W7MRvE= github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/flashbots/go-boost-utils v1.8.1 h1:AD+1+4oCbBjXLK8IqWHYznD95K6/MmqXhozv5fFOCkU= +github.com/flashbots/go-boost-utils v1.8.1/go.mod h1:jFi2H1el7jGPr2ShkWpYPfKsY9vwsFNmBPJRCO7IPg8= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= @@ -238,14 +239,10 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= @@ -256,8 +253,8 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-yaml v1.9.2 h1:2Njwzw+0+pjU2gb805ZC1B/uBuAs2VcZ3K+ZgHwDs7w= -github.com/goccy/go-yaml v1.9.2/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= +github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ= +github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -510,7 +507,6 @@ github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4F github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -861,6 +857,8 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA 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/trailofbits/go-fuzz-utils v0.0.0-20210901195358-9657fcfd256c h1:4WU+p200eLYtBsx3M5CKXvkjVdf5SC3W9nMg37y0TFI= +github.com/trailofbits/go-fuzz-utils v0.0.0-20210901195358-9657fcfd256c/go.mod h1:f3jBhpWvuZmue0HZK52GzRHJOYHYSILs/c8+K2S/J+o= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= diff --git a/op-node/node/builder.go b/op-node/node/builder.go index e00db845883d..a635ba820ee4 100644 --- a/op-node/node/builder.go +++ b/op-node/node/builder.go @@ -3,6 +3,7 @@ package node import ( "context" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -13,9 +14,12 @@ import ( "github.com/attestantio/go-eth2-client/spec/bellatrix" "github.com/attestantio/go-eth2-client/spec/capella" "github.com/attestantio/go-eth2-client/spec/deneb" + "github.com/attestantio/go-eth2-client/spec/phase0" + "github.com/flashbots/go-boost-utils/ssz" "github.com/holiman/uint256" "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-node/rollup/builder" "github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/common" @@ -24,6 +28,7 @@ import ( ) const PathGetPayload = "/eth/v1/builder/payload" +const GenesisForkVersionMainnet = "0x00000000" type BuilderAPIConfig struct { Timeout time.Duration @@ -31,13 +36,19 @@ type BuilderAPIConfig struct { } type BuilderAPIClient struct { - log log.Logger - config *BuilderAPIConfig - rollupCfg *rollup.Config - httpClient *client.BasicHTTPClient + log log.Logger + config *BuilderAPIConfig + rollupCfg *rollup.Config + httpClient *client.BasicHTTPClient + domainBuilder phase0.Domain } func NewBuilderClient(log log.Logger, rollupCfg *rollup.Config, endpoint string, timeout time.Duration) *BuilderAPIClient { + domainBuilder, err := builder.ComputeDomain(ssz.DomainTypeAppBuilder, GenesisForkVersionMainnet, phase0.Root{}.String()) + if err != nil { + log.Error("failed to compute domain", "error", err) + } + httpClient := client.NewBasicHTTPClient(endpoint, log) config := &BuilderAPIConfig{ Timeout: timeout, @@ -45,10 +56,11 @@ func NewBuilderClient(log log.Logger, rollupCfg *rollup.Config, endpoint string, } return &BuilderAPIClient{ - httpClient: httpClient, - config: config, - rollupCfg: rollupCfg, - log: log, + httpClient: httpClient, + config: config, + rollupCfg: rollupCfg, + log: log, + domainBuilder: domainBuilder, } } @@ -65,6 +77,30 @@ type httpErrorResp struct { Message string `json:"message"` } +func verifySignature(submission *builderSpec.VersionedSubmitBlockRequest, domainBuilder phase0.Domain) error { + bid, err := submission.BidTrace() + if err != nil { + return err + } + + signature, err := submission.Signature() + if err != nil { + return err + } + + builderPubKey := bid.BuilderPubkey + + ok, err := ssz.VerifySignature(bid, domainBuilder, builderPubKey[:], signature[:]) + if err != nil { + return err + } + + if !ok { + return errors.New("invalid builder signature") + } + return nil +} + func (s *BuilderAPIClient) GetPayload(ctx context.Context, ref eth.L2BlockRef, log log.Logger) (*eth.ExecutionPayloadEnvelope, error) { submitBlockRequest := new(builderSpec.VersionedSubmitBlockRequest) slot := ref.Number + 1 @@ -97,10 +133,14 @@ func (s *BuilderAPIClient) GetPayload(ctx context.Context, ref eth.L2BlockRef, l return nil, err } + if err := verifySignature(submitBlockRequest, s.domainBuilder); err != nil { + return nil, err + } + // selects expected data version from the optimism version. // Bedrock - Bellatrix // Canyon - Capella - // Delta - Deneb + // Ecotone - Deneb var expectedVersion spec.DataVersion if s.rollupCfg.IsEcotone(ref.Time) { expectedVersion = spec.DataVersionDeneb From f8c5cc856296bb315ee3ad32810172b258948abf Mon Sep 17 00:00:00 2001 From: Jinsuk Park Date: Thu, 22 Aug 2024 23:52:10 +0900 Subject: [PATCH 2/6] add note to fork version --- op-node/node/builder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/op-node/node/builder.go b/op-node/node/builder.go index a635ba820ee4..b5ff4ace2aad 100644 --- a/op-node/node/builder.go +++ b/op-node/node/builder.go @@ -28,7 +28,7 @@ import ( ) const PathGetPayload = "/eth/v1/builder/payload" -const GenesisForkVersionMainnet = "0x00000000" +const GenesisForkVersionMainnet = "0x00000000" // NOTE: Optimism does not have any fork version. Use Mainnet fork version for now. type BuilderAPIConfig struct { Timeout time.Duration From aef4f3a1c95200e9566230307b0a05ce0ee22887 Mon Sep 17 00:00:00 2001 From: Jinsuk Park Date: Thu, 22 Aug 2024 23:53:46 +0900 Subject: [PATCH 3/6] refactor to use computeDomain function in builder.go --- op-node/node/builder.go | 63 ++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/op-node/node/builder.go b/op-node/node/builder.go index b5ff4ace2aad..ab968d1ebd33 100644 --- a/op-node/node/builder.go +++ b/op-node/node/builder.go @@ -19,10 +19,10 @@ import ( "github.com/holiman/uint256" "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-node/rollup/builder" "github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" ) @@ -43,8 +43,43 @@ type BuilderAPIClient struct { domainBuilder phase0.Domain } +func verifySignature(submission *builderSpec.VersionedSubmitBlockRequest, domainBuilder phase0.Domain) error { + bid, err := submission.BidTrace() + if err != nil { + return err + } + + signature, err := submission.Signature() + if err != nil { + return err + } + + builderPubKey := bid.BuilderPubkey + + ok, err := ssz.VerifySignature(bid, domainBuilder, builderPubKey[:], signature[:]) + if err != nil { + return err + } + + if !ok { + return errors.New("invalid builder signature") + } + return nil +} + +func computeDomain(domainType phase0.DomainType, forkVersionHex, genesisValidatorsRootHex string) (domain phase0.Domain, err error) { + genesisValidatorsRoot := phase0.Root(common.HexToHash(genesisValidatorsRootHex)) + forkVersionBytes, err := hexutil.Decode(forkVersionHex) + if err != nil || len(forkVersionBytes) != 4 { + return domain, errors.New("invalid fork version") + } + var forkVersion [4]byte + copy(forkVersion[:], forkVersionBytes[:4]) + return ssz.ComputeDomain(domainType, forkVersion, genesisValidatorsRoot), nil +} + func NewBuilderClient(log log.Logger, rollupCfg *rollup.Config, endpoint string, timeout time.Duration) *BuilderAPIClient { - domainBuilder, err := builder.ComputeDomain(ssz.DomainTypeAppBuilder, GenesisForkVersionMainnet, phase0.Root{}.String()) + domainBuilder, err := computeDomain(ssz.DomainTypeAppBuilder, GenesisForkVersionMainnet, phase0.Root{}.String()) if err != nil { log.Error("failed to compute domain", "error", err) } @@ -77,30 +112,6 @@ type httpErrorResp struct { Message string `json:"message"` } -func verifySignature(submission *builderSpec.VersionedSubmitBlockRequest, domainBuilder phase0.Domain) error { - bid, err := submission.BidTrace() - if err != nil { - return err - } - - signature, err := submission.Signature() - if err != nil { - return err - } - - builderPubKey := bid.BuilderPubkey - - ok, err := ssz.VerifySignature(bid, domainBuilder, builderPubKey[:], signature[:]) - if err != nil { - return err - } - - if !ok { - return errors.New("invalid builder signature") - } - return nil -} - func (s *BuilderAPIClient) GetPayload(ctx context.Context, ref eth.L2BlockRef, log log.Logger) (*eth.ExecutionPayloadEnvelope, error) { submitBlockRequest := new(builderSpec.VersionedSubmitBlockRequest) slot := ref.Number + 1 From d1af6082367b1e34ed91dd47ddaa9f56c49db4b9 Mon Sep 17 00:00:00 2001 From: Jinsuk Park Date: Thu, 22 Aug 2024 23:54:28 +0900 Subject: [PATCH 4/6] nit: move private functions to the end of the file --- op-node/node/builder.go | 70 ++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/op-node/node/builder.go b/op-node/node/builder.go index ab968d1ebd33..0d9c68ced33a 100644 --- a/op-node/node/builder.go +++ b/op-node/node/builder.go @@ -43,41 +43,6 @@ type BuilderAPIClient struct { domainBuilder phase0.Domain } -func verifySignature(submission *builderSpec.VersionedSubmitBlockRequest, domainBuilder phase0.Domain) error { - bid, err := submission.BidTrace() - if err != nil { - return err - } - - signature, err := submission.Signature() - if err != nil { - return err - } - - builderPubKey := bid.BuilderPubkey - - ok, err := ssz.VerifySignature(bid, domainBuilder, builderPubKey[:], signature[:]) - if err != nil { - return err - } - - if !ok { - return errors.New("invalid builder signature") - } - return nil -} - -func computeDomain(domainType phase0.DomainType, forkVersionHex, genesisValidatorsRootHex string) (domain phase0.Domain, err error) { - genesisValidatorsRoot := phase0.Root(common.HexToHash(genesisValidatorsRootHex)) - forkVersionBytes, err := hexutil.Decode(forkVersionHex) - if err != nil || len(forkVersionBytes) != 4 { - return domain, errors.New("invalid fork version") - } - var forkVersion [4]byte - copy(forkVersion[:], forkVersionBytes[:4]) - return ssz.ComputeDomain(domainType, forkVersion, genesisValidatorsRoot), nil -} - func NewBuilderClient(log log.Logger, rollupCfg *rollup.Config, endpoint string, timeout time.Duration) *BuilderAPIClient { domainBuilder, err := computeDomain(ssz.DomainTypeAppBuilder, GenesisForkVersionMainnet, phase0.Root{}.String()) if err != nil { @@ -309,3 +274,38 @@ func denebExecutionPayloadToExecutionPayload(payload *deneb.ExecutionPayload) *e } return envelope } + +func verifySignature(submission *builderSpec.VersionedSubmitBlockRequest, domainBuilder phase0.Domain) error { + bid, err := submission.BidTrace() + if err != nil { + return err + } + + signature, err := submission.Signature() + if err != nil { + return err + } + + builderPubKey := bid.BuilderPubkey + + ok, err := ssz.VerifySignature(bid, domainBuilder, builderPubKey[:], signature[:]) + if err != nil { + return err + } + + if !ok { + return errors.New("invalid builder signature") + } + return nil +} + +func computeDomain(domainType phase0.DomainType, forkVersionHex, genesisValidatorsRootHex string) (domain phase0.Domain, err error) { + genesisValidatorsRoot := phase0.Root(common.HexToHash(genesisValidatorsRootHex)) + forkVersionBytes, err := hexutil.Decode(forkVersionHex) + if err != nil || len(forkVersionBytes) != 4 { + return domain, errors.New("invalid fork version") + } + var forkVersion [4]byte + copy(forkVersion[:], forkVersionBytes[:4]) + return ssz.ComputeDomain(domainType, forkVersion, genesisValidatorsRoot), nil +} From 137ec53bb600a9619681dc8a1582e72139767cbb Mon Sep 17 00:00:00 2001 From: Jinsuk Park Date: Fri, 23 Aug 2024 00:01:13 +0900 Subject: [PATCH 5/6] handle errors from NewBuilderClient --- op-node/node/builder.go | 6 +++--- op-node/node/node.go | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/op-node/node/builder.go b/op-node/node/builder.go index 0d9c68ced33a..cb19356981ce 100644 --- a/op-node/node/builder.go +++ b/op-node/node/builder.go @@ -43,10 +43,10 @@ type BuilderAPIClient struct { domainBuilder phase0.Domain } -func NewBuilderClient(log log.Logger, rollupCfg *rollup.Config, endpoint string, timeout time.Duration) *BuilderAPIClient { +func NewBuilderClient(log log.Logger, rollupCfg *rollup.Config, endpoint string, timeout time.Duration) (*BuilderAPIClient, error) { domainBuilder, err := computeDomain(ssz.DomainTypeAppBuilder, GenesisForkVersionMainnet, phase0.Root{}.String()) if err != nil { - log.Error("failed to compute domain", "error", err) + return nil, fmt.Errorf("failed to compute domain: %w", err) } httpClient := client.NewBasicHTTPClient(endpoint, log) @@ -61,7 +61,7 @@ func NewBuilderClient(log log.Logger, rollupCfg *rollup.Config, endpoint string, rollupCfg: rollupCfg, log: log, domainBuilder: domainBuilder, - } + }, nil } func (s *BuilderAPIClient) Enabled() bool { diff --git a/op-node/node/node.go b/op-node/node/node.go index 1424c1ed838f..d5bae48ac754 100644 --- a/op-node/node/node.go +++ b/op-node/node/node.go @@ -401,7 +401,10 @@ func (n *OpNode) initL2(ctx context.Context, cfg *Config, snapshotLog log.Logger var payloadBuilder builder.PayloadBuilder = &builder.NoOpBuilder{} if cfg.BuilderEnabled { - payloadBuilder = NewBuilderClient(n.log, &cfg.Rollup, cfg.BuilderEndpoint, cfg.BuilderTimeout) + payloadBuilder, err = NewBuilderClient(n.log, &cfg.Rollup, cfg.BuilderEndpoint, cfg.BuilderTimeout) + if err != nil { + return fmt.Errorf("failed to create builder client: %w", err) + } } // if plasma is not explicitly activated in the node CLI, the config + any error will be ignored. From 5108382a780e3518b69a4da6d73802e4f69dd6ff Mon Sep 17 00:00:00 2001 From: Jinsuk Park Date: Fri, 23 Aug 2024 02:44:23 +0900 Subject: [PATCH 6/6] nit: remove builderPubKey variable --- op-node/node/builder.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/op-node/node/builder.go b/op-node/node/builder.go index 9c8b86777c15..0b7c92df127f 100644 --- a/op-node/node/builder.go +++ b/op-node/node/builder.go @@ -290,9 +290,7 @@ func verifySignature(submission *builderSpec.VersionedSubmitBlockRequest, domain return err } - builderPubKey := bid.BuilderPubkey - - ok, err := ssz.VerifySignature(bid, domainBuilder, builderPubKey[:], signature[:]) + ok, err := ssz.VerifySignature(bid, domainBuilder, bid.BuilderPubkey[:], signature[:]) if err != nil { return err }