Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[inabox] v2 onchain blob verification #1031

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contracts/script/SetUpEigenDA.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ contract SetupEigenDA is EigenDADeployer, EigenLayerUtils {
vm.serializeAddress(output, "operatorStateRetriever", address(operatorStateRetriever));
vm.serializeAddress(output, "blsApkRegistry" , address(apkRegistry));
vm.serializeAddress(output, "registryCoordinator", address(registryCoordinator));
vm.serializeAddress(output, "blobVerifier", address(eigenDABlobVerifier));

string memory finalJson = vm.serializeString(output, "object", output);

Expand Down
1 change: 1 addition & 0 deletions inabox/deploy/config_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ type EigenDAContract struct {
OperatorStateRetreiver string `json:"operatorStateRetriever"`
BlsApkRegistry string `json:"blsApkRegistry"`
RegistryCoordinator string `json:"registryCoordinator"`
BlobVerifier string `json:"blobVerifier"`
}

type Stakes struct {
Expand Down
4 changes: 4 additions & 0 deletions inabox/tests/integration_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
clientsv2 "github.com/Layr-Labs/eigenda/api/clients/v2"
"github.com/Layr-Labs/eigenda/common"
"github.com/Layr-Labs/eigenda/common/geth"
verifierbindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier"
rollupbindings "github.com/Layr-Labs/eigenda/contracts/bindings/MockRollup"
"github.com/Layr-Labs/eigenda/core"
"github.com/Layr-Labs/eigenda/core/eth"
Expand Down Expand Up @@ -47,6 +48,7 @@ var (
ethClient common.EthClient
rpcClient common.RPCEthClient
mockRollup *rollupbindings.ContractMockRollup
verifierContract *verifierbindings.ContractEigenDABlobVerifier
retrievalClient clients.RetrievalClient
retrievalClientV2 clientsv2.RetrievalClient
numConfirmations int = 3
Expand Down Expand Up @@ -137,6 +139,8 @@ var _ = BeforeSuite(func() {

mockRollup, err = rollupbindings.NewContractMockRollup(gcommon.HexToAddress(testConfig.MockRollup), ethClient)
Expect(err).To(BeNil())
verifierContract, err = verifierbindings.NewContractEigenDABlobVerifier(gcommon.HexToAddress(testConfig.EigenDA.BlobVerifier), ethClient)
Expect(err).To(BeNil())
err = setupRetrievalClient(testConfig)
Expect(err).To(BeNil())
}
Expand Down
225 changes: 214 additions & 11 deletions inabox/tests/integration_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ import (
"bytes"
"context"
"crypto/rand"
"fmt"
"math/big"
"time"

"github.com/Layr-Labs/eigenda/api/clients/v2"
commonpb "github.com/Layr-Labs/eigenda/api/grpc/common/v2"
disperserpb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2"
verifierbindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier"
"github.com/Layr-Labs/eigenda/core"
auth "github.com/Layr-Labs/eigenda/core/auth/v2"
corev2 "github.com/Layr-Labs/eigenda/core/v2"
dispv2 "github.com/Layr-Labs/eigenda/disperser/common/v2"
"github.com/Layr-Labs/eigenda/encoding/utils/codec"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/wealdtech/go-merkletree/v2"
Expand Down Expand Up @@ -64,8 +67,10 @@ var _ = Describe("Inabox v2 Integration", func() {
var reply2 *disperserpb.BlobStatusReply
var blobCert1 *corev2.BlobCertificate
var blobCert2 *corev2.BlobCertificate
var batchHeader1 *commonpb.BatchHeader
var batchHeader2 *commonpb.BatchHeader
var signedBatch1 *disperserpb.SignedBatch
var signedBatch2 *disperserpb.SignedBatch
var blobVerification1 *disperserpb.BlobVerificationInfo
var blobVerification2 *disperserpb.BlobVerificationInfo
for loop := true; loop; {
select {
case <-ctx.Done():
Expand All @@ -87,7 +92,8 @@ var _ = Describe("Inabox v2 Integration", func() {
continue
}

batchHeader1 = reply1.GetSignedBatch().GetHeader()
signedBatch1 = reply1.GetSignedBatch()
batchHeader1 := signedBatch1.GetHeader()
Expect(batchHeader1).To(Not(BeNil()))
Expect(batchHeader1.GetBatchRoot()).To(Not(BeNil()))
Expect(batchHeader1.GetReferenceBlockNumber()).To(BeNumerically(">", 0))
Expand All @@ -103,8 +109,8 @@ var _ = Describe("Inabox v2 Integration", func() {
Expect(blobVerification.GetBlobCertificate()).To(Not(BeNil()))
blobCert1, err = corev2.BlobCertificateFromProtobuf(blobVerification.GetBlobCertificate())
Expect(err).To(BeNil())
inclusionProofBytes := blobVerification.GetInclusionProof()
blobIndex := blobVerification.GetBlobIndex()
inclusionProofBytes := blobVerification1.GetInclusionProof()
blobIndex := blobVerification1.GetBlobIndex()
proof, err := core.DeserializeMerkleProof(inclusionProofBytes, uint64(blobIndex))
Expect(err).To(BeNil())
certHash, err := blobCert1.Hash()
Expand All @@ -115,7 +121,8 @@ var _ = Describe("Inabox v2 Integration", func() {
Expect(err).To(BeNil())
Expect(verified).To(BeTrue())

batchHeader2 = reply2.GetSignedBatch().GetHeader()
signedBatch2 = reply2.GetSignedBatch()
batchHeader2 := signedBatch2.GetHeader()
Expect(batchHeader2).To(Not(BeNil()))
Expect(batchHeader2.GetBatchRoot()).To(Not(BeNil()))
Expect(batchHeader2.GetReferenceBlockNumber()).To(BeNumerically(">", 0))
Expand All @@ -131,21 +138,71 @@ var _ = Describe("Inabox v2 Integration", func() {
Expect(blobVerification.GetBlobCertificate()).To(Not(BeNil()))
blobCert2, err = corev2.BlobCertificateFromProtobuf(blobVerification.GetBlobCertificate())
Expect(err).To(BeNil())
inclusionProofBytes = blobVerification.GetInclusionProof()
blobIndex = blobVerification.GetBlobIndex()
inclusionProofBytes = blobVerification2.GetInclusionProof()
blobIndex = blobVerification2.GetBlobIndex()
proof, err = core.DeserializeMerkleProof(inclusionProofBytes, uint64(blobIndex))
Expect(err).To(BeNil())
certHash, err = blobCert2.Hash()
Expect(err).To(BeNil())
verified, err = merkletree.VerifyProofUsing(certHash[:], false, proof, [][]byte{batchHeader2.BatchRoot}, keccak256.New())
Expect(err).To(BeNil())
Expect(verified).To(BeTrue())
// TODO(ian-shim): verify the blob onchain using a mock rollup contract
loop = false
}
}

// Test retrieval from relay
// necessary to ensure that reference block number < current block number
mineAnvilBlocks(1)

// test onchain verification
batchHeader1 := signedBatch1.GetHeader()
attestation, err := convertAttestation(signedBatch1.GetAttestation())
Expect(err).To(BeNil())
proof, err := convertBlobVerificationInfo(blobVerification1)
Expect(err).To(BeNil())
deserializedProof, err := core.DeserializeMerkleProof(proof.InclusionProof, uint64(proof.BlobIndex))
Expect(err).To(BeNil())
certHash, err := blobCert1.Hash()
Expect(err).To(BeNil())
verified, err := merkletree.VerifyProofUsing(certHash[:], false, deserializedProof, [][]byte{batchHeader1.BatchRoot}, keccak256.New())
Expect(err).To(BeNil())
Expect(verified).To(BeTrue())

var batchRoot [32]byte
copy(batchRoot[:], batchHeader1.BatchRoot)
err = verifierContract.VerifyBlobV2FromSignedBatch(
&bind.CallOpts{},
verifierbindings.SignedBatch{
BatchHeader: verifierbindings.BatchHeaderV2{
BatchRoot: batchRoot,
ReferenceBlockNumber: uint32(batchHeader1.ReferenceBlockNumber),
},
Attestation: *attestation,
},
*proof,
)
Expect(err).To(BeNil())

batchHeader2 := signedBatch2.GetHeader()
attestation, err = convertAttestation(signedBatch2.GetAttestation())
Expect(err).To(BeNil())
proof, err = convertBlobVerificationInfo(blobVerification2)
Expect(err).To(BeNil())
copy(batchRoot[:], batchHeader2.BatchRoot)
err = verifierContract.VerifyBlobV2FromSignedBatch(
&bind.CallOpts{},
verifierbindings.SignedBatch{
BatchHeader: verifierbindings.BatchHeaderV2{
BatchRoot: batchRoot,
ReferenceBlockNumber: uint32(batchHeader2.ReferenceBlockNumber),
},
Attestation: *attestation,
},
*proof,
)
Expect(err).To(BeNil())

// test retrieval from relay
relayClient, err := clients.NewRelayClient(&clients.RelayClientConfig{
Sockets: relays,
}, logger)
Expand Down Expand Up @@ -177,6 +234,7 @@ var _ = Describe("Inabox v2 Integration", func() {
}
}

// Test retrieval from DA network
b, err := retrievalClientV2.GetBlob(ctx, blobCert1.BlobHeader, batchHeader1.ReferenceBlockNumber, 0)
Expect(err).To(BeNil())
restored := bytes.TrimRight(b, "\x00")
Expand All @@ -195,3 +253,148 @@ var _ = Describe("Inabox v2 Integration", func() {
Expect(restored).To(BeNil())
})
})

func convertBlobVerificationInfo(verificationInfo *disperserpb.BlobVerificationInfo) (*verifierbindings.BlobVerificationProofV2, error) {
blobCertificate, err := corev2.BlobCertificateFromProtobuf(verificationInfo.GetBlobCertificate())
if err != nil {
return nil, err
}
paymentHeaderHash, err := blobCertificate.BlobHeader.PaymentMetadata.Hash()
if err != nil {
return nil, err
}

inclusionProof := verificationInfo.GetInclusionProof()
blobIndex := verificationInfo.GetBlobIndex()

commitX := big.NewInt(0)
blobCertificate.BlobHeader.BlobCommitments.Commitment.X.BigInt(commitX)
commitY := big.NewInt(0)
blobCertificate.BlobHeader.BlobCommitments.Commitment.Y.BigInt(commitY)
lengthCommitX0 := big.NewInt(0)
blobCertificate.BlobHeader.BlobCommitments.LengthCommitment.X.A0.BigInt(lengthCommitX0)
lengthCommitX1 := big.NewInt(0)
blobCertificate.BlobHeader.BlobCommitments.LengthCommitment.X.A1.BigInt(lengthCommitX1)
lengthCommitY0 := big.NewInt(0)
blobCertificate.BlobHeader.BlobCommitments.LengthCommitment.Y.A0.BigInt(lengthCommitY0)
lengthCommitY1 := big.NewInt(0)
blobCertificate.BlobHeader.BlobCommitments.LengthCommitment.Y.A1.BigInt(lengthCommitY1)
lengthProofX0 := big.NewInt(0)
blobCertificate.BlobHeader.BlobCommitments.LengthProof.X.A0.BigInt(lengthProofX0)
lengthProofX1 := big.NewInt(0)
blobCertificate.BlobHeader.BlobCommitments.LengthProof.X.A1.BigInt(lengthProofX1)
lengthProofY0 := big.NewInt(0)
blobCertificate.BlobHeader.BlobCommitments.LengthProof.Y.A0.BigInt(lengthProofY0)
lengthProofY1 := big.NewInt(0)
blobCertificate.BlobHeader.BlobCommitments.LengthProof.Y.A1.BigInt(lengthProofY1)
return &verifierbindings.BlobVerificationProofV2{
BlobCertificate: verifierbindings.BlobCertificate{
BlobHeader: verifierbindings.BlobHeaderV2{
Version: uint16(blobCertificate.BlobHeader.BlobVersion),
QuorumNumbers: blobCertificate.BlobHeader.QuorumNumbers,
Commitment: verifierbindings.BlobCommitment{
Commitment: verifierbindings.BN254G1Point{
X: commitX,
Y: commitY,
},
LengthCommitment: verifierbindings.BN254G2Point{
X: [2]*big.Int{lengthCommitX0, lengthCommitX1},
Y: [2]*big.Int{lengthCommitY0, lengthCommitY1},
},
LengthProof: verifierbindings.BN254G2Point{
X: [2]*big.Int{lengthProofX0, lengthProofX1},
Y: [2]*big.Int{lengthProofY0, lengthProofY1},
},
DataLength: uint32(blobCertificate.BlobHeader.BlobCommitments.Length),
},
PaymentHeaderHash: paymentHeaderHash,
},
RelayKeys: blobCertificate.RelayKeys,
},
InclusionProof: inclusionProof,
BlobIndex: blobIndex,
}, nil
}

func convertAttestation(attestation *disperserpb.Attestation) (*verifierbindings.Attestation, error) {
if attestation == nil {
return nil, fmt.Errorf("attestation is nil")
}
nonSignerPubkeys := make([]verifierbindings.BN254G1Point, 0)
for _, pubkey := range attestation.GetNonSignerPubkeys() {
pk, err := convertG1Point(pubkey)
if err != nil {
return nil, err
}
nonSignerPubkeys = append(nonSignerPubkeys, *pk)
}

quorumApks := make([]verifierbindings.BN254G1Point, 0)
for _, apk := range attestation.GetQuorumApks() {
apk, err := convertG1Point(apk)
if err != nil {
return nil, err
}
quorumApks = append(quorumApks, *apk)
}

if attestation.GetSigma() == nil {
return nil, fmt.Errorf("attestation sigma is nil")
}
sigma, err := convertG1Point(attestation.GetSigma())
if err != nil {
return nil, err
}

if attestation.GetApkG2() == nil {
return nil, fmt.Errorf("attestation apkG2 is nil")
}
apkg2, err := convertG2Point(attestation.GetApkG2())
if err != nil {
return nil, err
}

return &verifierbindings.Attestation{
NonSignerPubkeys: nonSignerPubkeys,
QuorumApks: quorumApks,
Sigma: *sigma,
ApkG2: *apkg2,
QuorumNumbers: attestation.GetQuorumNumbers(),
}, nil
}

func convertG1Point(data []byte) (*verifierbindings.BN254G1Point, error) {
point, err := new(core.G1Point).Deserialize(data)
if err != nil {
return nil, err
}
x := big.NewInt(0)
y := big.NewInt(0)

point.X.BigInt(x)
point.Y.BigInt(y)
return &verifierbindings.BN254G1Point{
X: x,
Y: y,
}, nil
}

func convertG2Point(data []byte) (*verifierbindings.BN254G2Point, error) {
point, err := new(core.G2Point).Deserialize(data)
if err != nil {
return nil, err
}
x0 := big.NewInt(0)
x1 := big.NewInt(0)
y0 := big.NewInt(0)
y1 := big.NewInt(0)

point.X.A0.BigInt(x0)
point.X.A1.BigInt(x1)
point.Y.A0.BigInt(y0)
point.Y.A1.BigInt(y1)
return &verifierbindings.BN254G2Point{
X: [2]*big.Int{x0, x1},
Y: [2]*big.Int{y0, y1},
}, nil
}
Loading