Check validity of outputs when initializing Transaction

This commit is contained in:
Mark Spanbroek 2021-06-29 11:00:40 +02:00
parent cc353875c8
commit f65ad13904
4 changed files with 39 additions and 9 deletions

6
abc/helpers.nim Normal file
View File

@ -0,0 +1,6 @@
func hasDuplicates*[T](elements: openArray[T]): bool =
for i in 0..<elements.len:
for j in i+1..<elements.len:
if elements[i] == elements[j]:
return true
false

View File

@ -1,6 +1,10 @@
import std/sequtils
import std/sugar
import pkg/nimcrypto
import pkg/stint
import pkg/questionable
import ./keys
import ./helpers
export stint
export keys
@ -22,11 +26,17 @@ func `==`*(a, b: TxHash): bool {.borrow.}
func init*(_: type Transaction,
inputs: openArray[TxInput],
outputs: openArray[TxOutput]): Transaction =
Transaction(inputs: @inputs, outputs: @outputs)
outputs: openArray[TxOutput]): ?Transaction =
if outputs.len == 0:
return none Transaction
if outputs.map(output => output.owner).hasDuplicates:
return none Transaction
some Transaction(inputs: @inputs, outputs: @outputs)
func init*(_: type Transaction,
outputs: openArray[TxOutput]): Transaction =
outputs: openArray[TxOutput]): ?Transaction =
Transaction.init([], outputs)
func inputs*(transaction: Transaction): seq[TxInput] =

View File

@ -1,5 +1,7 @@
import pkg/questionable
import abc/keys
import abc/transactions
import abc/wallet
proc example*(_: type PrivateKey): PrivateKey =
PrivateKey.random
@ -9,5 +11,9 @@ proc example*(_: type PublicKey): PublicKey =
proc example*(_: type Transaction): Transaction =
let alice, bob = PublicKey.example
let genesis = Transaction.init({alice: 32.u256, bob: 10.u256})
Transaction.init({genesis.hash: alice}, {alice: 2.u256, bob: 30.u256})
let genesis = !Transaction.init({alice: 32.u256, bob: 10.u256})
!Transaction.init({genesis.hash: alice}, {alice: 2.u256, bob: 30.u256})
proc example*(_: type Wallet): Wallet =
let key = PrivateKey.example
Wallet.init(key)

View File

@ -1,4 +1,5 @@
import std/unittest
import pkg/questionable
import abc/transactions
import ./examples
@ -8,6 +9,7 @@ suite "Transactions":
test "a genesis transaction can be made":
let genesis = Transaction.init({alice: 32.u256, bob: 10.u256})
check genesis.isSome
test "a transaction has a hash":
let transaction1, transaction2 = Transaction.example
@ -16,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})
let transaction = Transaction.init(
let genesis = !Transaction.init({alice: 32.u256, bob: 10.u256})
let transaction = !Transaction.init(
{genesis.hash: alice},
{alice: 2.u256, bob: 30.u256}
)
@ -25,8 +27,8 @@ suite "Transactions":
check transaction.outputs.len == 2
test "a transaction can be converted to bytes":
let genesis = Transaction.init({alice: 32.u256, bob: 10.u256})
let transaction = Transaction.init(
let genesis = !Transaction.init({alice: 32.u256, bob: 10.u256})
let transaction = !Transaction.init(
{genesis.hash: alice},
{alice: 2.u256, bob: 30.u256}
)
@ -50,3 +52,9 @@ suite "Transactions":
check transaction.signature == sig1
transaction.add(sig2)
check transaction.signature == aggregate(sig1, sig2)
test "transaction must have at least one output":
check Transaction.init([]).isNone
test "multiple outputs to the same owner are not allowed":
check Transaction.init({alice: 40.u256, alice: 2.u256}).isNone