コード例 #1
0
 public async Task StopAsync()
 {
     await(BlockchainProcessor?.StopAsync() ?? Task.CompletedTask);
     await(BlockProducer?.StopAsync() ?? Task.CompletedTask);
     await(PeerPool?.StopAsync() ?? Task.CompletedTask);
     await(Synchronizer?.StopAsync() ?? Task.CompletedTask);
     Logger?.Flush();
 }
コード例 #2
0
 public BeaconNodeApiAdapter(ILogger <BeaconNodeApiAdapter> logger,
                             BeaconNodeConfiguration beaconNodeConfiguration,
                             BlockProducer blockProducer)
 {
     _logger = logger;
     _beaconNodeConfiguration = beaconNodeConfiguration;
     _blockProducer           = blockProducer;
 }
コード例 #3
0
        public async Task AddBlock(params Transaction[] transactions)
        {
            foreach (Transaction transaction in transactions)
            {
                TxPool.AddTransaction(transaction, TxHandlingOptions.None);
            }

            Timestamper.Add(TimeSpan.FromSeconds(1));
            BlockProducer.BuildNewBlock();
            await _resetEvent.WaitOneAsync(CancellationToken.None);
        }
コード例 #4
0
        private async Task AddBlockInternal(params Transaction[] transactions)
        {
            await _oneAtATime.WaitOneAsync(CancellationToken.None);

            foreach (Transaction transaction in transactions)
            {
                TxPool.AddTransaction(transaction, TxHandlingOptions.None);
            }

            Timestamper.Add(TimeSpan.FromSeconds(1));
            BlockProducer.BuildNewBlock();
        }
コード例 #5
0
 public virtual void Dispose()
 {
     BlockProducer?.StopAsync();
     CodeDb?.Dispose();
     StateDb?.Dispose();
 }
コード例 #6
0
        private Round GenerateNextRoundOrder()
        {
            try
            {
                var infosOfNextRound = new Round();
                var signatureDict    = new Dictionary <Hash, string>();
                var orderDict        = new Dictionary <int, string>();

                var blockProducerCount = _miners.Nodes.Count;

                foreach (var node in _miners.Nodes)
                {
                    var s = this[node].Signature;
                    if (s == null)
                    {
                        s = Hash.Generate();
                    }

                    signatureDict[s] = node;
                }

                foreach (var sig in signatureDict.Keys)
                {
                    var sigNum = BitConverter.ToUInt64(
                        BitConverter.IsLittleEndian ? sig.Value.Reverse().ToArray() : sig.Value.ToArray(), 0);
                    var order = Math.Abs(GetModulus(sigNum, blockProducerCount));

                    if (orderDict.ContainsKey(order))
                    {
                        for (var i = 0; i < blockProducerCount; i++)
                        {
                            if (!orderDict.ContainsKey(i))
                            {
                                order = i;
                            }
                        }
                    }

                    orderDict.Add(order, signatureDict[sig]);
                }

                var blockTimeSlot = ExtraBlockTimeSlot;

                //Maybe because something happened with setting extra block time slot.
                if (blockTimeSlot.ToDateTime().AddMilliseconds(ConsensusConfig.Instance.DPoSMiningInterval * 1.5) <
                    GetTimestampOfUtcNow().ToDateTime())
                {
                    blockTimeSlot = GetTimestampOfUtcNow();
                }

                for (var i = 0; i < orderDict.Count; i++)
                {
                    var bpInfoNew = new BlockProducer
                    {
                        TimeSlot = GetTimestampWithOffset(blockTimeSlot,
                                                          i * ConsensusConfig.Instance.DPoSMiningInterval + ConsensusConfig.Instance.DPoSMiningInterval * 2),
                        Order = i + 1
                    };

                    infosOfNextRound.BlockProducers[orderDict[i]] = bpInfoNew;
                }

                infosOfNextRound.RoundNumber = CurrentRoundNumber.Value + 1;

                return(infosOfNextRound);
            }
            catch (Exception e)
            {
                _logger?.Error(e, "Failed to generate info of next round");
                return(new Round());
            }
        }
コード例 #7
0
        public AElfDPoSInformation GenerateInfoForFirstTwoRounds()
        {
            var dict = new Dictionary <string, int>();

            // First round
            foreach (var node in _miners.Nodes)
            {
                dict.Add(node, node[0]);
            }

            var sortedMiningNodes =
                from obj in dict
                orderby obj.Value descending
                select obj.Key;

            var enumerable = sortedMiningNodes.ToList();

            var infosOfRound1 = new Round();

            var selected = _miners.Nodes.Count / 2;

            for (var i = 0; i < enumerable.Count; i++)
            {
                var bpInfo = new BlockProducer {
                    IsEBP = false
                };

                if (i == selected)
                {
                    bpInfo.IsEBP = true;
                }

                bpInfo.Order     = i + 1;
                bpInfo.Signature = Hash.Generate();
                bpInfo.TimeSlot  =
                    GetTimestampOfUtcNow(i * ConsensusConfig.Instance.DPoSMiningInterval + GlobalConfig.AElfWaitFirstRoundTime);

                infosOfRound1.BlockProducers.Add(enumerable[i], bpInfo);
            }

            // Second round
            dict = new Dictionary <string, int>();

            foreach (var node in _miners.Nodes)
            {
                dict.Add(node, node[0]);
            }

            sortedMiningNodes =
                from obj in dict
                orderby obj.Value descending
                select obj.Key;

            enumerable = sortedMiningNodes.ToList();

            var infosOfRound2 = new Round();

            var addition = enumerable.Count * ConsensusConfig.Instance.DPoSMiningInterval + ConsensusConfig.Instance.DPoSMiningInterval;

            selected = _miners.Nodes.Count / 2;
            for (var i = 0; i < enumerable.Count; i++)
            {
                var bpInfo = new BlockProducer {
                    IsEBP = false
                };

                if (i == selected)
                {
                    bpInfo.IsEBP = true;
                }

                bpInfo.TimeSlot = GetTimestampOfUtcNow(i * ConsensusConfig.Instance.DPoSMiningInterval + addition +
                                                       GlobalConfig.AElfWaitFirstRoundTime);
                bpInfo.Order = i + 1;

                infosOfRound2.BlockProducers.Add(enumerable[i], bpInfo);
            }

            infosOfRound1.RoundNumber = 1;
            infosOfRound2.RoundNumber = 2;

            var dPoSInfo = new AElfDPoSInformation
            {
                Rounds = { infosOfRound1, infosOfRound2 }
            };

            return(dPoSInfo);
        }
コード例 #8
0
        public async Task BasicNewBlock()
        {
            // Arrange
            int numberOfValidators = 64;
            int genesisTime        = 1578009600;
            IServiceCollection testServiceCollection = TestSystem.BuildTestServiceCollection(useStore: true);
            IConfigurationRoot configuration         = new ConfigurationBuilder()
                                                       .AddInMemoryCollection(new Dictionary <string, string>
            {
                ["QuickStart:ValidatorCount"] = $"{numberOfValidators}",
                ["QuickStart:GenesisTime"]    = $"{genesisTime}"
            })
                                                       .Build();

            testServiceCollection.AddBeaconNodeQuickStart(configuration);
            testServiceCollection.AddBeaconNodeEth1Bridge(configuration);
            testServiceCollection.AddSingleton <IHostEnvironment>(Substitute.For <IHostEnvironment>());
            ServiceProvider testServiceProvider = testServiceCollection.BuildServiceProvider();

            Eth1BridgeWorker eth1BridgeWorker =
                testServiceProvider.GetServices <IHostedService>().OfType <Eth1BridgeWorker>().First();
            await eth1BridgeWorker.ExecuteEth1GenesisAsync(CancellationToken.None);

            IBeaconNodeApi     beaconNode   = testServiceProvider.GetService <IBeaconNodeApi>();
            ApiResponse <Fork> forkResponse = await beaconNode.GetNodeForkAsync(CancellationToken.None);

            Fork fork = forkResponse.Content;

            fork.CurrentVersion.ShouldBe(new ForkVersion(new byte[4] {
                0x00, 0x00, 0x00, 0x01
            }));

            // Act
            BlockProducer blockProducer = testServiceProvider.GetService <BlockProducer>();
            Slot          targetSlot    = new Slot(1);

            // With QuickStart64, proposer for Slot 1 is validator index 29, 0xa98ed496...
            QuickStartMockEth1GenesisProvider quickStartMockEth1GenesisProvider = (QuickStartMockEth1GenesisProvider)testServiceProvider.GetService <IEth1GenesisProvider>();

            byte[]       privateKey   = quickStartMockEth1GenesisProvider.GeneratePrivateKey(29);
            BlsSignature randaoReveal = GetEpochSignature(testServiceProvider, privateKey, fork.CurrentVersion, targetSlot);

            // value for quickstart 20/64, fork 0, slot 1
            randaoReveal.ToString().StartsWith("0x932f8730");
            BeaconBlock newBlock = await blockProducer.NewBlockAsync(targetSlot, randaoReveal, CancellationToken.None);

            // Assert
            newBlock.Slot.ShouldBe(targetSlot);
            newBlock.Body.RandaoReveal.ShouldBe(randaoReveal);

            newBlock.ParentRoot.ToString().ShouldStartWith("0x4d4e9a16");

            newBlock.Body.Eth1Data.DepositCount.ShouldBe((ulong)numberOfValidators);

            newBlock.Body.Eth1Data.DepositRoot.ToString().ShouldStartWith("0x66687aad");

            newBlock.StateRoot.ToString().ShouldStartWith("0x0138b69f");

            newBlock.Body.Attestations.Count.ShouldBe(0);
            newBlock.Body.Deposits.Count.ShouldBe(0);
        }
コード例 #9
0
        protected virtual async Task <TestBlockchain> Build(ISpecProvider specProvider = null, UInt256?initialValues = null)
        {
            Timestamper    = new ManualTimestamper(new DateTime(2020, 2, 15, 12, 50, 30, DateTimeKind.Utc));
            JsonSerializer = new EthereumJsonSerializer();
            SpecProvider   = specProvider ?? MainnetSpecProvider.Instance;
            EthereumEcdsa  = new EthereumEcdsa(ChainId.Mainnet, LogManager);
            ITxStorage txStorage = new InMemoryTxStorage();

            DbProvider = await TestMemDbProvider.InitAsync();

            TrieStore = new TrieStore(StateDb.Innermost, LogManager);
            State     = new StateProvider(TrieStore, DbProvider.CodeDb, LogManager);
            State.CreateAccount(TestItem.AddressA, (initialValues ?? InitialValue));
            State.CreateAccount(TestItem.AddressB, (initialValues ?? InitialValue));
            State.CreateAccount(TestItem.AddressC, (initialValues ?? InitialValue));
            byte[] code     = Bytes.FromHexString("0xabcd");
            Keccak codeHash = Keccak.Compute(code);

            State.UpdateCode(code);
            State.UpdateCodeHash(TestItem.AddressA, codeHash, SpecProvider.GenesisSpec);

            Storage = new StorageProvider(TrieStore, State, LogManager);
            Storage.Set(new StorageCell(TestItem.AddressA, UInt256.One), Bytes.FromHexString("0xabcdef"));
            Storage.Commit();

            State.Commit(SpecProvider.GenesisSpec);
            State.CommitTree(0);



            IDb blockDb     = new MemDb();
            IDb headerDb    = new MemDb();
            IDb blockInfoDb = new MemDb();

            BlockTree = new BlockTree(blockDb, headerDb, blockInfoDb, new ChainLevelInfoRepository(blockInfoDb), SpecProvider, NullBloomStorage.Instance, LimboLogs.Instance);
            TransactionComparerProvider = new TransactionComparerProvider(specProvider, BlockTree);
            TxPool = CreateTxPool(txStorage);

            new OnChainTxWatcher(BlockTree, TxPool, SpecProvider, LimboLogs.Instance);

            ReceiptStorage = new InMemoryReceiptStorage();
            VirtualMachine virtualMachine = new VirtualMachine(State, Storage, new BlockhashProvider(BlockTree, LogManager), SpecProvider, LogManager);

            TxProcessor           = new TransactionProcessor(SpecProvider, State, Storage, virtualMachine, LogManager);
            BlockProcessor        = CreateBlockProcessor();
            BlockPreprocessorStep = new RecoverSignatures(EthereumEcdsa, TxPool, SpecProvider, LogManager);
            BlockchainProcessor chainProcessor = new BlockchainProcessor(BlockTree, BlockProcessor, BlockPreprocessorStep, LogManager, Nethermind.Blockchain.Processing.BlockchainProcessor.Options.Default);

            BlockchainProcessor  = chainProcessor;
            BlockProcessingQueue = chainProcessor;
            chainProcessor.Start();

            ReadOnlyTrieStore = TrieStore.AsReadOnly();

            StateReader = new StateReader(ReadOnlyTrieStore, CodeDb, LogManager);
            TxPoolTxSource txPoolTxSource        = CreateTxPoolTxSource();
            ISealer        sealer                = new NethDevSealEngine(TestItem.AddressD);
            IStateProvider producerStateProvider = new StateProvider(ReadOnlyTrieStore, CodeDb, LogManager);

            BlockProducer = CreateTestBlockProducer(txPoolTxSource, chainProcessor, producerStateProvider, sealer);
            BlockProducer.Start();

            _resetEvent = new SemaphoreSlim(0);
            _suggestedBlockResetEvent = new ManualResetEvent(true);
            BlockTree.NewHeadBlock   += (s, e) =>
            {
                _resetEvent.Release(1);
            };
            BlockProducer.LastProducedBlockChanged += (s, e) =>
            {
                _suggestedBlockResetEvent.Set();
            };

            var genesis = GetGenesisBlock();

            BlockTree.SuggestBlock(genesis);
            await _resetEvent.WaitAsync();

            //if (!await _resetEvent.WaitAsync(1000))
            // {
            //     throw new InvalidOperationException("Failed to process genesis in 1s.");
            // }

            await AddBlocksOnStart();

            return(this);
        }
コード例 #10
0
        public async Task BasicNewBlock()
        {
            // Arrange
            int numberOfValidators = 64;
            int genesisTime        = 1578009600;
            IServiceCollection testServiceCollection = TestSystem.BuildTestServiceCollection(useStore: true);
            IConfigurationRoot configuration         = new ConfigurationBuilder()
                                                       .AddInMemoryCollection(new Dictionary <string, string>
            {
                ["QuickStart:ValidatorCount"] = $"{numberOfValidators}",
                ["QuickStart:GenesisTime"]    = $"{genesisTime}"
            })
                                                       .Build();

            testServiceCollection.AddBeaconNodeQuickStart(configuration);
            testServiceCollection.AddSingleton <IHostEnvironment>(Substitute.For <IHostEnvironment>());
            ServiceProvider testServiceProvider = testServiceCollection.BuildServiceProvider();

            QuickStart quickStart = (QuickStart)testServiceProvider.GetService <INodeStart>();
            await quickStart.InitializeNodeAsync();

            IBeaconNodeApi beaconNode = testServiceProvider.GetService <IBeaconNodeApi>();

            Core2.Containers.Fork fork = await beaconNode.GetNodeForkAsync(CancellationToken.None);

            fork.CurrentVersion.ShouldBe(new ForkVersion());

            // Act
            BlockProducer blockProducer = testServiceProvider.GetService <BlockProducer>();
            Slot          targetSlot    = new Slot(1);

            // With QuickStart64, proposer for Slot 1 is validator index 20, 0xa1c76af1...
            byte[]       privateKey   = quickStart.GeneratePrivateKey(20);
            BlsSignature randaoReveal = GetEpochSignature(testServiceProvider, privateKey, fork.CurrentVersion, targetSlot);

            // value for quickstart 20/64, fork 0, slot 1
            randaoReveal.ToString().ShouldBe("0xa3426b6391a29c88f2280428d5fdae9e20f4c75a8d38d0714e3aa5b9e55594dbd555c4bc685191e83d39158c3be9744d06adc34b21d2885998a206e3b3fd435eab424cf1c01b8fd562deb411348a601e83d7332d8774d1fd3bf8b88d7a33c67c");
            BeaconBlock newBlock = await blockProducer.NewBlockAsync(targetSlot, randaoReveal);

            // Assert
            newBlock.Slot.ShouldBe(targetSlot);
            newBlock.Body.RandaoReveal.ShouldBe(randaoReveal);

            Hash32 expectedParentRoot = new Hash32("0x91b06cbcd6dc97b89dc8b95e0b01a497932683b182e6c722ddfa10cd005b2180");

            newBlock.ParentRoot.ShouldBe(expectedParentRoot);

            newBlock.Body.Eth1Data.DepositCount.ShouldBe((ulong)numberOfValidators);

            Hash32 expectedEth1DataDepositRoot = new Hash32("0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925");

            newBlock.Body.Eth1Data.DepositRoot.ShouldBe(expectedEth1DataDepositRoot);

            Hash32 expectedStateRoot = new Hash32("0xe05ccf6347cac0b0dab0ad0d5c941fe7c7e2ed4c69550ed9a628bc9d62914242");

            newBlock.StateRoot.ShouldBe(expectedStateRoot);

            newBlock.Signature.ShouldBe(new BlsSignature(new byte[96])); // signature should be empty

            newBlock.Body.Attestations.Count.ShouldBe(0);
            newBlock.Body.Deposits.Count.ShouldBe(0);
        }
コード例 #11
0
ファイル: AElfDPoSObserver.cs プロジェクト: wyk125/AElf
        public IDisposable SubscribeAElfDPoSMiningProcess(BlockProducer infoOfMe, Timestamp extraBlockTimeSlot)
        {
//            _logger?.Trace("Extra block time slot of current round: " +
//                           extraBlockTimeSlot.ToDateTime().ToLocalTime().ToString("HH:mm:ss"));
//            if (extraBlockTimeSlot.ToDateTime() < DateTime.UtcNow)
//            {
//                extraBlockTimeSlot = extraBlockTimeSlot.ToDateTime()
//                    .AddMilliseconds(GlobalConfig.AElfDPoSMiningInterval * (GlobalConfig.BlockProducerNumber + 2))
//                    .ToTimestamp();
//                _logger?.Trace("Extra block time slot changed to: " +
//                               extraBlockTimeSlot.ToDateTime().ToString("HH:mm:ss"));
//            }

            var nopObservable = Observable
                                .Timer(TimeSpan.FromSeconds(0))
                                .Select(_ => ConsensusBehavior.NoOperationPerformed);

            var timeSlot = infoOfMe.TimeSlot;
            var now      = DateTime.UtcNow.ToTimestamp();
            var distanceToProduceNormalBlock = (timeSlot - now).Seconds;

            IObservable <ConsensusBehavior> produceNormalBlock;

            if (distanceToProduceNormalBlock >= 0)
            {
                produceNormalBlock = Observable
                                     .Timer(TimeSpan.FromSeconds(distanceToProduceNormalBlock))
                                     .Select(_ => ConsensusBehavior.PublishOutValueAndSignature);

                if (distanceToProduceNormalBlock >= 0)
                {
                    _logger?.Trace($"Will produce normal block after {distanceToProduceNormalBlock} seconds");
                }
            }
            else
            {
                distanceToProduceNormalBlock = 0;
                produceNormalBlock           = nopObservable;
            }

            var distanceToPublishInValue = (extraBlockTimeSlot - now).Seconds;

            IObservable <ConsensusBehavior> publishInValue;

            if (distanceToPublishInValue >= 0)
            {
                var after = distanceToPublishInValue - distanceToProduceNormalBlock;
                publishInValue = Observable
                                 .Timer(TimeSpan.FromSeconds(after))
                                 .Select(_ => ConsensusBehavior.PublishInValue);

                if (distanceToPublishInValue >= 0)
                {
                    _logger?.Trace($"Will publish in value after {distanceToPublishInValue} seconds");
                }
            }
            else
            {
                publishInValue = nopObservable;
            }

            IObservable <ConsensusBehavior> produceExtraBlock;

            if (distanceToPublishInValue < 0 && GlobalConfig.BlockProducerNumber != 1)
            {
                produceExtraBlock = nopObservable;
                if (GlobalConfig.BlockProducerNumber != 1)
                {
                    produceExtraBlock = nopObservable;
                }
            }
            else if (infoOfMe.IsEBP)
            {
                var after = distanceToPublishInValue + ConsensusConfig.Instance.DPoSMiningInterval / 1000;
                produceExtraBlock = Observable
                                    .Timer(TimeSpan.FromMilliseconds(ConsensusConfig.Instance.DPoSMiningInterval))
                                    .Select(_ => ConsensusBehavior.UpdateAElfDPoS);

                if (after >= 0)
                {
                    _logger?.Trace($"Will produce extra block after {after} seconds");
                }
            }
            else
            {
                var after = distanceToPublishInValue + ConsensusConfig.Instance.DPoSMiningInterval / 1000 +
                            ConsensusConfig.Instance.DPoSMiningInterval * infoOfMe.Order / 1000 +
                            ConsensusConfig.Instance.DPoSMiningInterval / 750;
                produceExtraBlock = Observable
                                    .Timer(TimeSpan.FromMilliseconds(ConsensusConfig.Instance.DPoSMiningInterval +
                                                                     ConsensusConfig.Instance.DPoSMiningInterval * infoOfMe.Order +
                                                                     ConsensusConfig.Instance.DPoSMiningInterval / 2))
                                    .Select(_ => ConsensusBehavior.UpdateAElfDPoS);

                if (after >= 0)
                {
                    _logger?.Trace($"Will help to produce extra block after {after} seconds");
                }
            }

            return(Observable.Return(ConsensusBehavior.NoOperationPerformed)
                   .Concat(produceNormalBlock)
                   .Concat(publishInValue)
                   .Concat(produceExtraBlock)
                   .SubscribeOn(NewThreadScheduler.Default)
                   .Subscribe(this));
        }
コード例 #12
0
        public async Task BasicNewBlock()
        {
            // Arrange
            int numberOfValidators = 64;
            int genesisTime        = 1578009600;
            IServiceCollection testServiceCollection = TestSystem.BuildTestServiceCollection(useStore: true);
            IConfigurationRoot configuration         = new ConfigurationBuilder()
                                                       .AddInMemoryCollection(new Dictionary <string, string>
            {
                ["QuickStart:ValidatorCount"] = $"{numberOfValidators}",
                ["QuickStart:GenesisTime"]    = $"{genesisTime}"
            })
                                                       .Build();

            testServiceCollection.AddQuickStart(configuration);
            testServiceCollection.AddSingleton <IHostEnvironment>(Substitute.For <IHostEnvironment>());
            ServiceProvider testServiceProvider = testServiceCollection.BuildServiceProvider();

            QuickStart quickStart = (QuickStart)testServiceProvider.GetService <INodeStart>();
            await quickStart.InitializeNodeAsync();

            IBeaconNodeApi beaconNode = testServiceProvider.GetService <IBeaconNodeApi>();

            Core2.Containers.Fork fork = await beaconNode.GetNodeForkAsync();

            fork.CurrentVersion.ShouldBe(new ForkVersion());

            // Act
            BlockProducer blockProducer = testServiceProvider.GetService <BlockProducer>();
            Slot          targetSlot    = new Slot(1);

            // With QuickStart64, proposer for Slot 1 is validator index 20, 0xa1c76af1...
            byte[]       privateKey   = quickStart.GeneratePrivateKey(20);
            BlsSignature randaoReveal = GetEpochSignature(testServiceProvider, privateKey, fork.CurrentVersion, targetSlot);

            // value for quickstart 20/64, fork 0, slot 1
            randaoReveal.ToString().ShouldBe("0xa3426b6391a29c88f2280428d5fdae9e20f4c75a8d38d0714e3aa5b9e55594dbd555c4bc685191e83d39158c3be9744d06adc34b21d2885998a206e3b3fd435eab424cf1c01b8fd562deb411348a601e83d7332d8774d1fd3bf8b88d7a33c67c");
            BeaconBlock newBlock = await blockProducer.NewBlockAsync(targetSlot, randaoReveal);

            // Assert
            newBlock.Slot.ShouldBe(targetSlot);
            newBlock.Body.RandaoReveal.ShouldBe(randaoReveal);

            Hash32 expectedParentRoot = new Hash32(Bytes.FromHexString("0x3111350140726cc0501223143ae5c7baad7f5a06764fcc7d444a657016e7d616"));

            newBlock.ParentRoot.ShouldBe(expectedParentRoot);

            newBlock.Body.Eth1Data.DepositCount.ShouldBe((ulong)numberOfValidators);

            Hash32 expectedEth1DataDepositRoot = new Hash32(Bytes.FromHexString("0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925"));

            newBlock.Body.Eth1Data.DepositRoot.ShouldBe(expectedEth1DataDepositRoot);

            Hash32 expectedStateRoot = new Hash32(Bytes.FromHexString("0x9c7d3e5180f95175691511fd56f8a610299f0b5a682b6fe178230493d74f6d13"));

            newBlock.StateRoot.ShouldBe(expectedStateRoot);

            newBlock.Signature.ShouldBe(new BlsSignature(new byte[96])); // signature should be empty

            newBlock.Body.Attestations.Count.ShouldBe(0);
            newBlock.Body.Deposits.Count.ShouldBe(0);
        }