< Summary

Information
Class: EF.Blockchain.Server.Endpoints.BlockEndpoints
Assembly: EF.Blockchain.Server
File(s): C:\dev\@web3\web3-001-ef-blockchain\backend\EF.Blockchain\src\EF.Blockchain.Server\Endpoints\BlockEndpoints.cs
Line coverage
100%
Covered lines: 47
Uncovered lines: 0
Coverable lines: 47
Total lines: 98
Line coverage: 100%
Branch coverage
90%
Covered branches: 9
Total branches: 10
Branch coverage: 90%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
MapBlockEndpoints(...)100%11100%
GetNextBlock(...)100%11100%
GetBlockByIndexOrHash(...)100%44100%
PostBlock()83.33%66100%

File(s)

C:\dev\@web3\web3-001-ef-blockchain\backend\EF.Blockchain\src\EF.Blockchain.Server\Endpoints\BlockEndpoints.cs

#LineLine coverage
 1using EF.Blockchain.Domain;
 2using EF.Blockchain.Server.Dtos;
 3using EF.Blockchain.Server.Mappers;
 4using Microsoft.AspNetCore.Mvc;
 5
 6namespace EF.Blockchain.Server.Endpoints;
 7
 8/// <summary>
 9/// Provides endpoints for accessing and submitting blocks in the blockchain.
 10/// </summary>
 11public static class BlockEndpoints
 12{
 13    /// <summary>
 14    /// Maps the block-related endpoints to the application.
 15    /// </summary>
 16    /// <param name="app">The route builder to register endpoints.</param>
 17    public static void MapBlockEndpoints(this IEndpointRouteBuilder app)
 11218    {
 11219        app.MapGet("/blocks/next", GetNextBlock)
 11220            .WithName("GetNextBlock")
 11221            .WithTags("Block")
 11222            .WithSummary("Get info for the next block to be mined")
 11223            .WithDescription("Returns the data needed for mining the next block, including transactions and metadata.")
 11224            .Produces<BlockInfoDto>(StatusCodes.Status200OK)
 11225            .WithOpenApi();
 26
 11227        app.MapGet("/blocks/{indexOrHash}", GetBlockByIndexOrHash)
 11228            .WithName("GetBlockByIndexOrHash")
 11229            .WithTags("Block")
 11230            .WithSummary("Get block by index or hash")
 11231            .WithDescription("Returns a block from the chain by its index or hash.")
 11232            .Produces<BlockDto>(StatusCodes.Status200OK)
 11233            .Produces(StatusCodes.Status404NotFound)
 11234            .WithOpenApi();
 35
 11236        app.MapPost("/blocks", PostBlock)
 11237            .WithName("PostBlock")
 11238            .WithTags("Block")
 11239            .WithSummary("Add a new block to the blockchain")
 11240            .WithDescription("Receives a mined block and attempts to add it to the blockchain.")
 11241            .Accepts<BlockDto>("application/json")
 11242            .Produces<BlockDto>(StatusCodes.Status201Created)
 11243            .Produces(StatusCodes.Status400BadRequest)
 11244            .Produces(StatusCodes.Status422UnprocessableEntity)
 11245            .WithOpenApi();
 11246    }
 47
 48    /// <summary>
 49    /// Handles GET /blocks/next
 50    /// </summary>
 51    /// <param name="blockchain">Injected blockchain instance.</param>
 52    /// <returns>Returns the next block to be mined.</returns>
 53    private static IResult GetNextBlock([FromServices] Domain.Blockchain blockchain)
 854    {
 855        var info = blockchain.GetNextBlock();
 856        return Results.Ok(BlockInfoMapper.ToDto(info));
 857    }
 58
 59    /// <summary>
 60    /// Handles GET /blocks/{indexOrHash}
 61    /// </summary>
 62    /// <param name="indexOrHash">Block index (int) or hash (string).</param>
 63    /// <param name="blockchain">Injected blockchain instance.</param>
 64    /// <returns>Returns the block if found, or 404 if not.</returns>
 65    private static IResult GetBlockByIndexOrHash(
 66        [FromRoute] string indexOrHash,
 67        [FromServices] Domain.Blockchain blockchain)
 2468    {
 2469        Block? block = int.TryParse(indexOrHash, out var index)
 2470            ? blockchain.Blocks.ElementAtOrDefault(index)
 3271            : blockchain.Blocks.FirstOrDefault(b => b.Hash == indexOrHash);
 72
 2473        return block is null ? Results.NotFound() : Results.Ok(BlockMapper.ToDto(block));
 2474    }
 75
 76    /// <summary>
 77    /// Handles POST /blocks
 78    /// </summary>
 79    /// <param name="context">HTTP context to read request body.</param>
 80    /// <param name="blockchain">Injected blockchain instance.</param>
 81    /// <returns>Returns 201 if block is added, otherwise error code.</returns>
 82    private static async Task<IResult> PostBlock(
 83        HttpContext context,
 84        [FromServices] Domain.Blockchain blockchain)
 2485    {
 2486        var blockDto = await context.Request.ReadFromJsonAsync<BlockDto>();
 87
 2488        if (blockDto is null || string.IsNullOrEmpty(blockDto.Hash))
 889            return Results.UnprocessableEntity("Missing or invalid hash");
 90
 1691        var block = BlockMapper.ToDomain(blockDto);
 1692        var result = blockchain.AddBlock(block);
 93
 1694        return result.Success
 1695            ? Results.Created($"/blocks/{block.Index}", BlockMapper.ToDto(block))
 1696            : Results.BadRequest(result);
 2497    }
 98}