public async Task <BeaconBlock> NewBlockAsync(Slot slot, BlsSignature randaoReveal, CancellationToken cancellationToken) { if (slot == Slot.Zero) { throw new ArgumentException("Can't generate new block for slot 0, as it is the genesis block."); } Slot previousSlot = slot - Slot.One; Root head = await _forkChoice.GetHeadAsync(_store).ConfigureAwait(false); BeaconBlock headBeaconBlock = (await _store.GetSignedBlockAsync(head).ConfigureAwait(false)).Message; BeaconState parentState; Root parentRoot; if (headBeaconBlock !.Slot > previousSlot) { // Requesting a block for a past slot? Root ancestorRoot = await _forkChoice.GetAncestorAsync(_store, head, previousSlot).ConfigureAwait(false); parentState = await _store.GetBlockStateAsync(ancestorRoot).ConfigureAwait(false); parentRoot = ancestorRoot; }
private static BlsSignature DecodeBlsSignature(Span <byte> span, ref int offset) { BlsSignature blsSignature = DecodeBlsSignature(span.Slice(offset, BlsSignature.SszLength)); offset += BlsSignature.SszLength; return(blsSignature); }
public DepositData(BlsPublicKey publicKey, Bytes32 withdrawalCredentials, Gwei amount, BlsSignature signature) { PublicKey = publicKey; WithdrawalCredentials = withdrawalCredentials; Amount = amount; Signature = signature; // Signing over DepositMessage }
private static SignedVoluntaryExit DecodeSignedVoluntaryExit(ReadOnlySpan <byte> span, ref int offset) { VoluntaryExit message = DecodeVoluntaryExit(span, ref offset); BlsSignature signature = DecodeBlsSignature(span, ref offset); return(new SignedVoluntaryExit(message, signature)); }
// ReSharper disable once InconsistentNaming // ReSharper disable once IdentifierTypo public async Task <IActionResult> GetAsync([FromQuery] ulong slot, [FromQuery] byte[] randao_reveal, CancellationToken cancellationToken) { if (_logger.IsInfo()) { Log.NewBlockRequested(_logger, slot, Bytes.ToHexString(randao_reveal), null); } Slot targetSlot = new Slot(slot); BlsSignature randaoReveal = new BlsSignature(randao_reveal); ApiResponse <BeaconBlock> apiResponse = await _beaconNode.NewBlockAsync(targetSlot, randaoReveal, cancellationToken).ConfigureAwait(false); switch (apiResponse.StatusCode) { case Core2.Api.StatusCode.Success: return(Ok(apiResponse.Content)); case Core2.Api.StatusCode.InvalidRequest: return(Problem("Invalid request syntax.", statusCode: (int)apiResponse.StatusCode)); case Core2.Api.StatusCode.CurrentlySyncing: return(Problem("Beacon node is currently syncing, try again later.", statusCode: (int)apiResponse.StatusCode)); } return(Problem("Beacon node internal error.", statusCode: (int)apiResponse.StatusCode)); }
private static SignedBeaconBlockHeader DecodeSignedBeaconBlockHeader(ReadOnlySpan <byte> span, ref int offset) { BeaconBlockHeader message = DecodeBeaconBlockHeader(span, ref offset); BlsSignature signature = DecodeBlsSignature(span, ref offset); return(new SignedBeaconBlockHeader(message, signature)); }
private static BlsSignature DecodeBlsSignature(ReadOnlySpan <byte> span, ref int offset) { BlsSignature blsSignature = DecodeBlsSignature(span.Slice(offset, Ssz.BlsSignatureLength)); offset += Ssz.BlsSignatureLength; return(blsSignature); }
public static void SignDepositData(IServiceProvider testServiceProvider, DepositData depositData, byte[] privateKey, BeaconState?state) { SignatureDomains signatureDomains = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value; BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>(); Domain domain; if (state == null) { // Genesis domain = beaconChainUtility.ComputeDomain(signatureDomains.Deposit); } else { BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); domain = beaconStateAccessor.GetDomain(state, signatureDomains.Deposit, Epoch.None); } DepositMessage depositMessage = new DepositMessage(depositData.PublicKey, depositData.WithdrawalCredentials, depositData.Amount); Root depositMessageRoot = cryptographyService.HashTreeRoot(depositMessage); Root signingRoot = beaconChainUtility.ComputeSigningRoot(depositMessageRoot, domain); BlsSignature signature = TestSecurity.BlsSign(signingRoot, privateKey); depositData.SetSignature(signature); }
public async Task <ApiResponse <BeaconBlock> > NewBlockAsync(Slot slot, BlsSignature randaoReveal, CancellationToken cancellationToken) { string baseUri = "validator/block"; Dictionary <string, string> queryParameters = new Dictionary <string, string> { ["slot"] = slot.ToString(), ["randao_reveal"] = randaoReveal.ToString() }; string uri = QueryHelpers.AddQueryString(baseUri, queryParameters); using HttpResponseMessage httpResponse = await _httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead, cancellationToken); int statusCode = (int)httpResponse.StatusCode; if (statusCode == (int)StatusCode.InvalidRequest || statusCode == (int)StatusCode.CurrentlySyncing) { return(ApiResponse.Create <BeaconBlock>((StatusCode)statusCode)); } httpResponse.EnsureSuccessStatusCode(); // throws if not 200-299 await using Stream contentStream = await httpResponse.Content.ReadAsStreamAsync(); BeaconBlock content = await JsonSerializer.DeserializeAsync <BeaconBlock>(contentStream, _jsonSerializerOptions, cancellationToken); return(ApiResponse.Create((StatusCode)statusCode, content)); }
public BlsSignature GetBlockSignature(BeaconBlock block, BlsPublicKey blsPublicKey) { Fork fork = _beaconChainInformation.Fork; Epoch epoch = ComputeEpochAtSlot(block.Slot); ForkVersion forkVersion; if (epoch < fork.Epoch) { forkVersion = fork.PreviousVersion; } else { forkVersion = fork.CurrentVersion; } DomainType domainType = _signatureDomainOptions.CurrentValue.BeaconProposer; Domain proposerDomain = ComputeDomain(domainType, forkVersion); /* * JsonSerializerOptions options = new System.Text.Json.JsonSerializerOptions { WriteIndented = true }; * options.ConfigureNethermindCore2(); * string blockJson = System.Text.Json.JsonSerializer.Serialize(block, options); */ Root blockRoot = _cryptographyService.HashTreeRoot(block); Root signingRoot = ComputeSigningRoot(blockRoot, proposerDomain); BlsSignature signature = _validatorKeyProvider.SignRoot(blsPublicKey, signingRoot); return(signature); }
public BlsSignature GetEpochSignature(Slot slot, BlsPublicKey blsPublicKey) { Fork fork = _beaconChainInformation.Fork; Epoch epoch = ComputeEpochAtSlot(slot); ForkVersion forkVersion; if (epoch < fork.Epoch) { forkVersion = fork.PreviousVersion; } else { forkVersion = fork.CurrentVersion; } DomainType domainType = _signatureDomainOptions.CurrentValue.Randao; Domain randaoDomain = ComputeDomain(domainType, forkVersion); Root epochRoot = _cryptographyService.HashTreeRoot(epoch); Root signingRoot = ComputeSigningRoot(epochRoot, randaoDomain); BlsSignature randaoReveal = _validatorKeyProvider.SignRoot(blsPublicKey, signingRoot); return(randaoReveal); }
public async Task <BlsSignature> GetAttestationSignatureAsync(Attestation unsignedAttestation, BlsPublicKey blsPublicKey) { Fork fork = _beaconChainInformation.Fork; Epoch epoch = ComputeEpochAtSlot(unsignedAttestation.Data.Slot); ForkVersion forkVersion; if (epoch < fork.Epoch) { forkVersion = fork.PreviousVersion; } else { forkVersion = fork.CurrentVersion; } DomainType domainType = _signatureDomainOptions.CurrentValue.BeaconAttester; (DomainType domainType, ForkVersion forkVersion)cacheKey = (domainType, forkVersion); Domain attesterDomain = await _cache.GetOrCreateAsync(cacheKey, entry => { return(Task.FromResult(ComputeDomain(domainType, forkVersion))); }).ConfigureAwait(false); Root attestationDataRoot = _cryptographyService.HashTreeRoot(unsignedAttestation.Data); Root signingRoot = ComputeSigningRoot(attestationDataRoot, attesterDomain); BlsSignature signature = _validatorKeyProvider.SignRoot(blsPublicKey, signingRoot); return(signature); }
public async Task <BeaconBlock> NewBlockAsync(Slot slot, BlsSignature randaoReveal) { if (slot == Slot.Zero) { throw new ArgumentException("Can't generate new block for slot 0, as it is the genesis block."); } if (!_storeProvider.TryGetStore(out IStore? retrievedStore)) { throw new Exception("Beacon chain is currently syncing or waiting for genesis."); } IStore store = retrievedStore !; Slot previousSlot = slot - Slot.One; Hash32 head = await _forkChoice.GetHeadAsync(store).ConfigureAwait(false); BeaconBlock headBlock = await store.GetBlockAsync(head).ConfigureAwait(false); BeaconBlock parentBlock; BeaconState parentState; Hash32 parentRoot; if (headBlock !.Slot > previousSlot) { // Requesting a block for a past slot? Hash32 ancestorSigningRoot = await _forkChoice.GetAncestorAsync(store, head, previousSlot); parentBlock = await store.GetBlockAsync(ancestorSigningRoot).ConfigureAwait(false); parentState = await store.GetBlockStateAsync(ancestorSigningRoot).ConfigureAwait(false); parentRoot = ancestorSigningRoot; }
public DepositData(BlsPublicKey publicKey, Hash32 withdrawalCredentials, Gwei amount) { PublicKey = publicKey; WithdrawalCredentials = withdrawalCredentials; Amount = amount; Signature = new BlsSignature(); }
public Attestation(BitArray aggregationBits, AttestationData data, BitArray custodyBits, BlsSignature signature) { AggregationBits = aggregationBits; Data = data; CustodyBits = custodyBits; Signature = signature; }
public async Task ProcessProposalDutiesAsync(Slot slot, CancellationToken cancellationToken) { // If proposer, get block, sign block, return to node // Retry if not successful; need to queue this up to send immediately if connection issue. (or broadcast?) BlsPublicKey?blsPublicKey = _validatorState.GetProposalDutyForSlot(slot); if (!(blsPublicKey is null)) { if (_logger.IsInfo()) { Log.ProposalDutyFor(_logger, slot, blsPublicKey, null); } BlsSignature randaoReveal = GetEpochSignature(slot, blsPublicKey); if (_logger.IsDebug()) { LogDebug.RequestingBlock(_logger, slot, blsPublicKey.ToShortString(), randaoReveal.ToString().Substring(0, 10), null); } BeaconBlock unsignedBlock = await _beaconNodeApi.NewBlockAsync(slot, randaoReveal, cancellationToken).ConfigureAwait(false); BeaconBlock signedBlock = SignBlock(unsignedBlock, blsPublicKey); if (_logger.IsDebug()) { LogDebug.PublishingSignedBlock(_logger, slot, blsPublicKey.ToShortString(), randaoReveal.ToString().Substring(0, 10), signedBlock, signedBlock.Signature.ToString().Substring(0, 10), null); } bool nodeAccepted = await _beaconNodeApi.PublishBlockAsync(signedBlock, cancellationToken).ConfigureAwait(false); _validatorState.ClearProposalDutyForSlot(slot); } }
public BeaconBlock(Hash32 genesisStateRoot) { Slot = new Slot(0); ParentRoot = Hash32.Zero; StateRoot = genesisStateRoot; Body = new BeaconBlockBody(); Signature = new BlsSignature(); }
public static void SignAttestation(IServiceProvider testServiceProvider, BeaconState state, Attestation attestation) { BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); IReadOnlyList <ValidatorIndex> participants = beaconStateAccessor.GetAttestingIndices(state, attestation.Data, attestation.AggregationBits); BlsSignature signature = SignAggregateAttestation(testServiceProvider, state, attestation.Data, participants); attestation.SetSignature(signature); }
public IndexedAttestation( IEnumerable <ValidatorIndex> attestingIndices, AttestationData data, BlsSignature signature) { _attestingIndices = new List <ValidatorIndex>(attestingIndices); Data = data; Signature = signature; }
public bool BlsVerify(BlsPublicKey publicKey, Hash32 messageHash, BlsSignature signature, Domain domain) { var blsParameters = new BLSParameters() { PublicKey = publicKey.AsSpan().ToArray() }; using var signatureAlgorithm = SignatureAlgorithmFactory(blsParameters); return(signatureAlgorithm.VerifyHash(messageHash.AsSpan(), signature.AsSpan(), domain.AsSpan())); }
public bool BlsVerify(BlsPublicKey publicKey, Root signingRoot, BlsSignature signature) { BLSParameters blsParameters = new BLSParameters() { PublicKey = publicKey.AsSpan().ToArray() }; using BLS signatureAlgorithm = SignatureAlgorithmFactory(blsParameters); return(signatureAlgorithm.VerifyHash(signingRoot.AsSpan(), signature.AsSpan())); }
public static void SignBlock(IServiceProvider testServiceProvider, BeaconState state, BeaconBlock block, ValidatorIndex proposerIndex) { MiscellaneousParameters miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value; TimeParameters timeParameters = testServiceProvider.GetService <IOptions <TimeParameters> >().Value; MaxOperationsPerBlock maxOperationsPerBlock = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value; SignatureDomains signatureDomains = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value; ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>(); BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>(); if (state.Slot > block.Slot) { throw new ArgumentOutOfRangeException("block.Slot", block.Slot, $"Slot of block must be equal or less that state slot {state.Slot}"); } Epoch blockEpoch = beaconChainUtility.ComputeEpochAtSlot(block.Slot); if (proposerIndex == ValidatorIndex.None) { if (block.Slot == state.Slot) { proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(state); } else { Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot); if (stateEpoch + 1 > blockEpoch) { Console.WriteLine("WARNING: Block slot far away, and no proposer index manually given." + " Signing block is slow due to transition for proposer index calculation."); } // use stub state to get proposer index of future slot BeaconState stubState = BeaconState.Clone(state); beaconStateTransition.ProcessSlots(stubState, block.Slot); proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(stubState); } } byte[][] privateKeys = TestKeys.PrivateKeys(timeParameters).ToArray(); byte[] privateKey = privateKeys[(int)(ulong)proposerIndex]; Domain randaoDomain = beaconStateAccessor.GetDomain(state, signatureDomains.Randao, blockEpoch); Hash32 randaoRevealHash = blockEpoch.HashTreeRoot(); BlsSignature randaoReveal = TestSecurity.BlsSign(randaoRevealHash, privateKey, randaoDomain); block.Body.SetRandaoReveal(randaoReveal); Domain signatureDomain = beaconStateAccessor.GetDomain(state, signatureDomains.BeaconProposer, blockEpoch); Hash32 signingRoot = cryptographyService.SigningRoot(block); BlsSignature signature = TestSecurity.BlsSign(signingRoot, privateKey, signatureDomain); block.SetSignature(signature); }
public IndexedAttestation( IEnumerable <ValidatorIndex> custodyBit0Indices, IEnumerable <ValidatorIndex> custodyBit1Indices, AttestationData data, BlsSignature signature) { _custodyBit0Indices = new List <ValidatorIndex>(custodyBit0Indices); _custodyBit1Indices = new List <ValidatorIndex>(custodyBit1Indices); Data = data; Signature = signature; }
public BeaconBlock(Slot slot, Hash32 parentRoot, Hash32 stateRoot, BeaconBlockBody body, BlsSignature signature) { Slot = slot; ParentRoot = parentRoot; StateRoot = stateRoot; Body = body; Signature = signature; //Body = new BeaconBlockBody(randaoReveal, // new Eth1Data(Hash32.Zero, 0), // new Bytes32(), Array.Empty<Deposit>()); }
public static IndexedAttestation DecodeIndexedAttestation(ReadOnlySpan <byte> span) { int offset = 0; DecodeDynamicOffset(span, ref offset, out int dynamicOffset1); ValidatorIndex[] attestingIndices = DecodeValidatorIndexes(span.Slice(dynamicOffset1)); AttestationData data = DecodeAttestationData(span, ref offset); BlsSignature signature = DecodeBlsSignature(span, ref offset); IndexedAttestation container = new IndexedAttestation(attestingIndices, data, signature); return(container); }
public static SignedBeaconBlock SignBlock(IServiceProvider testServiceProvider, BeaconState state, BeaconBlock block, ValidatorIndex?optionalProposerIndex) { TimeParameters timeParameters = testServiceProvider.GetService <IOptions <TimeParameters> >().Value; SignatureDomains signatureDomains = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value; ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>(); BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>(); if (state.Slot > block.Slot) { throw new ArgumentOutOfRangeException("block.Slot", block.Slot, $"Slot of block must be equal or less that state slot {state.Slot}"); } Epoch blockEpoch = beaconChainUtility.ComputeEpochAtSlot(block.Slot); ValidatorIndex proposerIndex; if (optionalProposerIndex.HasValue) { proposerIndex = optionalProposerIndex.Value; } else { if (block.Slot == state.Slot) { proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(state); } else { Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot); if (stateEpoch + 1 > blockEpoch) { Console.WriteLine("WARNING: Block slot far away, and no proposer index manually given." + " Signing block is slow due to transition for proposer index calculation."); } // use stub state to get proposer index of future slot BeaconState stubState = BeaconState.Clone(state); beaconStateTransition.ProcessSlots(stubState, block.Slot); proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(stubState); } } byte[][] privateKeys = TestKeys.PrivateKeys(timeParameters).ToArray(); byte[] privateKey = privateKeys[(int)(ulong)proposerIndex]; Root blockHashTreeRoot = cryptographyService.HashTreeRoot(block); Domain proposerDomain = beaconStateAccessor.GetDomain(state, signatureDomains.BeaconProposer, blockEpoch); Root signingRoot = beaconChainUtility.ComputeSigningRoot(blockHashTreeRoot, proposerDomain); BlsSignature signature = TestSecurity.BlsSign(signingRoot, privateKey); return(new SignedBeaconBlock(block, signature)); }
public void CheckEmptyBlockRootAfterDeserializing() { // Arrange Eth1Data eth1Data = new Eth1Data( new Root(Enumerable.Repeat((byte)0x12, 32).ToArray()), 64, new Bytes32(Enumerable.Repeat((byte)0x34, 32).ToArray())); BlsSignature randaoReveal = new BlsSignature(Enumerable.Repeat((byte)0xfe, 96).ToArray()); BeaconBlockBody beaconBlockBody = new BeaconBlockBody( randaoReveal, eth1Data, new Bytes32(new byte[32]), new ProposerSlashing[0], new AttesterSlashing [0], new Attestation[0], new Deposit[0], new SignedVoluntaryExit[0] ); BeaconBlock beaconBlock = new BeaconBlock( new Slot(1), new Root(Enumerable.Repeat((byte)0x78, 32).ToArray()), new Root(Enumerable.Repeat((byte)0x9a, 32).ToArray()), beaconBlockBody); Merkle.Ize(out UInt256 blockRoot256, beaconBlock); Span <byte> blockRootSpan = MemoryMarshal.Cast <UInt256, byte>(MemoryMarshal.CreateSpan(ref blockRoot256, 1)); Root blockRoot = new Root(blockRootSpan); SignedBeaconBlock signedBeaconBlock = new SignedBeaconBlock( beaconBlock, new BlsSignature(Enumerable.Repeat((byte)0x0e, 96).ToArray()) ); // Act Span <byte> encoded = new byte[Ssz.SignedBeaconBlockLength(signedBeaconBlock)]; Ssz.Encode(encoded, signedBeaconBlock); SignedBeaconBlock decoded = Ssz.DecodeSignedBeaconBlock(encoded); // Assert Merkle.Ize(out UInt256 decodedBlockRoot256, decoded.Message); Span <byte> decodedBlockRootSpan = MemoryMarshal.Cast <UInt256, byte>(MemoryMarshal.CreateSpan(ref decodedBlockRoot256, 1)); Root decodedBlockRoot = new Root(decodedBlockRootSpan); decodedBlockRoot.ShouldBe(blockRoot); }
public static BlsSignature GetAttestationSignature(IServiceProvider testServiceProvider, BeaconState state, AttestationData attestationData, byte[] privateKey) { SignatureDomains signatureDomains = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value; BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); Root attestationDataRoot = attestationData.HashTreeRoot(); Domain domain = beaconStateAccessor.GetDomain(state, signatureDomains.BeaconAttester, attestationData.Target.Epoch); Root signingRoot = beaconChainUtility.ComputeSigningRoot(attestationDataRoot, domain); BlsSignature signature = TestSecurity.BlsSign(signingRoot, privateKey); return(signature); }
public BeaconBlockHeader( Slot slot, Hash32 parentRoot, Hash32 stateRoot, Hash32 bodyRoot, BlsSignature signature) { Slot = slot; ParentRoot = parentRoot; StateRoot = stateRoot; BodyRoot = bodyRoot; Signature = signature; }
public async Task SignedBeaconBlock_RoundTripEmpty() { // Arrange JsonSerializerOptions options = new JsonSerializerOptions(); options.ConfigureNethermindCore2(); Eth1Data eth1Data = new Eth1Data( new Root(Enumerable.Repeat((byte)0x12, 32).ToArray()), 64, new Bytes32(Enumerable.Repeat((byte)0x34, 32).ToArray())); BlsSignature randaoReveal = new BlsSignature(Enumerable.Repeat((byte)0xfe, 96).ToArray()); BeaconBlockBody beaconBlockBody = new BeaconBlockBody( randaoReveal, eth1Data, new Bytes32(new byte[32]), new ProposerSlashing[0], new AttesterSlashing [0], new Attestation[0], new Deposit[0], new SignedVoluntaryExit[0] ); BeaconBlock beaconBlock = new BeaconBlock( new Slot(1), new Root(Enumerable.Repeat((byte)0x78, 32).ToArray()), new Root(Enumerable.Repeat((byte)0x9a, 32).ToArray()), beaconBlockBody); SignedBeaconBlock signedBeaconBlock = new SignedBeaconBlock( beaconBlock, new BlsSignature(Enumerable.Repeat((byte)0x0e, 96).ToArray()) ); // Act - round trip to string await using MemoryStream outputMemoryStream = new MemoryStream(); await JsonSerializer.SerializeAsync(outputMemoryStream, signedBeaconBlock, options); string jsonString = Encoding.UTF8.GetString(outputMemoryStream.ToArray()); Console.WriteLine(jsonString); // Assert - Round trip await using MemoryStream inputMemoryStream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)); SignedBeaconBlock roundTripSignedBeaconBlock = await JsonSerializer.DeserializeAsync <SignedBeaconBlock>(inputMemoryStream, options); roundTripSignedBeaconBlock.Message.Body.Eth1Data.BlockHash.AsSpan()[1].ShouldBe((byte)0x34); }