From ac4413fce58eeba72906e4ae9fa33d8e0a4ccece Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Wed, 4 Dec 2024 15:10:22 +0100 Subject: [PATCH] serialize transactions using protobuf --- codexvalidator.nimble | 16 ++++++-- codexvalidator/serialization.nim | 36 +++++++++++++++++ codexvalidator/serialization/protobuf.nim | 28 ++++++++++++++ codexvalidator/transaction.nim | 7 +++- tests/codexvalidator/testSerialization.nim | 45 ++++++++++++++++++++++ tests/tests.nim | 1 + 6 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 codexvalidator/serialization.nim create mode 100644 codexvalidator/serialization/protobuf.nim create mode 100644 tests/codexvalidator/testSerialization.nim diff --git a/codexvalidator.nimble b/codexvalidator.nimble index 5f1764f..9d7ce32 100644 --- a/codexvalidator.nimble +++ b/codexvalidator.nimble @@ -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" diff --git a/codexvalidator/serialization.nim b/codexvalidator/serialization.nim new file mode 100644 index 0000000..5cc3ea6 --- /dev/null +++ b/codexvalidator/serialization.nim @@ -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) diff --git a/codexvalidator/serialization/protobuf.nim b/codexvalidator/serialization/protobuf.nim new file mode 100644 index 0000000..1e9b06b --- /dev/null +++ b/codexvalidator/serialization/protobuf.nim @@ -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] + diff --git a/codexvalidator/transaction.nim b/codexvalidator/transaction.nim index b08b625..2c8f98f 100644 --- a/codexvalidator/transaction.nim +++ b/codexvalidator/transaction.nim @@ -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 diff --git a/tests/codexvalidator/testSerialization.nim b/tests/codexvalidator/testSerialization.nim new file mode 100644 index 0000000..6a99ca9 --- /dev/null +++ b/tests/codexvalidator/testSerialization.nim @@ -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() diff --git a/tests/tests.nim b/tests/tests.nim index f64b2dd..3cf621e 100644 --- a/tests/tests.nim +++ b/tests/tests.nim @@ -1,4 +1,5 @@ import ./codexvalidator/testSignatures +import ./codexvalidator/testSerialization import ./codexvalidator/testTransaction {.warning[UnusedImport]:off.}