serialize transactions using protobuf

This commit is contained in:
Mark Spanbroek 2024-12-04 15:10:22 +01:00
parent 19b82c93cb
commit ac4413fce5
6 changed files with 127 additions and 6 deletions

View File

@ -3,8 +3,16 @@ author = "Codex Validator contributors"
description = "Validation network for Codex"
license = "MIT"
requires "https://github.com/codex-storage/nim-mysticeti >= 0.1.0 & < 0.2.0"
requires "https://github.com/codex-storage/nim-stint-versioned.git >= 1.0.0 & < 2.0.0"
requires "blscurve#de2d3c79264bba18dbea469c8c5c4b3bb3c8bc55"
requires "nimcrypto >= 0.6.2 & < 0.7.0"
# pinning non-versioned dependencies of dependencies
requires "stew#a6e198132097fb544d04959aeb3b839e1408f942"
requires "faststreams#cf8d4d22636b8e514caf17e49f9c786ac56b0e85"
requires "serialization#2086c99608b4bf472e1ef5fe063710f280243396"
# pinning non-versioned dependencies
requires "stint#ae665d6546c57b4acaf194e9a8e33ebb6aab5213"
requires "protobuf_serialization#5a31137a82c2b6a989c9ed979bb636c7a49f570e"
requires "blscurve#de2d3c79264bba18dbea469c8c5c4b3bb3c8bc55"
# versioned dependencies
requires "https://github.com/codex-storage/nim-mysticeti >= 0.1.0 & < 0.2.0"
requires "nimcrypto >= 0.6.2 & < 0.7.0"

View File

@ -0,0 +1,36 @@
import ./basics
import ./transaction
import ./serialization/protobuf
func toBytes*(transaction: Transaction): seq[byte] =
var message = TransactionMessage(
version: transaction.version.uint32,
kind: transaction.kind.uint32,
requestId: @(array[32, byte](transaction.requestId)),
slotIndex: transaction.slotIndex,
period: transaction.period.uint64,
merkleRoot: @(transaction.merkleRoot.toBytesBE()), # TODO: should this not be array[32, byte]?
challenge: @(transaction.challenge.toBytesBE()) # TODO ^^^
)
if transaction.kind == TransactionKind.storageProof:
message.proof = Groth16ProofMessage(
a: G1PointMessage(
x: @(transaction.proof.a.x.toBytesBE()),
y: @(transaction.proof.a.y.toBytesBE())
),
b: G2PointMessage(
x: Fp2ElementMessage(
imag: @(transaction.proof.b.x.imag.toBytesBE()),
real: @(transaction.proof.b.x.real.toBytesBE())
),
y: Fp2ElementMessage(
imag: @(transaction.proof.b.y.imag.toBytesBE()),
real: @(transaction.proof.b.y.real.toBytesBE())
)
),
c: G1PointMessage(
x: @(transaction.proof.c.x.toBytesBE()),
y: @(transaction.proof.c.y.toBytesBE())
)
)
ProtoBuf.encode(message)

View File

@ -0,0 +1,28 @@
import pkg/protobuf_serialization
export protobuf_serialization
type
TransactionMessage* {.proto3.} = object
version* {.fieldNumber: 1, pint.}: uint32
kind* {.fieldNumber: 2, pint.}: uint32
requestId* {.fieldNumber: 3.}: seq[byte]
slotIndex* {.fieldNumber: 4, pint.}: uint32
period* {.fieldNumber: 5, pint.}: uint64
merkleRoot* {.fieldNumber: 6.}: seq[byte]
challenge* {.fieldNumber: 7.}: seq[byte]
proof* {.fieldNumber: 8.}: Groth16ProofMessage
Groth16ProofMessage* {.proto3.} = object
a* {.fieldNumber: 1.}: G1PointMessage
b* {.fieldNumber: 2.}: G2PointMessage
c* {.fieldNumber: 3.}: G1PointMessage
G1PointMessage* {.proto3.} = object
x* {.fieldNumber: 1.}: seq[byte]
y* {.fieldNumber: 2.}: seq[byte]
G2PointMessage* {.proto3.} = object
x* {.fieldNumber: 1.}: Fp2ElementMessage
y* {.fieldNumber: 2.}: Fp2ElementMessage
Fp2ElementMessage* {.proto3.} = object
real* {.fieldNumber: 1.}: seq[byte]
imag* {.fieldNumber: 2.}: seq[byte]

View File

@ -25,7 +25,7 @@ type
of missingProof:
discard
proc storageProof*(
func storageProof*(
_: type Transaction,
requestId: StorageRequestId,
slotIndex: uint32,
@ -44,7 +44,7 @@ proc storageProof*(
proof: proof
)
proc missingProof*(
func missingProof*(
_: type Transaction,
requestId: StorageRequestId,
slotIndex: uint32,
@ -64,6 +64,9 @@ proc missingProof*(
func version*(transaction: Transaction): TransactionVersion =
TransactionVersion.version0
func kind*(transaction: Transaction): TransactionKind =
transaction.kind
func requestId*(transaction: Transaction): StorageRequestId =
transaction.requestId

View File

@ -0,0 +1,45 @@
import std/unittest
import codexvalidator/basics
import codexvalidator/transaction
import codexvalidator/serialization
import codexvalidator/serialization/protobuf
import ./examples
suite "Serialization":
test "serializes a transaction with protobuf":
let transaction = Transaction.example
let serialized = transaction.toBytes()
{.warning[Deprecated]: off.} # ignore warning in protobuf_serialization
let protobuf = ProtoBuf.decode(serialized, TransactionMessage)
{.warning[Deprecated]: on.}
check protobuf.version == transaction.version.uint32
check protobuf.kind == transaction.kind.uint32
check protobuf.requestId == array[32, byte](transaction.requestId)
check protobuf.slotIndex == transaction.slotIndex
check protobuf.period == transaction.period.uint64
check protobuf.merkleRoot == transaction.merkleRoot.toBytesBE()
check protobuf.challenge == transaction.challenge.toBytesBE()
test "serializes a storage proof with protobuf":
let proof = Groth16Proof.example
let transaction = Transaction.storageProof(
StorageRequestId.example,
uint32.example,
Period.example,
UInt256.example,
UInt256.example,
proof
)
let serialized = transaction.toBytes()
{.warning[Deprecated]: off.} # ignore warning in protobuf_serialization
let protobuf = ProtoBuf.decode(serialized, TransactionMessage)
{.warning[Deprecated]: on.}
check protobuf.proof.a.x == transaction.proof.a.x.toBytesBE()
check protobuf.proof.a.y == transaction.proof.a.y.toBytesBE()
check protobuf.proof.b.x.real == transaction.proof.b.x.real.toBytesBE()
check protobuf.proof.b.x.imag == transaction.proof.b.x.imag.toBytesBE()
check protobuf.proof.b.y.real == transaction.proof.b.y.real.toBytesBE()
check protobuf.proof.b.y.imag == transaction.proof.b.y.imag.toBytesBE()
check protobuf.proof.c.x == transaction.proof.c.x.toBytesBE()
check protobuf.proof.c.y == transaction.proof.c.y.toBytesBE()

View File

@ -1,4 +1,5 @@
import ./codexvalidator/testSignatures
import ./codexvalidator/testSerialization
import ./codexvalidator/testTransaction
{.warning[UnusedImport]:off.}