mirror of https://github.com/status-im/nim-abc.git
Convert Transaction and Ack to ref types
Reason: performance, copying transactions and acks around leads to significant slowdowns
This commit is contained in:
parent
db1e8b805b
commit
67176b3687
12
abc/acks.nim
12
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,7 +21,7 @@ func toBytes*(ack: Ack): seq[byte] =
|
|||
result.add(transaction.toBytes)
|
||||
result.add(ack.validator.toBytes)
|
||||
|
||||
func init(_: type Ack,
|
||||
func new(_: type Ack,
|
||||
previous: ?Hash,
|
||||
transactions: openArray[Hash],
|
||||
validator: PublicKey): ?Ack =
|
||||
|
@ -43,16 +43,16 @@ func init(_: type Ack,
|
|||
ack.hash = hash(ack.toBytes, HashKind.Ack)
|
||||
some ack
|
||||
|
||||
func init*(_: type Ack,
|
||||
func new*(_: type Ack,
|
||||
transactions: openArray[Hash],
|
||||
validator: PublicKey): ?Ack =
|
||||
Ack.init(Hash.none, transactions, validator)
|
||||
Ack.new(Hash.none, transactions, validator)
|
||||
|
||||
func init*(_: type Ack,
|
||||
func new*(_: type Ack,
|
||||
previous: Hash,
|
||||
transactions: openArray[Hash],
|
||||
validator: PublicKey): ?Ack =
|
||||
Ack.init(previous.some, transactions, validator)
|
||||
Ack.new(previous.some, transactions, validator)
|
||||
|
||||
func previous*(ack: Ack): ?Hash =
|
||||
ack.previous
|
||||
|
|
|
@ -12,7 +12,7 @@ export keys
|
|||
export hash
|
||||
|
||||
type
|
||||
Transaction* = object
|
||||
Transaction* = ref object
|
||||
inputs: seq[TxInput]
|
||||
outputs: seq[TxOutput]
|
||||
validator: PublicKey
|
||||
|
@ -36,7 +36,7 @@ func toBytes*(transaction: Transaction): seq[byte] =
|
|||
result.add(value.toBytes)
|
||||
result.add(transaction.validator.toBytes)
|
||||
|
||||
func init*(_: type Transaction,
|
||||
func new*(_: type Transaction,
|
||||
inputs: openArray[TxInput],
|
||||
outputs: openArray[TxOutput],
|
||||
validator: PublicKey): ?Transaction =
|
||||
|
@ -58,10 +58,10 @@ func init*(_: type Transaction,
|
|||
transaction.hash = hash(transaction.toBytes, HashKind.Tx)
|
||||
some transaction
|
||||
|
||||
func init*(_: type Transaction,
|
||||
func new*(_: type Transaction,
|
||||
outputs: openArray[TxOutput],
|
||||
validator: PublicKey): ?Transaction =
|
||||
Transaction.init([], outputs, validator)
|
||||
Transaction.new([], outputs, validator)
|
||||
|
||||
func inputs*(transaction: Transaction): seq[TxInput] =
|
||||
transaction.inputs
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue