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
|
Transaction* = object
|
||||||
inputs: seq[TxInput]
|
inputs: seq[TxInput]
|
||||||
outputs: seq[TxOutput]
|
outputs: seq[TxOutput]
|
||||||
|
validator: PublicKey
|
||||||
signature: Signature
|
signature: Signature
|
||||||
TxInput* = tuple
|
TxInput* = tuple
|
||||||
txHash: TxHash
|
txHash: TxHash
|
||||||
|
@ -26,18 +27,20 @@ func `==`*(a, b: TxHash): bool {.borrow.}
|
||||||
|
|
||||||
func init*(_: type Transaction,
|
func init*(_: type Transaction,
|
||||||
inputs: openArray[TxInput],
|
inputs: openArray[TxInput],
|
||||||
outputs: openArray[TxOutput]): ?Transaction =
|
outputs: openArray[TxOutput],
|
||||||
|
validator: PublicKey): ?Transaction =
|
||||||
if outputs.len == 0:
|
if outputs.len == 0:
|
||||||
return none Transaction
|
return none Transaction
|
||||||
|
|
||||||
if outputs.map(output => output.owner).hasDuplicates:
|
if outputs.map(output => output.owner).hasDuplicates:
|
||||||
return none Transaction
|
return none Transaction
|
||||||
|
|
||||||
some Transaction(inputs: @inputs, outputs: @outputs)
|
some Transaction(inputs: @inputs, outputs: @outputs, validator: validator)
|
||||||
|
|
||||||
func init*(_: type Transaction,
|
func init*(_: type Transaction,
|
||||||
outputs: openArray[TxOutput]): ?Transaction =
|
outputs: openArray[TxOutput],
|
||||||
Transaction.init([], outputs)
|
validator: PublicKey): ?Transaction =
|
||||||
|
Transaction.init([], outputs, validator)
|
||||||
|
|
||||||
func inputs*(transaction: Transaction): seq[TxInput] =
|
func inputs*(transaction: Transaction): seq[TxInput] =
|
||||||
transaction.inputs
|
transaction.inputs
|
||||||
|
@ -48,6 +51,9 @@ func outputs*(transaction: Transaction): seq[TxOutput] =
|
||||||
func signature*(transaction: Transaction): Signature =
|
func signature*(transaction: Transaction): Signature =
|
||||||
transaction.signature
|
transaction.signature
|
||||||
|
|
||||||
|
func validator*(transaction: Transaction): PublicKey =
|
||||||
|
transaction.validator
|
||||||
|
|
||||||
func add*(transaction: var Transaction, signature: Signature) =
|
func add*(transaction: var Transaction, signature: Signature) =
|
||||||
transaction.signature = aggregate(transaction.signature, signature)
|
transaction.signature = aggregate(transaction.signature, signature)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import pkg/questionable
|
import pkg/questionable
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
let a, b = PrivateKey.random
|
let a, b, v = PrivateKey.random
|
||||||
|
|
||||||
proc alice*(_: type PrivateKey): PrivateKey =
|
proc alice*(_: type PrivateKey): PrivateKey =
|
||||||
a
|
a
|
||||||
|
@ -9,13 +9,20 @@ proc alice*(_: type PrivateKey): PrivateKey =
|
||||||
proc bob*(_: type PrivateKey): PrivateKey =
|
proc bob*(_: type PrivateKey): PrivateKey =
|
||||||
b
|
b
|
||||||
|
|
||||||
|
proc victor*(_: type PrivateKey): PrivateKey =
|
||||||
|
v
|
||||||
|
|
||||||
proc alice*(_: type PublicKey): PublicKey =
|
proc alice*(_: type PublicKey): PublicKey =
|
||||||
a.toPublicKey
|
a.toPublicKey
|
||||||
|
|
||||||
proc bob*(_: type PublicKey): PublicKey =
|
proc bob*(_: type PublicKey): PublicKey =
|
||||||
b.toPublicKey
|
b.toPublicKey
|
||||||
|
|
||||||
|
proc victor*(_: type PublicKey): PublicKey =
|
||||||
|
v.toPublicKey
|
||||||
|
|
||||||
proc genesis*(_: type Transaction): Transaction =
|
proc genesis*(_: type Transaction): Transaction =
|
||||||
let alice = PublicKey.alice
|
let alice = PublicKey.alice
|
||||||
let bob = PublicKey.bob
|
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 =
|
proc example*(_: type Transaction): Transaction =
|
||||||
let alice = PublicKey.alice
|
let alice = PublicKey.alice
|
||||||
let bob = PublicKey.bob
|
let bob = PublicKey.bob
|
||||||
|
let victor = PublicKey.victor
|
||||||
let genesis = Transaction.genesis
|
let genesis = Transaction.genesis
|
||||||
let amount = rand(100).u256
|
let amount = rand(100).u256
|
||||||
var transaction = !Transaction.init(
|
var transaction = !Transaction.init(
|
||||||
{genesis.hash: alice},
|
{genesis.hash: alice},
|
||||||
{bob: amount, alice: 100.u256 - amount}
|
{bob: amount, alice: 100.u256 - amount},
|
||||||
|
victor
|
||||||
)
|
)
|
||||||
transaction
|
transaction
|
||||||
|
|
|
@ -5,9 +5,10 @@ suite "Transactions":
|
||||||
|
|
||||||
let alice = PublicKey.alice
|
let alice = PublicKey.alice
|
||||||
let bob = PublicKey.bob
|
let bob = PublicKey.bob
|
||||||
|
let victor = PublicKey.victor
|
||||||
|
|
||||||
test "a genesis transaction can be made":
|
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
|
check genesis.isSome
|
||||||
|
|
||||||
test "a transaction has a hash":
|
test "a transaction has a hash":
|
||||||
|
@ -17,19 +18,21 @@ suite "Transactions":
|
||||||
check transaction1.hash != transaction2.hash
|
check transaction1.hash != transaction2.hash
|
||||||
|
|
||||||
test "a transaction references outputs from other transactions":
|
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(
|
let transaction = !Transaction.init(
|
||||||
{genesis.hash: alice},
|
{genesis.hash: alice},
|
||||||
{alice: 2.u256, bob: 30.u256}
|
{alice: 2.u256, bob: 30.u256},
|
||||||
|
victor
|
||||||
)
|
)
|
||||||
check transaction.inputs.len == 1
|
check transaction.inputs.len == 1
|
||||||
check transaction.outputs.len == 2
|
check transaction.outputs.len == 2
|
||||||
|
|
||||||
test "a transaction can be converted to bytes":
|
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(
|
let transaction = !Transaction.init(
|
||||||
{genesis.hash: alice},
|
{genesis.hash: alice},
|
||||||
{alice: 2.u256, bob: 30.u256}
|
{alice: 2.u256, bob: 30.u256},
|
||||||
|
victor
|
||||||
)
|
)
|
||||||
var expected: seq[byte]
|
var expected: seq[byte]
|
||||||
expected.add(1) # amount of inputs
|
expected.add(1) # amount of inputs
|
||||||
|
@ -59,11 +62,12 @@ suite "Transactions":
|
||||||
check transaction.signature == key.sign(transaction.hash.toBytes)
|
check transaction.signature == key.sign(transaction.hash.toBytes)
|
||||||
|
|
||||||
test "transaction signature can be checked for validity":
|
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()
|
check not genesis.hasValidSignature()
|
||||||
var transaction = !Transaction.init(
|
var transaction = !Transaction.init(
|
||||||
{genesis.hash: alice},
|
{genesis.hash: alice},
|
||||||
{alice: 2.u256, bob: 30.u256}
|
{alice: 2.u256, bob: 30.u256},
|
||||||
|
victor
|
||||||
)
|
)
|
||||||
let hash = transaction.hash.toBytes
|
let hash = transaction.hash.toBytes
|
||||||
check not transaction.hasValidSignature
|
check not transaction.hasValidSignature
|
||||||
|
@ -73,7 +77,7 @@ suite "Transactions":
|
||||||
check not transaction.hasValidSignature
|
check not transaction.hasValidSignature
|
||||||
|
|
||||||
test "transaction must have at least one output":
|
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":
|
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 alice = PublicKey.alice
|
||||||
let bob = PublicKey.bob
|
let bob = PublicKey.bob
|
||||||
|
let victor = PublicKey.victor
|
||||||
let genesis = Transaction.genesis
|
let genesis = Transaction.genesis
|
||||||
var tx1, tx2: Transaction
|
var tx1, tx2: Transaction
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
tx1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256})
|
tx1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256}, victor)
|
||||||
tx2 = !Transaction.init({tx1.hash: bob}, {alice: 100.u256})
|
tx2 = !Transaction.init({tx1.hash: bob}, {alice: 100.u256}, victor)
|
||||||
PrivateKey.alice.sign(tx1)
|
PrivateKey.alice.sign(tx1)
|
||||||
PrivateKey.bob.sign(tx2)
|
PrivateKey.bob.sign(tx2)
|
||||||
|
|
||||||
|
@ -30,20 +31,20 @@ suite "Transaction validation":
|
||||||
|
|
||||||
test "checks that inputs and outputs match":
|
test "checks that inputs and outputs match":
|
||||||
var store = TxStore.init(genesis)
|
var store = TxStore.init(genesis)
|
||||||
var invalid1 = !Transaction.init({genesis.hash: alice}, {bob: 999.u256})
|
var bad1 = !Transaction.init({genesis.hash: alice}, {bob: 999.u256}, victor)
|
||||||
var invalid2 = !Transaction.init({invalid1.hash: bob}, {alice: 999.u256})
|
var bad2 = !Transaction.init({bad1.hash: bob}, {alice: 999.u256}, victor)
|
||||||
PrivateKey.alice.sign(invalid1)
|
PrivateKey.alice.sign(bad1)
|
||||||
PrivateKey.bob.sign(invalid2)
|
PrivateKey.bob.sign(bad2)
|
||||||
store.add(invalid1, invalid2)
|
store.add(bad1, bad2)
|
||||||
check not store.hasValidTx(invalid1.hash)
|
check not store.hasValidTx(bad1.hash)
|
||||||
check not store.hasValidTx(invalid2.hash)
|
check not store.hasValidTx(bad2.hash)
|
||||||
|
|
||||||
test "checks that signatures match":
|
test "checks that signatures match":
|
||||||
var store = TxStore.init(genesis)
|
var store = TxStore.init(genesis)
|
||||||
var invalid1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256})
|
var bad1 = !Transaction.init({genesis.hash: alice}, {bob: 100.u256}, victor)
|
||||||
var invalid2 = !Transaction.init({invalid1.hash: bob}, {alice: 100.u256})
|
var bad2 = !Transaction.init({bad1.hash: bob}, {alice: 100.u256}, victor)
|
||||||
PrivateKey.bob.sign(invalid1) # invalid signature, should be signed by alice
|
PrivateKey.bob.sign(bad1) # invalid signature, should be signed by alice
|
||||||
PrivateKey.bob.sign(invalid2)
|
PrivateKey.bob.sign(bad2)
|
||||||
store.add(invalid1, invalid2)
|
store.add(bad1, bad2)
|
||||||
check not store.hasValidTx(invalid1.hash)
|
check not store.hasValidTx(bad1.hash)
|
||||||
check not store.hasValidTx(invalid2.hash)
|
check not store.hasValidTx(bad2.hash)
|
||||||
|
|
Loading…
Reference in New Issue