Skip to content

Commit

Permalink
Merge pull request #38 from chainbound/feat/relay-proof-2
Browse files Browse the repository at this point in the history
Add proof verification to relay
  • Loading branch information
thedevbirb authored May 29, 2024
2 parents 9065e03 + 93e7c94 commit 242a660
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 34 deletions.
76 changes: 43 additions & 33 deletions mev-boost-relay/common/preconf.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,51 @@ import (
"strings"

fastSsz "github.com/ferranbt/fastssz"
"github.com/sirupsen/logrus"

builderSpec "github.com/attestantio/go-builder-client/spec"
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/sirupsen/logrus"
)

// VersionedSubmitBlockRequestWithPreconfsProofs is a wrapper struct
// over `builderSpec.VersionedSubmitBlockRequest`
// to include preconfirmation proofs
type VersionedSubmitBlockRequestWithPreconfsProofs struct {
Inner *VersionedSubmitBlockRequest `json:"inner"`
Proofs []*PreconfirmationWithProof `json:"proofs"`
}

func (v *VersionedSubmitBlockRequestWithPreconfsProofs) String() string {
out, err := json.Marshal(v)
if err != nil {
return err.Error()
}
return string(out)
}

type BidWithPreconfirmationsProofs struct {
// The block bid
Bid *builderSpec.VersionedSignedBuilderBid `json:"bid"`
// The preconfirmations with proofs
Proofs []*PreconfirmationWithProof `json:"proofs"`
}

func (b *BidWithPreconfirmationsProofs) String() string {
out, err := json.Marshal(b)
if err != nil {
return err.Error()
}
return string(out)
}

func (p *PreconfirmationWithProof) String() string {
proofs, err := json.Marshal(p)
if err != nil {
return err.Error()
}
return string(proofs)
}

type HexBytes []byte

// MarshalJSON implements json.Marshaler.
Expand Down Expand Up @@ -65,9 +104,11 @@ func (s *SerializedMerkleProof) FromFastSszProof(p *fastSsz.Proof) {
}
}

func (s *SerializedMerkleProof) ToFastSszProof() *fastSsz.Proof {
// ToFastSszProof converts a SerializedMerkleProof to a fastssz.Proof.
func (s *SerializedMerkleProof) ToFastSszProof(leaf []byte) *fastSsz.Proof {
p := &fastSsz.Proof{
Index: s.Index,
Leaf: leaf,
Hashes: make([][]byte, len(s.Hashes)),
}
for i, h := range s.Hashes {
Expand All @@ -85,37 +126,6 @@ type PreconfirmationWithProof struct {
MerkleProof *SerializedMerkleProof `json:"merkleProof"`
}

func (p PreconfirmationWithProof) String() string {
out, err := json.Marshal(p)
if err != nil {
return err.Error()
}
return string(out)
}

// VersionedSubmitBlockRequestWithPreconfsProofs is a wrapper struct
// over `builderSpec.VersionedSubmitBlockRequest`
// to include preconfirmation proofs
type VersionedSubmitBlockRequestWithPreconfsProofs struct {
Inner *VersionedSubmitBlockRequest `json:"inner"`
Proofs []*PreconfirmationWithProof `json:"proofs"`
}

func (v *VersionedSubmitBlockRequestWithPreconfsProofs) String() string {
out, err := json.Marshal(v)
if err != nil {
return err.Error()
}
return string(out)
}

type BidWithPreconfirmationsProofs struct {
// The block bid
Bid *builderSpec.VersionedSignedBuilderBid `json:"bid"`
// The preconfirmations with proofs
Proofs []*PreconfirmationWithProof `json:"proofs"`
}

func NewBoltLogger(service string) *logrus.Entry {
return LogSetup(false, "info").WithFields(logrus.Fields{
"service": fmt.Sprintf("BOLT-%s", service),
Expand Down
3 changes: 2 additions & 1 deletion mev-boost-relay/services/api/constraints.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// This code is taken from https://github.com/chainbound/bolt/pull/11/files#diff-0fa8405accc1cdc5b108ba0210a8f1d99e25e1a5173e45e1516d73c294b061c4
package api

import (
Expand All @@ -11,6 +10,8 @@ import (
"github.com/pkg/errors"
)

// These types are taken from https://github.com/chainbound/bolt/pull/11/files#diff-0fa8405accc1cdc5b108ba0210a8f1d99e25e1a5173e45e1516d73c294b061c4

type SignedConstraintSubmission struct {
Message *ConstraintSubmission
Signature phase0.BLSSignature `ssz-size:"96"`
Expand Down
81 changes: 81 additions & 0 deletions mev-boost-relay/services/api/proofs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package api

import (
"errors"
"fmt"
"time"

"github.com/attestantio/go-eth2-client/spec/phase0"
fastSsz "github.com/ferranbt/fastssz"
"github.com/flashbots/mev-boost-relay/common"
"github.com/sirupsen/logrus"
)

var (
ErrNilProof = errors.New("nil proof")
ErrInvalidProofs = errors.New("proof verification failed")
ErrInvalidRoot = errors.New("failed getting tx root from bid")
)

// verifyConstraintProofs verifies the proofs against the constraints, and returns an error if the proofs are invalid.
func (api *RelayAPI) verifyConstraintProofs(transactionsRoot phase0.Root, proofs []*common.PreconfirmationWithProof, constraints Constraints) error {
log := api.log.WithFields(logrus.Fields{})
// BOLT: verify preconfirmation inclusion proofs. If they don't match, we don't consider the bid to be valid.
if proofs != nil {
// BOLT: remove unnecessary fields while logging
log.WithFields(logrus.Fields{})

log.WithField("len", len(proofs)).Info("[BOLT]: Verifying constraint proofs")

for _, proof := range proofs {
if proof == nil {
log.Warn("[BOLT]: Nil proof!")
return ErrNilProof
}

// Find the raw tx with the hash specified
constraint, ok := constraints[proof.TxHash]
if !ok {
log.Warnf("[BOLT]: Tx hash %s not found in constraints", proof.TxHash.String())
// We don't actually have to return an error here, the relay just provided a proof that was unnecessary
continue
}

rawTx := constraint.RawTx

if len(rawTx) == 0 {
log.Warnf("[BOLT]: Raw tx is empty for tx hash %s", proof.TxHash.String())
continue
}

// Compute the hash tree root for the raw preconfirmed transaction
// and use it as "Leaf" in the proof to be verified against
txHashTreeRoot, err := rawTx.HashTreeRoot()
if err != nil {
log.WithError(err).Error("[BOLT]: error getting tx hash tree root")
return ErrInvalidRoot
}

// Verify the proof
sszProof := proof.MerkleProof.ToFastSszProof(txHashTreeRoot[:])

currentTime := time.Now()
ok, err = fastSsz.VerifyProof(transactionsRoot[:], sszProof)
elapsed := time.Since(currentTime)

if err != nil {
log.WithError(err).Error("error verifying merkle proof")
return err
}

if !ok {
log.Error("[BOLT]: proof verification failed: 'not ok' for tx hash: ", proof.TxHash.String())
return ErrInvalidProofs
} else {
log.Info(fmt.Sprintf("[BOLT]: Preconfirmation proof verified for tx hash %s in %s", proof.TxHash.String(), elapsed))
}
}
}

return nil
}
14 changes: 14 additions & 0 deletions mev-boost-relay/services/api/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -1980,6 +1980,20 @@ func (api *RelayAPI) updateRedisBid(
return nil, nil, false
}

slotConstraints, _ := api.constraints.Get(api.headSlot.Load())
if slotConstraints != nil {
transactionsRoot, err := getHeaderResponse.TransactionsRoot()
if err != nil {
api.RespondError(opts.w, http.StatusBadRequest, err.Error())
return nil, nil, false
}
err = api.verifyConstraintProofs(transactionsRoot, proofs, *slotConstraints)
if err != nil {
api.RespondError(opts.w, http.StatusBadRequest, err.Error())
return nil, nil, false
}
}

getPayloadResponse, err := common.BuildGetPayloadResponse(opts.payload)
if err != nil {
opts.log.WithError(err).Error("could not build getPayload response")
Expand Down

0 comments on commit 242a660

Please sign in to comment.