Hi all, 來到第13天 昨天由於依賴衝突的關係,導致延後套用 SDK~~~今天就來把專案引入昨天寫好的 SDK吧。
今日的目標就是: 替區塊補上 Cameleon Hash, 此次套用的SDK 版本為: 1.0.4
首先我們必須於 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);
接著就是使用的地方,我們必須於建構子中注入 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);
}
}
public class GenerateNewBlockRequest
{
public string Data { get; set; }
public GenerateNewBlockDto ToDto(KeyPair keyPair, SessionKey sessionKey)
{
return new GenerateNewBlockDto()
{
KeyPair = keyPair,
SessionKey = sessionKey,
Data = Data
};
}
}
需要替第一個 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,
})
};
}
}
經過一番 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;
}
}
接著就是計算下個區塊以及轉換 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()
};
}
}
新增 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
};
}
}
經過一番努力,總算是可以正常替區塊計算簽章值了,明天接著進行 edit 區塊的部分
結語: SDK 輸出的東西,能的話就多墊一層 model,可以避免翻車