Skip to content
Merged
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
14 changes: 4 additions & 10 deletions node/types/blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func RetrieveBlobBytes(blob *kzg4844.Blob) ([]byte, error) {
return data, nil
}

func makeBCP(bz []byte) (b kzg4844.Blob, c kzg4844.Commitment, p kzg4844.Proof, err error) {
func makeBlobCommitment(bz []byte) (b kzg4844.Blob, c kzg4844.Commitment, err error) {
blob, err := MakeBlobCanonical(bz)
if err != nil {
return
Expand All @@ -62,10 +62,6 @@ func makeBCP(bz []byte) (b kzg4844.Blob, c kzg4844.Commitment, p kzg4844.Proof,
if err != nil {
return
}
p, err = kzg4844.ComputeBlobProof(&b, c)
if err != nil {
return
}
return
}

Expand All @@ -85,28 +81,26 @@ func MakeBlobTxSidecar(blobBytes []byte) (*eth.BlobTxSidecar, error) {
err error
blobs = make([]kzg4844.Blob, blobCount)
commitments = make([]kzg4844.Commitment, blobCount)
proofs = make([]kzg4844.Proof, blobCount)
)
switch blobCount {
case 1:
blobs[0], commitments[0], proofs[0], err = makeBCP(blobBytes)
blobs[0], commitments[0], err = makeBlobCommitment(blobBytes)
if err != nil {
return nil, err
}
case 2:
blobs[0], commitments[0], proofs[0], err = makeBCP(blobBytes[:MaxBlobBytesSize])
blobs[0], commitments[0], err = makeBlobCommitment(blobBytes[:MaxBlobBytesSize])
if err != nil {
return nil, err
}
blobs[1], commitments[1], proofs[1], err = makeBCP(blobBytes[MaxBlobBytesSize:])
blobs[1], commitments[1], err = makeBlobCommitment(blobBytes[MaxBlobBytesSize:])
if err != nil {
return nil, err
}
}
return &eth.BlobTxSidecar{
Blobs: blobs,
Commitments: commitments,
Proofs: proofs,
}, nil
}

Expand Down
126 changes: 126 additions & 0 deletions tx-submitter/services/blob_hash_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package services

import (
"crypto/sha256"
"testing"

"github.com/morph-l2/go-ethereum/common"
"github.com/morph-l2/go-ethereum/crypto/kzg4844"
"github.com/stretchr/testify/assert"
)

// TestCalcBlobHashV1VsKZGToVersionedHash verifies that CalcBlobHashV1 and kZGToVersionedHash
// produce the same results for the same commitment.
func TestCalcBlobHashV1VsKZGToVersionedHash(t *testing.T) {
tests := []struct {
name string
commitment kzg4844.Commitment
}{
{
name: "zero commitment",
commitment: kzg4844.Commitment{},
},
{
name: "all ones commitment",
commitment: func() kzg4844.Commitment {
var c kzg4844.Commitment
for i := range c {
c[i] = 0xFF
}
return c
}(),
},
{
name: "pattern commitment",
commitment: func() kzg4844.Commitment {
var c kzg4844.Commitment
for i := range c {
c[i] = byte(i % 256)
}
return c
}(),
},
{
name: "reversed pattern commitment",
commitment: func() kzg4844.Commitment {
var c kzg4844.Commitment
for i := range c {
c[i] = byte(255 - (i % 256))
}
return c
}(),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Calculate using kZGToVersionedHash (v0 method)
hashV0 := kZGToVersionedHash(tt.commitment)

// Calculate using CalcBlobHashV1 (v1 method)
hasher := sha256.New()
hashV1 := kzg4844.CalcBlobHashV1(hasher, &tt.commitment)

// Convert hashV1 to common.Hash for comparison
hashV1CommonHash := common.Hash(hashV1)

// They should be equal
assert.Equal(t, hashV0, hashV1CommonHash,
"CalcBlobHashV1 and kZGToVersionedHash should produce the same result")

// Verify the first byte is 0x01 (version byte)
assert.Equal(t, uint8(0x01), hashV0[0], "First byte should be version 0x01")
assert.Equal(t, uint8(0x01), hashV1[0], "First byte should be version 0x01")
})
}
}

// TestCalcBlobHashV1ReuseHasher verifies that CalcBlobHashV1 can correctly reuse a hasher
// for multiple commitments.
func TestCalcBlobHashV1ReuseHasher(t *testing.T) {
// Create multiple commitments
commitments := []kzg4844.Commitment{
{0x01, 0x02, 0x03}, // Will be padded with zeros
{0xFF, 0xFE, 0xFD}, // Will be padded with zeros
{}, // Zero commitment
}

// Calculate hashes using reused hasher
hasher := sha256.New()
hashesV1 := make([]common.Hash, len(commitments))
for i, commit := range commitments {
hashV1 := kzg4844.CalcBlobHashV1(hasher, &commit)
hashesV1[i] = common.Hash(hashV1)
}

// Calculate hashes using kZGToVersionedHash (should produce same results)
hashesV0 := make([]common.Hash, len(commitments))
for i, commit := range commitments {
hashesV0[i] = kZGToVersionedHash(commit)
}

// Compare results
for i := range commitments {
assert.Equal(t, hashesV0[i], hashesV1[i],
"Hash %d should be equal regardless of hasher reuse", i)
}
}

// TestCalcBlobHashV1MultipleCalls verifies that CalcBlobHashV1 produces consistent
// results when called multiple times with the same commitment.
func TestCalcBlobHashV1MultipleCalls(t *testing.T) {
commitment := kzg4844.Commitment{0x42}

hasher1 := sha256.New()
hash1 := kzg4844.CalcBlobHashV1(hasher1, &commitment)

hasher2 := sha256.New()
hash2 := kzg4844.CalcBlobHashV1(hasher2, &commitment)

// Same commitment should produce same hash
assert.Equal(t, hash1, hash2, "Same commitment should produce same hash")

// Should also match kZGToVersionedHash
hashV0 := kZGToVersionedHash(commitment)
assert.Equal(t, common.Hash(hash1), hashV0, "Should match kZGToVersionedHash result")
}
81 changes: 49 additions & 32 deletions tx-submitter/services/rollup.go
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ func (r *Rollup) finalize() error {
if err != nil {
return fmt.Errorf("pack finalizeBatch error:%v", err)
}
tip, feecap, _, err := r.GetGasTipAndCap()
tip, feecap, _, _, err := r.GetGasTipAndCap()
if err != nil {
log.Error("get gas tip and cap error", "business", "finalize")
return fmt.Errorf("get gas tip and cap error:%v", err)
Expand Down Expand Up @@ -1068,7 +1068,7 @@ func (r *Rollup) rollup() error {
}

// tip and cap
tip, gasFeeCap, blobFee, err := r.GetGasTipAndCap()
tip, gasFeeCap, blobFee, head, err := r.GetGasTipAndCap()
if err != nil {
return fmt.Errorf("get gas tip and cap error:%v", err)
}
Expand Down Expand Up @@ -1105,7 +1105,7 @@ func (r *Rollup) rollup() error {
}

// Create and sign transaction
tx, err := r.createRollupTx(batch, nonce, gas, tip, gasFeeCap, blobFee, calldata)
tx, err := r.createRollupTx(batch, nonce, gas, tip, gasFeeCap, blobFee, calldata, head)
if err != nil {
return fmt.Errorf("failed to create rollup tx: %w", err)
}
Expand All @@ -1119,14 +1119,14 @@ func (r *Rollup) rollup() error {
r.logTxInfo(signedTx, batchIndex)

// Send transaction
if err := r.SendTx(signedTx); err != nil {
if err = r.SendTx(signedTx); err != nil {
return fmt.Errorf("failed to send tx: %w", err)
}

// Update pending state
r.pendingTxs.SetPindex(batchIndex)
r.pendingTxs.SetNonce(tx.Nonce())
if err := r.pendingTxs.Add(signedTx); err != nil {
if err = r.pendingTxs.Add(signedTx); err != nil {
log.Error("Failed to track transaction", "error", err)
}

Expand All @@ -1146,17 +1146,36 @@ func (r *Rollup) getNextNonce() uint64 {
return nonce
}

func (r *Rollup) createRollupTx(batch *eth.RPCRollupBatch, nonce, gas uint64, tip, gasFeeCap, blobFee *big.Int, calldata []byte) (*ethtypes.Transaction, error) {
func (r *Rollup) createRollupTx(batch *eth.RPCRollupBatch, nonce, gas uint64, tip, gasFeeCap, blobFee *big.Int, calldata []byte, head *ethtypes.Header) (*ethtypes.Transaction, error) {
if len(batch.Sidecar.Blobs) > 0 {
return r.createBlobTx(batch, nonce, gas, tip, gasFeeCap, blobFee, calldata)
return r.createBlobTx(batch, nonce, gas, tip, gasFeeCap, blobFee, calldata, head)
}
return r.createDynamicFeeTx(nonce, gas, tip, gasFeeCap, calldata)
}

func (r *Rollup) createBlobTx(batch *eth.RPCRollupBatch, nonce, gas uint64, tip, gasFeeCap, blobFee *big.Int, calldata []byte) (*ethtypes.Transaction, error) {
versionedHashes := make([]common.Hash, 0, len(batch.Sidecar.Commitments))
for _, commit := range batch.Sidecar.Commitments {
versionedHashes = append(versionedHashes, kZGToVersionedHash(commit))
func (r *Rollup) createBlobTx(batch *eth.RPCRollupBatch, nonce, gas uint64, tip, gasFeeCap, blobFee *big.Int, calldata []byte, head *ethtypes.Header) (*ethtypes.Transaction, error) {
versionedHashes := types.BlobHashes(batch.Sidecar.Blobs, batch.Sidecar.Commitments)
sidecar := &ethtypes.BlobTxSidecar{
Blobs: batch.Sidecar.Blobs,
Commitments: batch.Sidecar.Commitments,
}
switch types.DetermineBlobVersion(head, r.chainId.Uint64()) {
case ethtypes.BlobSidecarVersion0:
sidecar.Version = ethtypes.BlobSidecarVersion0
proof, err := types.MakeBlobProof(sidecar.Blobs, sidecar.Commitments)
if err != nil {
return nil, fmt.Errorf("gen blob proof failed %v", err)
}
sidecar.Proofs = proof
case ethtypes.BlobSidecarVersion1:
sidecar.Version = ethtypes.BlobSidecarVersion1
proof, err := types.MakeCellProof(sidecar.Blobs)
if err != nil {
return nil, fmt.Errorf("gen cell proof failed %v", err)
}
sidecar.Proofs = proof
default:
return nil, fmt.Errorf("unsupported blob version")
}

return ethtypes.NewTx(&ethtypes.BlobTx{
Expand All @@ -1169,11 +1188,7 @@ func (r *Rollup) createBlobTx(batch *eth.RPCRollupBatch, nonce, gas uint64, tip,
Data: calldata,
BlobFeeCap: uint256.MustFromBig(blobFee),
BlobHashes: versionedHashes,
Sidecar: &ethtypes.BlobTxSidecar{
Blobs: batch.Sidecar.Blobs,
Commitments: batch.Sidecar.Commitments,
Proofs: batch.Sidecar.Proofs,
},
Sidecar: sidecar,
}), nil
}

Expand Down Expand Up @@ -1242,21 +1257,21 @@ func (r *Rollup) buildSignatureInput(batch *eth.RPCRollupBatch) (*bindings.IRoll
return &sigData, nil
}

func (r *Rollup) GetGasTipAndCap() (*big.Int, *big.Int, *big.Int, error) {
func (r *Rollup) GetGasTipAndCap() (*big.Int, *big.Int, *big.Int, *ethtypes.Header, error) {
head, err := r.L1Client.HeaderByNumber(context.Background(), nil)
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
if head.BaseFee != nil {
log.Info("market fee info", "feecap", head.BaseFee)
if r.cfg.MaxBaseFee > 0 && head.BaseFee.Cmp(big.NewInt(int64(r.cfg.MaxBaseFee))) > 0 {
return nil, nil, nil, fmt.Errorf("base fee is too high, base fee %v exceeds max %v", head.BaseFee, r.cfg.MaxBaseFee)
return nil, nil, nil, nil, fmt.Errorf("base fee is too high, base fee %v exceeds max %v", head.BaseFee, r.cfg.MaxBaseFee)
}
}

tip, err := r.L1Client.SuggestGasTipCap(context.Background())
if err != nil {
return nil, nil, nil, err
return nil, nil, nil, nil, err
}
log.Info("market fee info", "tip", tip)

Expand All @@ -1265,7 +1280,7 @@ func (r *Rollup) GetGasTipAndCap() (*big.Int, *big.Int, *big.Int, error) {
tip = new(big.Int).Div(tip, big.NewInt(100))
}
if r.cfg.MaxTip > 0 && tip.Cmp(big.NewInt(int64(r.cfg.MaxTip))) > 0 {
return nil, nil, nil, fmt.Errorf("tip is too high, tip %v exceeds max %v", tip, r.cfg.MaxTip)
return nil, nil, nil, nil, fmt.Errorf("tip is too high, tip %v exceeds max %v", tip, r.cfg.MaxTip)
}

var gasFeeCap *big.Int
Expand All @@ -1282,7 +1297,7 @@ func (r *Rollup) GetGasTipAndCap() (*big.Int, *big.Int, *big.Int, error) {
var blobFee *big.Int
if head.ExcessBlobGas != nil {
log.Info("market blob fee info", "excess blob gas", *head.ExcessBlobGas)
blobConfig, exist := r.ChainConfigMap[r.chainId.Uint64()]
blobConfig, exist := types.ChainConfigMap[r.chainId.Uint64()]
if !exist {
blobConfig = types.DefaultBlobConfig
}
Expand All @@ -1298,7 +1313,7 @@ func (r *Rollup) GetGasTipAndCap() (*big.Int, *big.Int, *big.Int, error) {
"blobfee", blobFee,
)

return tip, gasFeeCap, blobFee, nil
return tip, gasFeeCap, blobFee, head, nil
}

// PreCheck is run before the submitter to check whether the submitter can be started
Expand Down Expand Up @@ -1578,7 +1593,7 @@ func (r *Rollup) ReSubmitTx(resend bool, tx *ethtypes.Transaction) (*ethtypes.Tr
"nonce", tx.Nonce(),
)

tip, gasFeeCap, blobFeeCap, err := r.GetGasTipAndCap()
tip, gasFeeCap, blobFeeCap, head, err := r.GetGasTipAndCap()
if err != nil {
return nil, fmt.Errorf("get gas tip and cap error:%w", err)
}
Expand Down Expand Up @@ -1606,11 +1621,6 @@ func (r *Rollup) ReSubmitTx(resend bool, tx *ethtypes.Transaction) (*ethtypes.Tr
if r.cfg.MinTip > 0 && tip.Cmp(big.NewInt(int64(r.cfg.MinTip))) < 0 {
log.Info("replace tip is too low, update tip to min tip ", "tip", tip, "min_tip", r.cfg.MinTip)
tip = big.NewInt(int64(r.cfg.MinTip))
// recalc feecap
head, err := r.L1Client.HeaderByNumber(context.Background(), nil)
if err != nil {
return nil, fmt.Errorf("get l1 head error:%w", err)
}
var recalculatedFeecap *big.Int
if head.BaseFee != nil {
recalculatedFeecap = new(big.Int).Add(
Expand Down Expand Up @@ -1640,7 +1650,14 @@ func (r *Rollup) ReSubmitTx(resend bool, tx *ethtypes.Transaction) (*ethtypes.Tr
Data: tx.Data(),
})
case ethtypes.BlobTxType:

sidecar := tx.BlobTxSidecar()
version := types.DetermineBlobVersion(head, r.chainId.Uint64())
if sidecar.Version == ethtypes.BlobSidecarVersion0 && version == ethtypes.BlobSidecarVersion1 {
err = types.BlobSidecarVersionToV1(sidecar)
if err != nil {
return nil, err
}
}
newTx = ethtypes.NewTx(&ethtypes.BlobTx{
ChainID: uint256.MustFromBig(tx.ChainId()),
Nonce: tx.Nonce(),
Expand All @@ -1652,7 +1669,7 @@ func (r *Rollup) ReSubmitTx(resend bool, tx *ethtypes.Transaction) (*ethtypes.Tr
Data: tx.Data(),
BlobFeeCap: uint256.MustFromBig(blobFeeCap),
BlobHashes: tx.BlobHashes(),
Sidecar: tx.BlobTxSidecar(),
Sidecar: sidecar,
})

default:
Expand Down Expand Up @@ -1818,7 +1835,7 @@ func (r *Rollup) CancelTx(tx *ethtypes.Transaction) (*ethtypes.Transaction, erro
"nonce", tx.Nonce(),
)

tip, gasFeeCap, blobFeeCap, err := r.GetGasTipAndCap()
tip, gasFeeCap, blobFeeCap, _, err := r.GetGasTipAndCap()
if err != nil {
return nil, fmt.Errorf("get gas tip and cap error:%w", err)
}
Expand Down
Loading
Loading