From e17c7cfedc729b848129749223a0e9007b7f9eb9 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Wed, 30 Jun 2021 11:23:04 +0200 Subject: [PATCH] Transaction validation --- abc/txvalidation.nim | 32 +++++++++++++++++++++++++ tests/testTxValidation.nim | 49 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 abc/txvalidation.nim create mode 100644 tests/testTxValidation.nim diff --git a/abc/txvalidation.nim b/abc/txvalidation.nim new file mode 100644 index 0000000..a5030f4 --- /dev/null +++ b/abc/txvalidation.nim @@ -0,0 +1,32 @@ +import ./txstore + +func checkValue(store: TxStore, transaction: Transaction): bool = + var valueIn, valueOut = 0.u256 + + for (hash, owner) in transaction.inputs: + for output in store[hash].outputs: + if output.owner == owner: + valueIn += output.amount + + for (_, amount) in transaction.outputs: + valueOut += amount + + valueIn == valueOut + +func hasValidTx*(store: TxStore, hash: TxHash): bool = + if hash == store.genesis: + return true + + if not store.hasTx(hash): + return false + + let transaction = store[hash] + + if not transaction.hasValidSignature: + return false + + for (hash, _) in transaction.inputs: + if not store.hasValidTx(hash): + return false + + store.checkValue(transaction) diff --git a/tests/testTxValidation.nim b/tests/testTxValidation.nim new file mode 100644 index 0000000..3c9ff14 --- /dev/null +++ b/tests/testTxValidation.nim @@ -0,0 +1,49 @@ +import abc/txstore +import abc/txvalidation +import ./basics +import ./alicebob + +suite "Transaction validation": + + let alice = PublicKey.alice + let bob = PublicKey.bob + let genesis = Transaction.genesis + var tx1, tx2: Transaction + + setup: + tx1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256}) + tx2 = !Transaction.init({tx1.hash: bob}, {alice: 100.u256}) + PrivateKey.alice.sign(tx1) + PrivateKey.bob.sign(tx2) + + test "checks validity of transactions": + var store = TxStore.init(genesis) + store.add(tx1, tx2) + check store.hasValidTx(genesis.hash) + check store.hasValidTx(tx1.hash) + check store.hasValidTx(tx2.hash) + + test "checks that no input is missing": + var store = TxStore.init(genesis) + store.add(tx2) # tx2 depends on tx1, which is missing + check not store.hasValidTx(tx2.hash) + + test "checks that inputs and outputs match": + var store = TxStore.init(genesis) + var invalid1 = !Transaction.init({genesis.hash: alice}, {bob: 999.u256}) + var invalid2 = !Transaction.init({invalid1.hash: bob}, {alice: 999.u256}) + PrivateKey.alice.sign(invalid1) + PrivateKey.bob.sign(invalid2) + store.add(invalid1, invalid2) + check not store.hasValidTx(invalid1.hash) + check not store.hasValidTx(invalid2.hash) + + test "checks that signatures match": + var store = TxStore.init(genesis) + var invalid1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256}) + var invalid2 = !Transaction.init({invalid1.hash: bob}, {alice: 100.u256}) + PrivateKey.bob.sign(invalid1) # invalid signature, should be signed by alice + PrivateKey.bob.sign(invalid2) + store.add(invalid1, invalid2) + check not store.hasValidTx(invalid1.hash) + check not store.hasValidTx(invalid2.hash)