serialization algorithm can be set at compile time

- calculate block id once
- sign hashes, not byte sequences
- simplify Transaction abstraction
This commit is contained in:
Mark Spanbroek 2024-11-20 15:51:34 +01:00
parent 01cbefe898
commit 030bbf3367
11 changed files with 67 additions and 29 deletions

View File

@ -63,4 +63,3 @@ export hashing.`$`
import ./mysticeti/dependencies/transacting
export transacting.Transaction
export transacting.`$`

View File

@ -4,11 +4,18 @@ import ./blockid
type
Block*[Dependencies] = object
id: BlockId[Dependencies]
author: CommitteeMember
round: uint64
parents: seq[BlockId[Dependencies]]
transactions: seq[Transaction[Dependencies]]
func calculateId(blck: var Block) =
type Dependencies = Block.Dependencies
let bytes = Dependencies.Serialization.toBytes(blck)
let hash = Hash[Dependencies].hash(bytes)
blck.id = BlockId[Dependencies].new(blck.author, blck.round, hash)
func new*[Dependencies](
_: type Block[Dependencies];
author: CommitteeMember,
@ -16,12 +23,14 @@ func new*[Dependencies](
parents: seq[BlockId[Dependencies]],
transactions: seq[Transaction[Dependencies]]
): auto =
Block[Dependencies](
var blck = Block[Dependencies](
author: author,
round: round,
parents: parents,
transactions: transactions
)
blck.calculateId()
blck
func author*(blck: Block): auto =
blck.author
@ -35,12 +44,5 @@ func parents*(blck: Block): auto =
func transactions*(blck: Block): auto =
blck.transactions
func toBytes*(blck: Block): seq[byte] =
cast[seq[byte]]($blck) # TODO: proper serialization
func id*(blck: Block): auto =
BlockId[Block.Dependencies].new(
blck.author,
blck.round,
Hash[Block.Dependencies].hash(blck.toBytes)
)
blck.id

View File

@ -1,5 +1,6 @@
import ../basics
import ./blck
import ./blockid
type SignedBlock*[Dependencies] = object
blck: Block[Dependencies]
@ -12,8 +13,8 @@ func blck*(signed: SignedBlock): auto =
signed.blck
func sign*(identity: Identity, blck: Block): auto =
let signature = identity.sign(blck.toBytes)
let signature = identity.sign(blck.id.hash)
SignedBlock.new(blck, signature)
func signer*(signed: SignedBlock): auto =
signed.signature.signer(signed.blck.toBytes)
signed.signature.signer(signed.blck.id.hash)

View File

@ -9,5 +9,6 @@ export transacting
type Dependencies*[
Hashing,
Signing,
Transacting
Transacting,
Serialization
] = object

View File

@ -1,3 +1,5 @@
import ./hashing
type
Identity*[Dependencies] = object
value: Dependencies.Signing.Identity
@ -15,13 +17,13 @@ func identifier*(identity: Identity): auto =
mixin identifier
Identifier[Identity.Dependencies](value: identity.value.identifier)
func sign*(identity: Identity, bytes: openArray[byte]): auto =
func sign*(identity: Identity, hash: Hash): auto =
mixin sign
Signature[Identity.Dependencies](value: identity.value.sign(bytes))
Signature[Identity.Dependencies](value: identity.value.sign(hash))
func signer*(signature: Signature, bytes: openArray[byte]): auto =
func signer*(signature: Signature, hash: Hash): auto =
mixin signer
Identifier[Signature.Dependencies](value: signature.value.signer(bytes))
Identifier[Signature.Dependencies](value: signature.value.signer(hash))
func `$`*(identity: Identity): string =
$identity.value

View File

@ -1,10 +1,3 @@
type
Transaction*[Dependencies] = object
value: Dependencies.Transacting.Transaction
Transaction*[Dependencies] = Dependencies.Transacting.Transaction
Transacting*[Transaction] = object
func init*[T: Transaction](_: type T, value: T.Dependencies.Transacting.Transaction): T =
T(value: value)
func `$`*(transaction: Transaction): string =
$transaction.value

View File

@ -2,13 +2,16 @@ import mysticeti/dependencies
import ./mocks/signing
import ./mocks/hashing
import ./mocks/transacting
import ./mocks/serialization
export signing
export hashing
export transacting
export serialization
type MockDependencies* = Dependencies[
MockHashing,
MockSigning,
MockTransacting
MockTransacting,
MockSerialization
]

View File

@ -0,0 +1,32 @@
import std/json
import mysticeti
import ./transacting
type MockSerialization* = object
proc `%`*(member: CommitteeMember): JsonNode =
%member.int
proc `%`*(id: BlockId): JsonNode =
%*{
"author": id.author,
"round": id.round,
"hash": $id.hash
}
proc `%`*(transaction: MockTransacting.Transaction): JsonNode =
%*{
"nonce": transaction.nonce
}
proc `%`*(blck: Block): JsonNode =
%*{
"author": blck.author,
"round": blck.round,
"parents": blck.parents,
"transactions": blck.transactions
}
func toBytes*(_: type MockSerialization, blck: Block): seq[byte] =
let json = %blck
cast[seq[byte]]($json)

View File

@ -2,6 +2,7 @@ import std/random
import std/sequtils
import std/strutils
import mysticeti/dependencies/signing
import mysticeti/dependencies/hashing
type
Identity = object
@ -18,8 +19,8 @@ proc init*(_: type Identity): Identity =
func identifier*(identity: Identity): Identifier =
Identifier(id: identity.id)
func sign*(identity: Identity, bytes: openArray[byte]): Signature =
func sign*(identity: Identity, hash: Hash): Signature =
Signature(signer: identity.id)
func signer*(signature: Signature, bytes: openArray[byte]): Identifier =
func signer*(signature: Signature, hash: Hash): Identifier =
Identifier(id: signature.signer)

View File

@ -6,5 +6,8 @@ type
nonce: int
MockTransacting* = Transacting[MockTransaction]
proc nonce*(transaction: MockTransaction): int =
transaction.nonce
proc example*(_: type MockTransaction): MockTransaction =
MockTransaction(nonce: rand(int))

View File

@ -10,6 +10,7 @@ suite "Blocks":
type Identity = mysticeti.Identity[MockDependencies]
type Transaction = mysticeti.Transaction[MockDependencies]
type Hash = hashing.Hash[MockDependencies]
type Serialization = MockDependencies.Serialization
test "blocks have an author, a round, parents and transactions":
let author = CommitteeMember.example
@ -27,7 +28,7 @@ suite "Blocks":
let id = blck.id
check id.author == blck.author
check id.round == blck.round
check id.hash == Hash.hash(blck.toBytes)
check id.hash == Hash.hash(Serialization.toBytes(blck))
test "blocks can be signed":
let signer = Identity.init