diff --git a/src/Nethermind/Nethermind.Optimism.Test/CL/BlobDecoderTests.cs b/src/Nethermind/Nethermind.Optimism.Test/CL/BlobDecoderTests.cs
new file mode 100644
index 00000000000..ddfd4b59a66
--- /dev/null
+++ b/src/Nethermind/Nethermind.Optimism.Test/CL/BlobDecoderTests.cs
@@ -0,0 +1,60 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Linq;
+using Nethermind.Core.Extensions;
+using Nethermind.Optimism.CL;
+using NUnit.Framework;
+
+namespace Nethermind.Optimism.Test.CL;
+
+public class BlobDecoderTests
+{
+ private static byte[] StringToByteArray(string hex) {
+ return Enumerable.Range(0, hex.Length)
+ .Where(x => x % 2 == 0)
+ .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
+ .ToArray();
+ }
+
+ [TestCase(994040)]
+ [TestCase(2243081)]
+ [TestCase(35443070)]
+ [TestCase(1484649)]
+ [TestCase(76888454)]
+ [TestCase(69007144)] // isLast = false
+ public void Blob_decode_test(int index)
+ {
+ StreamReader inputReader = new StreamReader($"/home/deffrian/Documents/testvectors/input{index}");
+ StreamReader outputReader = new StreamReader($"/home/deffrian/Documents/testvectors/output{index}");
+ byte[] blob = StringToByteArray(inputReader.ReadToEnd());
+ byte[] decoded = StringToByteArray(outputReader.ReadToEnd());
+ inputReader.Close();
+ outputReader.Close();
+ byte[] result = BlobDecoder.DecodeBlob(new BlobSidecar { Blob = blob });
+ Assert.That(decoded, Is.EqualTo(result));
+
+ var frames = FrameDecoder.DecodeFrames(result);
+ Assert.That(frames.Length, Is.EqualTo(1));
+ Assert.That(frames[0].IsLast, Is.True);
+
+ var end = ChannelDecoder.DecodeChannel(frames[0]);
+ }
+
+ public static IEnumerable BlobTestCases
+ {
+ get
+ {
+ yield return new TestCaseData(
+ Bytes.FromHexString(""),
+ Bytes.FromHexString("")
+ )
+ {
+ TestName = "Sepolia blob 1"
+ };
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Optimism/CL/Decoders/BlobDecoder.cs b/src/Nethermind/Nethermind.Optimism/CL/Decoders/BlobDecoder.cs
new file mode 100644
index 00000000000..e1b55734044
--- /dev/null
+++ b/src/Nethermind/Nethermind.Optimism/CL/Decoders/BlobDecoder.cs
@@ -0,0 +1,97 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+
+namespace Nethermind.Optimism.CL;
+
+public class BlobDecoder
+{
+ static public byte[] DecodeBlob(BlobSidecar blobSidecar)
+ {
+ int MaxBlobDataSize = (4 * 31 + 3) * 1024 - 4;
+ int BlobSize = 4096 * 32;
+ int length = ((int)blobSidecar.Blob[2] << 16) | ((int)blobSidecar.Blob[3] << 8) |
+ ((int)blobSidecar.Blob[4]);
+ if (length > MaxBlobDataSize)
+ {
+ throw new Exception("Blob size is too big");
+ }
+
+ byte[] output = new byte[MaxBlobDataSize];
+ for (int i = 0; i < 27; ++i)
+ {
+ output[i] = blobSidecar.Blob[i + 5];
+ }
+
+ byte[] encodedByte = new byte[4];
+ int blobPos = 32;
+ int outputPos = 28;
+
+ encodedByte[0] = blobSidecar.Blob[0];
+ for (int i = 1; i < 4; ++i)
+ {
+ (encodedByte[i], outputPos, blobPos) = DecodeFieldElement(blobSidecar.Blob, outputPos, blobPos, output);
+ }
+
+ outputPos = ReassembleBytes(outputPos, encodedByte, output);
+
+ for (int i = 1; i < 1024 && outputPos < length; i++)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ (encodedByte[j], outputPos, blobPos) =
+ DecodeFieldElement(blobSidecar.Blob, outputPos, blobPos, output);
+ }
+
+ outputPos = ReassembleBytes(outputPos, encodedByte, output);
+ }
+
+ for (int i = length; i < MaxBlobDataSize; i++)
+ {
+ if (output[i] != 0)
+ {
+ throw new Exception("Wrong output");
+ }
+ }
+
+ output = output[..length];
+ for (; blobPos < BlobSize; blobPos++)
+ {
+ if (blobSidecar.Blob[blobPos] != 0)
+ {
+ throw new Exception("Blob excess data");
+ }
+ }
+
+ return output;
+ }
+
+ static private (byte, int, int) DecodeFieldElement(byte[] blob, int outPos, int blobPos, byte[] output) {
+ // two highest order bits of the first byte of each field element should always be 0
+ if ((blob[blobPos] & 0b1100_0000) != 0) {
+ // TODO: remove exception
+ throw new Exception("Invalid field element");
+ }
+
+ for (int i = 0; i < 31; i++)
+ {
+ output[outPos + i] = blob[blobPos + i + 1];
+ }
+
+ return (blob[blobPos], outPos + 32, blobPos + 32);
+ }
+
+ static int ReassembleBytes(int outPos, byte[] encodedByte, byte[] output)
+ {
+ outPos--; // account for fact that we don't output a 128th byte
+ byte x = (byte)((encodedByte[0] & 0b0011_1111) | ((encodedByte[1] & 0b0011_0000) << 2));
+ byte y = (byte)((encodedByte[1] & 0b0000_1111) | ((encodedByte[3] & 0b0000_1111) << 4));
+ byte z = (byte)((encodedByte[2] & 0b0011_1111) | ((encodedByte[3] & 0b0011_0000) << 2));
+ // put the re-assembled bytes in their appropriate output locations
+ output[outPos - 32] = z;
+ output[outPos - 32 * 2] = y;
+ output[outPos - 32 * 3] = x;
+ return outPos;
+ }
+}
diff --git a/src/Nethermind/Nethermind.Optimism/CL/Decoders/ChannelDecoder.cs b/src/Nethermind/Nethermind.Optimism/CL/Decoders/ChannelDecoder.cs
new file mode 100644
index 00000000000..77bf1828395
--- /dev/null
+++ b/src/Nethermind/Nethermind.Optimism/CL/Decoders/ChannelDecoder.cs
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.IO;
+using System.IO.Compression;
+using Nethermind.Core;
+using Nethermind.Serialization.Rlp;
+
+namespace Nethermind.Optimism.CL;
+
+public class ChannelDecoder
+{
+ public static byte[] DecodeChannel(Frame frame)
+ {
+ if ((frame.FrameData[0] & 0x0F) == 8 || (frame.FrameData[0] & 0x0F) == 15)
+ {
+ // zlib
+ var deflateStream = new DeflateStream(new MemoryStream(frame.FrameData[2..]), CompressionMode.Decompress);
+ var memoryStream = new MemoryStream();
+ deflateStream.CopyTo(memoryStream);
+ return memoryStream.ToArray();
+ } else if (frame.FrameData[0] == 1)
+ {
+ // brotli
+ throw new NotImplementedException("Brotli is not supported");
+ }
+ else
+ {
+ throw new Exception($"Unsupported compression algorithm {frame.FrameData[0]}");
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Optimism/CL/Decoders/FrameDecoder.cs b/src/Nethermind/Nethermind.Optimism/CL/Decoders/FrameDecoder.cs
new file mode 100644
index 00000000000..cb4ae0bce4e
--- /dev/null
+++ b/src/Nethermind/Nethermind.Optimism/CL/Decoders/FrameDecoder.cs
@@ -0,0 +1,64 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Nethermind.Network.Rlpx;
+
+namespace Nethermind.Optimism.CL;
+
+public class FrameDecoder
+{
+ private static (Frame, int) DecodeFrame(byte[] data)
+ {
+ byte[] channelId = data[..16];
+ UInt16 frameNumber = BitConverter.ToUInt16(data[16..18].Reverse().ToArray());
+ UInt32 frameDataLength = BitConverter.ToUInt32(data[18..22].Reverse().ToArray());
+ byte[] frameData = data[22..(22 + (int)frameDataLength)];
+ byte isLast = data[22 + (int)frameDataLength];
+ if (isLast != 0 && isLast != 1)
+ {
+ throw new Exception("Invalid isLast flag");
+ }
+ return (new Frame()
+ {
+ ChannelId = channelId,
+ FrameNumber = frameNumber,
+ FrameData = frameData,
+ IsLast = isLast == 0
+ }, 23 + (int)frameDataLength);
+ }
+
+ public static Frame[] DecodeFrames(byte[] data)
+ {
+ byte version = data[0];
+ if (version != 0)
+ {
+ throw new Exception($"Frame Decoder version {version} is not supported.");
+ }
+
+ List frames = new List();
+ int pos = 1;
+ while (pos < data.Length)
+ {
+ (Frame frame, int decoded) = DecodeFrame(data[pos..]);
+ pos += decoded;
+ frames.Add(frame);
+ }
+
+ if (pos != data.Length)
+ {
+ throw new Exception("Excess frame data");
+ }
+ return frames.ToArray();
+ }
+}
+
+public struct Frame
+{
+ public byte[] ChannelId;
+ public UInt16 FrameNumber;
+ public byte[] FrameData;
+ public bool IsLast;
+}
diff --git a/src/Nethermind/Nethermind.Optimism/CL/Driver.cs b/src/Nethermind/Nethermind.Optimism/CL/Driver.cs
index 14d345e7c96..49e0ed6eb5c 100644
--- a/src/Nethermind/Nethermind.Optimism/CL/Driver.cs
+++ b/src/Nethermind/Nethermind.Optimism/CL/Driver.cs
@@ -1,12 +1,11 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System;
using System.Linq;
-using Nethermind.Blockchain.Find;
+using System.Threading;
using Nethermind.Core;
-using Nethermind.Core.Crypto;
-using Nethermind.Facade.Eth;
-using Nethermind.JsonRpc.Modules.Eth;
+using Nethermind.Logging;
namespace Nethermind.Optimism.CL;
@@ -14,28 +13,34 @@ public class Driver
{
private readonly ICLConfig _config;
private readonly IL1Bridge _l1Bridge;
+ private readonly ILogger _logger;
- public Driver(IL1Bridge l1Bridge, ICLConfig config)
+ public Driver(IL1Bridge l1Bridge, ICLConfig config, ILogger logger)
{
_config = config;
_l1Bridge = l1Bridge;
+ _logger = logger;
}
- private void Start()
+ public void Start()
{
_l1Bridge.OnNewL1Head += OnNewL1Head;
}
- private void OnNewL1Head(BlockForRpc block, ulong slotNumber)
+ private void OnNewL1Head(BeaconBlock block, ulong slotNumber)
{
+ _logger.Error("INVOKED");
+ Address sepoliaBatcher = new("0x8F23BB38F531600e5d8FDDaAEC41F13FaB46E98c");
+ Address batcherInboxAddress = new("0xff00000000000000000000000000000011155420");
// Filter batch submitter transaction
- foreach (TransactionForRpc transaction in block.Transactions.Cast())
+ foreach (Transaction transaction in block.Transactions)
{
- if (_config.BatcherInboxAddress == transaction.To && _config.BatcherAddress == transaction.From)
+ // _logger.Error($"Tx To: {transaction.To}, From: {transaction.SenderAddress} end");
+ if (batcherInboxAddress == transaction.To && sepoliaBatcher == transaction.SenderAddress)
{
if (transaction.Type == TxType.Blob)
{
- ProcessBlobBatcherTransaction(transaction);
+ ProcessBlobBatcherTransaction(transaction, slotNumber);
}
else
{
@@ -45,16 +50,35 @@ private void OnNewL1Head(BlockForRpc block, ulong slotNumber)
}
}
- private void ProcessBlobBatcherTransaction(TransactionForRpc transaction)
+ private async void ProcessBlobBatcherTransaction(Transaction transaction, ulong slotNumber)
{
- int numberOfBlobs = transaction.BlobVersionedHashes!.Length;
- for (int i = 0; i < numberOfBlobs; ++i)
+ if (_logger.IsError)
{
-
+ _logger.Error($"GOT BLOB TRANSACTION To: {transaction.To}, From: {transaction.SenderAddress}");
+ }
+ BlobSidecar[] blobSidecars = await _l1Bridge.GetBlobSidecars(slotNumber);
+ for (int i = 0; i < transaction.BlobVersionedHashes!.Length; i++)
+ {
+ for (int j = 0; j < blobSidecars.Length; ++j)
+ {
+ if (blobSidecars[j].BlobVersionedHash.SequenceEqual(transaction.BlobVersionedHashes[i]!))
+ {
+ _logger.Error($"GOT BLOB VERSIONED HASH: {BitConverter.ToString(transaction.BlobVersionedHashes[i]!).Replace("-", "")}");
+ _logger.Error($"BLOB: {BitConverter.ToString(blobSidecars[j].Blob[..32]).Replace("-", "")}");
+ byte[] data = BlobDecoder.DecodeBlob(blobSidecars[j]);
+ FrameDecoder.DecodeFrames(data);
+ // _logger.Error($"DATA: {BitConverter.ToString(data).Replace("-", "")}");
+ }
+ }
}
+
}
- private void ProcessCalldataBatcherTransaction(TransactionForRpc transaction)
+ private void ProcessCalldataBatcherTransaction(Transaction transaction)
{
+ if (_logger.IsError)
+ {
+ _logger.Error($"GOT REGULAR TRANSACTION");
+ }
}
}
diff --git a/src/Nethermind/Nethermind.Optimism/CL/EthereumBeaconApi.cs b/src/Nethermind/Nethermind.Optimism/CL/EthereumBeaconApi.cs
index b70a5456843..87b33de9f8c 100644
--- a/src/Nethermind/Nethermind.Optimism/CL/EthereumBeaconApi.cs
+++ b/src/Nethermind/Nethermind.Optimism/CL/EthereumBeaconApi.cs
@@ -1,17 +1,149 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System;
+using System.Linq;
+using System.Net.Http;
+using System.Security.Cryptography;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Threading;
+using System.Threading.Tasks;
+using Nethermind.Core;
+using Nethermind.Core.Collections;
+using Nethermind.Core.Crypto;
+using Nethermind.Crypto;
+using Nethermind.Logging;
+using Nethermind.Serialization.Json;
+using Nethermind.Serialization.Rlp;
+
namespace Nethermind.Optimism.CL;
public class EthereumBeaconApi : IBeaconApi
{
- public BeaconBlock GetHead()
+ private readonly HttpClient _client;
+ private readonly IJsonSerializer _jsonSerializer;
+ private readonly CancellationToken _cancellationToken;
+ private readonly IEthereumEcdsa _ecdsa;
+ private readonly ILogger _logger;
+
+ public EthereumBeaconApi(Uri beaconApiUri, IJsonSerializer jsonSerializer, IEthereumEcdsa ecdsa, ILogger logger, CancellationToken cancellationToken)
+ {
+ _client = new HttpClient { BaseAddress = beaconApiUri };
+ _jsonSerializer = jsonSerializer;
+ _cancellationToken = cancellationToken;
+ _ecdsa = ecdsa;
+ _logger = logger;
+ }
+
+ public async Task GetHead()
+ {
+ GetBlockResponse data = await GetData("/eth/v2/beacon/blocks/head");
+ return new BeaconBlock
+ {
+ PayloadNumber = data.Data.Message.Body.ExecutionPayload.BlockNumber,
+ SlotNumber = data.Data.Message.Slot,
+ ExecutionBlockHash = data.Data.Message.Body.ExecutionPayload.BlockHash,
+ Transactions = data.Data.Message.Body.ExecutionPayload.Transactions.Select(x =>
+ {
+ // Should we remove this and use L1 EL to retrieve data?
+ var tx = Rlp.Decode(x);
+ tx.SenderAddress = _ecdsa.RecoverAddress(tx, true);
+ return tx;
+ }).ToArray()
+ };
+ }
+
+ public async Task GetFinalized()
+ {
+ GetBlockResponse data = await GetData("/eth/v2/beacon/blocks/finalized");
+ return new BeaconBlock
+ {
+ PayloadNumber = data.Data.Message.Body.ExecutionPayload.BlockNumber,
+ SlotNumber = data.Data.Message.Slot,
+ ExecutionBlockHash = data.Data.Message.Body.ExecutionPayload.BlockHash,
+ Transactions = data.Data.Message.Body.ExecutionPayload.Transactions.Select(x =>
+ {
+ // Should we remove this and use L1 EL to retrieve data?
+ var tx = Rlp.Decode(x);
+ tx.SenderAddress = _ecdsa.RecoverAddress(tx, true);
+ return tx;
+ }).ToArray()
+ };
+ }
+
+ public async Task GetBlobSidecars(ulong slot)
+ {
+ GetBlobSidecarsResponse data = await GetData($"/eth/v1/beacon/blob_sidecars/{slot}");
+ for (int i = 0; i < data.Data.Length; ++i)
+ {
+ data.Data[i].BlobVersionedHash = (new byte[]{1}).Concat(SHA256.HashData(data.Data[i].KzgCommitment)[1..]).ToArray();
+ }
+ return data.Data;
+ }
+
+ private async Task GetData(string uri)
+ {
+ HttpResponseMessage response = await _client.GetAsync(uri, _cancellationToken);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ if (_logger.IsWarn)
+ {
+ _logger.Warn($"Unsuccessful {uri} request");
+ }
+ // TODO: remove exception
+ throw new Exception($"Unsuccessful {uri} request");
+ }
+
+ if (_logger.IsDebug)
+ {
+ _logger.Debug($"GetData<{typeof(T)}({uri}) result: {await response.Content.ReadAsStringAsync(_cancellationToken)}");
+ }
+
+ T decoded =
+ _jsonSerializer.Deserialize(await response.Content.ReadAsStreamAsync(_cancellationToken));
+
+ return decoded;
+ }
+
+ // TODO: remove
+#pragma warning disable 0649
+ private struct GetBlockResponse
+ {
+ public GetBlockData Data;
+ }
+
+ // TODO: can we avoid additional structs
+ private struct GetBlockData
+ {
+ public GetBlockMessage Message;
+ }
+
+ private struct GetBlockMessage
+ {
+ public ulong Slot;
+ public GetBlockBody Body;
+ }
+
+ private struct GetBlockBody
+ {
+ [JsonPropertyName("execution_payload")]
+ public GetBlockExecutionPayload ExecutionPayload;
+ }
+
+ private struct GetBlockExecutionPayload
{
- throw new System.NotImplementedException();
+ [JsonPropertyName("block_number")]
+ public ulong BlockNumber;
+ [JsonPropertyName("block_hash")]
+ public Hash256 BlockHash;
+ public byte[][] Transactions;
}
- public BlobSidecar[] GetBlobSidecars(int slot)
+ private struct GetBlobSidecarsResponse
{
- throw new System.NotImplementedException();
+ public BlobSidecar[] Data;
}
+#pragma warning restore 0649
}
diff --git a/src/Nethermind/Nethermind.Optimism/CL/EthereumL1Bridge.cs b/src/Nethermind/Nethermind.Optimism/CL/EthereumL1Bridge.cs
index 440a34fed4e..9d19d3671c5 100644
--- a/src/Nethermind/Nethermind.Optimism/CL/EthereumL1Bridge.cs
+++ b/src/Nethermind/Nethermind.Optimism/CL/EthereumL1Bridge.cs
@@ -20,7 +20,6 @@ public class EthereumL1Bridge : IL1Bridge
public EthereumL1Bridge(IEthApi ethL1Rpc, IBeaconApi beaconApi, ICLConfig config, ILogManager logManager)
{
- ArgumentNullException.ThrowIfNull(config.L1EthApiEndpoint);
_logger = logManager.GetClassLogger();
_config = config;
_ethL1Api = ethL1Rpc;
@@ -36,23 +35,26 @@ private async void HeadUpdateLoop()
// TODO: Cancellation token
while (true)
{
- BeaconBlock beaconBlock = _beaconApi.GetHead();
+ // TODO: can we do it with subscription?
+ BeaconBlock beaconBlock = await _beaconApi.GetHead();
while (beaconBlock.SlotNumber <= _currentSlot)
{
- beaconBlock = _beaconApi.GetHead();
+ await Task.Delay(100);
+ beaconBlock = await _beaconApi.GetHead();
}
+ _logger.Error($"HEAD UPDATED: slot {beaconBlock.SlotNumber}");
// new slot
_currentSlot = beaconBlock.SlotNumber;
- BlockForRpc? block = await _ethL1Api.GetBlockByNumber(beaconBlock.PayloadNumber);
+ // BlockForRpc? block = await _ethL1Api.GetBlockByNumber(beaconBlock.PayloadNumber);
- if (block is null)
- {
- if (_logger.IsError) _logger.Error($"Unable to get L1 block");
- return;
- }
+ // if (block is null)
+ // {
+ // if (_logger.IsError) _logger.Error($"Unable to get L1 block");
+ // return;
+ // }
- OnNewL1Head?.Invoke(block, _currentSlot);
+ OnNewL1Head?.Invoke(beaconBlock, _currentSlot);
// Wait next slot
await Task.Delay(12000);
@@ -61,12 +63,14 @@ private async void HeadUpdateLoop()
public void Start()
{
+ // var res = await _beaconApi.GetHead();
+ // await _beaconApi.GetBlobSidecars(res.SlotNumber);
_headUpdateTask.Start();
}
- public event Action? OnNewL1Head;
+ public event Action? OnNewL1Head;
- public BlobSidecar[] GetBlobSidecars(int slotNumber)
+ public Task GetBlobSidecars(ulong slotNumber)
{
return _beaconApi.GetBlobSidecars(slotNumber);
}
diff --git a/src/Nethermind/Nethermind.Optimism/CL/IBeaconApi.cs b/src/Nethermind/Nethermind.Optimism/CL/IBeaconApi.cs
index f04adb13f34..5407e169bfb 100644
--- a/src/Nethermind/Nethermind.Optimism/CL/IBeaconApi.cs
+++ b/src/Nethermind/Nethermind.Optimism/CL/IBeaconApi.cs
@@ -1,25 +1,40 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+
namespace Nethermind.Optimism.CL;
public interface IBeaconApi
{
// /eth/v2/beacon/blocks/head
- BeaconBlock GetHead();
+ Task GetHead();
+
+ // /eth/v2/beacon/blocks/finalized
+ Task GetFinalized();
// /eth/v1/beacon/blob_sidecars/:slot:
- BlobSidecar[] GetBlobSidecars(int slot);
+ Task GetBlobSidecars(ulong slot);
}
public struct BeaconBlock
{
public ulong SlotNumber;
public ulong PayloadNumber;
+ public Hash256 ExecutionBlockHash;
+ public Hash256 BeaconBlockHash;
+ public Transaction[] Transactions;
}
public struct BlobSidecar
{
public byte[] Blob;
- public byte[] Kzg;
+
+ [JsonPropertyName("kzg_commitment")]
+ public byte[] KzgCommitment;
+
+ public byte[] BlobVersionedHash;
}
diff --git a/src/Nethermind/Nethermind.Optimism/CL/IL1Bridge.cs b/src/Nethermind/Nethermind.Optimism/CL/IL1Bridge.cs
index 670b151dab0..c8d1ce016dd 100644
--- a/src/Nethermind/Nethermind.Optimism/CL/IL1Bridge.cs
+++ b/src/Nethermind/Nethermind.Optimism/CL/IL1Bridge.cs
@@ -2,12 +2,13 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using System.Threading.Tasks;
using Nethermind.Facade.Eth;
namespace Nethermind.Optimism.CL;
public interface IL1Bridge
{
- event Action? OnNewL1Head;
- BlobSidecar[] GetBlobSidecars(int slotNumber);
+ event Action? OnNewL1Head;
+ Task GetBlobSidecars(ulong slotNumber);
}
diff --git a/src/Nethermind/Nethermind.Optimism/CL/OptimismCL.cs b/src/Nethermind/Nethermind.Optimism/CL/OptimismCL.cs
index 6d2b93515e3..c9e0d5d2253 100644
--- a/src/Nethermind/Nethermind.Optimism/CL/OptimismCL.cs
+++ b/src/Nethermind/Nethermind.Optimism/CL/OptimismCL.cs
@@ -6,6 +6,7 @@
using Microsoft.Extensions.DependencyInjection;
using Nethermind.Core;
using Nethermind.Core.Specs;
+using Nethermind.Crypto;
using Nethermind.Init.Steps;
using Nethermind.JsonRpc.Client;
using Nethermind.Libp2p.Protocols.Pubsub;
@@ -23,20 +24,24 @@ public class OptimismCL
private readonly Driver _driver;
private readonly IOptimismEngineRpcModule _engineRpcModule;
- public OptimismCL(ISpecProvider specProvider, ICLConfig config, IJsonSerializer jsonSerializer, ITimestamper timestamper, ILogManager logManager, IOptimismEngineRpcModule engineRpcModule)
+ public OptimismCL(ISpecProvider specProvider, ICLConfig config, IJsonSerializer jsonSerializer, IEthereumEcdsa ecdsa,
+ CancellationToken cancellationToken, ITimestamper timestamper, ILogManager logManager,
+ IOptimismEngineRpcModule engineRpcModule)
{
_logger = logManager.GetClassLogger();
_engineRpcModule = engineRpcModule;
_p2p = new OptimismCLP2P(specProvider.ChainId, timestamper, logManager, engineRpcModule);
IEthApi ethApi = new EthereumEthApi(config, jsonSerializer, logManager);
- IBeaconApi beaconApi = new EthereumBeaconApi();
+ IBeaconApi beaconApi = new EthereumBeaconApi(new Uri(config.L1BeaconApiEndpoint!), jsonSerializer, ecdsa, _logger,
+ cancellationToken);
_l1Bridge = new EthereumL1Bridge(ethApi, beaconApi, config, logManager);
- _driver = new Driver(_l1Bridge, config);
+ _driver = new Driver(_l1Bridge, config, _logger);
}
public void Start()
{
_p2p.Start();
_l1Bridge.Start();
+ _driver.Start();
}
}
diff --git a/src/Nethermind/Nethermind.Optimism/CL/IP2PBlockValidator.cs b/src/Nethermind/Nethermind.Optimism/CL/P2P/IP2PBlockValidator.cs
similarity index 100%
rename from src/Nethermind/Nethermind.Optimism/CL/IP2PBlockValidator.cs
rename to src/Nethermind/Nethermind.Optimism/CL/P2P/IP2PBlockValidator.cs
diff --git a/src/Nethermind/Nethermind.Optimism/CL/IPayloadDecoder.cs b/src/Nethermind/Nethermind.Optimism/CL/P2P/IPayloadDecoder.cs
similarity index 100%
rename from src/Nethermind/Nethermind.Optimism/CL/IPayloadDecoder.cs
rename to src/Nethermind/Nethermind.Optimism/CL/P2P/IPayloadDecoder.cs
diff --git a/src/Nethermind/Nethermind.Optimism/CL/OptimismCLP2P.cs b/src/Nethermind/Nethermind.Optimism/CL/P2P/OptimismCLP2P.cs
similarity index 90%
rename from src/Nethermind/Nethermind.Optimism/CL/OptimismCLP2P.cs
rename to src/Nethermind/Nethermind.Optimism/CL/P2P/OptimismCLP2P.cs
index 3212b25ccae..fc0d59a5fa6 100644
--- a/src/Nethermind/Nethermind.Optimism/CL/OptimismCLP2P.cs
+++ b/src/Nethermind/Nethermind.Optimism/CL/P2P/OptimismCLP2P.cs
@@ -91,7 +91,7 @@ public void Start()
proto.OnAddPeer?.Invoke(["/ip4/217.22.153.164/tcp/31660/p2p/16Uiu2HAmG5hBYavoanawCzz1cu5H7XNNSaA7BYNvwa7DNmojei6g"]);
}
- async void OnMessage(byte[] msg)
+ void OnMessage(byte[] msg)
{
int length = Snappy.GetUncompressedLength(msg);
byte[] decompressed = new byte[length];
@@ -131,15 +131,15 @@ async void OnMessage(byte[] msg)
// await Task.Delay(5000);
- var npResult = await _engineRpcModule.engine_newPayloadV3(payloadDecoded, Array.Empty(),
- payloadDecoded.ParentBeaconBlockRoot);
-
- _logger.Error($"NP RESULT {npResult.Data.Status}");
-
- var fcuResult = await _engineRpcModule.engine_forkchoiceUpdatedV3(
- new ForkchoiceStateV1(payloadDecoded.BlockHash, payloadDecoded.BlockHash, payloadDecoded.BlockHash), null);
-
- _logger.Error($"FCU RESULT {fcuResult.Data.PayloadStatus.Status}");
+ // var npResult = await _engineRpcModule.engine_newPayloadV3(payloadDecoded, Array.Empty(),
+ // payloadDecoded.ParentBeaconBlockRoot);
+ //
+ // _logger.Error($"NP RESULT {npResult.Data.Status}");
+ //
+ // var fcuResult = await _engineRpcModule.engine_forkchoiceUpdatedV3(
+ // new ForkchoiceStateV1(payloadDecoded.BlockHash, payloadDecoded.BlockHash, payloadDecoded.BlockHash), null);
+ //
+ // _logger.Error($"FCU RESULT {fcuResult.Data.PayloadStatus.Status}");
}
private MessageId CalculateMessageId(Message message)
diff --git a/src/Nethermind/Nethermind.Optimism/CL/P2PBlockValidator.cs b/src/Nethermind/Nethermind.Optimism/CL/P2P/P2PBlockValidator.cs
similarity index 100%
rename from src/Nethermind/Nethermind.Optimism/CL/P2PBlockValidator.cs
rename to src/Nethermind/Nethermind.Optimism/CL/P2P/P2PBlockValidator.cs
diff --git a/src/Nethermind/Nethermind.Optimism/CL/PayloadDecoder.cs b/src/Nethermind/Nethermind.Optimism/CL/P2P/PayloadDecoder.cs
similarity index 100%
rename from src/Nethermind/Nethermind.Optimism/CL/PayloadDecoder.cs
rename to src/Nethermind/Nethermind.Optimism/CL/P2P/PayloadDecoder.cs
diff --git a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs
index ab5b155527d..2f0f2c0135a 100644
--- a/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs
+++ b/src/Nethermind/Nethermind.Optimism/OptimismPlugin.cs
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using System.Threading;
using System.Threading.Tasks;
using Nethermind.Api;
using Nethermind.Api.Extensions;
@@ -23,6 +24,7 @@
using Nethermind.Merge.Plugin.Synchronization;
using Nethermind.Synchronization.ParallelSync;
using Nethermind.HealthChecks;
+using Nethermind.Init.Steps;
using Nethermind.Optimism.CL;
using Nethermind.Serialization.Json;
using Nethermind.Specs.ChainSpecStyle;
@@ -284,9 +286,11 @@ public async Task InitRpcModules()
_api.RpcModuleProvider.RegisterSingle(opEngine);
+ StepDependencyException.ThrowIfNull(_api.EthereumEcdsa);
+
ICLConfig clConfig = _api.Config();
- _cl = new OptimismCL(_api.SpecProvider, clConfig, _api.EthereumJsonSerializer, _api.Timestamper, _api!.LogManager, opEngine);
- _cl.Start();
+ _cl = new OptimismCL(_api.SpecProvider, clConfig, _api.EthereumJsonSerializer, _api.EthereumEcdsa, new CancellationToken(), _api.Timestamper, _api!.LogManager, opEngine);
+ // _cl.Start();
if (_logger.IsInfo) _logger.Info("Optimism Engine Module has been enabled");
}