iT邦幫忙

2024 iThome 鐵人賽

DAY 13
0

Hi all, 來到第13天 昨天由於依賴衝突的關係,導致延後套用 SDK~~~今天就來把專案引入昨天寫好的 SDK吧。

今日的目標就是: 替區塊補上 Cameleon Hash, 此次套用的SDK 版本為: 1.0.4

Programs

首先我們必須於 Programs 中替 KeyPair, SessionKey 物件做DI的註冊。

至於為甚麼是 Singleton,主要原因是我期望每個 request 進來時使用的 key都是同組。code 如下:

var keyPair = EccGenerator.GenerateKeyPair(256);
var sessionKey = SessionKeyGenerator.GenerateSessionKey();
builder.Services.AddSingleton(keyPair);
builder.Services.AddSingleton(sessionKey);

Controller

接著就是使用的地方,我們必須於建構子中注入 keypair, SessionKey 物件,並導入Dto物件,最後再從Dto物件中透過 EccGenerator 物件進行變色龍雜湊函數的計算,code 如下:

[Route("api/v1/[controller]")]
public class ChainController(IChainService chainService, KeyPair keyPair, SessionKey sessionKey) : ControllerBase 
{

    [HttpGet("{id}")]
    public async Task<ApiResponse> GetBlockById(int id)
    {
        var block = await chainService.GetBlockById(id);
        return ApiResponse.SuccessWithData(block);
    }

    [HttpPost("new")]
    public async Task<ApiResponse> GenerateNewBlock([FromBody] GenerateNewBlockRequest request)
    {
        var newBlock = await chainService.GenerateNewBlock(request.ToDto(keyPair, sessionKey));
        return ApiResponse.SuccessWithData(newBlock);
    }
}

Request:

  • 需要新增兩個 property 的 setter
public class GenerateNewBlockRequest
{
    public string Data { get; set; }

    public GenerateNewBlockDto ToDto(KeyPair keyPair, SessionKey sessionKey)
    {
        return new GenerateNewBlockDto()
        {
            KeyPair = keyPair,
            SessionKey = sessionKey,
            Data =  Data
        };
    }
}

DTO

需要替第一個 Block計算簽章值,會有點 confus的地方是在於,原本我們是把 new Block 這段code寫在service層,

但基於單一職責的問題,我把他抽 method 之後在塞進 dto 內,code如下。

public class GenerateNewBlockDto
{
    public string Data { get; set; }
    public DateTime TimeStamp { get; set; }
    public KeyPair KeyPair { get; set; }
    public SessionKey SessionKey { get; set; }

    public BlockDomain GetGenesisBlock()
    {
        return new BlockDomain
        {
            Data = "Genesis Block",
            Hash = "0",
            PreviousHash = "0",
            TimeStamp = DateTime.Now,
            Nonce = 0,
            ChameleonSignature = ChameleonHashHelper.Sign(new ChameleonHashRequest
            {
                KeyPair = KeyPair,
                Message = "Genesis Block",
                SessionKey = SessionKey.Key,
                Order = KeyPair.PublicKey.Curve.Order,
            })
        };
    }
}

Service

經過一番 refactor 後,變成這樣

public class ChainService(IChainRepository chainRepository) : IChainService
{
    private const int Nonce = 0;

    public async Task<BlockDomain> GetBlockById(int i)
    {
        return await chainRepository.GetBlockBy(i);
    }

    public async Task<BlockDomain> GenerateNewBlock(GenerateNewBlockDto dto)
    {
        var chainLength = await chainRepository.GetChainLength();
        
        var newBlock = chainLength == 0
            ? dto.GetGenesisBlock()
            : (await chainRepository.GetBlockBy(chainLength)).GenerateNextBlock(dto, Nonce);

        await chainRepository.InsertBlock(newBlock);
        return newBlock;
    }
}

Domain

接著就是計算下個區塊以及轉換 Entity的地方需要計算與新增簽章,code 如下

public class BlockDomain
{
    public string Data { get; set; }
    public string Hash { get; set; }
    public string PreviousHash { get; set; }
    public DateTime TimeStamp { get; set; }
    public int Nonce { get; set; }

    public ChameleonSignature ChameleonSignature { get; set; }
    
    public BlockDomain GenerateNextBlock(GenerateNewBlockDto dto, int nonce)
    {
        return new BlockDomain
        {
            Data = dto.Data,
            PreviousHash = Hash,
            TimeStamp = dto.TimeStamp,
            Hash = HashHelper.ToSha256($"{dto.TimeStamp}:{Hash}:{dto.Data}:{nonce}"),
            Nonce = nonce,
            ChameleonSignature = ChameleonHashHelper.Sign(new ChameleonHashRequest
            {
                KeyPair = dto.KeyPair,
                Message = $"{dto.TimeStamp}:{Hash}:{dto.Data}:{nonce}",
                SessionKey = dto.SessionKey.Key,
                Order = dto.KeyPair.PublicKey.Curve.Order,
            }),
        };
    }

    public Block ToEntity()
    {
        return new Block
        {
            Data = Data,
            Hash = Hash,
            PreviousHash = PreviousHash,
            TimeStamp = TimeStamp,
            Nonce = Nonce,
            ChameleonSignature = ChameleonSignature.Value.ToString()
        };
    }
}

Entity

新增 property

public class Block
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    public string Data { get; set; }

    [Required]
    public string Hash { get; set; }

    [Required]
    public string PreviousHash { get; set; }

    [Required]
    public DateTime TimeStamp { get; set; }

    [Required]
    public int Nonce { get; set; }

    public string ChameleonSignature { get; set; }

    public BlockDomain ToDomain()
    {
        return new BlockDomain
        {
            Data = Data,
            Hash = Hash,
            PreviousHash = PreviousHash,
            TimeStamp = TimeStamp,
            Nonce = Nonce
        };
    }
}

Conclusion

經過一番努力,總算是可以正常替區塊計算簽章值了,明天接著進行 edit 區塊的部分

結語: SDK 輸出的東西,能的話就多墊一層 model,可以避免翻車


上一篇
Day12 SDK 放送事故…
下一篇
Day14 Make a Editable Block
系列文
Side-Project:: 為自己打造個可編輯的區塊鏈30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言