Skip to content

Commit

Permalink
feat: Batch hash verification
Browse files Browse the repository at this point in the history
  • Loading branch information
EthenNotEthan committed Jun 18, 2024
1 parent 322002e commit ba05698
Show file tree
Hide file tree
Showing 12 changed files with 373 additions and 20 deletions.
1 change: 1 addition & 0 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,6 @@ jobs:
- name: Run holesky tests
env:
SIGNER_PRIVATE_KEY: ${{ secrets.SIGNER_PRIVATE_KEY }}
ETHEREUM_RPC: ${{ secrets.ETHEREUM_RPC }}
run: |
SIGNER_PRIVATE_KEY=$SIGNER_PRIVATE_KEY make holesky-test
9 changes: 9 additions & 0 deletions e2e/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

const (
privateKey = "SIGNER_PRIVATE_KEY"
ethRPC = "ETHEREUM_RPC"
transport = "http"
svcName = "eigenda_proxy"
host = "127.0.0.1"
Expand All @@ -43,6 +44,12 @@ func CreateTestSuite(t *testing.T, useMemory bool) (TestSuite, func()) {
t.Fatal("SIGNER_PRIVATE_KEY environment variable not set")
}

// load node url from environment
ethRPC := os.Getenv(ethRPC)
if ethRPC != "" && !useMemory {
t.Fatal("ETHEREUM_RPC environment variable is not set")
}

log := oplog.NewLogger(os.Stdout, oplog.CLIConfig{
Level: log.LevelDebug,
Format: oplog.FormatLogFmt,
Expand All @@ -57,6 +64,8 @@ func CreateTestSuite(t *testing.T, useMemory bool) (TestSuite, func()) {
DisableTLS: false,
SignerPrivateKeyHex: pk,
},
EthRPC: ethRPC,
SvcManagerAddr: "0xD4A7E1Bd8015057293f0D0A557088c286942e84b", // incompatible with non holeskly networks
CacheDir: "../operator-setup/resources/SRSTables",
G1Path: "../operator-setup/resources/g1_abbr.point",
G2Path: "../test/resources/kzg/g2.point", // do we need this?
Expand Down
39 changes: 37 additions & 2 deletions eigenda/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/Layr-Labs/eigenda-proxy/common"
"github.com/Layr-Labs/eigenda-proxy/verify"
"github.com/Layr-Labs/eigenda/api/clients"
"github.com/Layr-Labs/eigenda/api/clients/codecs"
"github.com/Layr-Labs/eigenda/encoding/kzg"
Expand All @@ -16,6 +17,8 @@ import (

const (
RPCFlagName = "eigenda-rpc"
EthRPCFlagName = "eigenda-eth-rpc"
SvcManagerAddrFlagName = "eigenda-svc-manager-addr"
StatusQueryRetryIntervalFlagName = "eigenda-status-query-retry-interval"
StatusQueryTimeoutFlagName = "eigenda-status-query-timeout"
DisableTlsFlagName = "eigenda-disable-tls"
Expand Down Expand Up @@ -44,6 +47,10 @@ type Config struct {
// The blob encoding version to use when writing blobs from the high level interface.
PutBlobEncodingVersion codecs.BlobEncodingVersion

// ETH vars
EthRPC string
SvcManagerAddr string

// KZG vars
CacheDir string

Expand Down Expand Up @@ -73,21 +80,37 @@ func (c *Config) GetMaxBlobLength() (uint64, error) {
return c.maxBlobLengthBytes, nil
}

func (c *Config) KzgConfig() *kzg.KzgConfig {
func (c *Config) VerificationCfg() *verify.Config {
numBytes, err := c.GetMaxBlobLength()
if err != nil {
panic(fmt.Errorf("Check() was not called on config object, err is not nil: %w", err))
}

numPointsNeeded := uint64(math.Ceil(float64(numBytes) / BytesPerSymbol))
return &kzg.KzgConfig{

kzgCfg := &kzg.KzgConfig{
G1Path: c.G1Path,
G2PowerOf2Path: c.G2PowerOfTauPath,
CacheDir: c.CacheDir,
SRSOrder: numPointsNeeded,
SRSNumberToLoad: numPointsNeeded,
NumWorker: uint64(runtime.GOMAXPROCS(0)),
}

if c.EthRPC == "" || c.SvcManagerAddr == "" {
return &verify.Config{
Verify: false,
KzgConfig: kzgCfg,
}
}

return &verify.Config{
Verify: true,
RPCURL: c.EthRPC,
SvcManagerAddr: c.SvcManagerAddr,
KzgConfig: kzgCfg,
}

}

// NewConfig parses the Config from the provided flags or environment variables.
Expand All @@ -109,6 +132,8 @@ func ReadConfig(ctx *cli.Context) Config {
G2PowerOfTauPath: ctx.String(G2TauFlagName),
CacheDir: ctx.String(CachePathFlagName),
MaxBlobLength: ctx.String(MaxBlobLengthFlagName),
SvcManagerAddr: ctx.String(SvcManagerAddrFlagName),
EthRPC: ctx.String(EthRPCFlagName),
}
return cfg
}
Expand Down Expand Up @@ -199,5 +224,15 @@ func CLIFlags(envPrefix string) []cli.Flag {
Usage: "Directory path to SRS tables",
EnvVars: prefixEnvVars("TARGET_CACHE_PATH"),
},
&cli.StringFlag{
Name: EthRPCFlagName,
Usage: "JSON RPC node endpoint for the Ethereum network used for finalizing DA blobs.",
EnvVars: prefixEnvVars("ETH_RPC"),
},
&cli.StringFlag{
Name: SvcManagerAddrFlagName,
Usage: "Deployed EigenDA service manager address.",
EnvVars: prefixEnvVars("SERVICE_MANAGER_ADDR"),
},
}
}
11 changes: 9 additions & 2 deletions server/load_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,20 @@ import (
)

func LoadStore(cfg CLIConfig, ctx context.Context, log log.Logger) (store.Store, error) {
log.Info("Using eigenda backend")
daCfg := cfg.EigenDAConfig
vCfg := daCfg.VerificationCfg()

verifier, err := verify.NewVerifier(daCfg.KzgConfig())
verifier, err := verify.NewVerifier(vCfg, log)
if err != nil {
return nil, err
}

if vCfg.Verify {
log.Info("Certificate verification with Ethereum enabled")
} else {
log.Warn("Verification disabled")
}

maxBlobLength, err := daCfg.GetMaxBlobLength()
if err != nil {
return nil, err
Expand All @@ -28,6 +34,7 @@ func LoadStore(cfg CLIConfig, ctx context.Context, log log.Logger) (store.Store,
return store.NewMemStore(ctx, &cfg.MemStoreCfg, verifier, log, maxBlobLength)
}

log.Info("Using eigenda backend")
client, err := clients.NewEigenDAClient(log, daCfg.ClientConfig)
if err != nil {
return nil, err
Expand Down
13 changes: 9 additions & 4 deletions store/eigenda.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,15 @@ func (e EigenDAStore) Get(ctx context.Context, key []byte, domain common.DomainT
// reencode blob for verification
encodedBlob, err := e.client.GetCodec().EncodeBlob(decodedBlob)
if err != nil {
return nil, fmt.Errorf("EigenDA client failed to reencode blob: %w", err)
return nil, fmt.Errorf("EigenDA client failed to re-encode blob: %w", err)
}

err = e.verifier.Verify(cert.BlobHeader.Commitment, encodedBlob)
err = e.verifier.VerifyCommitment(cert.BlobHeader.Commitment, encodedBlob)
if err != nil {
return nil, err
}

err = e.verifier.VerifyCert(&cert)
if err != nil {
return nil, err
}
Expand All @@ -73,9 +78,9 @@ func (e EigenDAStore) Put(ctx context.Context, value []byte) (comm []byte, err e

encodedBlob, err := e.client.GetCodec().EncodeBlob(value)
if err != nil {
return nil, fmt.Errorf("EigenDA client failed to reencode blob: %w", err)
return nil, fmt.Errorf("EigenDA client failed to re-encode blob: %w", err)
}
err = e.verifier.Verify(cert.BlobHeader.Commitment, encodedBlob)
err = e.verifier.VerifyCommitment(cert.BlobHeader.Commitment, encodedBlob)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion store/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func (e *MemStore) Get(ctx context.Context, commit []byte, domain eigendacommon.
}

// Don't need to do this really since it's a mock store
err = e.verifier.Verify(cert.BlobHeader.Commitment, encodedBlob)
err = e.verifier.VerifyCommitment(cert.BlobHeader.Commitment, encodedBlob)
if err != nil {
return nil, err
}
Expand Down
16 changes: 14 additions & 2 deletions store/memory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,13 @@ func TestGetSet(t *testing.T) {
SRSNumberToLoad: 3000,
NumWorker: uint64(runtime.GOMAXPROCS(0)),
}
verifier, err := verify.NewVerifier(kzgConfig)

cfg := &verify.Config{
Verify: false,
KzgConfig: kzgConfig,
}

verifier, err := verify.NewVerifier(cfg, nil)
assert.NoError(t, err)

ms, err := NewMemStore(
Expand Down Expand Up @@ -68,7 +74,13 @@ func TestExpiration(t *testing.T) {
SRSNumberToLoad: 3000,
NumWorker: uint64(runtime.GOMAXPROCS(0)),
}
verifier, err := verify.NewVerifier(kzgConfig)

cfg := &verify.Config{
Verify: false,
KzgConfig: kzgConfig,
}

verifier, err := verify.NewVerifier(cfg, nil)
assert.NoError(t, err)

ms, err := NewMemStore(
Expand Down
72 changes: 72 additions & 0 deletions verify/cert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package verify

import (
"fmt"

proxy_common "github.com/Layr-Labs/eigenda-proxy/common"
binding "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDAServiceManager"
"github.com/ethereum/go-ethereum/common"

"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
)

// CertVerifier verifies the DA certificate against on-chain EigenDA contracts
// to ensure disperser returned fields haven't been tampered with
type CertVerifier struct {
manager *binding.ContractEigenDAServiceManagerCaller
}

func NewCertVerifier(cfg *Config, l log.Logger) (*CertVerifier, error) {
client, err := ethclient.Dial(cfg.RPCURL)
if err != nil {
return nil, fmt.Errorf("failed to dial ETH RPC node: %s", err.Error())
}

// construct binding
m, err := binding.NewContractEigenDAServiceManagerCaller(common.HexToAddress(cfg.SvcManagerAddr), client)
if err != nil {
return nil, err
}

return &CertVerifier{
manager: m,
}, nil
}

func (cv *CertVerifier) VerifyBatch(header *binding.IEigenDAServiceManagerBatchHeader,
id uint32, recordHash [32]byte, blockNum uint32) error {
// 1 - Verify batch hash

// 1.a - ensure that a batch hash can be looked up for a batch ID
expectedHash, err := cv.manager.BatchIdToBatchMetadataHash(nil, id)
if err != nil {
return err
}

// 1.b - ensure that hash generated from local cert matches one stored on-chain

actualHash, err := HashBatchMetadata(header, recordHash, blockNum)

if err != nil {
return err
}

equal := proxy_common.EqualSlices(expectedHash[:], actualHash[:])
if !equal {
return fmt.Errorf("batch hash mismatch, expected: %x, got: %x", expectedHash, actualHash)
}

return nil
}

// 2 - (TODO) merkle proof verification

func (cv *CertVerifier) VerifyMerkleProof(inclusionProof []byte, rootHash []byte, leafHash []byte, index uint64) error {
return nil
}

// 3 - (TODO) verify blob security params
func (cv *CertVerifier) Verify(inclusionProof []byte, rootHash []byte, leafHash []byte, index uint64) error {
return nil
}
Loading

0 comments on commit ba05698

Please sign in to comment.