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

e2e test for L2 Blob #142

Merged
merged 8 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 1 addition & 1 deletion da-server
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20241126105717-d31591e83048
github.com/ethereum/go-ethereum v1.14.11
github.com/ethstorage/da-server v0.0.0-20240925084712-169d238000e5
github.com/ethstorage/da-server v0.0.0-20241224013916-2bd2256b6a70
github.com/fsnotify/fsnotify v1.8.0
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/google/go-cmp v0.6.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHE
github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A=
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
github.com/ethstorage/da-server v0.0.0-20240925084712-169d238000e5 h1:pxtnGOGOChxCETGUg2yEIC3nfB5C7ZWzblm4/JE7108=
github.com/ethstorage/da-server v0.0.0-20240925084712-169d238000e5/go.mod h1:QfuYw2wCpbpW7k+Fwq4s9EMWNu40XDc1KKJICPaNUgQ=
github.com/ethstorage/da-server v0.0.0-20241224013916-2bd2256b6a70 h1:g3H1N+WC/nDFL1H+rpKwsSKT0cCWu1fTHjKDqEMyuq0=
github.com/ethstorage/da-server v0.0.0-20241224013916-2bd2256b6a70/go.mod h1:4VnU8W5POGWvaUKd+SDns3cooFGU5wWpIu9M1KhEe1s=
github.com/ethstorage/op-geth v0.0.0-20241215102240-7b4b3277d4ad h1:9EJNrIPvxNHOCloz1hs51ZTGFOw3SCHYmdfI8YHvh5k=
github.com/ethstorage/op-geth v0.0.0-20241215102240-7b4b3277d4ad/go.mod h1:zBADVb3+aon0Idb3uEg/1TFpep+Jdkz3ge9SLFDBXOo=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
Expand Down
174 changes: 174 additions & 0 deletions op-e2e/l2blobs/l2blob_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package l2blobs
ping-ke marked this conversation as resolved.
Show resolved Hide resolved

import (
"bytes"
"context"
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
mrand "math/rand"
"testing"
"time"

"github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-node/node"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/testutils"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethstorage/da-server/pkg/da"
"github.com/ethstorage/da-server/pkg/da/client"
"github.com/holiman/uint256"
"github.com/stretchr/testify/require"
)

const (
dacPort = 37777
)

var (
ctx, _ = context.WithTimeout(context.Background(), 10*time.Second)
dacUrl = fmt.Sprintf("http://127.0.0.1:%d", dacPort)
)

func TestSubmitTXWithBlobsFunctionSuccess(t *testing.T) {
op_e2e.InitParallel(t)
dacServer := startDACServer(t)
defer dacServer.Stop(ctx)

sys, l2Client := startSystemWithDAC(t)
t.Cleanup(sys.Close)

var (
toAddress = testutils.RandomAddress(mrand.New(mrand.NewSource(dacPort)))
blobs = make([]*eth.Blob, 3)
)
for i := range blobs {
b := getRandBlob(t, int64(i))
blobs[i] = &b
}

tx, err := sendTransactionWithBlobs(t, ctx, l2Client, sys.TestAccount(0), toAddress, blobs)
require.NoError(t, err)
_, err = wait.ForReceiptOK(ctx, l2Client, tx.Hash())

dblobs, err := downloadBlobs(dacUrl, tx.BlobHashes())
require.NoError(t, err)
require.True(t, len(dblobs) == len(tx.BlobHashes()), "blobs downloaded is not equal to blob hashes")

for i, blob := range dblobs {
require.True(t, len(blob) == eth.BlobSize, fmt.Sprintf("invalid downloaded blob, index %d; len %d", i, len(blob)))
require.True(t, bytes.Compare(blob, blobs[i][:]) == 0, fmt.Sprintf("blob content diff: %s vs %s",
common.Bytes2Hex(blob[:32]), common.Bytes2Hex(blobs[i][:32])))
}
}

func startSystemWithDAC(t *testing.T) (*e2esys.System, *ethclient.Client) {
cfg := e2esys.DefaultSystemConfig(t)
delete(cfg.Nodes, "verifier")
c, ok := cfg.Nodes["sequencer"]
require.True(t, ok, "sequencer is required")
if ok {
ping-ke marked this conversation as resolved.
Show resolved Hide resolved
c.SafeDBPath = t.TempDir()
c.DACConfig = &node.DACConfig{URLS: []string{dacUrl}}
c.Driver.SequencerEnabled = true
}
cfg.DeployConfig.L2GenesisBlobTimeOffset = new(hexutil.Uint64)
// Disable proposer creating fast games automatically - required games are manually created
cfg.DisableProposer = true
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
return sys, sys.NodeClient(e2esys.RoleSeq)
}

func sendTransactionWithBlobs(t *testing.T, ctx context.Context, l2Client *ethclient.Client, sender *ecdsa.PrivateKey,
toAddr common.Address, blobs []*eth.Blob) (*types.Transaction, error) {
chainID, err := l2Client.ChainID(ctx)
require.NoError(t, err)
gasTipCap, gasFeeCap, blobFeeCap, err := gasPriceEstimator(ctx, l2Client)
require.NoError(t, err)
nonce, err := l2Client.NonceAt(ctx, crypto.PubkeyToAddress(sender.PublicKey), nil)
require.NoError(t, err)
sidecar, blobHashes, err := txmgr.MakeSidecar(blobs)
require.NoError(t, err)
tx := types.MustSignNewTx(sender, types.LatestSignerForChainID(chainID), &types.BlobTx{
ChainID: uint256.NewInt(chainID.Uint64()),
Nonce: nonce,
GasFeeCap: uint256.NewInt(gasFeeCap.Uint64()),
GasTipCap: uint256.NewInt(gasTipCap.Uint64()),
Gas: uint64(22000),
To: toAddr,
Value: uint256.NewInt(0),
BlobFeeCap: uint256.NewInt(blobFeeCap.Uint64()),
BlobHashes: blobHashes,
Sidecar: sidecar,
})
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
err = l2Client.SendTransaction(ctx, tx)
return tx, err
}

func gasPriceEstimator(ctx context.Context, client *ethclient.Client) (*big.Int, *big.Int, *big.Int, error) {
tip, err := client.SuggestGasTipCap(ctx)
if err != nil {
return nil, nil, nil, err
}

head, err := client.HeaderByNumber(ctx, nil)
if err != nil {
return nil, nil, nil, err
}
if head.BaseFee == nil {
return nil, nil, nil, errors.New("head BaseFee is nil")
}

var blobFee *big.Int
if head.ExcessBlobGas != nil {
blobFee = eip4844.CalcBlobFee(*head.ExcessBlobGas)
}

gasFeeCap := new(big.Int).Add(
tip,
new(big.Int).Mul(head.BaseFee, big.NewInt(2)),
)
return tip, gasFeeCap, blobFee, nil
}

func getRandBlob(t *testing.T, seed int64) eth.Blob {
r := mrand.New(mrand.NewSource(seed))
bigData := eth.Data(make([]byte, eth.MaxBlobDataSize))
_, err := r.Read(bigData)
require.NoError(t, err)
var b eth.Blob
err = b.FromData(bigData)
require.NoError(t, err)
return b
}

func startDACServer(t *testing.T) *da.Server {
config := da.Config{
SequencerIP: "127.0.0.1",
ListenAddr: fmt.Sprintf("0.0.0.0:%d", dacPort),
StorePath: t.TempDir(),
}
server := da.NewServer(&config)
err := server.Start(ctx)
require.NoError(t, err)

return server
}

func downloadBlobs(dacUrl string, blobHashes []common.Hash) (blobs []hexutil.Bytes, err error) {
client := client.New([]string{dacUrl})
blobs, err = client.GetBlobs(ctx, blobHashes)
return
}
8 changes: 8 additions & 0 deletions op-e2e/system/e2esys/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,13 @@ func (cfg SystemConfig) Start(t *testing.T, startOpts ...StartOption) (*System,
}
}

var l2BlobConfig *rollup.L2BlobConfig
if cfg.DeployConfig.L2GenesisBlobTimeOffset != nil {
l2BlobConfig = &rollup.L2BlobConfig{
ping-ke marked this conversation as resolved.
Show resolved Hide resolved
L2BlobTime: cfg.DeployConfig.L2BlobTime(l1Block.Time()),
}
}

makeRollupConfig := func() rollup.Config {
return rollup.Config{
Genesis: rollup.Genesis{
Expand Down Expand Up @@ -653,6 +660,7 @@ func (cfg SystemConfig) Start(t *testing.T, startOpts ...StartOption) (*System,
InteropTime: cfg.DeployConfig.InteropTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
ProtocolVersionsAddress: cfg.L1Deployments.ProtocolVersionsProxy,
AltDAConfig: rollupAltDAConfig,
L2BlobConfig: l2BlobConfig,
}
}
defaultConfig := makeRollupConfig()
Expand Down
1 change: 1 addition & 0 deletions op-node/rollup/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,7 @@ func (c *Config) LogDescription(log log.Logger, l2Chains map[string]string) {
"holocene_time", fmtForkTimeOrUnset(c.HoloceneTime),
"interop_time", fmtForkTimeOrUnset(c.InteropTime),
"alt_da", c.AltDAConfig != nil,
"l2_blob_config", c.L2BlobConfig != nil,
)
}

Expand Down