Skip to content

Commit

Permalink
[v2] Refactor object serialization (#870)
Browse files Browse the repository at this point in the history
  • Loading branch information
ian-shim authored Nov 8, 2024
1 parent bab71e8 commit 6e14746
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 202 deletions.
4 changes: 2 additions & 2 deletions api/grpc/common/v2/common.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api/proto/common/v2/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ message BlobHeader {
// BlobCertificate is what gets attested by the network
message BlobCertificate {
BlobHeader blob_header = 1;
repeated uint32 relays = 3;
repeated uint32 relays = 2;
}

// BatchHeader is the header of a batch of blobs
Expand Down
265 changes: 265 additions & 0 deletions core/v2/serialization.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
package v2

import (
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi"
"golang.org/x/crypto/sha3"
)

type abiG1Commit struct {
X *big.Int
Y *big.Int
}
type abiG2Commit struct {
X [2]*big.Int
Y [2]*big.Int
}
type abiBlobCommitments struct {
Commitment abiG1Commit
LengthCommitment abiG2Commit
LengthProof abiG2Commit
Length uint32
}
type abiBlobHeader struct {
BlobVersion uint8
BlobCommitments abiBlobCommitments
QuorumNumbers []byte
PaymentMetadataHash [32]byte
}

func blobHeaderArgMarshaling() []abi.ArgumentMarshaling {
return []abi.ArgumentMarshaling{
{
Name: "blobVersion",
Type: "uint8",
},
{
Name: "blobCommitments",
Type: "tuple",
Components: []abi.ArgumentMarshaling{
{
Name: "commitment",
Type: "tuple",
Components: []abi.ArgumentMarshaling{
{
Name: "X",
Type: "uint256",
},
{
Name: "Y",
Type: "uint256",
},
},
},
{
Name: "lengthCommitment",
Type: "tuple",
Components: []abi.ArgumentMarshaling{
{
Name: "X",
Type: "uint256[2]",
},
{
Name: "Y",
Type: "uint256[2]",
},
},
},
{
Name: "lengthProof",
Type: "tuple",
Components: []abi.ArgumentMarshaling{
{
Name: "X",
Type: "uint256[2]",
},
{
Name: "Y",
Type: "uint256[2]",
},
},
},
{
Name: "length",
Type: "uint32",
},
},
},
{
Name: "quorumNumbers",
Type: "bytes",
},
{
Name: "paymentMetadataHash",
Type: "bytes32",
},
}
}

func (b *BlobHeader) toABIStruct() (abiBlobHeader, error) {
paymentHash, err := b.PaymentMetadata.Hash()
if err != nil {
return abiBlobHeader{}, err
}
return abiBlobHeader{
BlobVersion: uint8(b.BlobVersion),
BlobCommitments: abiBlobCommitments{
Commitment: abiG1Commit{
X: b.BlobCommitments.Commitment.X.BigInt(new(big.Int)),
Y: b.BlobCommitments.Commitment.Y.BigInt(new(big.Int)),
},
LengthCommitment: abiG2Commit{
X: [2]*big.Int{
b.BlobCommitments.LengthCommitment.X.A0.BigInt(new(big.Int)),
b.BlobCommitments.LengthCommitment.X.A1.BigInt(new(big.Int)),
},
Y: [2]*big.Int{
b.BlobCommitments.LengthCommitment.Y.A0.BigInt(new(big.Int)),
b.BlobCommitments.LengthCommitment.Y.A1.BigInt(new(big.Int)),
},
},
LengthProof: abiG2Commit{
X: [2]*big.Int{
b.BlobCommitments.LengthProof.X.A0.BigInt(new(big.Int)),
b.BlobCommitments.LengthProof.X.A1.BigInt(new(big.Int)),
},
Y: [2]*big.Int{
b.BlobCommitments.LengthProof.Y.A0.BigInt(new(big.Int)),
b.BlobCommitments.LengthProof.Y.A1.BigInt(new(big.Int)),
},
},
Length: uint32(b.BlobCommitments.Length),
},
QuorumNumbers: b.QuorumNumbers,
PaymentMetadataHash: paymentHash,
}, nil
}

func (b *BlobHeader) BlobKey() (BlobKey, error) {
blobHeaderType, err := abi.NewType("tuple", "", blobHeaderArgMarshaling())
if err != nil {
return [32]byte{}, err
}

arguments := abi.Arguments{
{
Type: blobHeaderType,
},
}

s, err := b.toABIStruct()
if err != nil {
return [32]byte{}, err
}

bytes, err := arguments.Pack(s)
if err != nil {
return [32]byte{}, err
}

var headerHash [32]byte
hasher := sha3.NewLegacyKeccak256()
hasher.Write(bytes)
copy(headerHash[:], hasher.Sum(nil)[:32])

return headerHash, nil
}

func (c *BlobCertificate) Hash() ([32]byte, error) {
if c.BlobHeader == nil {
return [32]byte{}, fmt.Errorf("blob header is nil")
}

blobCertType, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{
{
Name: "blobHeader",
Type: "tuple",
Components: blobHeaderArgMarshaling(),
},
{
Name: "relayKeys",
Type: "uint16[]",
},
})
if err != nil {
return [32]byte{}, err
}

arguments := abi.Arguments{
{
Type: blobCertType,
},
}

bh, err := c.BlobHeader.toABIStruct()
if err != nil {
return [32]byte{}, err
}
s := struct {
BlobHeader abiBlobHeader
RelayKeys []RelayKey
}{
BlobHeader: bh,
RelayKeys: c.RelayKeys,
}

bytes, err := arguments.Pack(s)
if err != nil {
return [32]byte{}, err
}

var blobCertHash [32]byte
hasher := sha3.NewLegacyKeccak256()
hasher.Write(bytes)
copy(blobCertHash[:], hasher.Sum(nil)[:32])

return blobCertHash, nil
}

// GetBatchHeaderHash returns the hash of the batch header
func (h BatchHeader) Hash() ([32]byte, error) {
var headerHash [32]byte

// The order here has to match the field ordering of ReducedBatchHeader defined in IEigenDAServiceManager.sol
// ref: https://github.com/Layr-Labs/eigenda/blob/master/contracts/src/interfaces/IEigenDAServiceManager.sol#L43
batchHeaderType, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{
{
Name: "blobHeadersRoot",
Type: "bytes32",
},
{
Name: "referenceBlockNumber",
Type: "uint32",
},
})
if err != nil {
return headerHash, err
}

arguments := abi.Arguments{
{
Type: batchHeaderType,
},
}

s := struct {
BlobHeadersRoot [32]byte
ReferenceBlockNumber uint32
}{
BlobHeadersRoot: h.BatchRoot,
ReferenceBlockNumber: uint32(h.ReferenceBlockNumber),
}

bytes, err := arguments.Pack(s)
if err != nil {
return headerHash, err
}

hasher := sha3.NewLegacyKeccak256()
hasher.Write(bytes)
copy(headerHash[:], hasher.Sum(nil)[:32])

return headerHash, nil
}
30 changes: 29 additions & 1 deletion core/v2/types_test.go → core/v2/serialization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func TestBlobKeyFromHeader(t *testing.T) {
assert.Equal(t, "b19d368345990c79744fe571fe99f427f35787b9383c55089fb5bd6a5c171bbc", blobKey.Hex())
}

func TestBatchHeaderHAsh(t *testing.T) {
func TestBatchHeaderHash(t *testing.T) {
batchRoot := [32]byte{}
copy(batchRoot[:], []byte("1"))
batchHeader := &v2.BatchHeader{
Expand All @@ -69,3 +69,31 @@ func TestBatchHeaderHAsh(t *testing.T) {
// 0x891d0936da4627f445ef193aad63afb173409af9e775e292e4e35aff790a45e2 verified in solidity
assert.Equal(t, "891d0936da4627f445ef193aad63afb173409af9e775e292e4e35aff790a45e2", hex.EncodeToString(hash[:]))
}

func TestBlobCertHash(t *testing.T) {
data := codec.ConvertByPaddingEmptyByte(GETTYSBURG_ADDRESS_BYTES)
commitments, err := p.GetCommitments(data)
if err != nil {
t.Fatal(err)
}

blobCert := &v2.BlobCertificate{
BlobHeader: &v2.BlobHeader{
BlobVersion: 0,
BlobCommitments: commitments,
QuorumNumbers: []core.QuorumID{0, 1},
PaymentMetadata: core.PaymentMetadata{
AccountID: "0x123",
BinIndex: 5,
CumulativePayment: big.NewInt(100),
},
Signature: []byte{1, 2, 3},
},
RelayKeys: []v2.RelayKey{4, 5, 6},
}

hash, err := blobCert.Hash()
assert.NoError(t, err)
// 0xc4512b8702f69cb837fff50a93d3d28aada535b1f151b64db45859c3f5bb096a verified in solidity
assert.Equal(t, "c4512b8702f69cb837fff50a93d3d28aada535b1f151b64db45859c3f5bb096a", hex.EncodeToString(hash[:]))
}
Loading

0 comments on commit 6e14746

Please sign in to comment.