From 0fff583d58cb4963528977bab8927ad4556dd630 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Tue, 17 Dec 2024 13:10:22 +0100 Subject: [PATCH] wrap storage proof inputs into an object --- .../transaction/deserialization.nim | 36 +++++------- codexvalidator/transaction/proofinput.nim | 42 ++++++++++++++ codexvalidator/transaction/serialization.nim | 32 ++++++---- codexvalidator/transaction/transaction.nim | 58 ++++--------------- tests/codexvalidator/examples.nim | 31 +++++----- .../transaction/testSerialization.nim | 52 ++++++++--------- .../transaction/testTransaction.nim | 32 ++-------- 7 files changed, 135 insertions(+), 148 deletions(-) create mode 100644 codexvalidator/transaction/proofinput.nim diff --git a/codexvalidator/transaction/deserialization.nim b/codexvalidator/transaction/deserialization.nim index 6cf9b5e..469c0e2 100644 --- a/codexvalidator/transaction/deserialization.nim +++ b/codexvalidator/transaction/deserialization.nim @@ -21,6 +21,18 @@ func fromBytes( ): ?!StorageRequestId = success StorageRequestId(? array[32, byte].fromBytes(bytes)) +func init*( + _: type StorageProofInput, + message: StorageProofInputMessage +): ?!StorageProofInput = + success StorageProofInput.init( + ? StorageRequestId.fromBytes(message.requestId), + message.slotIndex, + Period(message.period), + ? array[32, byte].fromBytes(message.merkleRoot), + ? array[32, byte].fromBytes(message.challenge) + ) + func init(_: type Groth16Proof, message: Groth16ProofMessage): Groth16Proof = Groth16Proof.init( G1Point.init( @@ -46,29 +58,13 @@ func init(_: type Groth16Proof, message: Groth16ProofMessage): Groth16Proof = func init(_: type Transaction, message: TransactionMessage): ?!Transaction = if message.version != TransactionVersion.version0.uint32: return failure "unsupported transaction version: " & $message.version - let requestId = ? StorageRequestId.fromBytes(message.requestId) - let slotIndex = message.slotIndex - let period = Period(message.period) - let merkleRoot = ? array[32, byte].fromBytes(message.merkleRoot) - let challenge = ? array[32, byte].fromBytes(message.challenge) + let proofInput = ? StorageProofInput.init(message.proofInput) case message.kind of TransactionKind.storageProof.uint32: - success Transaction.storageProof( - requestId, - slotIndex, - period, - merkleRoot, - challenge, - Groth16Proof.init(message.proof) - ) + let proof = Groth16Proof.init(message.proof) + success Transaction.storageProof(proofInput, proof) of TransactionKind.missingProof.uint32: - success Transaction.missingProof( - requestId, - message.slotIndex, - period, - merkleRoot, - challenge, - ) + success Transaction.missingProof(proofInput) else: failure "invalid transaction kind: " & $message.kind diff --git a/codexvalidator/transaction/proofinput.nim b/codexvalidator/transaction/proofinput.nim new file mode 100644 index 0000000..1aa5ac6 --- /dev/null +++ b/codexvalidator/transaction/proofinput.nim @@ -0,0 +1,42 @@ +import ./storagerequest +import ./period + +type + StorageProofInput* = object + requestId: StorageRequestId + slotIndex: uint32 + period: Period + merkleRoot: array[32, byte] + challenge: array[32, byte] + +func init*( + _: type StorageProofInput, + requestId: StorageRequestId, + slotIndex: uint32, + period: Period, + merkleRoot: array[32, byte], + challenge: array[32, byte] +): StorageProofInput = + StorageProofInput( + requestId: requestId, + slotIndex: slotIndex, + period: period, + merkleRoot: merkleRoot, + challenge: challenge + ) + +func requestId*(input: StorageProofInput): StorageRequestId = + input.requestId + +func slotIndex*(input: StorageProofInput): uint32 = + input.slotIndex + +func period*(input: StorageProofInput): Period = + input.period + +func merkleRoot*(input: StorageProofInput): array[32, byte] = + input.merkleRoot + +func challenge*(input: StorageProofInput): array[32, byte] = + input.challenge + diff --git a/codexvalidator/transaction/serialization.nim b/codexvalidator/transaction/serialization.nim index 6b82dba..23051df 100644 --- a/codexvalidator/transaction/serialization.nim +++ b/codexvalidator/transaction/serialization.nim @@ -9,12 +9,14 @@ 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 + proofInput* {.fieldNumber: 3.}: StorageProofInputMessage + proof* {.fieldNumber: 4.}: Groth16ProofMessage + StorageProofInputMessage* {.proto3.} = object + requestId* {.fieldNumber: 1.}: seq[byte] + slotIndex* {.fieldNumber: 2, pint.}: uint32 + period* {.fieldNumber: 3, pint.}: uint64 + merkleRoot* {.fieldNumber: 4.}: seq[byte] + challenge* {.fieldNumber: 5.}: seq[byte] Groth16ProofMessage* {.proto3.} = object a* {.fieldNumber: 1.}: G1PointMessage b* {.fieldNumber: 2.}: G2PointMessage @@ -29,15 +31,23 @@ type real* {.fieldNumber: 1.}: seq[byte] imag* {.fieldNumber: 2.}: seq[byte] +func init( + _: type StorageProofInputMessage, + input: StorageProofInput +): StorageProofInputMessage = + StorageProofInputMessage( + requestId: @(array[32, byte](input.requestId)), + slotIndex: input.slotIndex, + period: input.period.uint64, + merkleRoot: @(input.merkleRoot), + challenge: @(input.challenge) + ) + func init*(_: type TransactionMessage, transaction: Transaction): TransactionMessage = 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), - challenge: @(transaction.challenge) + proofInput: StorageProofInputMessage.init(transaction.proofInput) ) if transaction.kind == TransactionKind.storageProof: message.proof = Groth16ProofMessage( diff --git a/codexvalidator/transaction/transaction.nim b/codexvalidator/transaction/transaction.nim index 637200f..5b63c42 100644 --- a/codexvalidator/transaction/transaction.nim +++ b/codexvalidator/transaction/transaction.nim @@ -2,10 +2,12 @@ import ../basics import ../hashing import ./storagerequest import ./period +import ./proofinput import ./groth16 export storagerequest export period +export proofinput export groth16 type @@ -15,11 +17,7 @@ type storageProof missingProof Transaction* = ref object - requestId: StorageRequestId - slotIndex: uint32 - period: Period - merkleRoot: array[32, byte] - challenge: array[32, byte] + proofInput: StorageProofInput case kind: TransactionKind of storageProof: proof: Groth16Proof @@ -29,38 +27,22 @@ type func storageProof*( _: type Transaction, - requestId: StorageRequestId, - slotIndex: uint32, - period: Period, - merkleRoot: array[32, byte], - challenge: array[32, byte], + proofInput: StorageProofInput, proof: Groth16Proof ): Transaction = Transaction( kind: TransactionKind.storageProof, - requestId: requestId, - period: period, - slotIndex: slotIndex, - merkleRoot: merkleRoot, - challenge: challenge, + proofInput: proofInput, proof: proof ) func missingProof*( _: type Transaction, - requestId: StorageRequestId, - slotIndex: uint32, - period: Period, - merkleRoot: array[32, byte], - challenge: array[32, byte], + proofInput: StorageProofInput ): Transaction = Transaction( kind: TransactionKind.missingProof, - requestId: requestId, - slotIndex: slotIndex, - period: period, - merkleRoot: merkleRoot, - challenge: challenge + proofInput: proofInput ) func version*(transaction: Transaction): TransactionVersion = @@ -69,20 +51,8 @@ func version*(transaction: Transaction): TransactionVersion = func kind*(transaction: Transaction): TransactionKind = transaction.kind -func requestId*(transaction: Transaction): StorageRequestId = - transaction.requestId - -func slotIndex*(transaction: Transaction): uint32 = - transaction.slotIndex - -func period*(transaction: Transaction): Period = - transaction.period - -func merkleRoot*(transaction: Transaction): array[32, byte] = - transaction.merkleRoot - -func challenge*(transaction: Transaction): array[32, byte] = - transaction.challenge +func proofInput*(transaction: Transaction): StorageProofInput = + transaction.proofInput func proof*(transaction: Transaction): Groth16Proof = transaction.proof @@ -96,15 +66,7 @@ func hash*(transaction: Transaction): ?Hash = func `==`*(a, b: Transaction): bool = if a.kind != b.kind: return false - if a.requestId != b.requestId: - return false - if a.slotIndex != b.slotIndex: - return false - if a.period != b.period: - return false - if a.merkleRoot != b.merkleRoot: - return false - if a.challenge != b.challenge: + if a.proofInput != b.proofInput: return false case a.kind of TransactionKind.storageProof: diff --git a/tests/codexvalidator/examples.nim b/tests/codexvalidator/examples.nim index f5126eb..6736b83 100644 --- a/tests/codexvalidator/examples.nim +++ b/tests/codexvalidator/examples.nim @@ -44,32 +44,29 @@ proc example*(_: type Groth16Proof): Groth16Proof = G1Point.example ) -proc example*(_: type Transaction): Transaction = - let kind = [TransactionKind.storageProof, TransactionKind.missingProof].sample +proc example*(_: type StorageProofInput): StorageProofInput = let requestId = StorageRequestId.example let slotIndex = uint32.example let period = Period.example let merkleRoot = array[32, byte].example let challenge = array[32, byte].example + StorageProofInput.init( + requestId, + slotIndex, + period, + merkleRoot, + challenge + ) + +proc example*(_: type Transaction): Transaction = + let kind = [TransactionKind.storageProof, TransactionKind.missingProof].sample + let proofInput = StorageProofInput.example case kind of TransactionKind.missingProof: - Transaction.missingProof( - requestId, - slotIndex, - period, - merkleRoot, - challenge - ) + Transaction.missingProof(proofInput) of TransactionKind.storageProof: let proof = Groth16Proof.example - Transaction.storageProof( - requestId, - slotIndex, - period, - merkleRoot, - challenge, - proof - ) + Transaction.storageProof(proofInput, proof) proc example*(_: type Identity): Identity = Identity.random(result) diff --git a/tests/codexvalidator/transaction/testSerialization.nim b/tests/codexvalidator/transaction/testSerialization.nim index a7690ef..6dbcda0 100644 --- a/tests/codexvalidator/transaction/testSerialization.nim +++ b/tests/codexvalidator/transaction/testSerialization.nim @@ -13,32 +13,32 @@ suite "Transaction serialization": {.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 == array[32, byte](transaction.merkleRoot) - check protobuf.challenge == array[32, byte](transaction.challenge) - test "serializes a storage proof with protobuf": - let proof = Groth16Proof.example - let transaction = Transaction.storageProof( - StorageRequestId.example, - uint32.example, - Period.example, - array[32, byte].example, - array[32, byte].example, - proof - ) + test "serializes storage proof input with protobuf": + let transaction = Transaction.example + let proofInput = transaction.proofInput let serialized = transaction.toBytes() let protobuf = ProtoBuf.decode(serialized, TransactionMessage) - 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() + check protobuf.proofInput.requestId == array[32, byte](proofInput.requestId) + check protobuf.proofInput.slotIndex == proofInput.slotIndex + check protobuf.proofInput.period == proofInput.period.uint64 + check protobuf.proofInput.merkleRoot == array[32, byte](proofInput.merkleRoot) + check protobuf.proofInput.challenge == array[32, byte](proofInput.challenge) + + test "serializes a storage proof with protobuf": + let proofInput = StorageProofInput.example + let proof = Groth16Proof.example + let transaction = Transaction.storageProof(proofInput, proof) + let serialized = transaction.toBytes() + let protobuf = ProtoBuf.decode(serialized, TransactionMessage) + check protobuf.proof.a.x == proof.a.x.toBytesBE() + check protobuf.proof.a.y == proof.a.y.toBytesBE() + check protobuf.proof.b.x.real == proof.b.x.real.toBytesBE() + check protobuf.proof.b.x.imag == proof.b.x.imag.toBytesBE() + check protobuf.proof.b.y.real == proof.b.y.real.toBytesBE() + check protobuf.proof.b.y.imag == proof.b.y.imag.toBytesBE() + check protobuf.proof.c.x == proof.c.x.toBytesBE() + check protobuf.proof.c.y == proof.c.y.toBytesBE() test "serializes a signed transaction with protobuf": let signed = Signed[Transaction].example @@ -99,7 +99,7 @@ suite "Transaction serialization": test "deserialization fails when storage request id is invalid": let signed = Signed[Transaction].example var message = SignedTransactionMessage.init(signed) - message.transaction.requestid &= 42'u8 + message.transaction.proofInput.requestid &= 42'u8 let invalid = Protobuf.encode(message) let deserialized = Signed[Transaction].fromBytes(invalid) check deserialized.isFailure @@ -108,7 +108,7 @@ suite "Transaction serialization": test "deserialization fails when merkle root is invalid": let signed = Signed[Transaction].example var message = SignedTransactionMessage.init(signed) - message.transaction.merkleRoot &= 42'u8 + message.transaction.proofInput.merkleRoot &= 42'u8 let invalid = Protobuf.encode(message) let deserialized = Signed[Transaction].fromBytes(invalid) check deserialized.isFailure @@ -117,7 +117,7 @@ suite "Transaction serialization": test "deserialization fails when challenge is invalid": let signed = Signed[Transaction].example var message = SignedTransactionMessage.init(signed) - message.transaction.challenge &= 42'u8 + message.transaction.proofInput.challenge &= 42'u8 let invalid = Protobuf.encode(message) let deserialized = Signed[Transaction].fromBytes(invalid) check deserialized.isFailure diff --git a/tests/codexvalidator/transaction/testTransaction.nim b/tests/codexvalidator/transaction/testTransaction.nim index 1d76b5c..d42b1ad 100644 --- a/tests/codexvalidator/transaction/testTransaction.nim +++ b/tests/codexvalidator/transaction/testTransaction.nim @@ -4,36 +4,16 @@ import codexvalidator/transaction suite "Transaction": test "a transaction can contain a storage proof": - let requestId = StorageRequestId.example - let slotIndex = uint32.example - let period = Period.example - let merkleRoot = array[32, byte].example - let challenge = array[32, byte].example + let proofInput = StorageProofInput.example let proof = Groth16Proof.example - let transaction = Transaction.storageProof( - requestId, slotIndex, period, merkleRoot, challenge, proof - ) - check transaction.requestId == requestId - check transaction.slotIndex == slotIndex - check transaction.period == period - check transaction.merkleRoot == merkleRoot - check transaction.challenge == challenge + let transaction = Transaction.storageProof(proofInput, proof) + check transaction.proofInput == proofInput check transaction.proof == proof test "a transaction can indicate a missing storage proof": - let requestId = StorageRequestId.example - let slotIndex = uint32.example - let period = Period.example - let merkleRoot = array[32, byte].example - let challenge = array[32, byte].example - let transaction = Transaction.missingProof( - requestId, slotIndex, period, merkleRoot, challenge - ) - check transaction.requestId == requestId - check transaction.slotIndex == slotIndex - check transaction.period == period - check transaction.merkleRoot == merkleRoot - check transaction.challenge == challenge + let proofInput = StorageProofInput.example + let transaction = Transaction.missingProof(proofInput) + check transaction.proofInput == proofInput test "transactions have a fixed version": let transaction = Transaction.example