diff --git a/op-batcher/batcher/config.go b/op-batcher/batcher/config.go index ea356f963fc38..0fb33690171a7 100644 --- a/op-batcher/batcher/config.go +++ b/op-batcher/batcher/config.go @@ -83,13 +83,14 @@ type CLIConfig struct { // ActiveSequencerCheckDuration is the duration between checks to determine the active sequencer endpoint. ActiveSequencerCheckDuration time.Duration - TxMgrConfig txmgr.CLIConfig - LogConfig oplog.CLIConfig - MetricsConfig opmetrics.CLIConfig - PprofConfig oppprof.CLIConfig - RPC oprpc.CLIConfig - PlasmaDA plasma.CLIConfig - DAConfig eigenda.CLIConfig + TxMgrConfig txmgr.CLIConfig + LogConfig oplog.CLIConfig + MetricsConfig opmetrics.CLIConfig + PprofConfig oppprof.CLIConfig + RPC oprpc.CLIConfig + PlasmaDA plasma.CLIConfig + DAConfig eigenda.CLIConfig + PrefixDerivationEnabled bool } func (c *CLIConfig) Check() error { @@ -169,5 +170,6 @@ func NewConfig(ctx *cli.Context) *CLIConfig { RPC: oprpc.ReadCLIConfig(ctx), PlasmaDA: plasma.ReadCLIConfig(ctx), DAConfig: eigenda.ReadCLIConfig(ctx), + PrefixDerivationEnabled: ctx.Bool(flags.PrefixDerivationEnabledFlag.Name), } } diff --git a/op-batcher/batcher/driver.go b/op-batcher/batcher/driver.go index e5c0f4cc578d0..ee3712bc30eff 100644 --- a/op-batcher/batcher/driver.go +++ b/op-batcher/batcher/driver.go @@ -41,16 +41,17 @@ type RollupClient interface { // DriverSetup is the collection of input/output interfaces and configuration that the driver operates on. type DriverSetup struct { - Log log.Logger - Metr metrics.Metricer - RollupConfig *rollup.Config - Config BatcherConfig - Txmgr txmgr.TxManager - L1Client L1Client - EndpointProvider dial.L2EndpointProvider - ChannelConfig ChannelConfig - PlasmaDA *plasma.DAClient - DA eigenda.IEigenDA + Log log.Logger + Metr metrics.Metricer + RollupConfig *rollup.Config + Config BatcherConfig + Txmgr txmgr.TxManager + L1Client L1Client + EndpointProvider dial.L2EndpointProvider + ChannelConfig ChannelConfig + PlasmaDA *plasma.DAClient + DA eigenda.IEigenDA + PrefixDerivationEnabled bool } // BatchSubmitter encapsulates a service responsible for submitting L2 tx @@ -463,14 +464,20 @@ func (l *BatchSubmitter) sendTransaction(ctx context.Context, txdata txData, que blobInfo, err := l.DA.DisperseBlob(context.Background(), data) if err != nil { // fallback to posting raw frame to calldata, although still within this proto wrapper l.Log.Error("Unable to publish batch frameset to EigenDA, falling back to calldata", "err", err) - calldataFrame := &op_service.CalldataFrame{ - Value: &op_service.CalldataFrame_Frame{ - Frame: data, - }, - } - wrappedData, err = proto.Marshal(calldataFrame) - if err != nil { - return err + if l.PrefixDerivationEnabled { + // do not wrap + l.Log.Info("Prefix derivation enabled, not wrapping calldata with FrameRef") + wrappedData = data + } else { + calldataFrame := &op_service.CalldataFrame{ + Value: &op_service.CalldataFrame_Frame{ + Frame: data, + }, + } + wrappedData, err = proto.Marshal(calldataFrame) + if err != nil { + return err + } } } else { // happy path, post raw frame to eigenda then post frameRef to calldata quorumIDs := make([]uint32, len(blobInfo.BlobHeader.BlobQuorumParams)) @@ -492,6 +499,12 @@ func (l *BatchSubmitter) sendTransaction(ctx context.Context, txdata txData, que if err != nil { return err } + + if l.PrefixDerivationEnabled { + // prepend the derivation version to the data + l.Log.Info("Prepending derivation version to calldata") + wrappedData = append([]byte{eigenda.DerivationVersionEigenda}, wrappedData...) + } } data = wrappedData diff --git a/op-batcher/batcher/service.go b/op-batcher/batcher/service.go index 87d195a01c940..8a575c0dd2c9f 100644 --- a/op-batcher/batcher/service.go +++ b/op-batcher/batcher/service.go @@ -75,7 +75,8 @@ type BatcherService struct { NotSubmittingOnStart bool - DA eigenda.IEigenDA + DA eigenda.IEigenDA + PrefixDerivationEnabled bool } // BatcherServiceFromCLIConfig creates a new BatcherService from a CLIConfig. @@ -125,6 +126,7 @@ func (bs *BatcherService) initFromCLIConfig(ctx context.Context, version string, if err := bs.initDA(cfg); err != nil { return fmt.Errorf("failed to init DA: %w", err) } + bs.PrefixDerivationEnabled = cfg.PrefixDerivationEnabled bs.initDriver() if err := bs.initRPCServer(cfg); err != nil { return fmt.Errorf("failed to start RPC server: %w", err) @@ -293,16 +295,17 @@ func (bs *BatcherService) initMetricsServer(cfg *CLIConfig) error { func (bs *BatcherService) initDriver() { bs.driver = NewBatchSubmitter(DriverSetup{ - Log: bs.Log, - Metr: bs.Metrics, - RollupConfig: bs.RollupConfig, - Config: bs.BatcherConfig, - Txmgr: bs.TxManager, - L1Client: bs.L1Client, - EndpointProvider: bs.EndpointProvider, - ChannelConfig: bs.ChannelConfig, - PlasmaDA: bs.PlasmaDA, - DA: bs.DA, + Log: bs.Log, + Metr: bs.Metrics, + RollupConfig: bs.RollupConfig, + Config: bs.BatcherConfig, + Txmgr: bs.TxManager, + L1Client: bs.L1Client, + EndpointProvider: bs.EndpointProvider, + ChannelConfig: bs.ChannelConfig, + PlasmaDA: bs.PlasmaDA, + DA: bs.DA, + PrefixDerivationEnabled: bs.PrefixDerivationEnabled, }) } diff --git a/op-batcher/flags/flags.go b/op-batcher/flags/flags.go index aab159100cbbf..7ad7e25a50e22 100644 --- a/op-batcher/flags/flags.go +++ b/op-batcher/flags/flags.go @@ -128,6 +128,12 @@ var ( Value: 2 * time.Minute, EnvVars: prefixEnvVars("ACTIVE_SEQUENCER_CHECK_DURATION"), } + PrefixDerivationEnabledFlag = &cli.BoolFlag{ + Name: "da-prefix-derivation-enabled", + Usage: "Enable prefix derivation", + Value: false, + EnvVars: prefixEnvVars("DA_PREFIX_DERIVATION_ENABLED"), + } // Legacy Flags SequencerHDPathFlag = txmgr.SequencerHDPathFlag ) @@ -152,6 +158,7 @@ var optionalFlags = []cli.Flag{ BatchTypeFlag, DataAvailabilityTypeFlag, ActiveSequencerCheckDurationFlag, + PrefixDerivationEnabledFlag, } func init() { diff --git a/op-node/flags/flags.go b/op-node/flags/flags.go index 982bac23c4acf..24ca78b45c00d 100644 --- a/op-node/flags/flags.go +++ b/op-node/flags/flags.go @@ -359,6 +359,12 @@ var ( Value: "http://da:26658", EnvVars: prefixEnvVars("DA_RPC"), } + PrefixDerivationEnabledFlag = &cli.BoolFlag{ + Name: "da-prefix-derivation-enabled", + Usage: "Enable prefix derivation", + Value: false, + EnvVars: prefixEnvVars("DA_PREFIX_DERIVATION_ENABLED"), + } ) var requiredFlags = []cli.Flag{ @@ -406,6 +412,7 @@ var optionalFlags = []cli.Flag{ ConductorRpcFlag, ConductorRpcTimeoutFlag, SafeDBPath, + PrefixDerivationEnabledFlag, } var DeprecatedFlags = []cli.Flag{ diff --git a/op-node/node/config.go b/op-node/node/config.go index 1d01498d9dd1f..bae29f0ec8ab5 100644 --- a/op-node/node/config.go +++ b/op-node/node/config.go @@ -54,7 +54,8 @@ type Config struct { // but if log-events are not coming in (e.g. not syncing blocks) then the reload ensures the config stays accurate. RuntimeConfigReloadInterval time.Duration - DA eigenda.Config + DA eigenda.Config + PrefixDerivationEnabled bool // Optional Tracer Tracer diff --git a/op-node/node/node.go b/op-node/node/node.go index 12a3c0a16a20b..d1a3608b6200b 100644 --- a/op-node/node/node.go +++ b/op-node/node/node.go @@ -403,7 +403,7 @@ func (n *OpNode) initL2(ctx context.Context, cfg *Config, snapshotLog log.Logger } else { n.safeDB = safedb.Disabled } - n.l2Driver = driver.NewDriver(&cfg.Driver, &cfg.Rollup, n.l2Source, n.l1Source, n.beacon, n, n, n.log, snapshotLog, n.metrics, cfg.ConfigPersistence, n.safeDB, &cfg.Sync, sequencerConductor, plasmaDA, &cfg.DA) + n.l2Driver = driver.NewDriver(&cfg.Driver, &cfg.Rollup, n.l2Source, n.l1Source, n.beacon, n, n, n.log, snapshotLog, n.metrics, cfg.ConfigPersistence, n.safeDB, &cfg.Sync, sequencerConductor, plasmaDA, &cfg.DA, cfg.PrefixDerivationEnabled) return nil } diff --git a/op-node/rollup/derive/blob_data_source.go b/op-node/rollup/derive/blob_data_source.go index 3f78a788131fd..ab8a3dbb022e5 100644 --- a/op-node/rollup/derive/blob_data_source.go +++ b/op-node/rollup/derive/blob_data_source.go @@ -24,26 +24,28 @@ type blobOrCalldata struct { // BlobDataSource fetches blobs or calldata as appropriate and transforms them into usable rollup // data. type BlobDataSource struct { - data []blobOrCalldata - ref eth.L1BlockRef - batcherAddr common.Address - dsCfg DataSourceConfig - fetcher L1TransactionFetcher - blobsFetcher L1BlobsFetcher - log log.Logger - daClient eigenda.IEigenDA + data []blobOrCalldata + ref eth.L1BlockRef + batcherAddr common.Address + dsCfg DataSourceConfig + fetcher L1TransactionFetcher + blobsFetcher L1BlobsFetcher + log log.Logger + daClient eigenda.IEigenDA + prefixDerivationEnabled bool } // NewBlobDataSource creates a new blob data source. -func NewBlobDataSource(ctx context.Context, log log.Logger, dsCfg DataSourceConfig, fetcher L1TransactionFetcher, blobsFetcher L1BlobsFetcher, ref eth.L1BlockRef, batcherAddr common.Address, daClient eigenda.IEigenDA) DataIter { +func NewBlobDataSource(ctx context.Context, log log.Logger, dsCfg DataSourceConfig, fetcher L1TransactionFetcher, blobsFetcher L1BlobsFetcher, ref eth.L1BlockRef, batcherAddr common.Address, daClient eigenda.IEigenDA, prefixDerivationEnabled bool) DataIter { return &BlobDataSource{ - ref: ref, - dsCfg: dsCfg, - fetcher: fetcher, - log: log.New("origin", ref), - batcherAddr: batcherAddr, - blobsFetcher: blobsFetcher, - daClient: daClient, + ref: ref, + dsCfg: dsCfg, + fetcher: fetcher, + log: log.New("origin", ref), + batcherAddr: batcherAddr, + blobsFetcher: blobsFetcher, + daClient: daClient, + prefixDerivationEnabled: prefixDerivationEnabled, } } @@ -89,7 +91,7 @@ func (ds *BlobDataSource) open(ctx context.Context) ([]blobOrCalldata, error) { return nil, NewTemporaryError(fmt.Errorf("failed to open blob data source: %w", err)) } - data, hashes := dataAndHashesFromTxs(txs, &ds.dsCfg, ds.batcherAddr, ds.daClient) + data, hashes := dataAndHashesFromTxs(txs, &ds.dsCfg, ds.batcherAddr, ds.daClient, ds.prefixDerivationEnabled) if len(hashes) == 0 { // there are no blobs to fetch so we can return immediately @@ -118,7 +120,7 @@ func (ds *BlobDataSource) open(ctx context.Context) ([]blobOrCalldata, error) { // dataAndHashesFromTxs extracts calldata and datahashes from the input transactions and returns them. It // creates a placeholder blobOrCalldata element for each returned blob hash that must be populated // by fillBlobPointers after blob bodies are retrieved. -func dataAndHashesFromTxs(txs types.Transactions, config *DataSourceConfig, batcherAddr common.Address, daClient eigenda.IEigenDA) ([]blobOrCalldata, []eth.IndexedBlobHash) { +func dataAndHashesFromTxs(txs types.Transactions, config *DataSourceConfig, batcherAddr common.Address, daClient eigenda.IEigenDA, prefixDerivationEnabled bool) ([]blobOrCalldata, []eth.IndexedBlobHash) { data := []blobOrCalldata{} var hashes []eth.IndexedBlobHash blobIndex := 0 // index of each blob in the block's blob sidecar @@ -131,7 +133,7 @@ func dataAndHashesFromTxs(txs types.Transactions, config *DataSourceConfig, batc } // handle non-blob batcher transactions by extracting their calldata if tx.Type() != types.BlobTxType { - calldata := DataFromEVMTransactions(*config, batcherAddr, types.Transactions{tx}, logger, daClient) + calldata := DataFromEVMTransactions(*config, batcherAddr, types.Transactions{tx}, logger, daClient, prefixDerivationEnabled) if len(calldata) == 0 { log.Warn("eigenda: skipping empty calldata") continue diff --git a/op-node/rollup/derive/blob_data_source_test.go b/op-node/rollup/derive/blob_data_source_test.go index 0183ce98a72e3..3dada928337ba 100644 --- a/op-node/rollup/derive/blob_data_source_test.go +++ b/op-node/rollup/derive/blob_data_source_test.go @@ -42,7 +42,7 @@ func TestDataAndHashesFromTxs(t *testing.T) { } calldataTx, _ := types.SignNewTx(privateKey, signer, txData) txs := types.Transactions{calldataTx} - data, blobHashes := dataAndHashesFromTxs(txs, &config, batcherAddr, nil) + data, blobHashes := dataAndHashesFromTxs(txs, &config, batcherAddr, nil, false) require.Equal(t, 1, len(data)) require.Equal(t, 0, len(blobHashes)) @@ -57,14 +57,14 @@ func TestDataAndHashesFromTxs(t *testing.T) { } blobTx, _ := types.SignNewTx(privateKey, signer, blobTxData) txs = types.Transactions{blobTx} - data, blobHashes = dataAndHashesFromTxs(txs, &config, batcherAddr, nil) + data, blobHashes = dataAndHashesFromTxs(txs, &config, batcherAddr, nil, false) require.Equal(t, 1, len(data)) require.Equal(t, 1, len(blobHashes)) require.Nil(t, data[0].calldata) // try again with both the blob & calldata transactions and make sure both are picked up txs = types.Transactions{blobTx, calldataTx} - data, blobHashes = dataAndHashesFromTxs(txs, &config, batcherAddr, nil) + data, blobHashes = dataAndHashesFromTxs(txs, &config, batcherAddr, nil, false) require.Equal(t, 2, len(data)) require.Equal(t, 1, len(blobHashes)) require.NotNil(t, data[1].calldata) @@ -72,7 +72,7 @@ func TestDataAndHashesFromTxs(t *testing.T) { // make sure blob tx to the batch inbox is ignored if not signed by the batcher blobTx, _ = types.SignNewTx(testutils.RandomKey(), signer, blobTxData) txs = types.Transactions{blobTx} - data, blobHashes = dataAndHashesFromTxs(txs, &config, batcherAddr, nil) + data, blobHashes = dataAndHashesFromTxs(txs, &config, batcherAddr, nil, false) require.Equal(t, 0, len(data)) require.Equal(t, 0, len(blobHashes)) @@ -81,7 +81,7 @@ func TestDataAndHashesFromTxs(t *testing.T) { blobTxData.To = testutils.RandomAddress(rng) blobTx, _ = types.SignNewTx(privateKey, signer, blobTxData) txs = types.Transactions{blobTx} - data, blobHashes = dataAndHashesFromTxs(txs, &config, batcherAddr, nil) + data, blobHashes = dataAndHashesFromTxs(txs, &config, batcherAddr, nil, false) require.Equal(t, 0, len(data)) require.Equal(t, 0, len(blobHashes)) } diff --git a/op-node/rollup/derive/calldata_source.go b/op-node/rollup/derive/calldata_source.go index f034b1445ad72..525cef64fa686 100644 --- a/op-node/rollup/derive/calldata_source.go +++ b/op-node/rollup/derive/calldata_source.go @@ -32,28 +32,30 @@ type CalldataSource struct { fetcher L1TransactionFetcher log log.Logger - batcherAddr common.Address - daClient eigenda.IEigenDA + batcherAddr common.Address + daClient eigenda.IEigenDA + prefixDerivationEnabled bool } // NewCalldataSource creates a new calldata source. It suppresses errors in fetching the L1 block if they occur. // If there is an error, it will attempt to fetch the result on the next call to `Next`. -func NewCalldataSource(ctx context.Context, log log.Logger, dsCfg DataSourceConfig, fetcher L1TransactionFetcher, ref eth.L1BlockRef, batcherAddr common.Address, daClient eigenda.IEigenDA) DataIter { +func NewCalldataSource(ctx context.Context, log log.Logger, dsCfg DataSourceConfig, fetcher L1TransactionFetcher, ref eth.L1BlockRef, batcherAddr common.Address, daClient eigenda.IEigenDA, prefixDerivationEnabled bool) DataIter { _, txs, err := fetcher.InfoAndTxsByHash(ctx, ref.Hash) if err != nil { return &CalldataSource{ - open: false, - ref: ref, - dsCfg: dsCfg, - fetcher: fetcher, - log: log, - batcherAddr: batcherAddr, - daClient: daClient, + open: false, + ref: ref, + dsCfg: dsCfg, + fetcher: fetcher, + log: log, + batcherAddr: batcherAddr, + daClient: daClient, + prefixDerivationEnabled: prefixDerivationEnabled, } } else { return &CalldataSource{ open: true, - data: DataFromEVMTransactions(dsCfg, batcherAddr, txs, log.New("origin", ref), daClient), + data: DataFromEVMTransactions(dsCfg, batcherAddr, txs, log.New("origin", ref), daClient, prefixDerivationEnabled), } } } @@ -65,7 +67,7 @@ func (ds *CalldataSource) Next(ctx context.Context) (eth.Data, error) { if !ds.open { if _, txs, err := ds.fetcher.InfoAndTxsByHash(ctx, ds.ref.Hash); err == nil { ds.open = true - ds.data = DataFromEVMTransactions(ds.dsCfg, ds.batcherAddr, txs, ds.log, ds.daClient) + ds.data = DataFromEVMTransactions(ds.dsCfg, ds.batcherAddr, txs, ds.log, ds.daClient, ds.prefixDerivationEnabled) } else if errors.Is(err, ethereum.NotFound) { return nil, NewResetError(fmt.Errorf("failed to open calldata source: %w", err)) } else { @@ -84,12 +86,37 @@ func (ds *CalldataSource) Next(ctx context.Context) (eth.Data, error) { // DataFromEVMTransactions filters all of the transactions and returns the calldata from transactions // that are sent to the batch inbox address from the batch sender address. // This will return an empty array if no valid transactions are found. -func DataFromEVMTransactions(dsCfg DataSourceConfig, batcherAddr common.Address, txs types.Transactions, log log.Logger, daClient eigenda.IEigenDA) []eth.Data { +func DataFromEVMTransactions(dsCfg DataSourceConfig, batcherAddr common.Address, txs types.Transactions, log log.Logger, daClient eigenda.IEigenDA, prefixDerivationEnabled bool) []eth.Data { out := []eth.Data{} for j, tx := range txs { if isValidBatchTx(tx, dsCfg.l1Signer, dsCfg.batchInboxAddress, batcherAddr) { + data := tx.Data() + + if prefixDerivationEnabled { + log.Info("Prefix derivation enabled, checking derivation version") + switch len(data) { + case 0: + out = append(out, data) + // skip next tx + continue + default: + switch data[0] { + case eigenda.DerivationVersionEigenda: + log.Info("EigenDA derivation version detected") + // skip the first byte and unwrap the data with protobuf + data = data[1:] + default: + log.Info("No EigenDA derivation version detected, falling back to calldata") + out = append(out, data) + log.Info("Successfully read data from calldata (not EigenDA)") + // skip next tx + continue + } + } + } + calldataFrame := &op_service.CalldataFrame{} - err := proto.Unmarshal(tx.Data(), calldataFrame) + err := proto.Unmarshal(data, calldataFrame) if err != nil { log.Warn("unable to decode calldata frame", "index", j, "err", err) return nil diff --git a/op-node/rollup/derive/calldata_source_test.go b/op-node/rollup/derive/calldata_source_test.go index 57e8c43712782..e6eb4a2b547e8 100644 --- a/op-node/rollup/derive/calldata_source_test.go +++ b/op-node/rollup/derive/calldata_source_test.go @@ -158,7 +158,7 @@ func TestDataFromEVMTransactions(t *testing.T) { } } - out := DataFromEVMTransactions(DataSourceConfig{cfg.L1Signer(), cfg.BatchInboxAddress, false}, batcherAddr, txs, testlog.Logger(t, log.LevelCrit), daClient) + out := DataFromEVMTransactions(DataSourceConfig{cfg.L1Signer(), cfg.BatchInboxAddress, false}, batcherAddr, txs, testlog.Logger(t, log.LevelCrit), daClient, false) require.ElementsMatch(t, expectedData, out) } diff --git a/op-node/rollup/derive/data_source.go b/op-node/rollup/derive/data_source.go index 203516e6644ca..a117b0591879d 100644 --- a/op-node/rollup/derive/data_source.go +++ b/op-node/rollup/derive/data_source.go @@ -44,16 +44,17 @@ type PlasmaInputFetcher interface { // batch submitter transactions. // This is not a stage in the pipeline, but a wrapper for another stage in the pipeline type DataSourceFactory struct { - log log.Logger - dsCfg DataSourceConfig - fetcher L1Fetcher - blobsFetcher L1BlobsFetcher - plasmaFetcher PlasmaInputFetcher - ecotoneTime *uint64 - daClient eigenda.IEigenDA + log log.Logger + dsCfg DataSourceConfig + fetcher L1Fetcher + blobsFetcher L1BlobsFetcher + plasmaFetcher PlasmaInputFetcher + ecotoneTime *uint64 + daClient eigenda.IEigenDA + prefixDerivationEnabled bool } -func NewDataSourceFactory(log log.Logger, cfg *rollup.Config, fetcher L1Fetcher, blobsFetcher L1BlobsFetcher, plasmaFetcher PlasmaInputFetcher, daCfg *eigenda.Config) *DataSourceFactory { +func NewDataSourceFactory(log log.Logger, cfg *rollup.Config, fetcher L1Fetcher, blobsFetcher L1BlobsFetcher, plasmaFetcher PlasmaInputFetcher, daCfg *eigenda.Config, prefixDerivationEnabled bool) *DataSourceFactory { config := DataSourceConfig{ l1Signer: cfg.L1Signer(), batchInboxAddress: cfg.BatchInboxAddress, @@ -69,13 +70,14 @@ func NewDataSourceFactory(log log.Logger, cfg *rollup.Config, fetcher L1Fetcher, } return &DataSourceFactory{ - log: log, - dsCfg: config, - fetcher: fetcher, - blobsFetcher: blobsFetcher, - plasmaFetcher: plasmaFetcher, - ecotoneTime: cfg.EcotoneTime, - daClient: daClient, + log: log, + dsCfg: config, + fetcher: fetcher, + blobsFetcher: blobsFetcher, + plasmaFetcher: plasmaFetcher, + ecotoneTime: cfg.EcotoneTime, + daClient: daClient, + prefixDerivationEnabled: prefixDerivationEnabled, } } @@ -88,9 +90,9 @@ func (ds *DataSourceFactory) OpenData(ctx context.Context, ref eth.L1BlockRef, b if ds.blobsFetcher == nil { return nil, fmt.Errorf("ecotone upgrade active but beacon endpoint not configured") } - src = NewBlobDataSource(ctx, ds.log, ds.dsCfg, ds.fetcher, ds.blobsFetcher, ref, batcherAddr, ds.daClient) + src = NewBlobDataSource(ctx, ds.log, ds.dsCfg, ds.fetcher, ds.blobsFetcher, ref, batcherAddr, ds.daClient, ds.prefixDerivationEnabled) } else { - src = NewCalldataSource(ctx, ds.log, ds.dsCfg, ds.fetcher, ref, batcherAddr, ds.daClient) + src = NewCalldataSource(ctx, ds.log, ds.dsCfg, ds.fetcher, ref, batcherAddr, ds.daClient, ds.prefixDerivationEnabled) } if ds.dsCfg.plasmaEnabled { // plasma([calldata | blobdata](l1Ref)) -> data diff --git a/op-node/rollup/derive/pipeline.go b/op-node/rollup/derive/pipeline.go index c0198f2b1ca6e..90c5c79983903 100644 --- a/op-node/rollup/derive/pipeline.go +++ b/op-node/rollup/derive/pipeline.go @@ -70,11 +70,11 @@ type DerivationPipeline struct { // NewDerivationPipeline creates a derivation pipeline, which should be reset before use. -func NewDerivationPipeline(log log.Logger, rollupCfg *rollup.Config, l1Fetcher L1Fetcher, l1Blobs L1BlobsFetcher, plasma PlasmaInputFetcher, l2Source L2Source, engine LocalEngineControl, metrics Metrics, syncCfg *sync.Config, safeHeadListener SafeHeadListener, daCfg *eigenda.Config) *DerivationPipeline { +func NewDerivationPipeline(log log.Logger, rollupCfg *rollup.Config, l1Fetcher L1Fetcher, l1Blobs L1BlobsFetcher, plasma PlasmaInputFetcher, l2Source L2Source, engine LocalEngineControl, metrics Metrics, syncCfg *sync.Config, safeHeadListener SafeHeadListener, daCfg *eigenda.Config, prefixDerivationEnabled bool) *DerivationPipeline { // Pull stages l1Traversal := NewL1Traversal(log, rollupCfg, l1Fetcher) - dataSrc := NewDataSourceFactory(log, rollupCfg, l1Fetcher, l1Blobs, plasma, daCfg) // auxiliary stage for L1Retrieval + dataSrc := NewDataSourceFactory(log, rollupCfg, l1Fetcher, l1Blobs, plasma, daCfg, prefixDerivationEnabled) // auxiliary stage for L1Retrieval l1Src := NewL1Retrieval(log, dataSrc, l1Traversal) frameQueue := NewFrameQueue(log, l1Src) bank := NewChannelBank(log, rollupCfg, frameQueue, l1Fetcher, metrics) diff --git a/op-node/rollup/derive/plasma_data_source_test.go b/op-node/rollup/derive/plasma_data_source_test.go index 0a5be74a52be9..fa15aa4001517 100644 --- a/op-node/rollup/derive/plasma_data_source_test.go +++ b/op-node/rollup/derive/plasma_data_source_test.go @@ -96,7 +96,7 @@ func TestPlasmaDataSource(t *testing.T) { signer := cfg.L1Signer() - factory := NewDataSourceFactory(logger, cfg, l1F, nil, da, nil) + factory := NewDataSourceFactory(logger, cfg, l1F, nil, da, nil, false) nc := 0 firstChallengeExpirationBlock := uint64(95) @@ -328,7 +328,7 @@ func TestPlasmaDataSourceStall(t *testing.T) { signer := cfg.L1Signer() - factory := NewDataSourceFactory(logger, cfg, l1F, nil, da, nil) + factory := NewDataSourceFactory(logger, cfg, l1F, nil, da, nil, false) parent := l1Refs[0] // create a new mock l1 ref @@ -443,7 +443,7 @@ func TestPlasmaDataSourceInvalidData(t *testing.T) { signer := cfg.L1Signer() - factory := NewDataSourceFactory(logger, cfg, l1F, nil, da, nil) + factory := NewDataSourceFactory(logger, cfg, l1F, nil, da, nil, false) parent := l1Refs[0] // create a new mock l1 ref diff --git a/op-node/rollup/driver/driver.go b/op-node/rollup/driver/driver.go index 041e22c7e790e..1b0a57cf7b23b 100644 --- a/op-node/rollup/driver/driver.go +++ b/op-node/rollup/driver/driver.go @@ -132,6 +132,7 @@ func NewDriver( sequencerConductor conductor.SequencerConductor, plasma derive.PlasmaInputFetcher, daCfg *eigenda.Config, + prefixDerivationEnabled bool, ) *Driver { l1 = NewMeteredL1Fetcher(l1, metrics) l1State := NewL1State(log, metrics) @@ -139,7 +140,7 @@ func NewDriver( findL1Origin := NewL1OriginSelector(log, cfg, sequencerConfDepth) verifConfDepth := NewConfDepth(driverCfg.VerifierConfDepth, l1State.L1Head, l1) engine := derive.NewEngineController(l2, log, metrics, cfg, syncCfg.SyncMode) - derivationPipeline := derive.NewDerivationPipeline(log, cfg, verifConfDepth, l1Blobs, plasma, l2, engine, metrics, syncCfg, safeHeadListener, daCfg) + derivationPipeline := derive.NewDerivationPipeline(log, cfg, verifConfDepth, l1Blobs, plasma, l2, engine, metrics, syncCfg, safeHeadListener, daCfg, prefixDerivationEnabled) attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, l2) meteredEngine := NewMeteredEngine(cfg, engine, metrics, log) // Only use the metered engine in the sequencer b/c it records sequencing metrics. sequencer := NewSequencer(log, cfg, meteredEngine, attrBuilder, findL1Origin, metrics) diff --git a/op-node/service.go b/op-node/service.go index 8e65e41ac6420..b4216ae6892f2 100644 --- a/op-node/service.go +++ b/op-node/service.go @@ -119,7 +119,8 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) { Plasma: plasma.ReadCLIConfig(ctx), - DA: daCfg, + DA: daCfg, + PrefixDerivationEnabled: ctx.Bool(flags.PrefixDerivationEnabledFlag.Name), } if err := cfg.LoadPersisted(log); err != nil { diff --git a/op-program/client/driver/driver.go b/op-program/client/driver/driver.go index 742e8ba4ce1ac..aa3449f8f286c 100644 --- a/op-program/client/driver/driver.go +++ b/op-program/client/driver/driver.go @@ -40,9 +40,9 @@ type Driver struct { targetBlockNum uint64 } -func NewDriver(logger log.Logger, cfg *rollup.Config, l1Source derive.L1Fetcher, l1BlobsSource derive.L1BlobsFetcher, l2Source L2Source, targetBlockNum uint64, daCfg *eigenda.Config) *Driver { +func NewDriver(logger log.Logger, cfg *rollup.Config, l1Source derive.L1Fetcher, l1BlobsSource derive.L1BlobsFetcher, l2Source L2Source, targetBlockNum uint64, daCfg *eigenda.Config, prefixDerivationEnabled bool) *Driver { engine := derive.NewEngineController(l2Source, logger, metrics.NoopMetrics, cfg, sync.CLSync) - pipeline := derive.NewDerivationPipeline(logger, cfg, l1Source, l1BlobsSource, plasma.Disabled, l2Source, engine, metrics.NoopMetrics, &sync.Config{}, safedb.Disabled, daCfg) + pipeline := derive.NewDerivationPipeline(logger, cfg, l1Source, l1BlobsSource, plasma.Disabled, l2Source, engine, metrics.NoopMetrics, &sync.Config{}, safedb.Disabled, daCfg, prefixDerivationEnabled) pipeline.Reset() return &Driver{ logger: logger, diff --git a/op-program/client/program.go b/op-program/client/program.go index 32439bb3287e0..991e975429bb3 100644 --- a/op-program/client/program.go +++ b/op-program/client/program.go @@ -63,7 +63,7 @@ func RunProgram(logger log.Logger, preimageOracle io.ReadWriter, preimageHinter } // runDerivation executes the L2 state transition, given a minimal interface to retrieve data. -func runDerivation(logger log.Logger, cfg *rollup.Config, daCfg *eigenda.Config, l2Cfg *params.ChainConfig, l1Head common.Hash, l2OutputRoot common.Hash, l2Claim common.Hash, l2ClaimBlockNum uint64, l1Oracle l1.Oracle, l2Oracle l2.Oracle) error { +func runDerivation(logger log.Logger, cfg *rollup.Config, daCfg *eigenda.Config, prefixDerivationEnabled bool, l2Cfg *params.ChainConfig, l1Head common.Hash, l2OutputRoot common.Hash, l2Claim common.Hash, l2ClaimBlockNum uint64, l1Oracle l1.Oracle, l2Oracle l2.Oracle) error { l1Source := l1.NewOracleL1Client(logger, l1Oracle, l1Head) l1BlobsSource := l1.NewBlobFetcher(logger, l1Oracle) engineBackend, err := l2.NewOracleBackedL2Chain(logger, l2Oracle, l1Oracle /* kzg oracle */, l2Cfg, l2OutputRoot) @@ -73,7 +73,7 @@ func runDerivation(logger log.Logger, cfg *rollup.Config, daCfg *eigenda.Config, l2Source := l2.NewOracleEngine(cfg, logger, engineBackend) logger.Info("Starting derivation") - d := cldr.NewDriver(logger, cfg, l1Source, l1BlobsSource, l2Source, l2ClaimBlockNum, daCfg) + d := cldr.NewDriver(logger, cfg, l1Source, l1BlobsSource, l2Source, l2ClaimBlockNum, daCfg, prefixDerivationEnabled) for { if err = d.Step(context.Background()); errors.Is(err, io.EOF) { break diff --git a/op-service/eigenda/derivation.go b/op-service/eigenda/derivation.go new file mode 100644 index 0000000000000..bf8e2847bd72e --- /dev/null +++ b/op-service/eigenda/derivation.go @@ -0,0 +1,6 @@ +package eigenda + +// Taking inspiration from Celestia implementation +// Useful to dinstiguish between plain calldata and alt-da blob refs +// Support seamless migration of existing rollups using ETH DA +const DerivationVersionEigenda = 0xed