Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

txHandler: batch transactions to the verifier #4621

Merged
merged 185 commits into from
Dec 29, 2022

Conversation

algonautshant
Copy link
Contributor

@algonautshant algonautshant commented Oct 2, 2022

This PR delivers two main features:

  1. A method to batch the verifications of incoming transactions
  2. Streaming capabilities of transactions to the verifier

Why (1):
Batching transactions are more efficient to verify because of the cryptographic efficiency in doing so. It is used for verification of txns in the block and the Msig. With this work, it will also be possible for incoming txns.

Why (2):
Batch verifier should use the execution pool to keep the number of goroutines performing heavy lifting in check. This approach is also followed in PaysetGroups for verifying the txns in a block.
The transaction handler cannot block until the transaction is verified, for that reason it also uses the exec pool in txHandler.
The handler and the verifier cannot both use the exec pool, this may lead to a deadlock. For this reason, the streaming approach is adopted here.

Other considerations and future work:

  1. The signatures inside LogicSig (Msig or Sig) are not added to the main batch. Instead, they are batched in their own batch. This is a limitation and the performance can be improved by adding them to the top level batch. This requires the decoupling of the txn validity checks from the signature verification, and will be address in a different PR.

  2. In the crypto_sign_ed25519_open_batch implementation, the validity of every transaction is checked in case the batch verification fails. This can be improved for all workflows:
    a. in case we don't care with sig fails, and we reject the whole batch (Msig, block validation), we are doing the extra work of verifying each sig one by one when the batch fails.
    b. in case we are which txn sig failed, in case of batch verification of the incoming txns, the verification can be done by checking logarithmic number of the sigs, instead we check linearly all of them.

Benchmark results:

The benchmarks are implemented on the current Master, and the same benchmarks are ported to here. That is, the benchmarks reported here measure the same workflows, with the same test code, except for some adaptations since the backlog worker (blw) has some changes on how the transactions are passed from handler to the blw and out of it.

(inv) indicates the probability of a transaction group to have an invalid signature.

Note: the benchmarks use direct feed to the verifier. Benchmarks were added to use the backlog worker to evaluate the drop rate, but these results are not reported here. These benchmarks are not refined enough to get meaningful measurements from them.

txnTxngrp

msig

Single transaction with single signature

Single transaction with single signature is the case that will most benefit from this project. When the invalid signatures are rare, the results below show ~3x improvement. With high rate of invalid signatures, the gap gets smaller, because, the C code will retry every signature when the batch fails. The fix for this is a separate project as mentioned in future work above.

goos: darwin
goarch: amd64
pkg: github.com/algorand/go-algorand/data
cpu: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
BenchmarkHandleTxns/inv_0.500-8         	  100000	     20081 ns/op
--- BENCH: BenchmarkHandleTxns/inv_0.500-8
    txHandler_test.go:1632: Verified TPS: 53043 T(grp)PS: 53043
    txHandler_test.go:1634: Time/txn: 18(microsec)
    txHandler_test.go:1635: processed total: [100000 groups (50500 invalid)] [100000 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleTxns/inv_0.001-8         	  100000	     12036 ns/op
--- BENCH: BenchmarkHandleTxns/inv_0.001-8
    txHandler_test.go:1632: Verified TPS: 94066 T(grp)PS: 94066
    txHandler_test.go:1634: Time/txn: 10(microsec)
    txHandler_test.go:1635: processed total: [100000 groups (100 invalid)] [100000 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]

Before:

goos: darwin
goarch: amd64
pkg: github.com/algorand/go-algorand/data
cpu: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
BenchmarkHandleTxns/inv_0.500-8         	  100000	     22014 ns/op
--- BENCH: BenchmarkHandleTxns/inv_0.500-8
    txHandler_test.go:1593: Verified TPS: 45857 T(grp)PS: 45857
    txHandler_test.go:1595: Time/txn: 21(microsec)
    txHandler_test.go:1596: processed total: [100000 groups (50500 invalid)] [100000 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleTxns/inv_0.001-8         	  100000	     32046 ns/op
--- BENCH: BenchmarkHandleTxns/inv_0.001-8
    txHandler_test.go:1593: Verified TPS: 32541 T(grp)PS: 32541
    txHandler_test.go:1595: Time/txn: 30(microsec)
    txHandler_test.go:1596: processed total: [100000 groups (100 invalid)] [100000 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]

The signatures in a single Txn Group or in a multisig were already batched before this project. So improvements for those cases will be limited if any. However, it is important to make sure there is no regression.

Txn Groups

The txn group sizes are random, ranging from a single transaction to the maximum allowed sizes, equally distributed.
Improvements are observed when the invalid signature rate is low. This is mainly due to batching together smaller txn groups.

pkg: github.com/algorand/go-algorand/data
cpu: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
BenchmarkHandleTxnGroups/inv_0.500-8         	  100000	    134219 ns/op
--- BENCH: BenchmarkHandleTxnGroups/inv_0.500-8
    txHandler_test.go:1632: Verified TPS: 46087 T(grp)PS: 7529
    txHandler_test.go:1634: Time/txn: 21(microsec)
    txHandler_test.go:1635: processed total: [100000 groups (51000 invalid)] [612100 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleTxnGroups/inv_0.001-8         	  100000	     62531 ns/op
--- BENCH: BenchmarkHandleTxnGroups/inv_0.001-8
    txHandler_test.go:1632: Verified TPS: 97398 T(grp)PS: 16320
    txHandler_test.go:1634: Time/txn: 10(microsec)
    txHandler_test.go:1635: processed total: [100000 groups (100 invalid)] [596800 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]

Before:

pkg: github.com/algorand/go-algorand/data
cpu: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
BenchmarkHandleTxnGroups/inv_0.500-8         	  100000	    130737 ns/op
--- BENCH: BenchmarkHandleTxnGroups/inv_0.500-8
    txHandler_test.go:1593: Verified TPS: 47385 T(grp)PS: 7741
    txHandler_test.go:1595: Time/txn: 21(microsec)
    txHandler_test.go:1596: processed total: [100000 groups (51000 invalid)] [612100 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleTxnGroups/inv_0.001-8         	  100000	     94242 ns/op
--- BENCH: BenchmarkHandleTxnGroups/inv_0.001-8
    txHandler_test.go:1593: Verified TPS: 64503 T(grp)PS: 10808
    txHandler_test.go:1595: Time/txn: 15(microsec)
    txHandler_test.go:1596: processed total: [100000 groups (100 invalid)] [596800 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]

Msig

The msig sizes tested are 255, 64, and 16. The results are random, mainly because they perform similarly, and slight random variations pick a different winner randomly. Except for the smallest category, namely, Msigs with 16 signatures and low invalid rate, we see some considerable improvement there.

cpu: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
BenchmarkHandleMsigTxns/msigSize_255_inv_0.500-8         	   10000	   2628590 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_255_inv_0.500-8
    txHandler_test.go:1632: Verified TPS: 381 T(grp)PS: 381
    txHandler_test.go:1634: Time/txn: 2619(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (4980 invalid)] [10000 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_255_inv_0.001-8         	   10000	   2212049 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_255_inv_0.001-8
    txHandler_test.go:1632: Verified TPS: 455 T(grp)PS: 455
    txHandler_test.go:1634: Time/txn: 2196(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (10 invalid)] [10000 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_64_inv_0.500-8          	   10000	   1101997 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_64_inv_0.500-8
    txHandler_test.go:1632: Verified TPS: 916 T(grp)PS: 916
    txHandler_test.go:1634: Time/txn: 1090(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (5200 invalid)] [10000 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_64_inv_0.001-8          	   10000	    542293 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_64_inv_0.001-8
    txHandler_test.go:1632: Verified TPS: 1854 T(grp)PS: 1854
    txHandler_test.go:1634: Time/txn: 539(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (0 invalid)] [10000 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_16_inv_0.500-8          	   10000	    380968 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_16_inv_0.500-8
    txHandler_test.go:1632: Verified TPS: 2658 T(grp)PS: 2658
    txHandler_test.go:1634: Time/txn: 376(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (4900 invalid)] [10000 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_16_inv_0.001-8          	   10000	    140323 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_16_inv_0.001-8
    txHandler_test.go:1632: Verified TPS: 7880 T(grp)PS: 7880
    txHandler_test.go:1634: Time/txn: 126(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (0 invalid)] [10000 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]

Before:

cpu: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
BenchmarkHandleMsigTxns/msigSize_255_inv_0.500-8         	   10000	   2848690 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_255_inv_0.500-8
    txHandler_test.go:1593: Verified TPS: 352 T(grp)PS: 352
    txHandler_test.go:1595: Time/txn: 2837(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (4980 invalid)] [10000 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_255_inv_0.001-8         	   10000	   2333687 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_255_inv_0.001-8
    txHandler_test.go:1593: Verified TPS: 429 T(grp)PS: 429
    txHandler_test.go:1595: Time/txn: 2329(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (10 invalid)] [10000 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_64_inv_0.500-8          	   10000	   1184471 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_64_inv_0.500-8
    txHandler_test.go:1593: Verified TPS: 853 T(grp)PS: 853
    txHandler_test.go:1595: Time/txn: 1171(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (5190 invalid)] [10000 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_64_inv_0.001-8          	   10000	    583015 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_64_inv_0.001-8
    txHandler_test.go:1593: Verified TPS: 1718 T(grp)PS: 1718
    txHandler_test.go:1595: Time/txn: 582(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (0 invalid)] [10000 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_16_inv_0.500-8          	   10000	    301389 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_16_inv_0.500-8
    txHandler_test.go:1593: Verified TPS: 3337 T(grp)PS: 3337
    txHandler_test.go:1595: Time/txn: 299(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (4900 invalid)] [10000 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_16_inv_0.001-8          	   10000	    204738 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_16_inv_0.001-8
    txHandler_test.go:1593: Verified TPS: 5199 T(grp)PS: 5199
    txHandler_test.go:1595: Time/txn: 192(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (0 invalid)] [10000 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]

Msig TxnGroups
As expected, no significant difference here, since txn groups with many signatures per transaction were already batched, and the new code adds nothing of value here. However, this shows that the new code introduces no regression.

BenchmarkHandleMsigTxnGroups/msigSize_255_inv_0.500-8         	   10000	  14235407 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_255_inv_0.500-8
    txHandler_test.go:1632: Verified TPS: 430 T(grp)PS: 70
    txHandler_test.go:1634: Time/txn: 2324(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (4970 invalid)] [61200 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_255_inv_0.001-8         	   10000	  13022317 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_255_inv_0.001-8
    txHandler_test.go:1632: Verified TPS: 457 T(grp)PS: 76
    txHandler_test.go:1634: Time/txn: 2184(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (10 invalid)] [59530 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.500-8          	   10000	   4015848 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.500-8
    txHandler_test.go:1632: Verified TPS: 1519 T(grp)PS: 249
    txHandler_test.go:1634: Time/txn: 658(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (4980 invalid)] [60890 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.001-8          	   10000	   3472952 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.001-8
    txHandler_test.go:1632: Verified TPS: 1787 T(grp)PS: 289
    txHandler_test.go:1634: Time/txn: 559(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (20 invalid)] [61770 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.500-8          	   10000	   1344675 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.500-8
    txHandler_test.go:1632: Verified TPS: 4515 T(grp)PS: 747
    txHandler_test.go:1634: Time/txn: 221(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (4950 invalid)] [60380 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.001-8          	   10000	    864395 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.001-8
    txHandler_test.go:1632: Verified TPS: 7063 T(grp)PS: 1168
    txHandler_test.go:1634: Time/txn: 141(microsec)
    txHandler_test.go:1635: processed total: [10000 groups (10 invalid)] [60450 txns]
    txHandler_test.go:1636: dropped: [0 backlog] [0 pool]

Before:

BenchmarkHandleMsigTxnGroups/msigSize_255_inv_0.500-8         	   10000	  13308826 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_255_inv_0.500-8
    txHandler_test.go:1593: Verified TPS: 460 T(grp)PS: 75
    txHandler_test.go:1595: Time/txn: 2173(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (4970 invalid)] [61200 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_255_inv_0.001-8         	   10000	  13035461 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_255_inv_0.001-8
    txHandler_test.go:1593: Verified TPS: 456 T(grp)PS: 76
    txHandler_test.go:1595: Time/txn: 2188(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (10 invalid)] [59530 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.500-8          	   10000	   3952364 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.500-8
    txHandler_test.go:1593: Verified TPS: 1547 T(grp)PS: 254
    txHandler_test.go:1595: Time/txn: 646(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (4980 invalid)] [60890 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.001-8          	   10000	   3490898 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.001-8
    txHandler_test.go:1593: Verified TPS: 1769 T(grp)PS: 286
    txHandler_test.go:1595: Time/txn: 565(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (20 invalid)] [61770 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.500-8          	   10000	   1328955 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.500-8
    txHandler_test.go:1593: Verified TPS: 4581 T(grp)PS: 758
    txHandler_test.go:1595: Time/txn: 218(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (4950 invalid)] [60380 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.001-8          	   10000	    923246 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.001-8
    txHandler_test.go:1593: Verified TPS: 6656 T(grp)PS: 1101
    txHandler_test.go:1595: Time/txn: 150(microsec)
    txHandler_test.go:1596: processed total: [10000 groups (10 invalid)] [60450 txns]
    txHandler_test.go:1597: dropped: [0 backlog] [0 pool]

More Multisig with 4, 8, 16, 16 sig msigs

BenchmarkHandleMsigTxns/msigSize_64_inv_0.500-8         	   50000	    979405 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_64_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 1025 T(grp)PS: 1025
    txHandler_test.go:1749: Time/txn: 975(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (24900 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_64_inv_0.001-8         	   50000	    509845 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_64_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 1976 T(grp)PS: 1976
    txHandler_test.go:1749: Time/txn: 505(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (50 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_16_inv_0.500-8         	   50000	    281156 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_16_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 3595 T(grp)PS: 3595
    txHandler_test.go:1749: Time/txn: 278(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (25950 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_16_inv_0.001-8         	   50000	    164613 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_16_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 6207 T(grp)PS: 6207
    txHandler_test.go:1749: Time/txn: 161(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (0 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_8_inv_0.500-8          	   50000	    152612 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_8_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 6698 T(grp)PS: 6698
    txHandler_test.go:1749: Time/txn: 149(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (24500 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_8_inv_0.001-8          	   50000	    100192 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_8_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 10278 T(grp)PS: 10278
    txHandler_test.go:1749: Time/txn: 97(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (0 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_4_inv_0.500-8          	   50000	     88147 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_4_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 11730 T(grp)PS: 11730
    txHandler_test.go:1749: Time/txn: 85(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (24550 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_4_inv_0.001-8          	   50000	     68178 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_4_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 15409 T(grp)PS: 15409
    txHandler_test.go:1749: Time/txn: 64(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (50 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]

Before:

pkg: github.com/algorand/go-algorand/data
cpu: Intel(R) Core(TM) i7-8559U CPU @ 2.70GHz
BenchmarkHandleMsigTxns/msigSize_64_inv_0.500-8         	   50000	    979405 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_64_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 1025 T(grp)PS: 1025
    txHandler_test.go:1749: Time/txn: 975(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (24900 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_64_inv_0.001-8         	   50000	    509845 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_64_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 1976 T(grp)PS: 1976
    txHandler_test.go:1749: Time/txn: 505(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (50 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_16_inv_0.500-8         	   50000	    281156 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_16_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 3595 T(grp)PS: 3595
    txHandler_test.go:1749: Time/txn: 278(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (25950 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_16_inv_0.001-8         	   50000	    164613 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_16_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 6207 T(grp)PS: 6207
    txHandler_test.go:1749: Time/txn: 161(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (0 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_8_inv_0.500-8          	   50000	    152612 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_8_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 6698 T(grp)PS: 6698
    txHandler_test.go:1749: Time/txn: 149(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (24500 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_8_inv_0.001-8          	   50000	    100192 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_8_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 10278 T(grp)PS: 10278
    txHandler_test.go:1749: Time/txn: 97(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (0 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_4_inv_0.500-8          	   50000	     88147 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_4_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 11730 T(grp)PS: 11730
    txHandler_test.go:1749: Time/txn: 85(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (24550 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxns/msigSize_4_inv_0.001-8          	   50000	     68178 ns/op
--- BENCH: BenchmarkHandleMsigTxns/msigSize_4_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 15409 T(grp)PS: 15409
    txHandler_test.go:1749: Time/txn: 64(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (50 invalid)] [50000 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]

and Msig TxnGroups with 4, 8, 16, 16 sig msigs

BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.500-8    	   50000	   3657853 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 1677 T(grp)PS: 273
    txHandler_test.go:1749: Time/txn: 596(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (25700 invalid)] [306800 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.001-8    	   50000	   3079687 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 1956 T(grp)PS: 324
    txHandler_test.go:1749: Time/txn: 511(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (100 invalid)] [301100 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.500-8    	   50000	   1225838 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 4943 T(grp)PS: 816
    txHandler_test.go:1749: Time/txn: 202(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (25450 invalid)] [302850 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.001-8    	   50000	    792248 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 7689 T(grp)PS: 1265
    txHandler_test.go:1749: Time/txn: 130(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (100 invalid)] [303900 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_8_inv_0.500-8     	   50000	    767702 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_8_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 7848 T(grp)PS: 1303
    txHandler_test.go:1749: Time/txn: 127(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (24150 invalid)] [301150 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_8_inv_0.001-8     	   50000	    414727 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_8_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 14945 T(grp)PS: 2411
    txHandler_test.go:1749: Time/txn: 66(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (50 invalid)] [309900 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_4_inv_0.500-8     	   50000	    425635 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_4_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 14556 T(grp)PS: 2371
    txHandler_test.go:1749: Time/txn: 68(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (25750 invalid)] [306900 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_4_inv_0.001-8     	   50000	    229355 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_4_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 26655 T(grp)PS: 4414
    txHandler_test.go:1749: Time/txn: 37(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (0 invalid)] [301900 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]

Before:

BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.500-8    	   50000	   3657853 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 1677 T(grp)PS: 273
    txHandler_test.go:1749: Time/txn: 596(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (25700 invalid)] [306800 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.001-8    	   50000	   3079687 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_64_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 1956 T(grp)PS: 324
    txHandler_test.go:1749: Time/txn: 511(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (100 invalid)] [301100 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.500-8    	   50000	   1225838 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 4943 T(grp)PS: 816
    txHandler_test.go:1749: Time/txn: 202(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (25450 invalid)] [302850 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.001-8    	   50000	    792248 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_16_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 7689 T(grp)PS: 1265
    txHandler_test.go:1749: Time/txn: 130(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (100 invalid)] [303900 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_8_inv_0.500-8     	   50000	    767702 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_8_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 7848 T(grp)PS: 1303
    txHandler_test.go:1749: Time/txn: 127(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (24150 invalid)] [301150 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_8_inv_0.001-8     	   50000	    414727 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_8_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 14945 T(grp)PS: 2411
    txHandler_test.go:1749: Time/txn: 66(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (50 invalid)] [309900 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_4_inv_0.500-8     	   50000	    425635 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_4_inv_0.500-8
    txHandler_test.go:1747: Verified TPS: 14556 T(grp)PS: 2371
    txHandler_test.go:1749: Time/txn: 68(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (25750 invalid)] [306900 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]
BenchmarkHandleMsigTxnGroups/msigSize_4_inv_0.001-8     	   50000	    229355 ns/op
--- BENCH: BenchmarkHandleMsigTxnGroups/msigSize_4_inv_0.001-8
    txHandler_test.go:1747: Verified TPS: 26655 T(grp)PS: 4414
    txHandler_test.go:1749: Time/txn: 37(microsec)
    txHandler_test.go:1750: processed total: [50000 groups (0 invalid)] [301900 txns]
    txHandler_test.go:1751: dropped: [0 backlog] [0 pool]

@algonautshant algonautshant changed the base branch from master to batch_verify_incoming_txn October 2, 2022 17:12
@algonautshant algonautshant changed the title Batch-verify: Stream transactions to the verifier WIP: Batch-verify: Stream transactions to the verifier Oct 2, 2022
@algonautshant algonautshant requested review from id-ms and cce October 2, 2022 17:16
@brianolson
Copy link
Contributor

Looks good to me. I'd be satisfied with any other changes being a follow-on cleanup PR later.

}

func (handler *TxHandler) droppedTxnWatcher() {
for unverified := range handler.streamVerifierDropped {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't see where streamVerifierDropped is closed... so this goroutine never exits.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this goroutine never exits. It starts with the opening of the channels, and the channels are never re-opened and never closed, so is the goroutine.
You think this is a problem?

@@ -128,9 +130,14 @@ func (c *txSaltedCache) start(ctx context.Context, refreshInterval time.Duration
c.moreSalt()
}

func (c *txSaltedCache) WaitForStop() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WaitForStop is exported, so make start exported as well

numSigCategories++
}

if numSigCategories == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have the checks in stxnCoreChecks. It looks like there data flows do not intersect but the there is a code duplication that is very special.
so I suggest to 1) extract the prologue of this and stxnCoreChecks methods into a separate function.
2) use the same errors: errTxnSigHasNoSig vs errSignedTxnHasNoSig and errTxnSigNotWellFormed vs errSignedTxnMaxOneSig

if numberOfBatchableSigsInGroup == 0 {
err := sv.addVerificationTaskToThePoolNow([]*UnverifiedElement{stx})
if err != nil {
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this terminates the worker, it is like enqueuing error breaks the entire verification loop. In the old code EnqueueBacklog were just ignored.
I understand that the current code only gets context cancelled error here, but this might involve and this code will break. I suggest at least logging this situation, and have some kind investigation if backlog ctx cancellation is also in the same code path as txHandler stopping (and StreamVerifier stopping).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The EnqueueBacklog will return an error when the exec pool ctx is canceled, or when the ctx of the task being enqueued is canceled. The former case happens when the node shuts down, and the latter when the txHandler/StreamVerifier ctx is canceled, when they are stopped.

There are tests covering both cases. I added logging for this event, and added a check to the tests to make sure the event is properly logged.

hasMsig := false
hasLogicSig := false
// checkTxnSigTypeCounts checks the number of signature types and reports an error in case of a violation
func checkTxnSigTypeCounts(s *transactions.SignedTxn) (isStateProofTxn bool, err *TxGroupError) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about returning numSigs int, sigOrTxnType sigOrTxnType and let the caller to decide on the error?
where

type sigOrTxnType int
const regularSig sigOrTxnType = 1
const multiSig sigOrTxnType = 2
const logicSig sigOrTxnType = 3
const stateProofTxn sigOrTxnType = 4

then the caller might have very the same error condition checks as now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is more complex and we don't have a use case where two callers are interested in reporting different errors.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but in fact you are re-doing 64 bytes comparisons again for both sig and msig. Maybe this is not slower than int comparison on modern processors, not sure.
Btw, the second use

	isStateProofTxn, err := checkTxnSigTypeCounts(stx)
	if err != nil || isStateProofTxn {
		if err != nil {
			return 0, err
		}
		return 0, nil
	}

could be simplified to

	isStateProofTxn, err := checkTxnSigTypeCounts(stx)
	if err != nil || isStateProofTxn {
		return 0, err
	}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a tricky one. Returning err (instead of nil), when err == nil, the caller is receiving err != nil. I could not understand why.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but in fact you are re-doing 64 bytes comparisons again for both sig and msig. Maybe this is not slower than int comparison on modern processors, not sure.

Convinced.

@algorandskiy
Copy link
Contributor

Please fix some start usage in tests

algorandskiy
algorandskiy previously approved these changes Dec 29, 2022
Copy link
Contributor

@algorandskiy algorandskiy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last remark on unused error values.

Comment on lines 52 to 53
var errSignedTxnHasNoSig = errors.New("signedtxn has no sig")
var errSignedTxnMaxOneSig = errors.New("signedtxn should only have one of Sig or Msig or LogicSig")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these two only used in test, remove?

@algorandskiy algorandskiy merged commit 4f1ac12 into algorand:master Dec 29, 2022
@algorandskiy algorandskiy changed the title Batch-verify: Stream transactions to the verifier txHandler: batch transactions to the verifier Jan 4, 2023
PhearZero pushed a commit to PhearNet/crypto that referenced this pull request Jan 17, 2025
* Batching incoming transaction for crypto verification
* Streaming capabilities of transactions to the verifier
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants