From f0087300a19ded9a15fe7e1b8115606fcf5d0415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toni=20Ram=C3=ADrez?= <58293609+ToniRamirezM@users.noreply.github.com> Date: Tue, 9 Jul 2024 16:46:31 +0200 Subject: [PATCH 01/14] use dbTx in SequentialBatchSanityCheck (#3722) * use dbTx in SequentialBatchSanityCheck --- sequencer/batch.go | 14 +++++++------- sequencer/finalizer_test.go | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sequencer/batch.go b/sequencer/batch.go index b7cb731fe5..e960efa97a 100644 --- a/sequencer/batch.go +++ b/sequencer/batch.go @@ -57,7 +57,7 @@ func (f *finalizer) processBatchesPendingtoCheck(ctx context.Context) { oldStateRoot := prevBatch.StateRoot for _, notCheckedBatch := range notCheckedBatches { - _, _ = f.batchSanityCheck(ctx, notCheckedBatch.BatchNumber, oldStateRoot, notCheckedBatch.StateRoot) + _, _ = f.batchSanityCheck(ctx, notCheckedBatch.BatchNumber, oldStateRoot, notCheckedBatch.StateRoot, nil) oldStateRoot = notCheckedBatch.StateRoot } } @@ -397,11 +397,11 @@ func (f *finalizer) closeSIPBatch(ctx context.Context, dbTx pgx.Tx) error { // Reprocess full batch as sanity check if f.cfg.SequentialBatchSanityCheck { // Do the full batch reprocess now - _, _ = f.batchSanityCheck(ctx, batchNumber, initialStateRoot, finalStateRoot) + _, _ = f.batchSanityCheck(ctx, batchNumber, initialStateRoot, finalStateRoot, dbTx) } else { // Do the full batch reprocess in parallel go func() { - _, _ = f.batchSanityCheck(ctx, batchNumber, initialStateRoot, finalStateRoot) + _, _ = f.batchSanityCheck(ctx, batchNumber, initialStateRoot, finalStateRoot, nil) }() } @@ -416,7 +416,7 @@ func (f *finalizer) closeSIPBatch(ctx context.Context, dbTx pgx.Tx) error { } // batchSanityCheck reprocesses a batch used as sanity check -func (f *finalizer) batchSanityCheck(ctx context.Context, batchNum uint64, initialStateRoot common.Hash, expectedNewStateRoot common.Hash) (*state.ProcessBatchResponse, error) { +func (f *finalizer) batchSanityCheck(ctx context.Context, batchNum uint64, initialStateRoot common.Hash, expectedNewStateRoot common.Hash, dbTx pgx.Tx) (*state.ProcessBatchResponse, error) { reprocessError := func(batch *state.Batch) { rawL2Blocks, err := state.DecodeBatchV2(batch.BatchL2Data) if err != nil { @@ -442,7 +442,7 @@ func (f *finalizer) batchSanityCheck(ctx context.Context, batchNum uint64, initi log.Debugf("batch %d sanity check: initialStateRoot: %s, expectedNewStateRoot: %s", batchNum, initialStateRoot, expectedNewStateRoot) - batch, err := f.stateIntf.GetBatchByNumber(ctx, batchNum, nil) + batch, err := f.stateIntf.GetBatchByNumber(ctx, batchNum, dbTx) if err != nil { log.Errorf("failed to get batch %d, error: %v", batchNum, err) return nil, ErrGetBatchByNumber @@ -459,7 +459,7 @@ func (f *finalizer) batchSanityCheck(ctx context.Context, batchNum uint64, initi SkipVerifyL1InfoRoot_V2: true, Caller: stateMetrics.DiscardCallerLabel, } - batchRequest.L1InfoTreeData_V2, _, _, err = f.stateIntf.GetL1InfoTreeDataFromBatchL2Data(ctx, batch.BatchL2Data, nil) + batchRequest.L1InfoTreeData_V2, _, _, err = f.stateIntf.GetL1InfoTreeDataFromBatchL2Data(ctx, batch.BatchL2Data, dbTx) if err != nil { log.Errorf("failed to get L1InfoTreeData for batch %d, error: %v", batch.BatchNumber, err) reprocessError(nil) @@ -502,7 +502,7 @@ func (f *finalizer) batchSanityCheck(ctx context.Context, batchNum uint64, initi return nil, ErrStateRootNoMatch } - err = f.stateIntf.UpdateBatchAsChecked(ctx, batch.BatchNumber, nil) + err = f.stateIntf.UpdateBatchAsChecked(ctx, batch.BatchNumber, dbTx) if err != nil { log.Errorf("failed to update batch %d as checked, error: %v", batch.BatchNumber, err) reprocessError(batch) diff --git a/sequencer/finalizer_test.go b/sequencer/finalizer_test.go index 35a03ef4ea..7efdf59907 100644 --- a/sequencer/finalizer_test.go +++ b/sequencer/finalizer_test.go @@ -984,11 +984,11 @@ func TestFinalizer_finalizeSIPBatch(t *testing.T) { stateMock.On("CloseWIPBatch", ctx, receipt, mock.Anything).Return(tc.managerErr).Once() if tc.managerErr == nil { - stateMock.On("GetBatchByNumber", ctx, f.sipBatch.batchNumber, nil).Return(&state.Batch{BatchNumber: f.sipBatch.batchNumber}, nilErr).Once() + stateMock.On("GetBatchByNumber", ctx, f.sipBatch.batchNumber, mock.Anything).Return(&state.Batch{BatchNumber: f.sipBatch.batchNumber}, nilErr).Once() stateMock.On("GetForkIDByBatchNumber", f.wipBatch.batchNumber).Return(uint64(9)).Once() - stateMock.On("GetL1InfoTreeDataFromBatchL2Data", ctx, mock.Anything, nil).Return(map[uint32]state.L1DataV2{}, state.ZeroHash, state.ZeroHash, nil) + stateMock.On("GetL1InfoTreeDataFromBatchL2Data", ctx, mock.Anything, mock.Anything).Return(map[uint32]state.L1DataV2{}, state.ZeroHash, state.ZeroHash, nil) stateMock.On("ProcessBatchV2", ctx, mock.Anything, false).Return(&state.ProcessBatchResponse{}, "", nil) - stateMock.On("UpdateBatchAsChecked", ctx, f.sipBatch.batchNumber, nil).Return(nil) + stateMock.On("UpdateBatchAsChecked", ctx, f.sipBatch.batchNumber, mock.Anything).Return(nil) dbTxMock.On("Commit", ctx).Return(nilErr).Once() } else { dbTxMock.On("Rollback", ctx).Return(nilErr).Once() From 96648183b478ed9de82122c40227bf887c37d4bd Mon Sep 17 00:00:00 2001 From: Joan Esteban <129153821+joanestebanr@users.noreply.github.com> Date: Tue, 16 Jul 2024 10:13:55 +0200 Subject: [PATCH 02/14] support forkid 10 and forkid11 (#3731) --- state/forkid.go | 4 ++++ synchronizer/actions/forksids.go | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/state/forkid.go b/state/forkid.go index ed035a53e1..bfd78c6c91 100644 --- a/state/forkid.go +++ b/state/forkid.go @@ -19,6 +19,10 @@ const ( FORKID_ELDERBERRY = 8 // FORKID_9 is the fork id 9 FORKID_9 = 9 + // FORKID_10 is the fork id 10 + FORKID_10 = 10 + // FORKID_11 is the fork id 11 + FORKID_11 = 11 ) // ForkIDInterval is a fork id interval diff --git a/synchronizer/actions/forksids.go b/synchronizer/actions/forksids.go index 1383ef98c5..e379dcb136 100644 --- a/synchronizer/actions/forksids.go +++ b/synchronizer/actions/forksids.go @@ -14,6 +14,10 @@ const ( ForkIDElderberry = ForkIdType(8) //nolint:gomnd // ForkID9 is the forkId for 9 ForkID9 = ForkIdType(9) //nolint:gomnd + // ForkID10 is the forkId for 10 (support more counters) + ForkID10 = ForkIdType(10) //nolint:gomnd + // ForkID11 is the forkId for 11 (support even more counters) + ForkID11 = ForkIdType(11) //nolint:gomnd ) var ( @@ -22,7 +26,7 @@ var ( ForksIdAll = []ForkIdType{WildcardForkId} // ForksIdOnlyElderberry support only elderberry forkId - ForksIdOnlyElderberry = []ForkIdType{ForkIDElderberry, ForkID9} + ForksIdOnlyElderberry = []ForkIdType{ForkIDElderberry, ForkID9, ForkID10, ForkID11} // ForksIdOnlyEtrog support only etrog forkId ForksIdOnlyEtrog = []ForkIdType{ForkIDEtrog} From 7aa74dcfeff266fe3f56892d0d08b6745aa7a1c5 Mon Sep 17 00:00:00 2001 From: agnusmor <100322135+agnusmor@users.noreply.github.com> Date: Tue, 16 Jul 2024 10:14:37 +0200 Subject: [PATCH 03/14] kill inactive datastream clients (#3727) --- config/config_test.go | 8 +++ config/default.go | 2 + .../environments/local/local.node.config.toml | 2 + docs/config-file/node-config-doc.html | 4 ++ docs/config-file/node-config-doc.md | 54 +++++++++++++++++++ docs/config-file/node-config-schema.json | 20 +++++++ go.mod | 18 +++---- go.sum | 43 +++++++-------- sequencer/config.go | 4 ++ sequencer/sequencer.go | 2 +- test/config/debug.node.config.toml | 2 + test/config/test.node.config.toml | 2 + tools/datastreamer/config/config.go | 4 ++ tools/datastreamer/config/tool.config.toml | 2 + tools/datastreamer/main.go | 2 +- 15 files changed, 137 insertions(+), 32 deletions(-) diff --git a/config/config_test.go b/config/config_test.go index d6c40ed30a..3786da6023 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -173,6 +173,14 @@ func Test_Defaults(t *testing.T) { path: "Sequencer.StreamServer.WriteTimeout", expectedValue: types.NewDuration(5 * time.Second), }, + { + path: "Sequencer.StreamServer.InactivityTimeout", + expectedValue: types.NewDuration(120 * time.Second), + }, + { + path: "Sequencer.StreamServer.InactivityCheckInterval", + expectedValue: types.NewDuration(5 * time.Second), + }, { path: "Sequencer.StreamServer.Enabled", expectedValue: false, diff --git a/config/default.go b/config/default.go index bff3d90a70..4d2f50f1a4 100644 --- a/config/default.go +++ b/config/default.go @@ -164,6 +164,8 @@ StateConsistencyCheckInterval = "5s" Filename = "" Version = 0 WriteTimeout = "5s" + InactivityTimeout = "120s" + InactivityCheckInterval = "5s" Enabled = false [SequenceSender] diff --git a/config/environments/local/local.node.config.toml b/config/environments/local/local.node.config.toml index c403a0718a..d3ebc8e0e6 100644 --- a/config/environments/local/local.node.config.toml +++ b/config/environments/local/local.node.config.toml @@ -113,6 +113,8 @@ StateConsistencyCheckInterval = "5s" Port = 0 Filename = "" WriteTimeout = "5s" + InactivityTimeout = "120s" + InactivityCheckInterval = "5s" Enabled = false [SequenceSender] diff --git a/docs/config-file/node-config-doc.html b/docs/config-file/node-config-doc.html index 14800feab3..0c5400fb2a 100644 --- a/docs/config-file/node-config-doc.html +++ b/docs/config-file/node-config-doc.html @@ -58,6 +58,10 @@
"300ms"
 

Default: trueType: boolean

EnableLog is a flag to enable/disable metrics logs


StreamServerCfg is the config for the stream server
Default: 0Type: integer

Port to listen on


Default: ""Type: string

Filename of the binary data file


Default: 0Type: integer

Version of the binary data file


Default: 0Type: integer

ChainID is the chain ID


Default: falseType: boolean

Enabled is a flag to enable/disable the data streamer


Log is the log configuration
Default: ""Type: enum (of string)

Must be one of:

  • "production"
  • "development"

Default: ""Type: enum (of string)

Must be one of:

  • "debug"
  • "info"
  • "warn"
  • "error"
  • "dpanic"
  • "panic"
  • "fatal"

Type: array of string

Each item of this array must be:


Default: 0Type: integer

UpgradeEtrogBatchNumber is the batch number of the upgrade etrog


Default: "5s"Type: string

WriteTimeout is the TCP write timeout when sending data to a datastream client


Examples:

"1m"
 
"300ms"
+

Default: "2m0s"Type: string

InactivityTimeout is the timeout to kill an inactive datastream client connection


Examples:

"1m"
+
"300ms"
+

Default: "5s"Type: string

InactivityCheckInterval is the time interval to check for datastream client connections that have reached the inactivity timeout to kill them


Examples:

"1m"
+
"300ms"
 

Configuration of the sequence sender service
Default: "5s"Type: string

WaitPeriodSendSequence is the time the sequencer waits until
trying to send a sequence to L1


Examples:

"1m"
 
"300ms"
 

Default: "5s"Type: string

LastBatchVirtualizationTimeMaxWaitPeriod is time since sequences should be sent


Examples:

"1m"
diff --git a/docs/config-file/node-config-doc.md b/docs/config-file/node-config-doc.md
index 3dab591984..dc70d93791 100644
--- a/docs/config-file/node-config-doc.md
+++ b/docs/config-file/node-config-doc.md
@@ -2488,6 +2488,8 @@ EnableLog=true
 | - [Log](#Sequencer_StreamServer_Log )                                         | No      | object  | No         | -          | Log is the log configuration                                     |
 | - [UpgradeEtrogBatchNumber](#Sequencer_StreamServer_UpgradeEtrogBatchNumber ) | No      | integer | No         | -          | UpgradeEtrogBatchNumber is the batch number of the upgrade etrog |
 | - [WriteTimeout](#Sequencer_StreamServer_WriteTimeout )                       | No      | string  | No         | -          | Duration                                                         |
+| - [InactivityTimeout](#Sequencer_StreamServer_InactivityTimeout )             | No      | string  | No         | -          | Duration                                                         |
+| - [InactivityCheckInterval](#Sequencer_StreamServer_InactivityCheckInterval ) | No      | string  | No         | -          | Duration                                                         |
 
 #### 10.9.1. `Sequencer.StreamServer.Port`
 
@@ -2651,6 +2653,58 @@ UpgradeEtrogBatchNumber=0
 WriteTimeout="5s"
 ```
 
+#### 10.9.9. `Sequencer.StreamServer.InactivityTimeout`
+
+**Title:** Duration
+
+**Type:** : `string`
+
+**Default:** `"2m0s"`
+
+**Description:** InactivityTimeout is the timeout to kill an inactive datastream client connection
+
+**Examples:** 
+
+```json
+"1m"
+```
+
+```json
+"300ms"
+```
+
+**Example setting the default value** ("2m0s"):
+```
+[Sequencer.StreamServer]
+InactivityTimeout="2m0s"
+```
+
+#### 10.9.10. `Sequencer.StreamServer.InactivityCheckInterval`
+
+**Title:** Duration
+
+**Type:** : `string`
+
+**Default:** `"5s"`
+
+**Description:** InactivityCheckInterval is the time interval to check for datastream client connections that have reached the inactivity timeout to kill them
+
+**Examples:** 
+
+```json
+"1m"
+```
+
+```json
+"300ms"
+```
+
+**Example setting the default value** ("5s"):
+```
+[Sequencer.StreamServer]
+InactivityCheckInterval="5s"
+```
+
 ## 11. `[SequenceSender]`
 
 **Type:** : `object`
diff --git a/docs/config-file/node-config-schema.json b/docs/config-file/node-config-schema.json
index 489ee17274..5b1b218cf5 100644
--- a/docs/config-file/node-config-schema.json
+++ b/docs/config-file/node-config-schema.json
@@ -1008,6 +1008,26 @@
 								"1m",
 								"300ms"
 							]
+						},
+						"InactivityTimeout": {
+							"type": "string",
+							"title": "Duration",
+							"description": "InactivityTimeout is the timeout to kill an inactive datastream client connection",
+							"default": "2m0s",
+							"examples": [
+								"1m",
+								"300ms"
+							]
+						},
+						"InactivityCheckInterval": {
+							"type": "string",
+							"title": "Duration",
+							"description": "InactivityCheckInterval is the time interval to check for datastream client connections that have reached the inactivity timeout to kill them",
+							"default": "5s",
+							"examples": [
+								"1m",
+								"300ms"
+							]
 						}
 					},
 					"additionalProperties": false,
diff --git a/go.mod b/go.mod
index 64ced2a895..9544b9b958 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/0xPolygonHermez/zkevm-node
 go 1.21
 
 require (
-	github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-RC4
+	github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-RC5
 	github.com/didip/tollbooth/v6 v6.1.2
 	github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127
 	github.com/ethereum/go-ethereum v1.13.11
@@ -22,11 +22,11 @@ require (
 	github.com/prometheus/common v0.45.0
 	github.com/rubenv/sql-migrate v1.6.1
 	github.com/spf13/afero v1.11.0
-	github.com/spf13/viper v1.17.0
-	github.com/stretchr/testify v1.8.4
+	github.com/spf13/viper v1.18.2
+	github.com/stretchr/testify v1.9.0
 	github.com/umbracle/ethgo v0.1.3
-	github.com/urfave/cli/v2 v2.26.0
-	go.uber.org/zap v1.26.0
+	github.com/urfave/cli/v2 v2.27.1
+	go.uber.org/zap v1.27.0
 	golang.org/x/crypto v0.18.0
 	golang.org/x/net v0.20.0
 	golang.org/x/sync v0.5.0
@@ -68,7 +68,7 @@ require (
 	github.com/emirpasic/gods v1.18.1 // indirect
 	github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
 	github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
-	github.com/fsnotify/fsnotify v1.6.0 // indirect
+	github.com/fsnotify/fsnotify v1.7.0 // indirect
 	github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
 	github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect
 	github.com/getsentry/sentry-go v0.18.0 // indirect
@@ -128,17 +128,17 @@ require (
 	github.com/rogpeppe/go-internal v1.11.0 // indirect
 	github.com/rs/cors v1.7.0 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
-	github.com/sagikazarmark/locafero v0.3.0 // indirect
+	github.com/sagikazarmark/locafero v0.4.0 // indirect
 	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
 	github.com/sergi/go-diff v1.2.0 // indirect
 	github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
 	github.com/sirupsen/logrus v1.9.0 // indirect
 	github.com/skeema/knownhosts v1.2.1 // indirect
 	github.com/sourcegraph/conc v0.3.0 // indirect
-	github.com/spf13/cast v1.5.1 // indirect
+	github.com/spf13/cast v1.6.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/status-im/keycard-go v0.2.0 // indirect
-	github.com/stretchr/objx v0.5.0 // indirect
+	github.com/stretchr/objx v0.5.2 // indirect
 	github.com/subosito/gotenv v1.6.0 // indirect
 	github.com/supranational/blst v0.3.11 // indirect
 	github.com/tklauser/go-sysconf v0.3.12 // indirect
diff --git a/go.sum b/go.sum
index da7a1cbead..4aacd939e6 100644
--- a/go.sum
+++ b/go.sum
@@ -39,8 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
 dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
 dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-RC4 h1:+4K+xSzv0ImbK30B/T9FauNTrTFUmWcNKYhIgwsE4C4=
-github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-RC4/go.mod h1:0QkAXcFa92mFJrCbN3UPUJGJYes851yEgYHLONnaosE=
+github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-RC5 h1:ofcfKofJCn3AyOYnEeQ6YbKm0slEKRXk+TbeuvIUymw=
+github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-RC5/go.mod h1:bv7DjATsczN2WvFt26jv34TWv6rfvYM1SqegrgrFwfI=
 github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
@@ -209,13 +209,13 @@ github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4Nij
 github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
 github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
-github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
-github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
-github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
-github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
 github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
 github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
@@ -680,8 +680,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
-github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
+github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
+github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
 github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
 github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
@@ -719,8 +719,8 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
 github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
-github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
 github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
@@ -730,16 +730,17 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
 github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
-github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
-github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI=
+github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
+github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
 github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
 github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -750,8 +751,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
@@ -775,8 +777,8 @@ github.com/umbracle/ethgo v0.1.3 h1:s8D7Rmphnt71zuqrgsGTMS5gTNbueGO1zKLh7qsFzTM=
 github.com/umbracle/ethgo v0.1.3/go.mod h1:g9zclCLixH8liBI27Py82klDkW7Oo33AxUOr+M9lzrU=
 github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 h1:10Nbw6cACsnQm7r34zlpJky+IzxVLRk6MKTS2d3Vp0E=
 github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722/go.mod h1:c8J0h9aULj2i3umrfyestM6jCq0LK0U6ly6bWy96nd4=
-github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
-github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
+github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
+github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
 github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
@@ -830,8 +832,8 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
-go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
-go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
 go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
@@ -843,8 +845,8 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
 go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
-go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
-go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -1060,7 +1062,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/sequencer/config.go b/sequencer/config.go
index 5f34cad1d9..918042291c 100644
--- a/sequencer/config.go
+++ b/sequencer/config.go
@@ -54,6 +54,10 @@ type StreamServerCfg struct {
 	UpgradeEtrogBatchNumber uint64 `mapstructure:"UpgradeEtrogBatchNumber"`
 	// WriteTimeout is the TCP write timeout when sending data to a datastream client
 	WriteTimeout types.Duration `mapstructure:"WriteTimeout"`
+	// InactivityTimeout is the timeout to kill an inactive datastream client connection
+	InactivityTimeout types.Duration `mapstructure:"InactivityTimeout"`
+	// InactivityCheckInterval is the time interval to check for datastream client connections that have reached the inactivity timeout to kill them
+	InactivityCheckInterval types.Duration `mapstructure:"InactivityCheckInterval"`
 }
 
 // FinalizerCfg contains the finalizer's configuration properties
diff --git a/sequencer/sequencer.go b/sequencer/sequencer.go
index 3f57d9cc85..eaeab94f33 100644
--- a/sequencer/sequencer.go
+++ b/sequencer/sequencer.go
@@ -72,7 +72,7 @@ func (s *Sequencer) Start(ctx context.Context) {
 
 	// Start stream server if enabled
 	if s.cfg.StreamServer.Enabled {
-		s.streamServer, err = datastreamer.NewServer(s.cfg.StreamServer.Port, s.cfg.StreamServer.Version, s.cfg.StreamServer.ChainID, state.StreamTypeSequencer, s.cfg.StreamServer.Filename, s.cfg.StreamServer.WriteTimeout.Duration, &s.cfg.StreamServer.Log)
+		s.streamServer, err = datastreamer.NewServer(s.cfg.StreamServer.Port, s.cfg.StreamServer.Version, s.cfg.StreamServer.ChainID, state.StreamTypeSequencer, s.cfg.StreamServer.Filename, s.cfg.StreamServer.WriteTimeout.Duration, s.cfg.StreamServer.InactivityTimeout.Duration, s.cfg.StreamServer.InactivityCheckInterval.Duration, &s.cfg.StreamServer.Log)
 		if err != nil {
 			log.Fatalf("failed to create stream server, error: %v", err)
 		}
diff --git a/test/config/debug.node.config.toml b/test/config/debug.node.config.toml
index 54ca62a789..7ec0d496ea 100644
--- a/test/config/debug.node.config.toml
+++ b/test/config/debug.node.config.toml
@@ -113,6 +113,8 @@ StateConsistencyCheckInterval = "5s"
 		Filename = "/datastreamer/datastream.bin"
 		Version = 1
 		WriteTimeout = "5s"
+		InactivityTimeout = "120s"
+		InactivityCheckInterval = "5s"
 		Enabled = true
 
 [SequenceSender]
diff --git a/test/config/test.node.config.toml b/test/config/test.node.config.toml
index 0358afa59e..d13ff02ca5 100644
--- a/test/config/test.node.config.toml
+++ b/test/config/test.node.config.toml
@@ -129,6 +129,8 @@ StateConsistencyCheckInterval = "5s"
 		Version = 1
 		ChainID = 1337
 		WriteTimeout = "5s"
+		InactivityTimeout = "120s"
+		InactivityCheckInterval = "5s"		
 		Enabled = true
 
 [SequenceSender]
diff --git a/tools/datastreamer/config/config.go b/tools/datastreamer/config/config.go
index b6c841e591..b2651c538b 100644
--- a/tools/datastreamer/config/config.go
+++ b/tools/datastreamer/config/config.go
@@ -51,6 +51,10 @@ type StreamServerCfg struct {
 	UpgradeEtrogBatchNumber uint64 `mapstructure:"UpgradeEtrogBatchNumber"`
 	// WriteTimeout is the TCP write timeout when sending data to a datastream client
 	WriteTimeout types.Duration `mapstructure:"WriteTimeout"`
+	// InactivityTimeout is the timeout to kill an inactive datastream client connection
+	InactivityTimeout types.Duration `mapstructure:"InactivityTimeout"`
+	// InactivityCheckInterval is the time interval to check for datastream client connections that have reached the inactivity timeout to kill them
+	InactivityCheckInterval types.Duration `mapstructure:"InactivityCheckInterval"`
 }
 
 // Config is the configuration for the tool
diff --git a/tools/datastreamer/config/tool.config.toml b/tools/datastreamer/config/tool.config.toml
index f5530b8271..60d04aafb3 100644
--- a/tools/datastreamer/config/tool.config.toml
+++ b/tools/datastreamer/config/tool.config.toml
@@ -8,6 +8,8 @@ Filename = "datastream.bin"
 Version = 3
 ChainID = 1440
 WriteTimeout = "5s"
+InactivityTimeout = "120s"
+InactivityCheckInterval = "5s"
 UpgradeEtrogBatchNumber = 0
 
 [StateDB]
diff --git a/tools/datastreamer/main.go b/tools/datastreamer/main.go
index fc069117af..c6b43155f8 100644
--- a/tools/datastreamer/main.go
+++ b/tools/datastreamer/main.go
@@ -184,7 +184,7 @@ func main() {
 
 func initializeStreamServer(c *config.Config) (*datastreamer.StreamServer, error) {
 	// Create a stream server
-	streamServer, err := datastreamer.NewServer(c.Offline.Port, c.Offline.Version, c.Offline.ChainID, state.StreamTypeSequencer, c.Offline.Filename, c.Offline.WriteTimeout.Duration, &c.Log)
+	streamServer, err := datastreamer.NewServer(c.Offline.Port, c.Offline.Version, c.Offline.ChainID, state.StreamTypeSequencer, c.Offline.Filename, c.Offline.WriteTimeout.Duration, c.Offline.InactivityTimeout.Duration, c.Offline.InactivityCheckInterval.Duration, &c.Log)
 	if err != nil {
 		return nil, err
 	}

From 19beaa94880bec8098d88c675d28a7522e952577 Mon Sep 17 00:00:00 2001
From: agnusmor <100322135+agnusmor@users.noreply.github.com>
Date: Thu, 18 Jul 2024 12:48:59 +0200
Subject: [PATCH 04/14] Add mined l1blocknumber to MonitoredTxResult. Undo
 forkid10 and forkid11 changes (#3734)

---
 ethtxmanager/ethtxmanager.go     |  7 ++++---
 ethtxmanager/monitoredtx.go      |  7 ++++---
 sequencesender/sequencesender.go | 23 +++++------------------
 state/forkid.go                  |  4 ----
 synchronizer/actions/forksids.go |  6 +-----
 5 files changed, 14 insertions(+), 33 deletions(-)

diff --git a/ethtxmanager/ethtxmanager.go b/ethtxmanager/ethtxmanager.go
index 79f9262962..ae640bab7c 100644
--- a/ethtxmanager/ethtxmanager.go
+++ b/ethtxmanager/ethtxmanager.go
@@ -184,9 +184,10 @@ func (c *Client) buildResult(ctx context.Context, mTx monitoredTx) (MonitoredTxR
 	}
 
 	result := MonitoredTxResult{
-		ID:     mTx.id,
-		Status: mTx.status,
-		Txs:    txs,
+		ID:          mTx.id,
+		Status:      mTx.status,
+		BlockNumber: mTx.blockNumber,
+		Txs:         txs,
 	}
 
 	return result, nil
diff --git a/ethtxmanager/monitoredtx.go b/ethtxmanager/monitoredtx.go
index 716030763b..b0c4182b95 100644
--- a/ethtxmanager/monitoredtx.go
+++ b/ethtxmanager/monitoredtx.go
@@ -182,9 +182,10 @@ func (mTx *monitoredTx) blockNumberU64Ptr() *uint64 {
 
 // MonitoredTxResult represents the result of a execution of a monitored tx
 type MonitoredTxResult struct {
-	ID     string
-	Status MonitoredTxStatus
-	Txs    map[common.Hash]TxResult
+	ID          string
+	Status      MonitoredTxStatus
+	BlockNumber *big.Int
+	Txs         map[common.Hash]TxResult
 }
 
 // TxResult represents the result of a execution of a ethereum transaction in the block chain
diff --git a/sequencesender/sequencesender.go b/sequencesender/sequencesender.go
index 81b2c68fc6..80a467eafd 100644
--- a/sequencesender/sequencesender.go
+++ b/sequencesender/sequencesender.go
@@ -12,7 +12,6 @@ import (
 	"github.com/0xPolygonHermez/zkevm-node/event"
 	"github.com/0xPolygonHermez/zkevm-node/log"
 	"github.com/0xPolygonHermez/zkevm-node/state"
-	"github.com/ethereum/go-ethereum/common"
 	ethTypes "github.com/ethereum/go-ethereum/core/types"
 	"github.com/jackc/pgx/v4"
 )
@@ -97,25 +96,13 @@ func (s *SequenceSender) tryToSendSequence(ctx context.Context) {
 	s.ethTxManager.ProcessPendingMonitoredTxs(ctx, ethTxManagerOwner, func(result ethtxmanager.MonitoredTxResult, dbTx pgx.Tx) {
 		if result.Status == ethtxmanager.MonitoredTxStatusConfirmed {
 			if len(result.Txs) > 0 {
-				var txL1BlockNumber uint64
-				var txHash common.Hash
-				receiptFound := false
-				for _, tx := range result.Txs {
-					if tx.Receipt != nil {
-						txL1BlockNumber = tx.Receipt.BlockNumber.Uint64()
-						txHash = tx.Tx.Hash()
-						receiptFound = true
-						break
-					}
-				}
-
-				if !receiptFound {
-					s.halt(ctx, fmt.Errorf("monitored tx %s for sequence [%d-%d] is confirmed but doesn't have a receipt", result.ID, s.lastSequenceInitialBatch, s.lastSequenceEndBatch))
+				if result.BlockNumber == nil {
+					s.halt(ctx, fmt.Errorf("monitored tx %s for sequence [%d-%d] is confirmed but doesn't have L1 block number where tx was mined", result.ID, s.lastSequenceInitialBatch, s.lastSequenceEndBatch))
 				}
 
 				// wait L1 confirmation blocks
-				log.Infof("waiting %d L1 block confirmations for sequence [%d-%d], L1 block: %d, tx: %s",
-					s.cfg.SequenceL1BlockConfirmations, s.lastSequenceInitialBatch, s.lastSequenceEndBatch, txL1BlockNumber, txHash)
+				log.Infof("waiting %d L1 block confirmations for sequence [%d-%d], L1 block: %d",
+					s.cfg.SequenceL1BlockConfirmations, s.lastSequenceInitialBatch, s.lastSequenceEndBatch, result.BlockNumber)
 				for {
 					lastL1BlockHeader, err := s.etherman.GetLatestBlockHeader(ctx)
 					if err != nil {
@@ -123,7 +110,7 @@ func (s *SequenceSender) tryToSendSequence(ctx context.Context) {
 					} else {
 						lastL1BlockNumber := lastL1BlockHeader.Number.Uint64()
 
-						if lastL1BlockNumber >= txL1BlockNumber+s.cfg.SequenceL1BlockConfirmations {
+						if lastL1BlockNumber >= result.BlockNumber.Uint64()+s.cfg.SequenceL1BlockConfirmations {
 							log.Infof("continuing, last L1 block: %d", lastL1BlockNumber)
 							break
 						}
diff --git a/state/forkid.go b/state/forkid.go
index bfd78c6c91..ed035a53e1 100644
--- a/state/forkid.go
+++ b/state/forkid.go
@@ -19,10 +19,6 @@ const (
 	FORKID_ELDERBERRY = 8
 	// FORKID_9 is the fork id 9
 	FORKID_9 = 9
-	// FORKID_10 is the fork id 10
-	FORKID_10 = 10
-	// FORKID_11 is the fork id 11
-	FORKID_11 = 11
 )
 
 // ForkIDInterval is a fork id interval
diff --git a/synchronizer/actions/forksids.go b/synchronizer/actions/forksids.go
index e379dcb136..1383ef98c5 100644
--- a/synchronizer/actions/forksids.go
+++ b/synchronizer/actions/forksids.go
@@ -14,10 +14,6 @@ const (
 	ForkIDElderberry = ForkIdType(8) //nolint:gomnd
 	// ForkID9 is the forkId for 9
 	ForkID9 = ForkIdType(9) //nolint:gomnd
-	// ForkID10 is the forkId for 10 (support more counters)
-	ForkID10 = ForkIdType(10) //nolint:gomnd
-	// ForkID11 is the forkId for 11 (support even more counters)
-	ForkID11 = ForkIdType(11) //nolint:gomnd
 )
 
 var (
@@ -26,7 +22,7 @@ var (
 	ForksIdAll = []ForkIdType{WildcardForkId}
 
 	// ForksIdOnlyElderberry support only elderberry forkId
-	ForksIdOnlyElderberry = []ForkIdType{ForkIDElderberry, ForkID9, ForkID10, ForkID11}
+	ForksIdOnlyElderberry = []ForkIdType{ForkIDElderberry, ForkID9}
 
 	// ForksIdOnlyEtrog support only etrog forkId
 	ForksIdOnlyEtrog = []ForkIdType{ForkIDEtrog}

From 8a1e192bcea45185c7f37db4719d400c83ceab20 Mon Sep 17 00:00:00 2001
From: agnusmor <100322135+agnusmor@users.noreply.github.com>
Date: Thu, 18 Jul 2024 13:16:38 +0200
Subject: [PATCH 05/14] Wait the state to be synced when starting (#3735)

---
 aggregator/aggregator.go | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/aggregator/aggregator.go b/aggregator/aggregator.go
index 751ade1ff7..0e41d796de 100644
--- a/aggregator/aggregator.go
+++ b/aggregator/aggregator.go
@@ -124,6 +124,12 @@ func (a *Aggregator) Start(ctx context.Context) error {
 		return fmt.Errorf("failed to initialize proofs cache %w", err)
 	}
 
+	for !a.isSynced(ctx, nil) {
+		log.Info("Waiting for synchronizer to sync...")
+		time.Sleep(a.cfg.RetryTime.Duration)
+		continue
+	}
+
 	address := fmt.Sprintf("%s:%d", a.cfg.Host, a.cfg.Port)
 	lis, err := net.Listen("tcp", address)
 	if err != nil {

From 1adc67d1e00e737e2f3e0afb9636b15a1d382074 Mon Sep 17 00:00:00 2001
From: agnusmor <100322135+agnusmor@users.noreply.github.com>
Date: Wed, 24 Jul 2024 11:46:58 +0200
Subject: [PATCH 06/14] Fix update datastream file (#3741)

* Update datastream file fixes: end batch entry, previous L2 block timestamp, current batch number

* Use GetFirstEventAfterBookmark
---
 state/datastream.go | 57 ++++++++++++++++++++++++++++++---------------
 1 file changed, 38 insertions(+), 19 deletions(-)

diff --git a/state/datastream.go b/state/datastream.go
index 236a69df43..a9544d4e69 100644
--- a/state/datastream.go
+++ b/state/datastream.go
@@ -258,26 +258,43 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 			}
 
 			currentL2BlockNumber := transaction.L2BlockNumber
-			currentBatchNumber = transaction.L2BlockNumber
 			lastAddedL2BlockNumber = currentL2BlockNumber
 
-			// Get Previous l2block timestamp
-			bookMark := &datastream.BookMark{
+			// Get current batch number
+			bookMarkCurrentL2Block := &datastream.BookMark{
 				Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
-				Value: currentL2BlockNumber - 1,
+				Value: currentL2BlockNumber,
 			}
 
-			marshalledBookMark, err := proto.Marshal(bookMark)
+			marshalledBookMarkCurrentL2Block, err := proto.Marshal(bookMarkCurrentL2Block)
+			if err != nil {
+				return err
+			}
+
+			currentL2BlockEntry, err := streamServer.GetFirstEventAfterBookmark(marshalledBookMarkCurrentL2Block)
 			if err != nil {
 				return err
 			}
 
-			prevL2BlockEntryNumber, err := streamServer.GetBookmark(marshalledBookMark)
+			currentL2Block := &datastream.L2Block{}
+			if err := proto.Unmarshal(currentL2BlockEntry.Data, currentL2Block); err != nil {
+				return err
+			}
+
+			currentBatchNumber = currentL2Block.BatchNumber
+
+			// Get Previous l2block timestamp
+			bookMarkPrevL2Block := &datastream.BookMark{
+				Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
+				Value: currentL2BlockNumber - 1,
+			}
+
+			marshalledBookMarkPrevL2Block, err := proto.Marshal(bookMarkPrevL2Block)
 			if err != nil {
 				return err
 			}
 
-			prevL2BlockEntry, err := streamServer.GetEntry(prevL2BlockEntryNumber)
+			prevL2BlockEntry, err := streamServer.GetFirstEventAfterBookmark(marshalledBookMarkPrevL2Block)
 			if err != nil {
 				return err
 			}
@@ -610,20 +627,22 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 				}
 			}
 
-			batchEnd := &datastream.BatchEnd{
-				Number:        batch.BatchNumber,
-				LocalExitRoot: batch.LocalExitRoot.Bytes(),
-				StateRoot:     batch.StateRoot.Bytes(),
-			}
+			if !batch.WIP {
+				batchEnd := &datastream.BatchEnd{
+					Number:        batch.BatchNumber,
+					LocalExitRoot: batch.LocalExitRoot.Bytes(),
+					StateRoot:     batch.StateRoot.Bytes(),
+				}
 
-			marshalledBatch, err := proto.Marshal(batchEnd)
-			if err != nil {
-				return err
-			}
+				marshalledBatch, err := proto.Marshal(batchEnd)
+				if err != nil {
+					return err
+				}
 
-			_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH_END), marshalledBatch)
-			if err != nil {
-				return err
+				_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH_END), marshalledBatch)
+				if err != nil {
+					return err
+				}
 			}
 
 			// Commit at the end of each batch group

From f594715590511689c40abebba8e20e6915c20234 Mon Sep 17 00:00:00 2001
From: Thiago Coimbra Lemos 
Date: Wed, 24 Jul 2024 12:58:18 -0300
Subject: [PATCH 07/14] fix tracer previous step memory pointers (#3740)

---
 .../tracers/structlogger/structlogger.go      |   9 +
 state/trace.go                                |   3 +-
 test/contracts/auto/Sha.sol                   |   8 +
 test/contracts/bin/Sha/Sha.go                 | 224 ++++++++++++++++++
 .../bin/triggerErrors/triggerErrors.go        |   2 +-
 test/e2e/debug_calltracer_test.go             |   1 +
 test/e2e/debug_shared.go                      |  27 +++
 test/e2e/debug_test.go                        |  30 ++-
 8 files changed, 291 insertions(+), 13 deletions(-)
 create mode 100644 test/contracts/auto/Sha.sol
 create mode 100644 test/contracts/bin/Sha/Sha.go

diff --git a/state/runtime/instrumentation/tracers/structlogger/structlogger.go b/state/runtime/instrumentation/tracers/structlogger/structlogger.go
index 3a4cf037ad..bd9e20afd3 100644
--- a/state/runtime/instrumentation/tracers/structlogger/structlogger.go
+++ b/state/runtime/instrumentation/tracers/structlogger/structlogger.go
@@ -27,6 +27,7 @@ type StructLogRes struct {
 	Depth         int                `json:"depth"`
 	Error         string             `json:"error,omitempty"`
 	Stack         *[]string          `json:"stack,omitempty"`
+	ReturnData    *string            `json:"returnData,omitempty"`
 	Memory        *[]string          `json:"memory,omitempty"`
 	Storage       *map[string]string `json:"storage,omitempty"`
 	RefundCounter uint64             `json:"refund,omitempty"`
@@ -123,6 +124,14 @@ func (l *JSONLogger) ParseTrace(result *runtime.ExecutionResult, receipt types.R
 			structLogRes.Storage = &storage
 		}
 
+		var returnData *string
+		if l.cfg.EnableReturnData && len(step.ReturnData) > 0 {
+			rd := hex.EncodeToHex(step.ReturnData)
+			returnData = &rd
+		}
+
+		structLogRes.ReturnData = returnData
+
 		structLogs = append(structLogs, structLogRes)
 	}
 
diff --git a/state/trace.go b/state/trace.go
index a1c367f067..4fcca8f08d 100644
--- a/state/trace.go
+++ b/state/trace.go
@@ -502,7 +502,8 @@ func (s *State) buildTrace(evm *fakevm.FakeEVM, result *runtime.ExecutionResult,
 		}
 
 		// Populate the step memory for future steps
-		step.Memory = memory.Data()
+		step.Memory = make([]byte, len(memory.Data()))
+		copy(step.Memory[0:], memory.Data()[0:])
 
 		// set Contract
 		contract := fakevm.NewContract(
diff --git a/test/contracts/auto/Sha.sol b/test/contracts/auto/Sha.sol
new file mode 100644
index 0000000000..90621e59d2
--- /dev/null
+++ b/test/contracts/auto/Sha.sol
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-3.0
+pragma solidity ^0.8.4;
+
+contract Sha {
+    function hash() public {
+        sha256("hello world");
+    }
+}
diff --git a/test/contracts/bin/Sha/Sha.go b/test/contracts/bin/Sha/Sha.go
new file mode 100644
index 0000000000..887d168db1
--- /dev/null
+++ b/test/contracts/bin/Sha/Sha.go
@@ -0,0 +1,224 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package Sha
+
+import (
+	"errors"
+	"math/big"
+	"strings"
+
+	ethereum "github.com/ethereum/go-ethereum"
+	"github.com/ethereum/go-ethereum/accounts/abi"
+	"github.com/ethereum/go-ethereum/accounts/abi/bind"
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/event"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var (
+	_ = errors.New
+	_ = big.NewInt
+	_ = strings.NewReader
+	_ = ethereum.NotFound
+	_ = bind.Bind
+	_ = common.Big1
+	_ = types.BloomLookup
+	_ = event.NewSubscription
+	_ = abi.ConvertType
+)
+
+// ShaMetaData contains all meta data concerning the Sha contract.
+var ShaMetaData = &bind.MetaData{
+	ABI: "[{\"inputs\":[],\"name\":\"hash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+	Bin: "0x608060405234801561001057600080fd5b5060dd8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806309bd5a6014602d575b600080fd5b60336035565b005b6040516a1a195b1b1bc81ddbdc9b1960aa1b8152600290600b01602060405180830381855afa158015606b573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190608c9190608f565b50565b60006020828403121560a057600080fd5b505191905056fea2646970667358221220fe50f9cdaf095e844b048d17690c0862e54c7d7b550c4e2d9045215198e571d564736f6c634300080c0033",
+}
+
+// ShaABI is the input ABI used to generate the binding from.
+// Deprecated: Use ShaMetaData.ABI instead.
+var ShaABI = ShaMetaData.ABI
+
+// ShaBin is the compiled bytecode used for deploying new contracts.
+// Deprecated: Use ShaMetaData.Bin instead.
+var ShaBin = ShaMetaData.Bin
+
+// DeploySha deploys a new Ethereum contract, binding an instance of Sha to it.
+func DeploySha(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Sha, error) {
+	parsed, err := ShaMetaData.GetAbi()
+	if err != nil {
+		return common.Address{}, nil, nil, err
+	}
+	if parsed == nil {
+		return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+	}
+
+	address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ShaBin), backend)
+	if err != nil {
+		return common.Address{}, nil, nil, err
+	}
+	return address, tx, &Sha{ShaCaller: ShaCaller{contract: contract}, ShaTransactor: ShaTransactor{contract: contract}, ShaFilterer: ShaFilterer{contract: contract}}, nil
+}
+
+// Sha is an auto generated Go binding around an Ethereum contract.
+type Sha struct {
+	ShaCaller     // Read-only binding to the contract
+	ShaTransactor // Write-only binding to the contract
+	ShaFilterer   // Log filterer for contract events
+}
+
+// ShaCaller is an auto generated read-only Go binding around an Ethereum contract.
+type ShaCaller struct {
+	contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ShaTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type ShaTransactor struct {
+	contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ShaFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
+type ShaFilterer struct {
+	contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ShaSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type ShaSession struct {
+	Contract     *Sha              // Generic contract binding to set the session for
+	CallOpts     bind.CallOpts     // Call options to use throughout this session
+	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ShaCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type ShaCallerSession struct {
+	Contract *ShaCaller    // Generic contract caller binding to set the session for
+	CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// ShaTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type ShaTransactorSession struct {
+	Contract     *ShaTransactor    // Generic contract transactor binding to set the session for
+	TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ShaRaw is an auto generated low-level Go binding around an Ethereum contract.
+type ShaRaw struct {
+	Contract *Sha // Generic contract binding to access the raw methods on
+}
+
+// ShaCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type ShaCallerRaw struct {
+	Contract *ShaCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// ShaTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type ShaTransactorRaw struct {
+	Contract *ShaTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewSha creates a new instance of Sha, bound to a specific deployed contract.
+func NewSha(address common.Address, backend bind.ContractBackend) (*Sha, error) {
+	contract, err := bindSha(address, backend, backend, backend)
+	if err != nil {
+		return nil, err
+	}
+	return &Sha{ShaCaller: ShaCaller{contract: contract}, ShaTransactor: ShaTransactor{contract: contract}, ShaFilterer: ShaFilterer{contract: contract}}, nil
+}
+
+// NewShaCaller creates a new read-only instance of Sha, bound to a specific deployed contract.
+func NewShaCaller(address common.Address, caller bind.ContractCaller) (*ShaCaller, error) {
+	contract, err := bindSha(address, caller, nil, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &ShaCaller{contract: contract}, nil
+}
+
+// NewShaTransactor creates a new write-only instance of Sha, bound to a specific deployed contract.
+func NewShaTransactor(address common.Address, transactor bind.ContractTransactor) (*ShaTransactor, error) {
+	contract, err := bindSha(address, nil, transactor, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &ShaTransactor{contract: contract}, nil
+}
+
+// NewShaFilterer creates a new log filterer instance of Sha, bound to a specific deployed contract.
+func NewShaFilterer(address common.Address, filterer bind.ContractFilterer) (*ShaFilterer, error) {
+	contract, err := bindSha(address, nil, nil, filterer)
+	if err != nil {
+		return nil, err
+	}
+	return &ShaFilterer{contract: contract}, nil
+}
+
+// bindSha binds a generic wrapper to an already deployed contract.
+func bindSha(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+	parsed, err := ShaMetaData.GetAbi()
+	if err != nil {
+		return nil, err
+	}
+	return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Sha *ShaRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+	return _Sha.Contract.ShaCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Sha *ShaRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+	return _Sha.Contract.ShaTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Sha *ShaRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+	return _Sha.Contract.ShaTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Sha *ShaCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+	return _Sha.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Sha *ShaTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+	return _Sha.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Sha *ShaTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+	return _Sha.Contract.contract.Transact(opts, method, params...)
+}
+
+// Hash is a paid mutator transaction binding the contract method 0x09bd5a60.
+//
+// Solidity: function hash() returns()
+func (_Sha *ShaTransactor) Hash(opts *bind.TransactOpts) (*types.Transaction, error) {
+	return _Sha.contract.Transact(opts, "hash")
+}
+
+// Hash is a paid mutator transaction binding the contract method 0x09bd5a60.
+//
+// Solidity: function hash() returns()
+func (_Sha *ShaSession) Hash() (*types.Transaction, error) {
+	return _Sha.Contract.Hash(&_Sha.TransactOpts)
+}
+
+// Hash is a paid mutator transaction binding the contract method 0x09bd5a60.
+//
+// Solidity: function hash() returns()
+func (_Sha *ShaTransactorSession) Hash() (*types.Transaction, error) {
+	return _Sha.Contract.Hash(&_Sha.TransactOpts)
+}
diff --git a/test/contracts/bin/triggerErrors/triggerErrors.go b/test/contracts/bin/triggerErrors/triggerErrors.go
index d3778b808b..4fede2d110 100644
--- a/test/contracts/bin/triggerErrors/triggerErrors.go
+++ b/test/contracts/bin/triggerErrors/triggerErrors.go
@@ -32,7 +32,7 @@ var (
 // TriggerErrorsMetaData contains all meta data concerning the TriggerErrors contract.
 var TriggerErrorsMetaData = &bind.MetaData{
 	ABI: "[{\"inputs\":[],\"name\":\"count\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"outOfCountersKeccaks\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"test\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"outOfCountersPoseidon\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"outOfCountersSteps\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"outOfGas\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
-	Bin: "0x60806040526000805534801561001457600080fd5b5061016c806100246000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806306661abd1461005c5780632621002a1461007757806331fe52e8146100835780638bd7b5381461008d578063cb4e8cd114610095575b600080fd5b61006560005481565b60405190815260200160405180910390f35b620f4240600020610065565b61008b61009d565b005b61008b6100c3565b61008b6100e9565b60005b60648110156100c0578060005580806100b89061010d565b9150506100a0565b50565b60005b620186a08110156100c0576104d2600052806100e18161010d565b9150506100c6565b60005b61c3508110156100c0578060005580806101059061010d565b9150506100ec565b600060001982141561012f57634e487b7160e01b600052601160045260246000fd5b506001019056fea264697066735822122097beacfaa873e4896937143dfea406cc278b929a28023f7e7020b6dea6e9fc7364736f6c634300080c0033",
+	Bin: "0x60806040526000805534801561001457600080fd5b5061016c806100246000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806306661abd1461005c5780632621002a1461007757806331fe52e8146100835780638bd7b5381461008d578063cb4e8cd114610095575b600080fd5b61006560005481565b60405190815260200160405180910390f35b620f4240600020610065565b61008b61009d565b005b61008b6100c3565b61008b6100e9565b60005b60648110156100c0578060005580806100b89061010d565b9150506100a0565b50565b60005b620186a08110156100c0576104d2600052806100e18161010d565b9150506100c6565b60005b61c3508110156100c0578060005580806101059061010d565b9150506100ec565b600060001982141561012f57634e487b7160e01b600052601160045260246000fd5b506001019056fea26469706673582212208f01c5dc055b1f376f5da5deb33e2c96ee776174bf48874c5ebba0f606de2ac564736f6c634300080c0033",
 }
 
 // TriggerErrorsABI is the input ABI used to generate the binding from.
diff --git a/test/e2e/debug_calltracer_test.go b/test/e2e/debug_calltracer_test.go
index f2a8d756fe..1c28e132c4 100644
--- a/test/e2e/debug_calltracer_test.go
+++ b/test/e2e/debug_calltracer_test.go
@@ -107,6 +107,7 @@ func TestDebugTraceTransactionCallTracer(t *testing.T) {
 		{name: "log0 all zeros", prepare: prepareLog0, createSignedTx: createLog0AllZeros},
 		{name: "log0 empty", prepare: prepareLog0, createSignedTx: createLog0Empty},
 		{name: "log0 short", prepare: prepareLog0, createSignedTx: createLog0Short},
+		{name: "sha256", prepare: prepareSha256, createSignedTx: createSha256},
 
 		// failed transactions
 		{name: "sc deployment reverted", createSignedTx: createScDeployRevertedSignedTx},
diff --git a/test/e2e/debug_shared.go b/test/e2e/debug_shared.go
index f0c78ed663..67fc4dbeb8 100644
--- a/test/e2e/debug_shared.go
+++ b/test/e2e/debug_shared.go
@@ -30,6 +30,7 @@ import (
 	"github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/Memory"
 	"github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/OpCallAux"
 	"github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/Revert2"
+	"github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/Sha"
 	"github.com/0xPolygonHermez/zkevm-node/test/operations"
 	"github.com/0xPolygonHermez/zkevm-node/test/testutils"
 	"github.com/ethereum/go-ethereum"
@@ -953,3 +954,29 @@ func createLog0Short(t *testing.T, ctx context.Context, auth *bind.TransactOpts,
 
 	return tx, nil
 }
+
+func prepareSha256(t *testing.T, ctx context.Context, auth *bind.TransactOpts, client *ethclient.Client) (map[string]interface{}, error) {
+	_, tx, sc, err := Sha.DeploySha(auth, client)
+	require.NoError(t, err)
+
+	err = operations.WaitTxToBeMined(ctx, client, tx, operations.DefaultTimeoutTxToBeMined)
+	require.NoError(t, err)
+
+	return map[string]interface{}{
+		"sc": sc,
+	}, nil
+}
+
+func createSha256(t *testing.T, ctx context.Context, auth *bind.TransactOpts, client *ethclient.Client, customData map[string]interface{}) (*ethTypes.Transaction, error) {
+	scInterface := customData["sc"]
+	sc := scInterface.(*Sha.Sha)
+
+	opts := *auth
+	opts.NoSend = true
+	opts.GasLimit = fixedTxGasLimit
+
+	tx, err := sc.Hash(&opts)
+	require.NoError(t, err)
+
+	return tx, nil
+}
diff --git a/test/e2e/debug_test.go b/test/e2e/debug_test.go
index 0e425b4f6e..7923e67446 100644
--- a/test/e2e/debug_test.go
+++ b/test/e2e/debug_test.go
@@ -321,6 +321,7 @@ func TestDebugTraceTransaction(t *testing.T) {
 		{name: "log0 all zeros", prepare: prepareLog0, createSignedTx: createLog0AllZeros},
 		{name: "log0 empty", prepare: prepareLog0, createSignedTx: createLog0Empty},
 		{name: "log0 short", prepare: prepareLog0, createSignedTx: createLog0Short},
+		{name: "sha256", prepare: prepareSha256, createSignedTx: createSha256},
 
 		// failed transactions
 		{name: "sc deployment reverted", createSignedTx: createScDeployRevertedSignedTx},
@@ -479,20 +480,27 @@ func TestDebugTraceTransaction(t *testing.T) {
 					referenceStructLogMap := referenceStructLogsMap[structLogIndex].(map[string]interface{})
 					resultStructLogMap := resultStructLogsMap[structLogIndex].(map[string]interface{})
 
-					require.Equal(t, referenceStructLogMap["pc"], resultStructLogMap["pc"], fmt.Sprintf("invalid struct log pc for network %s", networkName))
-					require.Equal(t, referenceStructLogMap["op"], resultStructLogMap["op"], fmt.Sprintf("invalid struct log op for network %s", networkName))
-					require.Equal(t, referenceStructLogMap["depth"], resultStructLogMap["depth"], fmt.Sprintf("invalid struct log depth for network %s", networkName))
+					referencePC := referenceStructLogMap["pc"]
+					referenceOP := referenceStructLogMap["op"]
 
-					pc := referenceStructLogMap["pc"]
-					op := referenceStructLogMap["op"]
+					require.Equal(t, referencePC, resultStructLogMap["pc"], fmt.Sprintf("invalid struct log pc for network %s", networkName))
+					require.Equal(t, referenceOP, resultStructLogMap["op"], fmt.Sprintf("invalid struct log op for network %s pc %v", networkName, referencePC))
+					require.Equal(t, referenceStructLogMap["depth"], resultStructLogMap["depth"], fmt.Sprintf("invalid struct log depth for network %s pc %v op %v", networkName, referencePC, referenceOP))
+
+					referenceReturnData, found := referenceStructLogMap["returnData"].([]interface{})
+					if found {
+						resultReturnData := resultStructLogMap["returnData"].([]interface{})
+
+						require.Equal(t, referenceReturnData, resultReturnData, fmt.Sprintf("return data doesn't match for pc %v op %v", referencePC, referenceOP))
+					}
 
 					referenceStack, found := referenceStructLogMap["stack"].([]interface{})
 					if found {
 						resultStack := resultStructLogMap["stack"].([]interface{})
 
-						require.Equal(t, len(referenceStack), len(resultStack), fmt.Sprintf("stack size doesn't match for pc %v op %v", pc, op))
+						require.Equal(t, len(referenceStack), len(resultStack), fmt.Sprintf("stack size doesn't match for pc %v op %v", referencePC, referenceOP))
 						for stackIndex := range referenceStack {
-							require.Equal(t, referenceStack[stackIndex], resultStack[stackIndex], fmt.Sprintf("stack index %v doesn't match for pc %v op %v", stackIndex, pc, op))
+							require.Equal(t, referenceStack[stackIndex], resultStack[stackIndex], fmt.Sprintf("stack index %v doesn't match for pc %v op %v", stackIndex, referencePC, referenceOP))
 						}
 					}
 
@@ -500,9 +508,9 @@ func TestDebugTraceTransaction(t *testing.T) {
 					if found {
 						resultMemory := resultStructLogMap["memory"].([]interface{})
 
-						require.Equal(t, len(referenceMemory), len(resultMemory), fmt.Sprintf("memory size doesn't match for pc %v op %v", pc, op))
+						require.Equal(t, len(referenceMemory), len(resultMemory), fmt.Sprintf("memory size doesn't match for pc %v op %v", referencePC, referenceOP))
 						for memoryIndex := range referenceMemory {
-							require.Equal(t, referenceMemory[memoryIndex], resultMemory[memoryIndex], fmt.Sprintf("memory index %v doesn't match for pc %v op %v", memoryIndex, pc, op))
+							require.Equal(t, referenceMemory[memoryIndex], resultMemory[memoryIndex], fmt.Sprintf("memory index %v doesn't match for pc %v op %v", memoryIndex, referencePC, referenceOP))
 						}
 					}
 
@@ -510,11 +518,11 @@ func TestDebugTraceTransaction(t *testing.T) {
 					if found {
 						resultStorage := resultStructLogMap["storage"].(map[string]interface{})
 
-						require.Equal(t, len(referenceStorage), len(resultStorage), fmt.Sprintf("storage size doesn't match for pc %v op %v", pc, op))
+						require.Equal(t, len(referenceStorage), len(resultStorage), fmt.Sprintf("storage size doesn't match for pc %v op %v", referencePC, referenceOP))
 						for storageKey, referenceStorageValue := range referenceStorage {
 							resultStorageValue, found := resultStorage[storageKey]
 							require.True(t, found, "storage address not found")
-							require.Equal(t, referenceStorageValue, resultStorageValue, fmt.Sprintf("storage value doesn't match for address %v for pc %v op %v", storageKey, pc, op))
+							require.Equal(t, referenceStorageValue, resultStorageValue, fmt.Sprintf("storage value doesn't match for address %v for pc %v op %v", storageKey, referencePC, referenceOP))
 						}
 					}
 				}

From d20b6b2b981abaec24cc59ac6fd41e661d748435 Mon Sep 17 00:00:00 2001
From: agnusmor <100322135+agnusmor@users.noreply.github.com>
Date: Tue, 30 Jul 2024 10:00:57 +0200
Subject: [PATCH 08/14] Refactor datastream logs (#3743)

* refactor ds logs

* update ds library to v0.2.3
---
 go.mod | 2 +-
 go.sum | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/go.mod b/go.mod
index 9544b9b958..d85ab3ca10 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/0xPolygonHermez/zkevm-node
 go 1.21
 
 require (
-	github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-RC5
+	github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3
 	github.com/didip/tollbooth/v6 v6.1.2
 	github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127
 	github.com/ethereum/go-ethereum v1.13.11
diff --git a/go.sum b/go.sum
index 4aacd939e6..317b2623cd 100644
--- a/go.sum
+++ b/go.sum
@@ -39,8 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
 dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
 dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-RC5 h1:ofcfKofJCn3AyOYnEeQ6YbKm0slEKRXk+TbeuvIUymw=
-github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3-RC5/go.mod h1:bv7DjATsczN2WvFt26jv34TWv6rfvYM1SqegrgrFwfI=
+github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3 h1:zJ06KCGLMDOap4slop/QmiMUO+VPsKSS3+944SY06ww=
+github.com/0xPolygonHermez/zkevm-data-streamer v0.2.3/go.mod h1:bv7DjATsczN2WvFt26jv34TWv6rfvYM1SqegrgrFwfI=
 github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=

From adf526c97698a0e12bb0de977b51f235f4fb1a51 Mon Sep 17 00:00:00 2001
From: agnusmor <100322135+agnusmor@users.noreply.github.com>
Date: Fri, 2 Aug 2024 14:17:34 +0200
Subject: [PATCH 09/14] Fix tx OOC (node level) when first empty L2 block in
 batch (#3744)

* Fix tx OOC (node level) for first empty L2 block in batch

* change log level for ooc (node level) when adding tx to the worker

* fix check OOC (node level) when preexecuting the tx in RPC

* Fix linter and test
---
 pool/config_test.go      | 23 +++++++++++-------
 pool/pool.go             | 17 ++++++++------
 sequencer/finalizer.go   | 27 +++++++++++++++++----
 sequencer/interfaces.go  |  2 +-
 sequencer/l2block.go     |  2 +-
 sequencer/mock_worker.go | 33 ++++++++++++++++----------
 sequencer/worker.go      | 35 +++++++++++++++++++--------
 sequencer/worker_test.go |  2 +-
 state/config.go          | 51 +++++++++++++++++++++++++++++++---------
 9 files changed, 135 insertions(+), 57 deletions(-)

diff --git a/pool/config_test.go b/pool/config_test.go
index 96b2cd3831..52ae398329 100644
--- a/pool/config_test.go
+++ b/pool/config_test.go
@@ -1,9 +1,11 @@
 package pool
 
 import (
+	"fmt"
 	"testing"
 
 	"github.com/0xPolygonHermez/zkevm-node/state"
+	"github.com/stretchr/testify/assert"
 )
 
 func TestIsWithinConstraints(t *testing.T) {
@@ -20,9 +22,9 @@ func TestIsWithinConstraints(t *testing.T) {
 	}
 
 	testCases := []struct {
-		desc     string
-		counters state.ZKCounters
-		expected bool
+		desc        string
+		counters    state.ZKCounters
+		errExpected error
 	}{
 		{
 			desc: "All constraints within limits",
@@ -37,7 +39,7 @@ func TestIsWithinConstraints(t *testing.T) {
 				Steps:            2000,
 				Sha256Hashes_V2:  4000,
 			},
-			expected: true,
+			errExpected: nil,
 		},
 		{
 			desc: "All constraints exceed limits",
@@ -52,14 +54,17 @@ func TestIsWithinConstraints(t *testing.T) {
 				Steps:            5000,
 				Sha256Hashes_V2:  6000,
 			},
-			expected: false,
+			errExpected: fmt.Errorf("out of counters at node level (GasUsed, KeccakHashes, PoseidonHashes, PoseidonPaddings, MemAligns, Arithmetics, Binaries, Steps, Sha256Hashes)"),
 		},
 	}
 
-	for _, tC := range testCases {
-		t.Run(tC.desc, func(t *testing.T) {
-			if got := cfg.IsWithinConstraints(tC.counters); got != tC.expected {
-				t.Errorf("Expected %v, got %v", tC.expected, got)
+	for _, tc := range testCases {
+		t.Run(tc.desc, func(t *testing.T) {
+			err := cfg.CheckNodeLevelOOC(tc.counters)
+			if tc.errExpected != nil {
+				assert.EqualError(t, err, tc.errExpected.Error())
+			} else {
+				assert.NoError(t, err)
 			}
 		})
 	}
diff --git a/pool/pool.go b/pool/pool.go
index 62f7611ea4..1e5fc50736 100644
--- a/pool/pool.go
+++ b/pool/pool.go
@@ -196,7 +196,16 @@ func (p *Pool) StoreTx(ctx context.Context, tx types.Transaction, ip string, isW
 		return err
 	}
 
+	var oocError error
 	if preExecutionResponse.OOCError != nil {
+		oocError = preExecutionResponse.OOCError
+	} else {
+		if err = p.batchConstraintsCfg.CheckNodeLevelOOC(preExecutionResponse.reservedZKCounters); err != nil {
+			oocError = err
+		}
+	}
+
+	if oocError != nil {
 		event := &event.Event{
 			ReceivedAt:  time.Now(),
 			IPAddress:   ip,
@@ -212,7 +221,7 @@ func (p *Pool) StoreTx(ctx context.Context, tx types.Transaction, ip string, isW
 			log.Errorf("error adding event: %v", err)
 		}
 		// Do not add tx to the pool
-		return fmt.Errorf("failed to add tx to the pool: %w", preExecutionResponse.OOCError)
+		return fmt.Errorf("failed to add tx to the pool: %w", oocError)
 	} else if preExecutionResponse.OOGError != nil {
 		event := &event.Event{
 			ReceivedAt:  time.Now(),
@@ -332,12 +341,6 @@ func (p *Pool) preExecuteTx(ctx context.Context, tx types.Transaction) (preExecu
 			if errors.Is(errorToCheck, runtime.ErrOutOfGas) {
 				response.OOGError = err
 			}
-		} else {
-			if !p.batchConstraintsCfg.IsWithinConstraints(processBatchResponse.UsedZkCounters) {
-				err := fmt.Errorf("OutOfCounters Error (Node level) for tx: %s", tx.Hash().String())
-				response.OOCError = err
-				log.Error(err.Error())
-			}
 		}
 
 		response.usedZKCounters = processBatchResponse.UsedZkCounters
diff --git a/sequencer/finalizer.go b/sequencer/finalizer.go
index 4522a2e50a..f3124e9cc6 100644
--- a/sequencer/finalizer.go
+++ b/sequencer/finalizer.go
@@ -404,9 +404,26 @@ func (f *finalizer) finalizeBatches(ctx context.Context) {
 			f.finalizeWIPL2Block(ctx)
 		}
 
-		tx, err := f.workerIntf.GetBestFittingTx(f.wipBatch.imRemainingResources, f.wipBatch.imHighReservedZKCounters)
+		tx, oocTxs, err := f.workerIntf.GetBestFittingTx(f.wipBatch.imRemainingResources, f.wipBatch.imHighReservedZKCounters, (f.wipBatch.countOfL2Blocks == 0 && f.wipL2Block.isEmpty()))
 
-		// If we have txs pending to process but none of them fits into the wip batch, we close the wip batch and open a new one
+		// Set as invalid txs in the worker pool that will never fit into an empty batch
+		for _, oocTx := range oocTxs {
+			log.Infof("tx %s doesn't fits in empty batch %d (node OOC), setting tx as invalid in the pool", oocTx.HashStr, f.wipL2Block.trackingNum, f.wipBatch.batchNumber)
+
+			f.LogEvent(ctx, event.Level_Info, event.EventID_NodeOOC,
+				fmt.Sprintf("tx %s doesn't fits in empty batch %d (node OOC), from: %s, IP: %s", oocTx.HashStr, f.wipBatch.batchNumber, oocTx.FromStr, oocTx.IP), nil)
+
+			// Delete the transaction from the worker
+			f.workerIntf.DeleteTx(oocTx.Hash, oocTx.From)
+
+			errMsg := "node OOC"
+			err = f.poolIntf.UpdateTxStatus(ctx, oocTx.Hash, pool.TxStatusInvalid, false, &errMsg)
+			if err != nil {
+				log.Errorf("failed to update status to invalid in the pool for tx %s, error: %v", oocTx.Hash.String(), err)
+			}
+		}
+
+		// We have txs pending to process but none of them fits into the wip batch we close the wip batch and open a new one
 		if err == ErrNoFittingTransaction {
 			f.finalizeWIPBatch(ctx, state.NoTxFitsClosingReason)
 			continue
@@ -690,11 +707,11 @@ func (f *finalizer) handleProcessTransactionResponse(ctx context.Context, tx *Tx
 	} else {
 		log.Infof("current tx %s needed resources exceeds the remaining batch resources, overflow resource: %s, updating metadata for tx in worker and continuing. counters: {batch: %s, used: %s, reserved: %s, needed: %s, high: %s}",
 			tx.HashStr, overflowResource, f.logZKCounters(f.wipBatch.imRemainingResources.ZKCounters), f.logZKCounters(result.UsedZkCounters), f.logZKCounters(result.ReservedZkCounters), f.logZKCounters(neededZKCounters), f.logZKCounters(f.wipBatch.imHighReservedZKCounters))
-		if !f.batchConstraints.IsWithinConstraints(result.ReservedZkCounters) {
-			log.Infof("current tx %s reserved resources exceeds the max limit for batch resources (node OOC), setting tx as invalid in the pool", tx.HashStr)
+		if err := f.batchConstraints.CheckNodeLevelOOC(result.ReservedZkCounters); err != nil {
+			log.Infof("current tx %s reserved resources exceeds the max limit for batch resources (node OOC), setting tx as invalid in the pool, error: %v", tx.HashStr, err)
 
 			f.LogEvent(ctx, event.Level_Info, event.EventID_NodeOOC,
-				fmt.Sprintf("tx %s exceeds node max limit batch resources (node OOC), from: %s, IP: %s", tx.HashStr, tx.FromStr, tx.IP), nil)
+				fmt.Sprintf("tx %s exceeds node max limit batch resources (node OOC), from: %s, IP: %s, error: %v", tx.HashStr, tx.FromStr, tx.IP, err), nil)
 
 			// Delete the transaction from the txSorted list
 			f.workerIntf.DeleteTx(tx.Hash, tx.From)
diff --git a/sequencer/interfaces.go b/sequencer/interfaces.go
index 72beb71578..173635f90b 100644
--- a/sequencer/interfaces.go
+++ b/sequencer/interfaces.go
@@ -84,7 +84,7 @@ type stateInterface interface {
 }
 
 type workerInterface interface {
-	GetBestFittingTx(remainingResources state.BatchResources, highReservedCounters state.ZKCounters) (*TxTracker, error)
+	GetBestFittingTx(remainingResources state.BatchResources, highReservedCounters state.ZKCounters, fistL2Block bool) (*TxTracker, []*TxTracker, error)
 	UpdateAfterSingleSuccessfulTxExecution(from common.Address, touchedAddresses map[common.Address]*state.InfoReadWrite) []*TxTracker
 	UpdateTxZKCounters(txHash common.Hash, from common.Address, usedZKCounters state.ZKCounters, reservedZKCounters state.ZKCounters)
 	AddTxTracker(ctx context.Context, txTracker *TxTracker) (replacedTx *TxTracker, dropReason error)
diff --git a/sequencer/l2block.go b/sequencer/l2block.go
index 511d233988..a0da9fd0e3 100644
--- a/sequencer/l2block.go
+++ b/sequencer/l2block.go
@@ -657,7 +657,7 @@ func (f *finalizer) openNewWIPL2Block(ctx context.Context, prevTimestamp uint64,
 
 		f.wipBatch.imHighReservedZKCounters = newHighZKCounters
 	} else {
-		log.Infof("new wip L2 block [%d] reserved resources exceeds the remaining batch resources, overflow resource: %s, closing WIP batch and creating new one. counters: {batch: %s, used: %s, reserved: %s, needed: %s, high: %s}",
+		log.Infof("new wip L2 block [%d] needed resources exceeds the remaining batch resources, overflow resource: %s, closing WIP batch and creating new one. counters: {batch: %s, used: %s, reserved: %s, needed: %s, high: %s}",
 			f.wipL2Block.trackingNum, overflowResource,
 			f.logZKCounters(f.wipBatch.imRemainingResources.ZKCounters), f.logZKCounters(f.wipL2Block.usedZKCountersOnNew), f.logZKCounters(f.wipL2Block.reservedZKCountersOnNew), f.logZKCounters(neededZKCounters), f.logZKCounters(f.wipBatch.imHighReservedZKCounters))
 	}
diff --git a/sequencer/mock_worker.go b/sequencer/mock_worker.go
index 3ff546f724..a627bf5533 100644
--- a/sequencer/mock_worker.go
+++ b/sequencer/mock_worker.go
@@ -70,34 +70,43 @@ func (_m *WorkerMock) DeleteTxPendingToStore(txHash common.Hash, addr common.Add
 	_m.Called(txHash, addr)
 }
 
-// GetBestFittingTx provides a mock function with given fields: remainingResources, highReservedCounters
-func (_m *WorkerMock) GetBestFittingTx(remainingResources state.BatchResources, highReservedCounters state.ZKCounters) (*TxTracker, error) {
-	ret := _m.Called(remainingResources, highReservedCounters)
+// GetBestFittingTx provides a mock function with given fields: remainingResources, highReservedCounters, fistL2Block
+func (_m *WorkerMock) GetBestFittingTx(remainingResources state.BatchResources, highReservedCounters state.ZKCounters, fistL2Block bool) (*TxTracker, []*TxTracker, error) {
+	ret := _m.Called(remainingResources, highReservedCounters, fistL2Block)
 
 	if len(ret) == 0 {
 		panic("no return value specified for GetBestFittingTx")
 	}
 
 	var r0 *TxTracker
-	var r1 error
-	if rf, ok := ret.Get(0).(func(state.BatchResources, state.ZKCounters) (*TxTracker, error)); ok {
-		return rf(remainingResources, highReservedCounters)
+	var r1 []*TxTracker
+	var r2 error
+	if rf, ok := ret.Get(0).(func(state.BatchResources, state.ZKCounters, bool) (*TxTracker, []*TxTracker, error)); ok {
+		return rf(remainingResources, highReservedCounters, fistL2Block)
 	}
-	if rf, ok := ret.Get(0).(func(state.BatchResources, state.ZKCounters) *TxTracker); ok {
-		r0 = rf(remainingResources, highReservedCounters)
+	if rf, ok := ret.Get(0).(func(state.BatchResources, state.ZKCounters, bool) *TxTracker); ok {
+		r0 = rf(remainingResources, highReservedCounters, fistL2Block)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*TxTracker)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(state.BatchResources, state.ZKCounters) error); ok {
-		r1 = rf(remainingResources, highReservedCounters)
+	if rf, ok := ret.Get(1).(func(state.BatchResources, state.ZKCounters, bool) []*TxTracker); ok {
+		r1 = rf(remainingResources, highReservedCounters, fistL2Block)
 	} else {
-		r1 = ret.Error(1)
+		if ret.Get(1) != nil {
+			r1 = ret.Get(1).([]*TxTracker)
+		}
 	}
 
-	return r0, r1
+	if rf, ok := ret.Get(2).(func(state.BatchResources, state.ZKCounters, bool) error); ok {
+		r2 = rf(remainingResources, highReservedCounters, fistL2Block)
+	} else {
+		r2 = ret.Error(2)
+	}
+
+	return r0, r1, r2
 }
 
 // MoveTxPendingToStore provides a mock function with given fields: txHash, addr
diff --git a/sequencer/worker.go b/sequencer/worker.go
index c6be5ed5ab..94a5969cd1 100644
--- a/sequencer/worker.go
+++ b/sequencer/worker.go
@@ -64,8 +64,8 @@ func (w *Worker) addTxTracker(ctx context.Context, tx *TxTracker, mutex *sync.Mu
 	}
 
 	// Make sure the transaction's reserved ZKCounters are within the constraints.
-	if !w.batchConstraints.IsWithinConstraints(tx.ReservedZKCounters) {
-		log.Errorf("outOfCounters error (node level) for tx %s", tx.Hash.String())
+	if err := w.batchConstraints.CheckNodeLevelOOC(tx.ReservedZKCounters); err != nil {
+		log.Infof("out of counters (node level) when adding tx %s from address %s, error: %v", tx.Hash, tx.From, err)
 		mutexUnlock(mutex)
 		return nil, pool.ErrOutOfCounters
 	}
@@ -405,7 +405,7 @@ func (w *Worker) DeleteTxPendingToStore(txHash common.Hash, addr common.Address)
 }
 
 // GetBestFittingTx gets the most efficient tx that fits in the available batch resources
-func (w *Worker) GetBestFittingTx(remainingResources state.BatchResources, highReservedCounters state.ZKCounters) (*TxTracker, error) {
+func (w *Worker) GetBestFittingTx(remainingResources state.BatchResources, highReservedCounters state.ZKCounters, isFistL2BlockAndEmpty bool) (*TxTracker, []*TxTracker, error) {
 	w.workerMutex.Lock()
 	defer w.workerMutex.Unlock()
 
@@ -417,7 +417,7 @@ func (w *Worker) GetBestFittingTx(remainingResources state.BatchResources, highR
 		w.reorgedTxs = w.reorgedTxs[1:]
 		if addrQueue, found := w.pool[reorgedTx.FromStr]; found {
 			if addrQueue.readyTx != nil && addrQueue.readyTx.Hash == reorgedTx.Hash {
-				return reorgedTx, nil
+				return reorgedTx, nil, nil
 			} else {
 				log.Warnf("reorged tx %s is not the ready tx for addrQueue %s, this shouldn't happen", reorgedTx.Hash, reorgedTx.From)
 			}
@@ -427,12 +427,14 @@ func (w *Worker) GetBestFittingTx(remainingResources state.BatchResources, highR
 	}
 
 	if w.txSortedList.len() == 0 {
-		return nil, ErrTransactionsListEmpty
+		return nil, nil, ErrTransactionsListEmpty
 	}
 
 	var (
-		tx         *TxTracker
-		foundMutex sync.RWMutex
+		tx          *TxTracker
+		foundMutex  sync.RWMutex
+		oocTxs      []*TxTracker
+		oocTxsMutex sync.Mutex
 	)
 
 	nGoRoutines := runtime.NumCPU()
@@ -457,7 +459,14 @@ func (w *Worker) GetBestFittingTx(remainingResources state.BatchResources, highR
 				needed, _ := getNeededZKCounters(highReservedCounters, txCandidate.UsedZKCounters, txCandidate.ReservedZKCounters)
 				fits, _ := bresources.Fits(state.BatchResources{ZKCounters: needed, Bytes: txCandidate.Bytes})
 				if !fits {
-					// We don't add this Tx
+					// If we are looking for a tx for the first empty L2 block in the batch and this tx doesn't fits in the batch, then this tx will never fit in any batch.
+					// We add the tx to the oocTxs slice. That slice will be returned to set these txs as invalid (and delete them from the worker) from the finalizer code
+					if isFistL2BlockAndEmpty {
+						oocTxsMutex.Lock()
+						oocTxs = append(oocTxs, txCandidate)
+						oocTxsMutex.Unlock()
+					}
+					// We continue looking for a tx that fits in the batch
 					continue
 				}
 
@@ -477,9 +486,15 @@ func (w *Worker) GetBestFittingTx(remainingResources state.BatchResources, highR
 	if foundAt != -1 {
 		log.Debugf("best fitting tx %s found at index %d with gasPrice %d", tx.HashStr, foundAt, tx.GasPrice)
 		w.wipTx = tx
-		return tx, nil
+		return tx, oocTxs, nil
 	} else {
-		return nil, ErrNoFittingTransaction
+		// If the length of the oocTxs slice is equal to the length of the txSortedList this means that all the txs are ooc,
+		// therefore we need to return an error indicating that the list is empty
+		if w.txSortedList.len() == len(oocTxs) {
+			return nil, oocTxs, ErrTransactionsListEmpty
+		} else {
+			return nil, oocTxs, ErrNoFittingTransaction
+		}
 	}
 }
 
diff --git a/sequencer/worker_test.go b/sequencer/worker_test.go
index 0e2375ad37..3f489cc0be 100644
--- a/sequencer/worker_test.go
+++ b/sequencer/worker_test.go
@@ -258,7 +258,7 @@ func TestWorkerGetBestTx(t *testing.T) {
 	ct := 0
 
 	for {
-		tx, _ := worker.GetBestFittingTx(rc, state.ZKCounters{})
+		tx, _, _ := worker.GetBestFittingTx(rc, state.ZKCounters{}, true)
 		if tx != nil {
 			if ct >= len(expectedGetBestTx) {
 				t.Fatalf("Error getting more best tx than expected. Expected=%d, Actual=%d", len(expectedGetBestTx), ct+1)
diff --git a/state/config.go b/state/config.go
index 61e74e63d6..35975d1977 100644
--- a/state/config.go
+++ b/state/config.go
@@ -1,6 +1,8 @@
 package state
 
 import (
+	"fmt"
+
 	"github.com/0xPolygonHermez/zkevm-node/config/types"
 	"github.com/0xPolygonHermez/zkevm-node/db"
 )
@@ -71,15 +73,42 @@ type BatchConstraintsCfg struct {
 	MaxSHA256Hashes      uint32 `mapstructure:"MaxSHA256Hashes"`
 }
 
-// IsWithinConstraints checks if the counters are within the batch constraints
-func (c BatchConstraintsCfg) IsWithinConstraints(counters ZKCounters) bool {
-	return counters.GasUsed <= c.MaxCumulativeGasUsed &&
-		counters.KeccakHashes <= c.MaxKeccakHashes &&
-		counters.PoseidonHashes <= c.MaxPoseidonHashes &&
-		counters.PoseidonPaddings <= c.MaxPoseidonPaddings &&
-		counters.MemAligns <= c.MaxMemAligns &&
-		counters.Arithmetics <= c.MaxArithmetics &&
-		counters.Binaries <= c.MaxBinaries &&
-		counters.Steps <= c.MaxSteps &&
-		counters.Sha256Hashes_V2 <= c.MaxSHA256Hashes
+// CheckNodeLevelOOC checks if the counters are within the batch constraints
+func (c BatchConstraintsCfg) CheckNodeLevelOOC(counters ZKCounters) error {
+	oocList := ""
+
+	if counters.GasUsed > c.MaxCumulativeGasUsed {
+		oocList += "GasUsed, "
+	}
+	if counters.KeccakHashes > c.MaxKeccakHashes {
+		oocList += "KeccakHashes, "
+	}
+	if counters.PoseidonHashes > c.MaxPoseidonHashes {
+		oocList += "PoseidonHashes, "
+	}
+	if counters.PoseidonPaddings > c.MaxPoseidonPaddings {
+		oocList += "PoseidonPaddings, "
+	}
+	if counters.MemAligns > c.MaxMemAligns {
+		oocList += "MemAligns, "
+	}
+	if counters.Arithmetics > c.MaxArithmetics {
+		oocList += "Arithmetics, "
+	}
+	if counters.Binaries > c.MaxBinaries {
+		oocList += "Binaries, "
+	}
+	if counters.Steps > c.MaxSteps {
+		oocList += "Steps, "
+	}
+	if counters.Sha256Hashes_V2 > c.MaxSHA256Hashes {
+		oocList += "Sha256Hashes, "
+	}
+
+	if oocList != "" {
+		oocList = oocList[:len(oocList)-2] // Remove last comma and blank space
+		return fmt.Errorf("out of counters at node level (%s)", oocList)
+	}
+
+	return nil
 }

From b9e0f644aefbacfbf7c5cff6959701c6fd150c28 Mon Sep 17 00:00:00 2001
From: agnusmor <100322135+agnusmor@users.noreply.github.com>
Date: Fri, 2 Aug 2024 22:03:23 +0200
Subject: [PATCH 10/14] Fix release github action (#3745) (#3747)

* fix releaser

* goreleaser yaml update version 2

* fix goreleaser version

* remove testnet.zip from releaser
---
 .github/workflows/release.yml | 16 +++-------------
 .goreleaser.yaml              |  2 ++
 2 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f72164cc09..88f939c3d9 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -14,7 +14,7 @@ jobs:
           fetch-depth: 0
 
       - name: Set up Go
-        uses: actions/setup-go@v3
+        uses: actions/setup-go@v5
         with:
           go-version: 1.21
 
@@ -22,9 +22,9 @@ jobs:
         run: go install github.com/gobuffalo/packr/v2/packr2@v2.8.3
 
       - name: Run GoReleaser
-        uses: goreleaser/goreleaser-action@v4
+        uses: goreleaser/goreleaser-action@v6
         with:
-          version: latest
+          version: '~> v2'
           args: release --clean
         env:
           GITHUB_TOKEN: ${{ secrets.TOKEN_RELEASE }}
@@ -45,16 +45,6 @@ jobs:
           mv cardona/config/environments/cardona/example.env cardona
           sed -i -e "s/image: zkevm-node/image: hermeznetwork\/zkevm-node:$GIT_TAG_NAME/g" cardona/docker-compose.yml
           zip -r cardona.zip cardona
-          # TESTNET
-          mkdir -p testnet/config/environments/testnet
-          mkdir -p testnet/db/scripts
-          cp config/environments/testnet/* testnet/config/environments/testnet
-          cp docker-compose.yml testnet
-          sed -i 's/\/config\/environments\/${ZKEVM_NETWORK}/\/config\/environments\/testnet/g' testnet/docker-compose.yml
-          cp db/scripts/init_prover_db.sql testnet/db/scripts
-          mv testnet/config/environments/testnet/example.env testnet
-          sed -i -e "s/image: zkevm-node/image: hermeznetwork\/zkevm-node:$GIT_TAG_NAME/g" testnet/docker-compose.yml
-          zip -r testnet.zip testnet
           # MAINNET
           mkdir -p mainnet/config/environments/mainnet
           mkdir -p mainnet/db/scripts
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
index 09519520d1..c75746b82e 100644
--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -1,4 +1,6 @@
 # .goreleaser.yaml
+version: 2
+
 builds:
 - main: ./cmd/
   goos:

From 520c9e3a388226395a1eddb1e6638900dbb46192 Mon Sep 17 00:00:00 2001
From: agnusmor <100322135+agnusmor@users.noreply.github.com>
Date: Mon, 5 Aug 2024 15:42:54 +0200
Subject: [PATCH 11/14] fix invalid "updateGER" entry when updating datastream
 file on startup (#3748)

---
 state/datastream.go | 42 ++++++++++++++++++++++--------------------
 1 file changed, 22 insertions(+), 20 deletions(-)

diff --git a/state/datastream.go b/state/datastream.go
index a9544d4e69..c3aa6c814f 100644
--- a/state/datastream.go
+++ b/state/datastream.go
@@ -436,29 +436,31 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 			}
 
 			if len(batch.L2Blocks) == 0 {
-				// Empty batch
-				// Check if there is a GER update
-				if batch.GlobalExitRoot != currentGER && batch.GlobalExitRoot != (common.Hash{}) {
-					updateGER := &datastream.UpdateGER{
-						BatchNumber:    batch.BatchNumber,
-						Timestamp:      uint64(batch.Timestamp.Unix()),
-						GlobalExitRoot: batch.GlobalExitRoot.Bytes(),
-						Coinbase:       batch.Coinbase.Bytes(),
-						ForkId:         batch.ForkID,
-						ChainId:        chainID,
-						StateRoot:      batch.StateRoot.Bytes(),
-					}
+				if !batch.WIP && batch.ForkID < FORKID_ETROG {
+					// Empty batch
+					// Check if there is a GER update
+					if batch.GlobalExitRoot != currentGER && batch.GlobalExitRoot != (common.Hash{}) {
+						updateGER := &datastream.UpdateGER{
+							BatchNumber:    batch.BatchNumber,
+							Timestamp:      uint64(batch.Timestamp.Unix()),
+							GlobalExitRoot: batch.GlobalExitRoot.Bytes(),
+							Coinbase:       batch.Coinbase.Bytes(),
+							ForkId:         batch.ForkID,
+							ChainId:        chainID,
+							StateRoot:      batch.StateRoot.Bytes(),
+						}
 
-					marshalledUpdateGER, err := proto.Marshal(updateGER)
-					if err != nil {
-						return err
-					}
+						marshalledUpdateGER, err := proto.Marshal(updateGER)
+						if err != nil {
+							return err
+						}
 
-					_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_UPDATE_GER), marshalledUpdateGER)
-					if err != nil {
-						return err
+						_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_UPDATE_GER), marshalledUpdateGER)
+						if err != nil {
+							return err
+						}
+						currentGER = batch.GlobalExitRoot
 					}
-					currentGER = batch.GlobalExitRoot
 				}
 			} else {
 				for blockIndex, l2Block := range batch.L2Blocks {

From 8735f062b95e2731e82770e55a780e7a99983fef Mon Sep 17 00:00:00 2001
From: agnusmor <100322135+agnusmor@users.noreply.github.com>
Date: Mon, 5 Aug 2024 22:34:52 +0200
Subject: [PATCH 12/14] fix tx order in zkevm_getBatchByNumber endpoint (#3749)

---
 state/pgstatestorage/transaction.go | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/state/pgstatestorage/transaction.go b/state/pgstatestorage/transaction.go
index f25554d44e..109d266726 100644
--- a/state/pgstatestorage/transaction.go
+++ b/state/pgstatestorage/transaction.go
@@ -124,7 +124,13 @@ func (p *PostgresStorage) GetTxsOlderThanNL1Blocks(ctx context.Context, nL1Block
 // GetEncodedTransactionsByBatchNumber returns the encoded field of all
 // transactions in the given batch.
 func (p *PostgresStorage) GetEncodedTransactionsByBatchNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (encodedTxs []string, effectivePercentages []uint8, err error) {
-	const getEncodedTransactionsByBatchNumberSQL = "SELECT encoded, COALESCE(effective_percentage, 255) FROM state.transaction t INNER JOIN state.l2block b ON t.l2_block_num = b.block_num WHERE b.batch_num = $1 ORDER BY l2_block_num ASC"
+	const getEncodedTransactionsByBatchNumberSQL = `
+		SELECT encoded, COALESCE(effective_percentage, 255) FROM state.transaction t 
+		INNER JOIN state.l2block b ON t.l2_block_num = b.block_num 
+		INNER JOIN state.receipt r ON t.hash = r.tx_hash
+		WHERE b.batch_num = $1 
+		ORDER BY l2_block_num, r.tx_index ASC
+		`
 
 	e := p.getExecQuerier(dbTx)
 	rows, err := e.Query(ctx, getEncodedTransactionsByBatchNumberSQL, batchNumber)

From 45a74134e5dcd6c630d8a33bcc4a0d524551a38c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Toni=20Ram=C3=ADrez?=
 <58293609+ToniRamirezM@users.noreply.github.com>
Date: Tue, 6 Aug 2024 10:42:46 +0200
Subject: [PATCH 13/14] add l2blockend to DS (#3751)

* add l2blockend to DS

* move l2blockend creation
---
 .../src/proto/datastream/v1/datastream.proto  |   6 +
 sequencer/sequencer.go                        |  24 +-
 state/datastream.go                           |  75 ++++-
 state/datastream/datastream.pb.go             | 308 +++++++++++-------
 test/config/debug.node.config.toml            |   2 +-
 test/config/test.node.config.toml             |   2 +-
 tools/datastreamer/config/default.go          |   2 +-
 tools/datastreamer/config/tool.config.toml    |   2 +-
 tools/datastreamer/main.go                    |  35 +-
 9 files changed, 329 insertions(+), 127 deletions(-)

diff --git a/proto/src/proto/datastream/v1/datastream.proto b/proto/src/proto/datastream/v1/datastream.proto
index 9cdd0266c1..f514a03db4 100644
--- a/proto/src/proto/datastream/v1/datastream.proto
+++ b/proto/src/proto/datastream/v1/datastream.proto
@@ -36,6 +36,10 @@ message L2Block {
     Debug debug = 14;
 }
 
+message L2BlockEnd {
+  uint64 number = 1;
+}
+
 message Transaction {
     uint64 l2block_number = 1;
     uint64 index = 2;
@@ -79,6 +83,7 @@ enum EntryType {
     ENTRY_TYPE_TRANSACTION = 3;
     ENTRY_TYPE_BATCH_END = 4;
     ENTRY_TYPE_UPDATE_GER = 5;
+    ENTRY_TYPE_L2_BLOCK_END = 6;
 }
 
 enum BatchType {
@@ -86,4 +91,5 @@ enum BatchType {
     BATCH_TYPE_REGULAR = 1;
     BATCH_TYPE_FORCED = 2;
     BATCH_TYPE_INJECTED = 3;
+    BATCH_TYPE_INVALID = 4;
 }
diff --git a/sequencer/sequencer.go b/sequencer/sequencer.go
index eaeab94f33..dbee34221e 100644
--- a/sequencer/sequencer.go
+++ b/sequencer/sequencer.go
@@ -86,7 +86,7 @@ func (s *Sequencer) Start(ctx context.Context) {
 	}
 
 	if s.streamServer != nil {
-		go s.sendDataToStreamer(s.cfg.StreamServer.ChainID)
+		go s.sendDataToStreamer(s.cfg.StreamServer.ChainID, s.cfg.StreamServer.Version)
 	}
 
 	s.workerReadyTxsCond = newTimeoutCond(&sync.Mutex{})
@@ -129,7 +129,7 @@ func (s *Sequencer) checkStateInconsistency(ctx context.Context) {
 }
 
 func (s *Sequencer) updateDataStreamerFile(ctx context.Context, chainID uint64) {
-	err := state.GenerateDataStreamFile(ctx, s.streamServer, s.stateIntf, true, nil, chainID, s.cfg.StreamServer.UpgradeEtrogBatchNumber)
+	err := state.GenerateDataStreamFile(ctx, s.streamServer, s.stateIntf, true, nil, chainID, s.cfg.StreamServer.UpgradeEtrogBatchNumber, s.cfg.StreamServer.Version)
 	if err != nil {
 		log.Fatalf("failed to generate data streamer file, error: %v", err)
 	}
@@ -241,7 +241,7 @@ func (s *Sequencer) addTxToWorker(ctx context.Context, tx pool.Transaction) erro
 }
 
 // sendDataToStreamer sends data to the data stream server
-func (s *Sequencer) sendDataToStreamer(chainID uint64) {
+func (s *Sequencer) sendDataToStreamer(chainID uint64, version uint8) {
 	var err error
 	for {
 		// Read error from previous iteration
@@ -369,6 +369,24 @@ func (s *Sequencer) sendDataToStreamer(chainID uint64) {
 					}
 				}
 
+				if version >= state.DSVersion4 {
+					streamL2BlockEnd := &datastream.L2BlockEnd{
+						Number: l2Block.L2BlockNumber,
+					}
+
+					marshalledL2BlockEnd, err := proto.Marshal(streamL2BlockEnd)
+					if err != nil {
+						log.Errorf("failed to marshal l2block %d, error: %v", l2Block.L2BlockNumber, err)
+						continue
+					}
+
+					_, err = s.streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK_END), marshalledL2BlockEnd)
+					if err != nil {
+						log.Errorf("failed to add stream entry for l2blockEnd %d, error: %v", l2Block.L2BlockNumber, err)
+						continue
+					}
+				}
+
 				err = s.streamServer.CommitAtomicOp()
 				if err != nil {
 					log.Errorf("failed to commit atomic op for l2block %d, error: %v ", l2Block.L2BlockNumber, err)
diff --git a/state/datastream.go b/state/datastream.go
index c3aa6c814f..0b6024f3f5 100644
--- a/state/datastream.go
+++ b/state/datastream.go
@@ -23,6 +23,10 @@ const (
 	SystemSC = "0x000000000000000000000000000000005ca1ab1e"
 	// posConstant is the constant used to compute the position of the intermediate state root
 	posConstant = 1
+	// DSVersion3 is the first protobuf version
+	DSVersion3 uint8 = 3
+	// DSVersion4 is the second protobuf version, includes l2BlockEnd
+	DSVersion4 uint8 = 4
 )
 
 // DSBatch represents a data stream batch
@@ -87,7 +91,7 @@ type DSState interface {
 }
 
 // GenerateDataStreamFile generates or resumes a data stream file
-func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.StreamServer, stateDB DSState, readWIPBatch bool, imStateRoots *map[uint64][]byte, chainID uint64, upgradeEtrogBatchNumber uint64) error {
+func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.StreamServer, stateDB DSState, readWIPBatch bool, imStateRoots *map[uint64][]byte, chainID uint64, upgradeEtrogBatchNumber uint64, version uint8) error {
 	header := streamServer.GetHeader()
 
 	var currentBatchNumber uint64 = 0
@@ -177,6 +181,22 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 			return err
 		}
 
+		if version >= DSVersion4 {
+			genesisBlockEnd := &datastream.L2BlockEnd{
+				Number: genesisL2Block.L2BlockNumber,
+			}
+
+			marshalledGenesisBlockEnd, err := proto.Marshal(genesisBlockEnd)
+			if err != nil {
+				return err
+			}
+
+			_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK_END), marshalledGenesisBlockEnd)
+			if err != nil {
+				return err
+			}
+		}
+
 		genesisBatchEnd := &datastream.BatchEnd{
 			Number:        genesisL2Block.BatchNumber,
 			LocalExitRoot: common.Hash{}.Bytes(),
@@ -249,6 +269,43 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 			currentBatchNumber = l2Block.BatchNumber
 			previousTimestamp = l2Block.Timestamp
 			lastAddedL2BlockNumber = currentL2BlockNumber
+
+		case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK_END):
+			log.Info("Latest entry type is L2BlockEnd")
+
+			l2BlockEnd := &datastream.L2BlockEnd{}
+			if err := proto.Unmarshal(latestEntry.Data, l2BlockEnd); err != nil {
+				return err
+			}
+
+			currentL2BlockNumber := l2BlockEnd.Number
+
+			// Getting the l2 block is needed in order to get the batch number and the timestamp
+			bookMark := &datastream.BookMark{
+				Type:  datastream.BookmarkType_BOOKMARK_TYPE_L2_BLOCK,
+				Value: currentL2BlockNumber,
+			}
+
+			marshalledBookMark, err := proto.Marshal(bookMark)
+			if err != nil {
+				return err
+			}
+
+			l2BlockEntry, err := streamServer.GetFirstEventAfterBookmark(marshalledBookMark)
+			if err != nil {
+				return err
+			}
+
+			l2Block := &datastream.L2Block{}
+
+			if err := proto.Unmarshal(l2BlockEntry.Data, l2Block); err != nil {
+				return err
+			}
+
+			currentBatchNumber = l2Block.BatchNumber
+			previousTimestamp = l2Block.Timestamp
+			lastAddedL2BlockNumber = currentL2BlockNumber
+
 		case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_TRANSACTION):
 			log.Info("Latest entry type is Transaction")
 
@@ -626,6 +683,22 @@ func GenerateDataStreamFile(ctx context.Context, streamServer *datastreamer.Stre
 					}
 
 					currentGER = l2Block.GlobalExitRoot
+
+					if version >= DSVersion4 {
+						streamL2BlockEnd := &datastream.L2BlockEnd{
+							Number: l2Block.L2BlockNumber,
+						}
+
+						marshalledL2BlockEnd, err := proto.Marshal(streamL2BlockEnd)
+						if err != nil {
+							return err
+						}
+
+						_, err = streamServer.AddStreamEntry(datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK_END), marshalledL2BlockEnd)
+						if err != nil {
+							return err
+						}
+					}
 				}
 			}
 
diff --git a/state/datastream/datastream.pb.go b/state/datastream/datastream.pb.go
index 02a0e2267f..1c9535ee38 100644
--- a/state/datastream/datastream.pb.go
+++ b/state/datastream/datastream.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.32.0
-// 	protoc        v4.25.3
+// 	protoc-gen-go v1.34.1
+// 	protoc        v5.27.0
 // source: datastream.proto
 
 package datastream
@@ -72,12 +72,13 @@ func (BookmarkType) EnumDescriptor() ([]byte, []int) {
 type EntryType int32
 
 const (
-	EntryType_ENTRY_TYPE_UNSPECIFIED EntryType = 0
-	EntryType_ENTRY_TYPE_BATCH_START EntryType = 1
-	EntryType_ENTRY_TYPE_L2_BLOCK    EntryType = 2
-	EntryType_ENTRY_TYPE_TRANSACTION EntryType = 3
-	EntryType_ENTRY_TYPE_BATCH_END   EntryType = 4
-	EntryType_ENTRY_TYPE_UPDATE_GER  EntryType = 5
+	EntryType_ENTRY_TYPE_UNSPECIFIED  EntryType = 0
+	EntryType_ENTRY_TYPE_BATCH_START  EntryType = 1
+	EntryType_ENTRY_TYPE_L2_BLOCK     EntryType = 2
+	EntryType_ENTRY_TYPE_TRANSACTION  EntryType = 3
+	EntryType_ENTRY_TYPE_BATCH_END    EntryType = 4
+	EntryType_ENTRY_TYPE_UPDATE_GER   EntryType = 5
+	EntryType_ENTRY_TYPE_L2_BLOCK_END EntryType = 6
 )
 
 // Enum value maps for EntryType.
@@ -89,14 +90,16 @@ var (
 		3: "ENTRY_TYPE_TRANSACTION",
 		4: "ENTRY_TYPE_BATCH_END",
 		5: "ENTRY_TYPE_UPDATE_GER",
+		6: "ENTRY_TYPE_L2_BLOCK_END",
 	}
 	EntryType_value = map[string]int32{
-		"ENTRY_TYPE_UNSPECIFIED": 0,
-		"ENTRY_TYPE_BATCH_START": 1,
-		"ENTRY_TYPE_L2_BLOCK":    2,
-		"ENTRY_TYPE_TRANSACTION": 3,
-		"ENTRY_TYPE_BATCH_END":   4,
-		"ENTRY_TYPE_UPDATE_GER":  5,
+		"ENTRY_TYPE_UNSPECIFIED":  0,
+		"ENTRY_TYPE_BATCH_START":  1,
+		"ENTRY_TYPE_L2_BLOCK":     2,
+		"ENTRY_TYPE_TRANSACTION":  3,
+		"ENTRY_TYPE_BATCH_END":    4,
+		"ENTRY_TYPE_UPDATE_GER":   5,
+		"ENTRY_TYPE_L2_BLOCK_END": 6,
 	}
 )
 
@@ -134,6 +137,7 @@ const (
 	BatchType_BATCH_TYPE_REGULAR     BatchType = 1
 	BatchType_BATCH_TYPE_FORCED      BatchType = 2
 	BatchType_BATCH_TYPE_INJECTED    BatchType = 3
+	BatchType_BATCH_TYPE_INVALID     BatchType = 4
 )
 
 // Enum value maps for BatchType.
@@ -143,12 +147,14 @@ var (
 		1: "BATCH_TYPE_REGULAR",
 		2: "BATCH_TYPE_FORCED",
 		3: "BATCH_TYPE_INJECTED",
+		4: "BATCH_TYPE_INVALID",
 	}
 	BatchType_value = map[string]int32{
 		"BATCH_TYPE_UNSPECIFIED": 0,
 		"BATCH_TYPE_REGULAR":     1,
 		"BATCH_TYPE_FORCED":      2,
 		"BATCH_TYPE_INJECTED":    3,
+		"BATCH_TYPE_INVALID":     4,
 	}
 )
 
@@ -480,6 +486,53 @@ func (x *L2Block) GetDebug() *Debug {
 	return nil
 }
 
+type L2BlockEnd struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Number uint64 `protobuf:"varint,1,opt,name=number,proto3" json:"number,omitempty"`
+}
+
+func (x *L2BlockEnd) Reset() {
+	*x = L2BlockEnd{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_datastream_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *L2BlockEnd) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*L2BlockEnd) ProtoMessage() {}
+
+func (x *L2BlockEnd) ProtoReflect() protoreflect.Message {
+	mi := &file_datastream_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use L2BlockEnd.ProtoReflect.Descriptor instead.
+func (*L2BlockEnd) Descriptor() ([]byte, []int) {
+	return file_datastream_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *L2BlockEnd) GetNumber() uint64 {
+	if x != nil {
+		return x.Number
+	}
+	return 0
+}
+
 type Transaction struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -497,7 +550,7 @@ type Transaction struct {
 func (x *Transaction) Reset() {
 	*x = Transaction{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_datastream_proto_msgTypes[3]
+		mi := &file_datastream_proto_msgTypes[4]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -510,7 +563,7 @@ func (x *Transaction) String() string {
 func (*Transaction) ProtoMessage() {}
 
 func (x *Transaction) ProtoReflect() protoreflect.Message {
-	mi := &file_datastream_proto_msgTypes[3]
+	mi := &file_datastream_proto_msgTypes[4]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -523,7 +576,7 @@ func (x *Transaction) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Transaction.ProtoReflect.Descriptor instead.
 func (*Transaction) Descriptor() ([]byte, []int) {
-	return file_datastream_proto_rawDescGZIP(), []int{3}
+	return file_datastream_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *Transaction) GetL2BlockNumber() uint64 {
@@ -593,7 +646,7 @@ type UpdateGER struct {
 func (x *UpdateGER) Reset() {
 	*x = UpdateGER{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_datastream_proto_msgTypes[4]
+		mi := &file_datastream_proto_msgTypes[5]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -606,7 +659,7 @@ func (x *UpdateGER) String() string {
 func (*UpdateGER) ProtoMessage() {}
 
 func (x *UpdateGER) ProtoReflect() protoreflect.Message {
-	mi := &file_datastream_proto_msgTypes[4]
+	mi := &file_datastream_proto_msgTypes[5]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -619,7 +672,7 @@ func (x *UpdateGER) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UpdateGER.ProtoReflect.Descriptor instead.
 func (*UpdateGER) Descriptor() ([]byte, []int) {
-	return file_datastream_proto_rawDescGZIP(), []int{4}
+	return file_datastream_proto_rawDescGZIP(), []int{5}
 }
 
 func (x *UpdateGER) GetBatchNumber() uint64 {
@@ -690,7 +743,7 @@ type BookMark struct {
 func (x *BookMark) Reset() {
 	*x = BookMark{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_datastream_proto_msgTypes[5]
+		mi := &file_datastream_proto_msgTypes[6]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -703,7 +756,7 @@ func (x *BookMark) String() string {
 func (*BookMark) ProtoMessage() {}
 
 func (x *BookMark) ProtoReflect() protoreflect.Message {
-	mi := &file_datastream_proto_msgTypes[5]
+	mi := &file_datastream_proto_msgTypes[6]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -716,7 +769,7 @@ func (x *BookMark) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use BookMark.ProtoReflect.Descriptor instead.
 func (*BookMark) Descriptor() ([]byte, []int) {
-	return file_datastream_proto_rawDescGZIP(), []int{5}
+	return file_datastream_proto_rawDescGZIP(), []int{6}
 }
 
 func (x *BookMark) GetType() BookmarkType {
@@ -744,7 +797,7 @@ type Debug struct {
 func (x *Debug) Reset() {
 	*x = Debug{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_datastream_proto_msgTypes[6]
+		mi := &file_datastream_proto_msgTypes[7]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -757,7 +810,7 @@ func (x *Debug) String() string {
 func (*Debug) ProtoMessage() {}
 
 func (x *Debug) ProtoReflect() protoreflect.Message {
-	mi := &file_datastream_proto_msgTypes[6]
+	mi := &file_datastream_proto_msgTypes[7]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -770,7 +823,7 @@ func (x *Debug) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Debug.ProtoReflect.Descriptor instead.
 func (*Debug) Descriptor() ([]byte, []int) {
-	return file_datastream_proto_rawDescGZIP(), []int{6}
+	return file_datastream_proto_rawDescGZIP(), []int{7}
 }
 
 func (x *Debug) GetMessage() string {
@@ -837,77 +890,83 @@ var file_datastream_proto_rawDesc = []byte{
 	0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x64, 0x65, 0x62,
 	0x75, 0x67, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73,
 	0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x52, 0x05,
-	0x64, 0x65, 0x62, 0x75, 0x67, 0x22, 0x94, 0x02, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61,
-	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x32, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
-	0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6c,
-	0x32, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05,
-	0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x64,
-	0x65, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x18, 0x0a,
-	0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07,
-	0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x1e, 0x65, 0x66, 0x66, 0x65, 0x63,
-	0x74, 0x69, 0x76, 0x65, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x63, 0x65, 0x5f, 0x70,
-	0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52,
-	0x1b, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x47, 0x61, 0x73, 0x50, 0x72, 0x69,
-	0x63, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0d,
-	0x69, 0x6d, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20,
-	0x01, 0x28, 0x0c, 0x52, 0x0b, 0x69, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74,
-	0x12, 0x2a, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
-	0x14, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e,
-	0x44, 0x65, 0x62, 0x75, 0x67, 0x52, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x22, 0x91, 0x02, 0x0a,
-	0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x45, 0x52, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x61,
-	0x74, 0x63, 0x68, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x0b, 0x62, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a,
-	0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x28, 0x0a, 0x10, 0x67,
-	0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18,
-	0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x45, 0x78, 0x69,
-	0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73,
-	0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73,
-	0x65, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01,
-	0x28, 0x04, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68,
-	0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x63, 0x68,
-	0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72,
-	0x6f, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65,
-	0x52, 0x6f, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x08, 0x20,
-	0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,
-	0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x52, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67,
-	0x22, 0x51, 0x0a, 0x08, 0x42, 0x6f, 0x6f, 0x6b, 0x4d, 0x61, 0x72, 0x6b, 0x12, 0x2f, 0x0a, 0x04,
-	0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x64, 0x61, 0x74,
-	0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x6f, 0x6b, 0x6d,
-	0x61, 0x72, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a,
-	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61,
-	0x6c, 0x75, 0x65, 0x22, 0x21, 0x0a, 0x05, 0x44, 0x65, 0x62, 0x75, 0x67, 0x12, 0x18, 0x0a, 0x07,
-	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d,
-	0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x62, 0x0a, 0x0c, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61,
-	0x72, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x4f, 0x4f, 0x4b, 0x4d, 0x41,
-	0x52, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46,
-	0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x42, 0x4f, 0x4f, 0x4b, 0x4d, 0x41, 0x52,
-	0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x54, 0x43, 0x48, 0x10, 0x01, 0x12, 0x1a,
-	0x0a, 0x16, 0x42, 0x4f, 0x4f, 0x4b, 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f,
-	0x4c, 0x32, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x2a, 0xad, 0x01, 0x0a, 0x09, 0x45,
-	0x6e, 0x74, 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x4e, 0x54, 0x52,
-	0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49,
-	0x45, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59,
-	0x50, 0x45, 0x5f, 0x42, 0x41, 0x54, 0x43, 0x48, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x01,
-	0x12, 0x17, 0x0a, 0x13, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c,
-	0x32, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x4e, 0x54,
-	0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54,
-	0x49, 0x4f, 0x4e, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54,
-	0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x54, 0x43, 0x48, 0x5f, 0x45, 0x4e, 0x44, 0x10, 0x04, 0x12,
-	0x19, 0x0a, 0x15, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x50,
-	0x44, 0x41, 0x54, 0x45, 0x5f, 0x47, 0x45, 0x52, 0x10, 0x05, 0x2a, 0x6f, 0x0a, 0x09, 0x42, 0x61,
-	0x74, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x41, 0x54, 0x43, 0x48,
-	0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45,
-	0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x42, 0x41, 0x54, 0x43, 0x48, 0x5f, 0x54, 0x59, 0x50,
-	0x45, 0x5f, 0x52, 0x45, 0x47, 0x55, 0x4c, 0x41, 0x52, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x42,
-	0x41, 0x54, 0x43, 0x48, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x44,
-	0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x42, 0x41, 0x54, 0x43, 0x48, 0x5f, 0x54, 0x59, 0x50, 0x45,
-	0x5f, 0x49, 0x4e, 0x4a, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x03, 0x42, 0x38, 0x5a, 0x36, 0x67,
-	0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x78, 0x50, 0x6f, 0x6c, 0x79,
-	0x67, 0x6f, 0x6e, 0x48, 0x65, 0x72, 0x6d, 0x65, 0x7a, 0x2f, 0x7a, 0x6b, 0x65, 0x76, 0x6d, 0x2d,
-	0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73,
-	0x74, 0x72, 0x65, 0x61, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x64, 0x65, 0x62, 0x75, 0x67, 0x22, 0x24, 0x0a, 0x0a, 0x4c, 0x32, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
+	0x45, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x94, 0x02, 0x0a, 0x0b,
+	0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x6c,
+	0x32, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x04, 0x52, 0x0d, 0x6c, 0x32, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62,
+	0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x76,
+	0x61, 0x6c, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x56, 0x61,
+	0x6c, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x43, 0x0a,
+	0x1e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x67, 0x61, 0x73, 0x5f, 0x70,
+	0x72, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18,
+	0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x1b, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65,
+	0x47, 0x61, 0x73, 0x50, 0x72, 0x69, 0x63, 0x65, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61,
+	0x67, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x6d, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72,
+	0x6f, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x69, 0x6d, 0x53, 0x74, 0x61,
+	0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x72, 0x65,
+	0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x52, 0x05, 0x64, 0x65, 0x62,
+	0x75, 0x67, 0x22, 0x91, 0x02, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x47, 0x45, 0x52,
+	0x12, 0x21, 0x0a, 0x0c, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x75, 0x6d,
+	0x62, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
+	0x70, 0x12, 0x28, 0x0a, 0x10, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x69, 0x74,
+	0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x67, 0x6c, 0x6f,
+	0x62, 0x61, 0x6c, 0x45, 0x78, 0x69, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63,
+	0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63,
+	0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x6b, 0x5f,
+	0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6b, 0x49, 0x64,
+	0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73,
+	0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52,
+	0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x64, 0x65,
+	0x62, 0x75, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x64, 0x61, 0x74, 0x61,
+	0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x52,
+	0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x22, 0x51, 0x0a, 0x08, 0x42, 0x6f, 0x6f, 0x6b, 0x4d, 0x61,
+	0x72, 0x6b, 0x12, 0x2f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
+	0x32, 0x1b, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2e, 0x76, 0x31,
+	0x2e, 0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
+	0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x21, 0x0a, 0x05, 0x44, 0x65, 0x62,
+	0x75, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2a, 0x62, 0x0a, 0x0c,
+	0x42, 0x6f, 0x6f, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19,
+	0x42, 0x4f, 0x4f, 0x4b, 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e,
+	0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x42,
+	0x4f, 0x4f, 0x4b, 0x4d, 0x41, 0x52, 0x4b, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x54,
+	0x43, 0x48, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x4f, 0x4f, 0x4b, 0x4d, 0x41, 0x52, 0x4b,
+	0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c, 0x32, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02,
+	0x2a, 0xca, 0x01, 0x0a, 0x09, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a,
+	0x0a, 0x16, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53,
+	0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x4e,
+	0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x54, 0x43, 0x48, 0x5f, 0x53,
+	0x54, 0x41, 0x52, 0x54, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f,
+	0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c, 0x32, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x12,
+	0x1a, 0x0a, 0x16, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52,
+	0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x45,
+	0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x41, 0x54, 0x43, 0x48, 0x5f,
+	0x45, 0x4e, 0x44, 0x10, 0x04, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54,
+	0x59, 0x50, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x47, 0x45, 0x52, 0x10, 0x05,
+	0x12, 0x1b, 0x0a, 0x17, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4c,
+	0x32, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x5f, 0x45, 0x4e, 0x44, 0x10, 0x06, 0x2a, 0x87, 0x01,
+	0x0a, 0x09, 0x42, 0x61, 0x74, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x42,
+	0x41, 0x54, 0x43, 0x48, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
+	0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x42, 0x41, 0x54, 0x43, 0x48,
+	0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x47, 0x55, 0x4c, 0x41, 0x52, 0x10, 0x01, 0x12,
+	0x15, 0x0a, 0x11, 0x42, 0x41, 0x54, 0x43, 0x48, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x4f,
+	0x52, 0x43, 0x45, 0x44, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x42, 0x41, 0x54, 0x43, 0x48, 0x5f,
+	0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x4a, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12,
+	0x16, 0x0a, 0x12, 0x42, 0x41, 0x54, 0x43, 0x48, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e,
+	0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x04, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75,
+	0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x78, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x48,
+	0x65, 0x72, 0x6d, 0x65, 0x7a, 0x2f, 0x7a, 0x6b, 0x65, 0x76, 0x6d, 0x2d, 0x6e, 0x6f, 0x64, 0x65,
+	0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x72, 0x65, 0x61,
+	0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -923,7 +982,7 @@ func file_datastream_proto_rawDescGZIP() []byte {
 }
 
 var file_datastream_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
-var file_datastream_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
+var file_datastream_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
 var file_datastream_proto_goTypes = []interface{}{
 	(BookmarkType)(0),   // 0: datastream.v1.BookmarkType
 	(EntryType)(0),      // 1: datastream.v1.EntryType
@@ -931,24 +990,25 @@ var file_datastream_proto_goTypes = []interface{}{
 	(*BatchStart)(nil),  // 3: datastream.v1.BatchStart
 	(*BatchEnd)(nil),    // 4: datastream.v1.BatchEnd
 	(*L2Block)(nil),     // 5: datastream.v1.L2Block
-	(*Transaction)(nil), // 6: datastream.v1.Transaction
-	(*UpdateGER)(nil),   // 7: datastream.v1.UpdateGER
-	(*BookMark)(nil),    // 8: datastream.v1.BookMark
-	(*Debug)(nil),       // 9: datastream.v1.Debug
+	(*L2BlockEnd)(nil),  // 6: datastream.v1.L2BlockEnd
+	(*Transaction)(nil), // 7: datastream.v1.Transaction
+	(*UpdateGER)(nil),   // 8: datastream.v1.UpdateGER
+	(*BookMark)(nil),    // 9: datastream.v1.BookMark
+	(*Debug)(nil),       // 10: datastream.v1.Debug
 }
 var file_datastream_proto_depIdxs = []int32{
-	2, // 0: datastream.v1.BatchStart.type:type_name -> datastream.v1.BatchType
-	9, // 1: datastream.v1.BatchStart.debug:type_name -> datastream.v1.Debug
-	9, // 2: datastream.v1.BatchEnd.debug:type_name -> datastream.v1.Debug
-	9, // 3: datastream.v1.L2Block.debug:type_name -> datastream.v1.Debug
-	9, // 4: datastream.v1.Transaction.debug:type_name -> datastream.v1.Debug
-	9, // 5: datastream.v1.UpdateGER.debug:type_name -> datastream.v1.Debug
-	0, // 6: datastream.v1.BookMark.type:type_name -> datastream.v1.BookmarkType
-	7, // [7:7] is the sub-list for method output_type
-	7, // [7:7] is the sub-list for method input_type
-	7, // [7:7] is the sub-list for extension type_name
-	7, // [7:7] is the sub-list for extension extendee
-	0, // [0:7] is the sub-list for field type_name
+	2,  // 0: datastream.v1.BatchStart.type:type_name -> datastream.v1.BatchType
+	10, // 1: datastream.v1.BatchStart.debug:type_name -> datastream.v1.Debug
+	10, // 2: datastream.v1.BatchEnd.debug:type_name -> datastream.v1.Debug
+	10, // 3: datastream.v1.L2Block.debug:type_name -> datastream.v1.Debug
+	10, // 4: datastream.v1.Transaction.debug:type_name -> datastream.v1.Debug
+	10, // 5: datastream.v1.UpdateGER.debug:type_name -> datastream.v1.Debug
+	0,  // 6: datastream.v1.BookMark.type:type_name -> datastream.v1.BookmarkType
+	7,  // [7:7] is the sub-list for method output_type
+	7,  // [7:7] is the sub-list for method input_type
+	7,  // [7:7] is the sub-list for extension type_name
+	7,  // [7:7] is the sub-list for extension extendee
+	0,  // [0:7] is the sub-list for field type_name
 }
 
 func init() { file_datastream_proto_init() }
@@ -994,7 +1054,7 @@ func file_datastream_proto_init() {
 			}
 		}
 		file_datastream_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*Transaction); i {
+			switch v := v.(*L2BlockEnd); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1006,7 +1066,7 @@ func file_datastream_proto_init() {
 			}
 		}
 		file_datastream_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*UpdateGER); i {
+			switch v := v.(*Transaction); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1018,7 +1078,7 @@ func file_datastream_proto_init() {
 			}
 		}
 		file_datastream_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*BookMark); i {
+			switch v := v.(*UpdateGER); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -1030,6 +1090,18 @@ func file_datastream_proto_init() {
 			}
 		}
 		file_datastream_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*BookMark); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_datastream_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*Debug); i {
 			case 0:
 				return &v.state
@@ -1048,7 +1120,7 @@ func file_datastream_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_datastream_proto_rawDesc,
 			NumEnums:      3,
-			NumMessages:   7,
+			NumMessages:   8,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/test/config/debug.node.config.toml b/test/config/debug.node.config.toml
index 7ec0d496ea..ee79039ed3 100644
--- a/test/config/debug.node.config.toml
+++ b/test/config/debug.node.config.toml
@@ -111,7 +111,7 @@ StateConsistencyCheckInterval = "5s"
 	[Sequencer.StreamServer]
 		Port = 6900
 		Filename = "/datastreamer/datastream.bin"
-		Version = 1
+		Version = 4
 		WriteTimeout = "5s"
 		InactivityTimeout = "120s"
 		InactivityCheckInterval = "5s"
diff --git a/test/config/test.node.config.toml b/test/config/test.node.config.toml
index d13ff02ca5..040ef7058c 100644
--- a/test/config/test.node.config.toml
+++ b/test/config/test.node.config.toml
@@ -126,7 +126,7 @@ StateConsistencyCheckInterval = "5s"
 	[Sequencer.StreamServer]
 		Port = 6900
 		Filename = "/datastreamer/datastream.bin"
-		Version = 1
+		Version = 4
 		ChainID = 1337
 		WriteTimeout = "5s"
 		InactivityTimeout = "120s"
diff --git a/tools/datastreamer/config/default.go b/tools/datastreamer/config/default.go
index 74c6f35b24..dc7aa3bacf 100644
--- a/tools/datastreamer/config/default.go
+++ b/tools/datastreamer/config/default.go
@@ -9,7 +9,7 @@ StreamType = 1
 [Offline]
 Port = 6901
 Filename = "datastreamer.bin"
-Version = 1
+Version = 4
 ChainID = 1440
 UpgradeEtrogBatchNumber = 0
 
diff --git a/tools/datastreamer/config/tool.config.toml b/tools/datastreamer/config/tool.config.toml
index 60d04aafb3..8309edfe76 100644
--- a/tools/datastreamer/config/tool.config.toml
+++ b/tools/datastreamer/config/tool.config.toml
@@ -5,7 +5,7 @@ StreamType = 1
 [Offline]
 Port = 6901
 Filename = "datastream.bin"
-Version = 3
+Version = 4
 ChainID = 1440
 WriteTimeout = "5s"
 InactivityTimeout = "120s"
diff --git a/tools/datastreamer/main.go b/tools/datastreamer/main.go
index c6b43155f8..b0bc2680a0 100644
--- a/tools/datastreamer/main.go
+++ b/tools/datastreamer/main.go
@@ -297,7 +297,7 @@ func generate(cliCtx *cli.Context) error {
 		}
 	}
 
-	err = state.GenerateDataStreamFile(cliCtx.Context, streamServer, stateDB, false, &imStateRoots, c.Offline.ChainID, c.Offline.UpgradeEtrogBatchNumber)
+	err = state.GenerateDataStreamFile(cliCtx.Context, streamServer, stateDB, false, &imStateRoots, c.Offline.ChainID, c.Offline.UpgradeEtrogBatchNumber, c.Offline.Version)
 	if err != nil {
 		log.Error(err)
 		os.Exit(1)
@@ -424,6 +424,15 @@ func decodeL2Block(cliCtx *cli.Context) error {
 		i++
 	}
 
+	if c.Offline.Version >= state.DSVersion4 {
+		l2BlockEnd, err := client.ExecCommandGetEntry(secondEntry.Number)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+		printEntry(l2BlockEnd)
+	}
+
 	return nil
 }
 
@@ -505,6 +514,15 @@ func decodeL2BlockOffline(cliCtx *cli.Context) error {
 		i++
 	}
 
+	if c.Offline.Version >= state.DSVersion4 {
+		l2BlockEnd, err := streamServer.GetEntry(secondEntry.Number)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+		printEntry(l2BlockEnd)
+	}
+
 	return nil
 }
 
@@ -761,6 +779,21 @@ func printEntry(entry datastreamer.FileEntry) {
 			printColored(color.FgHiWhite, fmt.Sprintf("%s\n", l2Block.Debug))
 		}
 
+	case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_L2_BLOCK_END):
+		l2BlockEnd := &datastream.L2BlockEnd{}
+		err := proto.Unmarshal(entry.Data, l2BlockEnd)
+		if err != nil {
+			log.Error(err)
+			os.Exit(1)
+		}
+
+		printColored(color.FgGreen, "Entry Type......: ")
+		printColored(color.FgHiYellow, "L2 Block End\n")
+		printColored(color.FgGreen, "Entry Number....: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", entry.Number))
+		printColored(color.FgGreen, "L2 Block Number.: ")
+		printColored(color.FgHiWhite, fmt.Sprintf("%d\n", l2BlockEnd.Number))
+
 	case datastreamer.EntryType(datastream.EntryType_ENTRY_TYPE_BATCH_START):
 		batch := &datastream.BatchStart{}
 		err := proto.Unmarshal(entry.Data, batch)

From a774dc9bb0aa7bd23ff6f3c0db21960d9b69e1fd Mon Sep 17 00:00:00 2001
From: agnusmor <100322135+agnusmor@users.noreply.github.com>
Date: Wed, 7 Aug 2024 11:45:00 +0200
Subject: [PATCH 14/14] Fix timestamp when querying zkevm_getBatchByNumer and
 the batch is only in trusted state (#3750)

* fix timestamp when querying zkevm_getBatchByNumer and the batch is only in trusted state

* control timestamp to be returned for a batch in GetBatchTimestamp

* fix ErrNotFound

* fix state.ErrNotFound check

* fix comments

* fix GetRawBatchTimestamps

* fix comments

* fix GetRawBatchTimestamps return err
---
 state/batch.go                | 23 ++++++++++++++++++++---
 state/pgstatestorage/batch.go |  2 +-
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/state/batch.go b/state/batch.go
index f5325a08c7..c52d2eb278 100644
--- a/state/batch.go
+++ b/state/batch.go
@@ -568,10 +568,13 @@ func (s *State) GetLastBatch(ctx context.Context, dbTx pgx.Tx) (*Batch, error) {
 	return batches[0], nil
 }
 
-// GetBatchTimestamp returns the batch timestamp.
+// GetBatchTimestamp returns the batch timestamp
+// If batch >= etrog
 //
-//	   for >= etrog is stored on virtual_batch.batch_timestamp
-//		  previous batches is stored on batch.timestamp
+//	if the batch it's virtualized it will return virtual_batch.timestamp_batch_etrog field value
+//	if the batch if's only trusted and it has L2 blocks it will return the timestamp of the last L2 block, otherwise it will return batchTimestamp
+//
+// If batch < etrog it will return batchTimestamp value
 func (s *State) GetBatchTimestamp(ctx context.Context, batchNumber uint64, forcedForkId *uint64, dbTx pgx.Tx) (*time.Time, error) {
 	var forkid uint64
 	if forcedForkId != nil {
@@ -584,6 +587,20 @@ func (s *State) GetBatchTimestamp(ctx context.Context, batchNumber uint64, force
 		return nil, err
 	}
 	if forkid >= FORKID_ETROG {
+		if virtualTimestamp == nil {
+			lastL2Block, err := s.GetLastL2BlockByBatchNumber(ctx, batchNumber, dbTx)
+			if err != nil && !errors.Is(err, ErrNotFound) {
+				return nil, err
+			}
+
+			// If the batch has L2 blocks we will return the timestamp of the last L2 block as the timestamp of the batch
+			// else we will return the batchTimestamp value (timestamp of batch creation)
+			if lastL2Block != nil {
+				return &lastL2Block.ReceivedAt, nil
+			}
+
+			return batchTimestamp, nil
+		}
 		return virtualTimestamp, nil
 	}
 	return batchTimestamp, nil
diff --git a/state/pgstatestorage/batch.go b/state/pgstatestorage/batch.go
index b0b1aa6389..bbe12a355a 100644
--- a/state/pgstatestorage/batch.go
+++ b/state/pgstatestorage/batch.go
@@ -995,7 +995,7 @@ func (p *PostgresStorage) BuildChangeL2Block(deltaTimestamp uint32, l1InfoTreeIn
 }
 
 // GetRawBatchTimestamps returns the timestamp of the batch with the given number.
-// it returns batch_num.tstamp and virtual_batch.batch_timestamp
+// it returns batch.timestamp and virtual_batch.timestamp_batch_etrog
 func (p *PostgresStorage) GetRawBatchTimestamps(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*time.Time, *time.Time, error) {
 	const sql = `
 	SELECT b.timestamp AS batch_timestamp, v.timestamp_batch_etrog AS virtual_batch_timestamp