deserialize block

This commit is contained in:
Mark Spanbroek 2024-12-18 10:28:10 +01:00
parent ad3cfdbec5
commit a82e62522f
7 changed files with 136 additions and 3 deletions

View File

@ -5,8 +5,10 @@ export blockid
export blck except hash
import ./blocks/serialization
import ./blocks/deserialization
export serialization.toBytes
export deserialization.fromBytes
import ./blocks/hashing

View File

@ -0,0 +1,46 @@
import ../basics
import ../signatures
import ../hashing
import ../transaction
import ../transaction/deserialization
import ./blck
import ./blockid
import ./serialization
func init*(
_: type BlockId,
message: BlockIdMessage
): ?!BlockId =
success BlockId.init(
CommitteeMember(message.author),
message.round,
? Hash.fromBytes(message.hash)
)
func init*(
_: type Block,
message: BlockMessage
): ?!Block =
success Block(
author: CommitteeMember(message.author),
round: message.round,
parents: message.parents.mapIt(? BlockId.init(it)),
transactions: message.transactions.mapIt(? Transaction.init(it))
)
func init*(
_: type Signed[Block],
message: SignedBlockMessage
): ?!Signed[Block] =
success Signed[Block].init(
? Block.init(message.blck),
? Identifier.fromBytes(message.signer),
? Signature.fromBytes(message.signature)
)
func fromBytes*(
_: type Signed[Block],
bytes: openArray[byte]
): ?!Signed[Block] =
let message = ? Protobuf.decode(bytes, SignedBlockMessage).catch()
Signed[Block].init(message)

View File

@ -1,5 +1,6 @@
import pkg/nimcrypto/sha2
import pkg/nimcrypto/hash
import ./basics
export hash.`$`
@ -12,5 +13,12 @@ func hash*(_: type Hash, bytes: openArray[byte]): Hash =
result = context.finish()
context.clear()
func toBytes*(hash: Hash): auto =
hash.data
func toBytes*(hash: Hash): seq[byte] =
@(hash.data)
func fromBytes*(_: type Hash, bytes: openArray[byte]): ?!Hash =
if bytes.len != 32:
return failure "expected hash of 32 bytes, but got: " & $bytes.len
var data: array[32, byte]
data[0..<32] = bytes[0..<32]
success Hash(data: data)

View File

@ -55,7 +55,7 @@ func init(_: type Groth16Proof, message: Groth16ProofMessage): Groth16Proof =
)
)
func init(_: type Transaction, message: TransactionMessage): ?!Transaction =
func init*(_: type Transaction, message: TransactionMessage): ?!Transaction =
if message.version != TransactionVersion.version0.uint32:
return failure "unsupported transaction version: " & $message.version
let proofInput = ? StorageProofInput.init(message.proofInput)

View File

@ -1,6 +1,7 @@
import ../basics
import codexvalidator/blocks
import codexvalidator/blocks/serialization
import codexvalidator/transaction
import codexvalidator/transaction/serialization
import codexvalidator/hashing
import codexvalidator/signatures
@ -35,3 +36,54 @@ suite "Block serialization":
check protobuf.blck == BlockMessage.init(blck)
check protobuf.signer == signed.signer.toBytes()
check protobuf.signature == signed.signature.toBytes()
test "deserializes a signed block":
let signed = Signed[Block].example
let serialized = signed.toBytes()
let deserialized = Signed[Block].fromBytes(serialized)
check deserialized == success signed
test "deserialization fails when protobuf encoding is invalid":
let invalid = seq[byte].example
let deserialized = Signed[Block].fromBytes(invalid)
check deserialized.isFailure
check deserialized.errorOption.?msg == some "Invalid wire type"
test "deserialization fails when signer is invalid":
let signed = Signed[Block].example
var message = SignedBlockMessage.init(signed)
message.signer &= 42'u8
let invalid = Protobuf.encode(message)
let deserialized = Signed[Block].fromBytes(invalid)
check deserialized.isFailure
check deserialized.errorOption.?msg == some "invalid identifier"
test "deserialization fails when signature is invalid":
let signed = Signed[Block].example
var message = SignedBlockMessage.init(signed)
message.signature &= 42'u8
let invalid = Protobuf.encode(message)
let deserialized = Signed[Block].fromBytes(invalid)
check deserialized.isFailure
check deserialized.errorOption.?msg == some "invalid signature"
test "deserialization fails when parent block id is invalid":
let signed = Signed[Block].example
var message = SignedBlockMessage.init(signed)
let hash = array[32, byte].example
message.blck.parents &= BlockIdMessage(hash: @hash & 42'u8)
let invalid = Protobuf.encode(message)
let deserialized = Signed[Block].fromBytes(invalid)
check deserialized.isFailure
check deserialized.errorOption.?msg == some "expected hash of 32 bytes, but got: 33"
test "deserialization fails when transaction is invalid":
let signed = Signed[Block].example
var message = SignedBlockMessage.init(signed)
var transaction = TransactionMessage.init(Transaction.example)
transaction.version = 42'u8
message.blck.transactions &= transaction
let invalid = Protobuf.encode(message)
let deserialized = Signed[Block].fromBytes(invalid)
check deserialized.isFailure
check deserialized.errorOption.?msg == some "unsupported transaction version: 42"

View File

@ -0,0 +1,24 @@
import ./basics
import codexvalidator/hashing
suite "Hashing":
test "serializes a hash to bytes":
let hash = Hash.example
let serialized = hash.toBytes()
check serialized == hash.data
test "deserializes a hash from bytes":
let hash = Hash.example
let serialized = hash.toBytes()
let deserialized = Hash.fromBytes(serialized)
check deserialized == success hash
test "deserialization fails when number of bytes is not 32":
let hash = Hash.example
let serialized = hash.toBytes()
let invalid = serialized & 42'u8
let deserialized = Hash.fromBytes(invalid)
check deserialized.isFailure
check deserialized.errorOption.?msg == some "expected hash of 32 bytes, but got: 33"

View File

@ -1,4 +1,5 @@
import ./codexvalidator/testSignatures
import ./codexvalidator/testHashing
import ./codexvalidator/transaction/testTransaction
import ./codexvalidator/transaction/testSerialization
import ./codexvalidator/transaction/testHashing