From 67176b36879155760560d19bc8e1258f6ffbaa6a Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Thu, 5 Aug 2021 10:16:38 +0200 Subject: [PATCH] Convert Transaction and Ack to ref types Reason: performance, copying transactions and acks around leads to significant slowdowns --- abc/acks.nim | 28 ++++++++++++------------ abc/transactions.nim | 18 +++++++-------- tests/abc/alicebob.nim | 2 +- tests/abc/examples.nim | 4 ++-- tests/abc/testAcks.nim | 14 ++++++------ tests/abc/testHistory.nim | 40 +++++++++++++++++----------------- tests/abc/testTransactions.nim | 24 ++++++++++---------- tests/abc/testTxStore.nim | 24 ++++++++++---------- 8 files changed, 77 insertions(+), 77 deletions(-) diff --git a/abc/acks.nim b/abc/acks.nim index 7a3da69..90beb9d 100644 --- a/abc/acks.nim +++ b/abc/acks.nim @@ -6,7 +6,7 @@ export hash export keys type - Ack* = object + Ack* = ref object previous: ?Hash transactions: seq[Hash] validator: PublicKey @@ -21,10 +21,10 @@ func toBytes*(ack: Ack): seq[byte] = result.add(transaction.toBytes) result.add(ack.validator.toBytes) -func init(_: type Ack, - previous: ?Hash, - transactions: openArray[Hash], - validator: PublicKey): ?Ack = +func new(_: type Ack, + previous: ?Hash, + transactions: openArray[Hash], + validator: PublicKey): ?Ack = if previous =? previous and previous.kind != HashKind.Ack: return none Ack @@ -43,16 +43,16 @@ func init(_: type Ack, ack.hash = hash(ack.toBytes, HashKind.Ack) some ack -func init*(_: type Ack, - transactions: openArray[Hash], - validator: PublicKey): ?Ack = - Ack.init(Hash.none, transactions, validator) +func new*(_: type Ack, + transactions: openArray[Hash], + validator: PublicKey): ?Ack = + Ack.new(Hash.none, transactions, validator) -func init*(_: type Ack, - previous: Hash, - transactions: openArray[Hash], - validator: PublicKey): ?Ack = - Ack.init(previous.some, transactions, validator) +func new*(_: type Ack, + previous: Hash, + transactions: openArray[Hash], + validator: PublicKey): ?Ack = + Ack.new(previous.some, transactions, validator) func previous*(ack: Ack): ?Hash = ack.previous diff --git a/abc/transactions.nim b/abc/transactions.nim index ff8aec7..c1a5302 100644 --- a/abc/transactions.nim +++ b/abc/transactions.nim @@ -12,7 +12,7 @@ export keys export hash type - Transaction* = object + Transaction* = ref object inputs: seq[TxInput] outputs: seq[TxOutput] validator: PublicKey @@ -36,10 +36,10 @@ func toBytes*(transaction: Transaction): seq[byte] = result.add(value.toBytes) result.add(transaction.validator.toBytes) -func init*(_: type Transaction, - inputs: openArray[TxInput], - outputs: openArray[TxOutput], - validator: PublicKey): ?Transaction = +func new*(_: type Transaction, + inputs: openArray[TxInput], + outputs: openArray[TxOutput], + validator: PublicKey): ?Transaction = if outputs.len == 0: return none Transaction @@ -58,10 +58,10 @@ func init*(_: type Transaction, transaction.hash = hash(transaction.toBytes, HashKind.Tx) some transaction -func init*(_: type Transaction, - outputs: openArray[TxOutput], - validator: PublicKey): ?Transaction = - Transaction.init([], outputs, validator) +func new*(_: type Transaction, + outputs: openArray[TxOutput], + validator: PublicKey): ?Transaction = + Transaction.new([], outputs, validator) func inputs*(transaction: Transaction): seq[TxInput] = transaction.inputs diff --git a/tests/abc/alicebob.nim b/tests/abc/alicebob.nim index 95a445d..4542064 100644 --- a/tests/abc/alicebob.nim +++ b/tests/abc/alicebob.nim @@ -31,4 +31,4 @@ proc genesis*(_: type Transaction): Transaction = let alice = PublicKey.alice let bob = PublicKey.bob let victor = PublicKey.victor - !Transaction.init({alice: 100.u256, bob: 100.u256}, victor) + !Transaction.new({alice: 100.u256, bob: 100.u256}, victor) diff --git a/tests/abc/examples.nim b/tests/abc/examples.nim index 39e8fb6..9b6c26c 100644 --- a/tests/abc/examples.nim +++ b/tests/abc/examples.nim @@ -20,7 +20,7 @@ proc example*(_: type Transaction): Transaction = let victor = PublicKey.victor let genesis = Transaction.genesis let amount = rand(100).u256 - var transaction = !Transaction.init( + var transaction = !Transaction.new( {genesis.hash: alice}, {carol: amount, alice: 100.u256 - amount}, victor @@ -30,4 +30,4 @@ proc example*(_: type Transaction): Transaction = proc example*(_: type Ack): Ack = let tx1, tx2 = Transaction.example let validator = PublicKey.example - !Ack.init([tx1.hash, tx2.hash], validator) + !Ack.new([tx1.hash, tx2.hash], validator) diff --git a/tests/abc/testAcks.nim b/tests/abc/testAcks.nim index 63628df..c71ae5c 100644 --- a/tests/abc/testAcks.nim +++ b/tests/abc/testAcks.nim @@ -8,7 +8,7 @@ suite "Acknowledgements": let victor = PublicKey.victor test "a first acknowledgement can be made": - let ack = Ack.init([tx1.hash, tx2.hash], victor) + let ack = Ack.new([tx1.hash, tx2.hash], victor) check ack.isSome check ack.?transactions == @[tx1.hash, tx2.hash].some check ack.?previous == Hash.none @@ -22,7 +22,7 @@ suite "Acknowledgements": test "an acknowledgement references a previous acknowledgement": let previous = Ack.example - let ack = Ack.init(previous.hash, [tx1.hash, tx2.hash], victor) + let ack = Ack.new(previous.hash, [tx1.hash, tx2.hash], victor) check ack.isSome check ack.?transactions == @[tx1.hash, tx2.hash].some check ack.?previous == previous.hash.some @@ -30,7 +30,7 @@ suite "Acknowledgements": test "an acknowledgement can be converted to bytes": let previous = Ack.example - let ack = !Ack.init(previous.hash, [tx1.hash, tx2.hash], victor) + let ack = !Ack.new(previous.hash, [tx1.hash, tx2.hash], victor) var expected: seq[byte] expected.add(previous.hash.toBytes) expected.add(2) # amount of transactions @@ -53,7 +53,7 @@ suite "Acknowledgements": check ack.signature == key.sign(ack.hash.toBytes).some test "acknowledgement signature can be checked for validity": - var ack = !Ack.init([tx1.hash, tx2.hash], victor) + var ack = !Ack.new([tx1.hash, tx2.hash], victor) PrivateKey.bob.sign(ack) check not ack.hasValidSignature PrivateKey.victor.sign(ack) @@ -61,13 +61,13 @@ suite "Acknowledgements": test "an acknowledgement must contain at least one transaction": let previous = Ack.example - check Ack.init(previous.hash, [], victor).isNone + check Ack.new(previous.hash, [], victor).isNone test "previous acknowledgement must have correct hash type": let transaction = Transaction.example let invalidPrevious = Transaction.example - check Ack.init(invalidPrevious.hash, [transaction.hash], victor).isNone + check Ack.new(invalidPrevious.hash, [transaction.hash], victor).isNone test "acknowledged transactions must have correct hash type": let invalidTransaction = Ack.example - check Ack.init([invalidTransaction.hash], victor).isNone + check Ack.new([invalidTransaction.hash], victor).isNone diff --git a/tests/abc/testHistory.nim b/tests/abc/testHistory.nim index 169ff99..2d575f9 100644 --- a/tests/abc/testHistory.nim +++ b/tests/abc/testHistory.nim @@ -18,16 +18,16 @@ suite "Past transactions and acknowledgements": setup: store = TxStore.new(genesis) - tx1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256}, victor) - tx2 = !Transaction.init({genesis.hash: bob}, {alice: 100.u256}, victor) - tx3 = !Transaction.init( + tx1 = !Transaction.new({genesis.hash: alice}, {bob: 100.u256}, victor) + tx2 = !Transaction.new({genesis.hash: bob}, {alice: 100.u256}, victor) + tx3 = !Transaction.new( {tx1.hash: bob, tx2.hash: alice}, {alice: 200.u256}, victor ) - ack1 = !Ack.init([tx1.hash], victor) - ack2 = !Ack.init([tx2.hash], victor) - ack3 = !Ack.init(ack1.hash, [tx2.hash, tx3.hash], victor) + ack1 = !Ack.new([tx1.hash], victor) + ack2 = !Ack.new([tx2.hash], victor) + ack3 = !Ack.new(ack1.hash, [tx2.hash, tx3.hash], victor) PrivateKey.alice.sign(tx1) PrivateKey.bob.sign(tx2) PrivateKey.alice.sign(tx3) @@ -78,8 +78,8 @@ suite "Transaction validation": setup: store = TxStore.new(genesis) - tx1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256}, victor) - tx2 = !Transaction.init({tx1.hash: bob}, {alice: 100.u256}, victor) + tx1 = !Transaction.new({genesis.hash: alice}, {bob: 100.u256}, victor) + tx2 = !Transaction.new({tx1.hash: bob}, {alice: 100.u256}, victor) PrivateKey.alice.sign(tx1) PrivateKey.bob.sign(tx2) @@ -96,8 +96,8 @@ suite "Transaction validation": check past.missing == set(tx1.hash) test "checks that inputs and outputs match": - var bad1 = !Transaction.init({genesis.hash: alice}, {bob: 999.u256}, victor) - var bad2 = !Transaction.init({bad1.hash: bob}, {alice: 999.u256}, victor) + var bad1 = !Transaction.new({genesis.hash: alice}, {bob: 999.u256}, victor) + var bad2 = !Transaction.new({bad1.hash: bob}, {alice: 999.u256}, victor) PrivateKey.alice.sign(bad1) PrivateKey.bob.sign(bad2) store.add(bad1, bad2) @@ -107,8 +107,8 @@ suite "Transaction validation": check past.invalid == set(bad1.hash) test "checks that signatures match": - var bad1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256}, victor) - var bad2 = !Transaction.init({bad1.hash: bob}, {alice: 100.u256}, victor) + var bad1 = !Transaction.new({genesis.hash: alice}, {bob: 100.u256}, victor) + var bad2 = !Transaction.new({bad1.hash: bob}, {alice: 100.u256}, victor) PrivateKey.bob.sign(bad1) # invalid signature, should be signed by alice PrivateKey.bob.sign(bad2) store.add(bad1, bad2) @@ -129,10 +129,10 @@ suite "Acknowledgement validation": setup: store = TxStore.new(genesis) - tx1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256}, victor) - tx2 = !Transaction.init({tx1.hash: bob}, {alice: 100.u256}, victor) - ack1 = !Ack.init([tx1.hash], victor) - ack2 = !Ack.init(ack1.hash, [tx2.hash], victor) + tx1 = !Transaction.new({genesis.hash: alice}, {bob: 100.u256}, victor) + tx2 = !Transaction.new({tx1.hash: bob}, {alice: 100.u256}, victor) + ack1 = !Ack.new([tx1.hash], victor) + ack2 = !Ack.new(ack1.hash, [tx2.hash], victor) PrivateKey.alice.sign(tx1) PrivateKey.bob.sign(tx2) PrivateKey.victor.sign(ack1) @@ -159,8 +159,8 @@ suite "Acknowledgement validation": check past.missing == set(tx1.hash) test "checks that no transaction is invalid": - var bad = !Transaction.init({genesis.hash: alice}, {bob: 999.u256}, victor) - var ack = !Ack.init([bad.hash], victor) + var bad = !Transaction.new({genesis.hash: alice}, {bob: 999.u256}, victor) + var ack = !Ack.new([bad.hash], victor) PrivateKey.alice.sign(bad) PrivateKey.victor.sign(ack) store.add(bad) @@ -170,8 +170,8 @@ suite "Acknowledgement validation": check past.invalid == set(bad.hash) test "checks that signatures match": - var bad1 = !Ack.init([tx1.hash], victor) - var bad2 = !Ack.init(bad1.hash, [tx2.hash], victor) + var bad1 = !Ack.new([tx1.hash], victor) + var bad2 = !Ack.new(bad1.hash, [tx2.hash], victor) PrivateKey.bob.sign(bad1) # invalid signature, should be signed by victor PrivateKey.victor.sign(bad2) store.add(tx1, tx2) diff --git a/tests/abc/testTransactions.nim b/tests/abc/testTransactions.nim index b35d1b0..e6f8df6 100644 --- a/tests/abc/testTransactions.nim +++ b/tests/abc/testTransactions.nim @@ -8,7 +8,7 @@ suite "Transactions": let victor = PublicKey.victor test "a genesis transaction can be made": - let genesis = Transaction.init({alice: 32.u256, bob: 10.u256}, victor) + let genesis = Transaction.new({alice: 32.u256, bob: 10.u256}, victor) check genesis.isSome test "a transaction has a hash": @@ -18,8 +18,8 @@ suite "Transactions": check transaction1.hash != transaction2.hash test "a transaction references outputs from other transactions": - let genesis = !Transaction.init({alice: 32.u256, bob: 10.u256}, victor) - let transaction = !Transaction.init( + let genesis = !Transaction.new({alice: 32.u256, bob: 10.u256}, victor) + let transaction = !Transaction.new( {genesis.hash: alice}, {alice: 2.u256, bob: 30.u256}, victor @@ -28,18 +28,18 @@ suite "Transactions": check transaction.outputs.len == 2 test "transaction value is the sum of its output values": - let genesis = !Transaction.init({alice: 32.u256, bob: 10.u256}, victor) + let genesis = !Transaction.new({alice: 32.u256, bob: 10.u256}, victor) check genesis.value == 42.u256 test "output value is the value of the output for given owner": - let genesis = !Transaction.init({alice: 32.u256, bob: 10.u256}, victor) + let genesis = !Transaction.new({alice: 32.u256, bob: 10.u256}, victor) check genesis.outputValue(alice) == 32.u256 check genesis.outputValue(bob) == 10.u256 check genesis.outputValue(victor) == 0.u256 test "a transaction can be converted to bytes": - let genesis = !Transaction.init({alice: 32.u256, bob: 10.u256}, victor) - let transaction = !Transaction.init( + let genesis = !Transaction.new({alice: 32.u256, bob: 10.u256}, victor) + let transaction = !Transaction.new( {genesis.hash: alice}, {alice: 2.u256, bob: 30.u256}, victor @@ -73,9 +73,9 @@ suite "Transactions": check transaction.signature == key.sign(transaction.hash.toBytes) test "transaction signature can be checked for validity": - let genesis = !Transaction.init({alice: 32.u256, bob: 10.u256}, victor) + let genesis = !Transaction.new({alice: 32.u256, bob: 10.u256}, victor) check not genesis.hasValidSignature() - var transaction = !Transaction.init( + var transaction = !Transaction.new( {genesis.hash: alice}, {alice: 2.u256, bob: 30.u256}, victor @@ -88,11 +88,11 @@ suite "Transactions": check not transaction.hasValidSignature test "transaction must have at least one output": - check Transaction.init([], victor).isNone + check Transaction.new([], victor).isNone test "multiple outputs to the same owner are not allowed": - check Transaction.init({alice: 40.u256, alice: 2.u256}, victor).isNone + check Transaction.new({alice: 40.u256, alice: 2.u256}, victor).isNone test "inputs must have correct hash kind": let invalid = Ack.example - check Transaction.init({invalid.hash: alice}, {bob: 1.u256}, victor).isNone + check Transaction.new({invalid.hash: alice}, {bob: 1.u256}, victor).isNone diff --git a/tests/abc/testTxStore.nim b/tests/abc/testTxStore.nim index 3c14d53..d2cba58 100644 --- a/tests/abc/testTxStore.nim +++ b/tests/abc/testTxStore.nim @@ -39,8 +39,8 @@ suite "Transaction Store": check not store.isConfirmed(transaction.hash) test "transaction with acknowledgement by all stake is confirmed": - var tx = !Transaction.init({genesis.hash: bob}, {bob: 100.u256}, victor) - var ack = !Ack.init([tx.hash], victor) + var tx = !Transaction.new({genesis.hash: bob}, {bob: 100.u256}, victor) + var ack = !Ack.new([tx.hash], victor) PrivateKey.bob.sign(tx) PrivateKey.victor.sign(ack) let store = TxStore.new(genesis) @@ -49,11 +49,11 @@ suite "Transaction Store": check store.isConfirmed(tx.hash) test "transaction with acknowledgements > 2/3 stake is confirmed": - let genesis = !Transaction.init({alice: 67.u256, bob: 33.u256}, victor) - var tx1 = !Transaction.init({genesis.hash: alice}, {alice: 67.u256}, vanna) - var tx2 = !Transaction.init({tx1.hash: alice}, {alice: 67.u256}, victor) - var ack1 = !Ack.init([tx1.hash], victor) - var ack2 = !Ack.init([tx2.hash], vanna) + let genesis = !Transaction.new({alice: 67.u256, bob: 33.u256}, victor) + var tx1 = !Transaction.new({genesis.hash: alice}, {alice: 67.u256}, vanna) + var tx2 = !Transaction.new({tx1.hash: alice}, {alice: 67.u256}, victor) + var ack1 = !Ack.new([tx1.hash], victor) + var ack2 = !Ack.new([tx2.hash], vanna) PrivateKey.alice.sign(tx1) PrivateKey.alice.sign(tx2) PrivateKey.victor.sign(ack1) @@ -65,11 +65,11 @@ suite "Transaction Store": check store.isConfirmed(tx2.hash) test "transaction with acknowledgements < 2/3 stake is not confirmed": - let genesis = !Transaction.init({alice: 66.u256, bob: 34.u256}, victor) - var tx1 = !Transaction.init({genesis.hash: alice}, {alice: 66.u256}, vanna) - var tx2 = !Transaction.init({tx1.hash: alice}, {alice: 66.u256}, victor) - var ack1 = !Ack.init([tx1.hash], victor) - var ack2 = !Ack.init([tx2.hash], vanna) + let genesis = !Transaction.new({alice: 66.u256, bob: 34.u256}, victor) + var tx1 = !Transaction.new({genesis.hash: alice}, {alice: 66.u256}, vanna) + var tx2 = !Transaction.new({tx1.hash: alice}, {alice: 66.u256}, victor) + var ack1 = !Ack.new([tx1.hash], victor) + var ack2 = !Ack.new([tx2.hash], vanna) PrivateKey.alice.sign(tx1) PrivateKey.alice.sign(tx2) PrivateKey.victor.sign(ack1)