mirror of https://github.com/status-im/nim-abc.git
Add validator to transactions
This commit is contained in:
parent
96908b01b5
commit
c054636381
|
@ -13,6 +13,7 @@ type
|
|||
Transaction* = object
|
||||
inputs: seq[TxInput]
|
||||
outputs: seq[TxOutput]
|
||||
validator: PublicKey
|
||||
signature: Signature
|
||||
TxInput* = tuple
|
||||
txHash: TxHash
|
||||
|
@ -26,18 +27,20 @@ func `==`*(a, b: TxHash): bool {.borrow.}
|
|||
|
||||
func init*(_: type Transaction,
|
||||
inputs: openArray[TxInput],
|
||||
outputs: openArray[TxOutput]): ?Transaction =
|
||||
outputs: openArray[TxOutput],
|
||||
validator: PublicKey): ?Transaction =
|
||||
if outputs.len == 0:
|
||||
return none Transaction
|
||||
|
||||
if outputs.map(output => output.owner).hasDuplicates:
|
||||
return none Transaction
|
||||
|
||||
some Transaction(inputs: @inputs, outputs: @outputs)
|
||||
some Transaction(inputs: @inputs, outputs: @outputs, validator: validator)
|
||||
|
||||
func init*(_: type Transaction,
|
||||
outputs: openArray[TxOutput]): ?Transaction =
|
||||
Transaction.init([], outputs)
|
||||
outputs: openArray[TxOutput],
|
||||
validator: PublicKey): ?Transaction =
|
||||
Transaction.init([], outputs, validator)
|
||||
|
||||
func inputs*(transaction: Transaction): seq[TxInput] =
|
||||
transaction.inputs
|
||||
|
@ -48,6 +51,9 @@ func outputs*(transaction: Transaction): seq[TxOutput] =
|
|||
func signature*(transaction: Transaction): Signature =
|
||||
transaction.signature
|
||||
|
||||
func validator*(transaction: Transaction): PublicKey =
|
||||
transaction.validator
|
||||
|
||||
func add*(transaction: var Transaction, signature: Signature) =
|
||||
transaction.signature = aggregate(transaction.signature, signature)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import pkg/questionable
|
||||
import abc
|
||||
|
||||
let a, b = PrivateKey.random
|
||||
let a, b, v = PrivateKey.random
|
||||
|
||||
proc alice*(_: type PrivateKey): PrivateKey =
|
||||
a
|
||||
|
@ -9,13 +9,20 @@ proc alice*(_: type PrivateKey): PrivateKey =
|
|||
proc bob*(_: type PrivateKey): PrivateKey =
|
||||
b
|
||||
|
||||
proc victor*(_: type PrivateKey): PrivateKey =
|
||||
v
|
||||
|
||||
proc alice*(_: type PublicKey): PublicKey =
|
||||
a.toPublicKey
|
||||
|
||||
proc bob*(_: type PublicKey): PublicKey =
|
||||
b.toPublicKey
|
||||
|
||||
proc victor*(_: type PublicKey): PublicKey =
|
||||
v.toPublicKey
|
||||
|
||||
proc genesis*(_: type Transaction): Transaction =
|
||||
let alice = PublicKey.alice
|
||||
let bob = PublicKey.bob
|
||||
!Transaction.init({alice: 100.u256, bob: 100.u256})
|
||||
let victor = PublicKey.victor
|
||||
!Transaction.init({alice: 100.u256, bob: 100.u256}, victor)
|
||||
|
|
|
@ -16,10 +16,12 @@ proc example*(_: type Wallet): Wallet =
|
|||
proc example*(_: type Transaction): Transaction =
|
||||
let alice = PublicKey.alice
|
||||
let bob = PublicKey.bob
|
||||
let victor = PublicKey.victor
|
||||
let genesis = Transaction.genesis
|
||||
let amount = rand(100).u256
|
||||
var transaction = !Transaction.init(
|
||||
{genesis.hash: alice},
|
||||
{bob: amount, alice: 100.u256 - amount}
|
||||
{bob: amount, alice: 100.u256 - amount},
|
||||
victor
|
||||
)
|
||||
transaction
|
||||
|
|
|
@ -5,9 +5,10 @@ suite "Transactions":
|
|||
|
||||
let alice = PublicKey.alice
|
||||
let bob = PublicKey.bob
|
||||
let victor = PublicKey.victor
|
||||
|
||||
test "a genesis transaction can be made":
|
||||
let genesis = Transaction.init({alice: 32.u256, bob: 10.u256})
|
||||
let genesis = Transaction.init({alice: 32.u256, bob: 10.u256}, victor)
|
||||
check genesis.isSome
|
||||
|
||||
test "a transaction has a hash":
|
||||
|
@ -17,19 +18,21 @@ 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 genesis = !Transaction.init({alice: 32.u256, bob: 10.u256}, victor)
|
||||
let transaction = !Transaction.init(
|
||||
{genesis.hash: alice},
|
||||
{alice: 2.u256, bob: 30.u256}
|
||||
{alice: 2.u256, bob: 30.u256},
|
||||
victor
|
||||
)
|
||||
check transaction.inputs.len == 1
|
||||
check transaction.outputs.len == 2
|
||||
|
||||
test "a transaction can be converted to bytes":
|
||||
let genesis = !Transaction.init({alice: 32.u256, bob: 10.u256})
|
||||
let genesis = !Transaction.init({alice: 32.u256, bob: 10.u256}, victor)
|
||||
let transaction = !Transaction.init(
|
||||
{genesis.hash: alice},
|
||||
{alice: 2.u256, bob: 30.u256}
|
||||
{alice: 2.u256, bob: 30.u256},
|
||||
victor
|
||||
)
|
||||
var expected: seq[byte]
|
||||
expected.add(1) # amount of inputs
|
||||
|
@ -59,11 +62,12 @@ 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})
|
||||
let genesis = !Transaction.init({alice: 32.u256, bob: 10.u256}, victor)
|
||||
check not genesis.hasValidSignature()
|
||||
var transaction = !Transaction.init(
|
||||
{genesis.hash: alice},
|
||||
{alice: 2.u256, bob: 30.u256}
|
||||
{alice: 2.u256, bob: 30.u256},
|
||||
victor
|
||||
)
|
||||
let hash = transaction.hash.toBytes
|
||||
check not transaction.hasValidSignature
|
||||
|
@ -73,7 +77,7 @@ suite "Transactions":
|
|||
check not transaction.hasValidSignature
|
||||
|
||||
test "transaction must have at least one output":
|
||||
check Transaction.init([]).isNone
|
||||
check Transaction.init([], victor).isNone
|
||||
|
||||
test "multiple outputs to the same owner are not allowed":
|
||||
check Transaction.init({alice: 40.u256, alice: 2.u256}).isNone
|
||||
check Transaction.init({alice: 40.u256, alice: 2.u256}, victor).isNone
|
||||
|
|
|
@ -7,12 +7,13 @@ suite "Transaction validation":
|
|||
|
||||
let alice = PublicKey.alice
|
||||
let bob = PublicKey.bob
|
||||
let victor = PublicKey.victor
|
||||
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})
|
||||
tx1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256}, victor)
|
||||
tx2 = !Transaction.init({tx1.hash: bob}, {alice: 100.u256}, victor)
|
||||
PrivateKey.alice.sign(tx1)
|
||||
PrivateKey.bob.sign(tx2)
|
||||
|
||||
|
@ -30,20 +31,20 @@ suite "Transaction validation":
|
|||
|
||||
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)
|
||||
var bad1 = !Transaction.init({genesis.hash: alice}, {bob: 999.u256}, victor)
|
||||
var bad2 = !Transaction.init({bad1.hash: bob}, {alice: 999.u256}, victor)
|
||||
PrivateKey.alice.sign(bad1)
|
||||
PrivateKey.bob.sign(bad2)
|
||||
store.add(bad1, bad2)
|
||||
check not store.hasValidTx(bad1.hash)
|
||||
check not store.hasValidTx(bad2.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)
|
||||
var bad1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256}, victor)
|
||||
var bad2 = !Transaction.init({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)
|
||||
check not store.hasValidTx(bad1.hash)
|
||||
check not store.hasValidTx(bad2.hash)
|
||||
|
|
Loading…
Reference in New Issue