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

Rewrite expression parser to be non-recursive #775

Merged
merged 10 commits into from
Nov 25, 2024

Conversation

apoelstra
Copy link
Member

This PR does several things but the only big commit is "unify Taproot and non-Taproot parsing" which replaces the ad-hoc logic in Tr::from_str to handle Taproot parsing with unified expression-parsing logic.

In addition to this, we also:

  • rewrite the expression parser to be non-recursive, which is a reduction in LOC thanks to our prepatory work
  • introduces an error module whose types will eventually replace the top-level Error enum
  • relatedly, drops several error variants including the stringly-typed BadDescriptor (it does not get rid of Unexpected which is also a stringly-typed catch-all error, but we will..)

@apoelstra
Copy link
Member Author

Will run benchmarks once my server is idle.

Copy link
Member Author

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

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

On 6a8d687 successfully ran local tests

@apoelstra
Copy link
Member Author

Benchmarks on master

test benchmarks::parse_descriptor_balanced_segwit_a_0         ... bench:         465.89 ns/iter (+/- 13.02)
test benchmarks::parse_descriptor_balanced_segwit_b_1         ... bench:       6,597.31 ns/iter (+/- 61.55)
test benchmarks::parse_descriptor_balanced_segwit_c_10        ... bench:      68,402.39 ns/iter (+/- 441.03)
test benchmarks::parse_descriptor_balanced_segwit_d_20        ... bench:     137,767.80 ns/iter (+/- 624.76)
test benchmarks::parse_descriptor_balanced_segwit_e_40        ... bench:     275,717.27 ns/iter (+/- 1,546.82)
test benchmarks::parse_descriptor_balanced_segwit_f_60        ... bench:     414,038.60 ns/iter (+/- 2,082.34)
test benchmarks::parse_descriptor_balanced_segwit_g_80        ... bench:     554,599.20 ns/iter (+/- 4,152.20)
test benchmarks::parse_descriptor_balanced_segwit_h_90        ... bench:     623,262.80 ns/iter (+/- 4,691.03)
test benchmarks::parse_descriptor_balanced_segwit_thresh_a_1  ... bench:       6,589.24 ns/iter (+/- 48.19)
test benchmarks::parse_descriptor_balanced_segwit_thresh_b_10 ... bench:      72,866.36 ns/iter (+/- 492.22)
test benchmarks::parse_descriptor_balanced_segwit_thresh_c_20 ... bench:     146,935.67 ns/iter (+/- 712.95)
test benchmarks::parse_descriptor_balanced_segwit_thresh_d_40 ... bench:     294,765.77 ns/iter (+/- 2,196.87)
test benchmarks::parse_descriptor_balanced_segwit_thresh_e_60 ... bench:     443,131.05 ns/iter (+/- 3,384.32)
test benchmarks::parse_descriptor_balanced_segwit_thresh_f_80 ... bench:     592,657.30 ns/iter (+/- 4,791.92)
test benchmarks::parse_descriptor_balanced_segwit_thresh_g_90 ... bench:     666,919.80 ns/iter (+/- 5,135.12)
test benchmarks::parse_descriptor_deep_segwit_a_0             ... bench:         478.37 ns/iter (+/- 10.21)
test benchmarks::parse_descriptor_deep_segwit_b_1             ... bench:       6,567.93 ns/iter (+/- 56.41)
test benchmarks::parse_descriptor_deep_segwit_c_10            ... bench:      68,742.34 ns/iter (+/- 477.96)
test benchmarks::parse_descriptor_deep_segwit_d_20            ... bench:     137,875.35 ns/iter (+/- 1,030.64)
test benchmarks::parse_descriptor_deep_segwit_e_40            ... bench:     276,197.60 ns/iter (+/- 1,738.74)
test benchmarks::parse_descriptor_deep_segwit_f_60            ... bench:     413,451.15 ns/iter (+/- 2,683.51)
test benchmarks::parse_descriptor_deep_segwit_g_80            ... bench:     552,011.10 ns/iter (+/- 4,749.70)
test benchmarks::parse_descriptor_deep_segwit_h_90            ... bench:     622,394.10 ns/iter (+/- 4,594.77)
test benchmarks::parse_descriptor_deep_segwit_thresh_a_1      ... bench:       6,567.16 ns/iter (+/- 64.12)
test benchmarks::parse_descriptor_deep_segwit_thresh_b_10     ... bench:      73,577.97 ns/iter (+/- 192.60)
test benchmarks::parse_descriptor_deep_segwit_thresh_c_20     ... bench:     148,726.82 ns/iter (+/- 536.78)
test benchmarks::parse_descriptor_deep_segwit_thresh_d_40     ... bench:     298,703.57 ns/iter (+/- 1,246.14)
test benchmarks::parse_descriptor_deep_segwit_thresh_e_60     ... bench:     448,690.85 ns/iter (+/- 1,734.72)
test benchmarks::parse_descriptor_deep_segwit_thresh_f_80     ... bench:     600,598.70 ns/iter (+/- 14,983.91)
test benchmarks::parse_descriptor_deep_segwit_thresh_g_90     ... bench:     675,715.00 ns/iter (+/- 3,019.62)
test benchmarks::parse_descriptor_tr_bigtree_a_1              ... bench:      13,370.86 ns/iter (+/- 65.97)
test benchmarks::parse_descriptor_tr_bigtree_b_2              ... bench:      20,506.94 ns/iter (+/- 89.95)
test benchmarks::parse_descriptor_tr_bigtree_c_5              ... bench:      42,363.64 ns/iter (+/- 218.79)
test benchmarks::parse_descriptor_tr_bigtree_d_10             ... bench:      79,039.02 ns/iter (+/- 316.80)
test benchmarks::parse_descriptor_tr_bigtree_e_20             ... bench:     153,134.58 ns/iter (+/- 589.79)
test benchmarks::parse_descriptor_tr_bigtree_f_50             ... bench:     374,249.90 ns/iter (+/- 1,492.46)
test benchmarks::parse_descriptor_tr_bigtree_g_100            ... bench:     745,691.20 ns/iter (+/- 3,326.81)
test benchmarks::parse_descriptor_tr_bigtree_h_200            ... bench:   1,489,229.40 ns/iter (+/- 5,734.94)
test benchmarks::parse_descriptor_tr_bigtree_i_500            ... bench:   3,925,334.70 ns/iter (+/- 10,281.20)
test benchmarks::parse_descriptor_tr_bigtree_j_1000           ... bench:   7,935,760.10 ns/iter (+/- 19,353.37)
test benchmarks::parse_descriptor_tr_bigtree_k_2000           ... bench:  15,910,600.30 ns/iter (+/- 44,100.49)
test benchmarks::parse_descriptor_tr_bigtree_l_5000           ... bench:  39,977,807.80 ns/iter (+/- 147,594.49)
test benchmarks::parse_descriptor_tr_bigtree_m_10000          ... bench:  80,776,176.60 ns/iter (+/- 298,184.28)
test benchmarks::parse_descriptor_tr_deep_bigtree_a_1         ... bench:      13,373.61 ns/iter (+/- 81.58)
test benchmarks::parse_descriptor_tr_deep_bigtree_b_2         ... bench:      20,531.85 ns/iter (+/- 188.93)
test benchmarks::parse_descriptor_tr_deep_bigtree_c_5         ... bench:      42,375.48 ns/iter (+/- 254.94)
test benchmarks::parse_descriptor_tr_deep_bigtree_d_10        ... bench:      78,879.20 ns/iter (+/- 566.76)
test benchmarks::parse_descriptor_tr_deep_bigtree_e_20        ... bench:     154,271.45 ns/iter (+/- 1,588.20)
test benchmarks::parse_descriptor_tr_deep_bigtree_f_50        ... bench:     377,169.55 ns/iter (+/- 2,861.75)
test benchmarks::parse_descriptor_tr_deep_bigtree_g_100       ... bench:     744,043.10 ns/iter (+/- 5,380.24)
test benchmarks::parse_descriptor_tr_deep_bigtree_h_128       ... bench:     956,334.40 ns/iter (+/- 6,342.36)
test benchmarks::parse_descriptor_tr_deep_oneleaf_a_1         ... bench:      13,399.77 ns/iter (+/- 105.96)
test benchmarks::parse_descriptor_tr_deep_oneleaf_b_10        ... bench:      82,051.34 ns/iter (+/- 485.98)
test benchmarks::parse_descriptor_tr_deep_oneleaf_c_20        ... bench:     161,314.56 ns/iter (+/- 1,054.12)
test benchmarks::parse_descriptor_tr_deep_oneleaf_d_50        ... bench:     394,023.85 ns/iter (+/- 3,161.88)
test benchmarks::parse_descriptor_tr_deep_oneleaf_e_100       ... bench:     793,179.80 ns/iter (+/- 5,086.54)
test benchmarks::parse_descriptor_tr_deep_oneleaf_f_200       ... bench:   1,615,137.60 ns/iter (+/- 9,648.42)
test benchmarks::parse_descriptor_tr_oneleaf_a_1              ... bench:      13,444.67 ns/iter (+/- 107.97)
test benchmarks::parse_descriptor_tr_oneleaf_b_10             ... bench:      82,180.59 ns/iter (+/- 538.77)
test benchmarks::parse_descriptor_tr_oneleaf_c_20             ... bench:     161,952.91 ns/iter (+/- 1,220.03)
test benchmarks::parse_descriptor_tr_oneleaf_d_50             ... bench:     395,816.30 ns/iter (+/- 4,442.46)
test benchmarks::parse_descriptor_tr_oneleaf_e_100            ... bench:     794,898.10 ns/iter (+/- 3,452.93)
test benchmarks::parse_descriptor_tr_oneleaf_f_200            ... bench:   1,624,713.20 ns/iter (+/- 8,085.24)
test benchmarks::parse_descriptor_tr_oneleaf_g_500            ... bench:   4,127,597.60 ns/iter (+/- 12,541.62)
test benchmarks::parse_descriptor_tr_oneleaf_h_1000           ... bench:   8,393,876.20 ns/iter (+/- 27,310.88)
test benchmarks::parse_descriptor_tr_oneleaf_i_2000           ... bench:  16,971,642.50 ns/iter (+/- 55,966.49)
test benchmarks::parse_descriptor_tr_oneleaf_j_5000           ... bench:  48,622,186.60 ns/iter (+/- 166,228.02)
test benchmarks::parse_descriptor_tr_oneleaf_k_10000          ... bench: 101,239,307.00 ns/iter (+/- 248,620.43)
test benchmarks::parse_expression_balanced_a_0                ... bench:         158.13 ns/iter (+/- 2.52)
test benchmarks::parse_expression_balanced_b_1                ... bench:         431.17 ns/iter (+/- 6.79)
test benchmarks::parse_expression_balanced_c_2                ... bench:         788.64 ns/iter (+/- 12.22)
test benchmarks::parse_expression_balanced_d_5                ... bench:       1,938.73 ns/iter (+/- 14.29)
test benchmarks::parse_expression_balanced_e_10               ... bench:       4,112.92 ns/iter (+/- 53.97)
test benchmarks::parse_expression_balanced_f_20               ... bench:       8,169.31 ns/iter (+/- 131.74)
test benchmarks::parse_expression_balanced_g_50               ... bench:      20,087.98 ns/iter (+/- 315.16)
test benchmarks::parse_expression_balanced_h_100              ... bench:      40,489.81 ns/iter (+/- 313.45)
test benchmarks::parse_expression_balanced_i_200              ... bench:      80,639.21 ns/iter (+/- 679.48)
test benchmarks::parse_expression_balanced_j_500              ... bench:     200,178.08 ns/iter (+/- 3,613.59)
test benchmarks::parse_expression_balanced_k_1000             ... bench:     403,450.25 ns/iter (+/- 5,369.78)
test benchmarks::parse_expression_balanced_l_2000             ... bench:     802,836.05 ns/iter (+/- 9,533.49)
test benchmarks::parse_expression_balanced_m_5000             ... bench:   2,030,183.80 ns/iter (+/- 26,620.83)
test benchmarks::parse_expression_balanced_n_10000            ... bench:   4,159,970.60 ns/iter (+/- 59,766.04)
test benchmarks::parse_expression_deep_a_0                    ... bench:         143.35 ns/iter (+/- 4.26)
test benchmarks::parse_expression_deep_b_1                    ... bench:         425.64 ns/iter (+/- 12.74)
test benchmarks::parse_expression_deep_c_2                    ... bench:         767.49 ns/iter (+/- 15.56)
test benchmarks::parse_expression_deep_d_5                    ... bench:       1,903.38 ns/iter (+/- 23.07)
test benchmarks::parse_expression_deep_e_10                   ... bench:       4,050.42 ns/iter (+/- 76.06)
test benchmarks::parse_expression_deep_f_20                   ... bench:       7,877.37 ns/iter (+/- 119.96)
test benchmarks::parse_expression_deep_g_50                   ... bench:      19,092.16 ns/iter (+/- 58.22)
test benchmarks::parse_expression_deep_h_100                  ... bench:      38,052.99 ns/iter (+/- 266.18)
test benchmarks::parse_expression_deep_i_200                  ... bench:      75,396.99 ns/iter (+/- 636.95)
test benchmarks::parse_expression_deep_j_300                  ... bench:     114,219.85 ns/iter (+/- 519.24)
test benchmarks::parse_expression_deep_j_400                  ... bench:     151,819.67 ns/iter (+/- 862.04)
Benchmarks with this PR

test benchmarks::parse_descriptor_balanced_segwit_a_0         ... bench:         518.69 ns/iter (+/- 7.66)
test benchmarks::parse_descriptor_balanced_segwit_b_1         ... bench:       6,615.15 ns/iter (+/- 70.06)
test benchmarks::parse_descriptor_balanced_segwit_c_10        ... bench:      70,226.66 ns/iter (+/- 418.13)
test benchmarks::parse_descriptor_balanced_segwit_d_20        ... bench:     141,360.30 ns/iter (+/- 734.02)
test benchmarks::parse_descriptor_balanced_segwit_e_40        ... bench:     283,345.80 ns/iter (+/- 1,844.22)
test benchmarks::parse_descriptor_balanced_segwit_f_60        ... bench:     425,928.00 ns/iter (+/- 2,220.43)
test benchmarks::parse_descriptor_balanced_segwit_g_80        ... bench:     568,664.50 ns/iter (+/- 3,151.85)
test benchmarks::parse_descriptor_balanced_segwit_h_90        ... bench:     641,489.30 ns/iter (+/- 4,752.37)
test benchmarks::parse_descriptor_balanced_segwit_thresh_a_1  ... bench:       6,618.56 ns/iter (+/- 28.64)
test benchmarks::parse_descriptor_balanced_segwit_thresh_b_10 ... bench:      74,487.82 ns/iter (+/- 340.39)
test benchmarks::parse_descriptor_balanced_segwit_thresh_c_20 ... bench:     150,253.45 ns/iter (+/- 819.17)
test benchmarks::parse_descriptor_balanced_segwit_thresh_d_40 ... bench:     302,013.83 ns/iter (+/- 1,411.01)
test benchmarks::parse_descriptor_balanced_segwit_thresh_e_60 ... bench:     454,499.15 ns/iter (+/- 3,568.03)
test benchmarks::parse_descriptor_balanced_segwit_thresh_f_80 ... bench:     607,522.10 ns/iter (+/- 4,903.73)
test benchmarks::parse_descriptor_balanced_segwit_thresh_g_90 ... bench:     704,269.60 ns/iter (+/- 10,389.44)
test benchmarks::parse_descriptor_deep_segwit_a_0             ... bench:         531.30 ns/iter (+/- 9.92)
test benchmarks::parse_descriptor_deep_segwit_b_1             ... bench:       6,637.87 ns/iter (+/- 38.96)
test benchmarks::parse_descriptor_deep_segwit_c_10            ... bench:      70,843.63 ns/iter (+/- 352.96)
test benchmarks::parse_descriptor_deep_segwit_d_20            ... bench:     143,752.78 ns/iter (+/- 521.29)
test benchmarks::parse_descriptor_deep_segwit_e_40            ... bench:     294,008.60 ns/iter (+/- 1,502.46)
test benchmarks::parse_descriptor_deep_segwit_f_60            ... bench:     447,193.45 ns/iter (+/- 2,467.73)
test benchmarks::parse_descriptor_deep_segwit_g_80            ... bench:     606,963.10 ns/iter (+/- 2,506.64)
test benchmarks::parse_descriptor_deep_segwit_h_90            ... bench:     688,889.60 ns/iter (+/- 4,265.58)
test benchmarks::parse_descriptor_deep_segwit_thresh_a_1      ... bench:       6,620.36 ns/iter (+/- 154.25)
test benchmarks::parse_descriptor_deep_segwit_thresh_b_10     ... bench:      76,243.09 ns/iter (+/- 726.38)
test benchmarks::parse_descriptor_deep_segwit_thresh_c_20     ... bench:     155,144.63 ns/iter (+/- 881.53)
test benchmarks::parse_descriptor_deep_segwit_thresh_d_40     ... bench:     318,248.93 ns/iter (+/- 1,220.64)
test benchmarks::parse_descriptor_deep_segwit_thresh_e_60     ... bench:     485,963.40 ns/iter (+/- 3,386.75)
test benchmarks::parse_descriptor_deep_segwit_thresh_f_80     ... bench:     660,756.80 ns/iter (+/- 5,009.96)
test benchmarks::parse_descriptor_deep_segwit_thresh_g_90     ... bench:     751,026.60 ns/iter (+/- 9,264.98)
test benchmarks::parse_descriptor_tr_bigtree_a_1              ... bench:      13,409.34 ns/iter (+/- 106.06)
test benchmarks::parse_descriptor_tr_bigtree_b_2              ... bench:      21,060.34 ns/iter (+/- 114.85)
test benchmarks::parse_descriptor_tr_bigtree_c_5              ... bench:      43,404.63 ns/iter (+/- 263.49)
test benchmarks::parse_descriptor_tr_bigtree_d_10             ... bench:      80,643.79 ns/iter (+/- 415.42)
test benchmarks::parse_descriptor_tr_bigtree_e_20             ... bench:     154,859.08 ns/iter (+/- 670.83)
test benchmarks::parse_descriptor_tr_bigtree_f_50             ... bench:     378,918.95 ns/iter (+/- 2,191.64)
test benchmarks::parse_descriptor_tr_bigtree_g_100            ... bench:     755,423.10 ns/iter (+/- 6,214.46)
test benchmarks::parse_descriptor_tr_bigtree_h_200            ... bench:   1,518,676.60 ns/iter (+/- 10,765.17)
test benchmarks::parse_descriptor_tr_bigtree_i_500            ... bench:   3,873,520.50 ns/iter (+/- 11,089.93)
test benchmarks::parse_descriptor_tr_bigtree_j_1000           ... bench:   7,949,879.00 ns/iter (+/- 18,337.73)
test benchmarks::parse_descriptor_tr_bigtree_k_2000           ... bench:  15,784,262.20 ns/iter (+/- 187,559.79)
test benchmarks::parse_descriptor_tr_bigtree_l_5000           ... bench:  39,630,807.60 ns/iter (+/- 528,381.70)
test benchmarks::parse_descriptor_tr_bigtree_m_10000          ... bench:  80,709,159.70 ns/iter (+/- 1,309,070.98)
test benchmarks::parse_descriptor_tr_deep_bigtree_a_1         ... bench:      13,623.26 ns/iter (+/- 99.79)
test benchmarks::parse_descriptor_tr_deep_bigtree_b_2         ... bench:      21,072.47 ns/iter (+/- 104.78)
test benchmarks::parse_descriptor_tr_deep_bigtree_c_5         ... bench:      43,397.38 ns/iter (+/- 159.29)
test benchmarks::parse_descriptor_tr_deep_bigtree_d_10        ... bench:      80,800.83 ns/iter (+/- 321.88)
test benchmarks::parse_descriptor_tr_deep_bigtree_e_20        ... bench:     155,226.32 ns/iter (+/- 825.53)
test benchmarks::parse_descriptor_tr_deep_bigtree_f_50        ... bench:     380,806.15 ns/iter (+/- 3,422.11)
test benchmarks::parse_descriptor_tr_deep_bigtree_g_100       ... bench:     749,295.30 ns/iter (+/- 3,449.85)
test benchmarks::parse_descriptor_tr_deep_bigtree_h_128       ... bench:     961,225.10 ns/iter (+/- 8,182.50)
test benchmarks::parse_descriptor_tr_deep_oneleaf_a_1         ... bench:      13,655.38 ns/iter (+/- 120.17)
test benchmarks::parse_descriptor_tr_deep_oneleaf_b_10        ... bench:      87,845.84 ns/iter (+/- 289.37)
test benchmarks::parse_descriptor_tr_deep_oneleaf_c_20        ... bench:     179,415.04 ns/iter (+/- 1,071.47)
test benchmarks::parse_descriptor_tr_deep_oneleaf_d_50        ... bench:     447,582.20 ns/iter (+/- 3,101.41)
test benchmarks::parse_descriptor_tr_deep_oneleaf_e_100       ... bench:     940,563.80 ns/iter (+/- 5,621.17)
test benchmarks::parse_descriptor_tr_deep_oneleaf_f_200       ... bench:   2,031,933.50 ns/iter (+/- 10,906.15)
test benchmarks::parse_descriptor_tr_oneleaf_a_1              ... bench:      13,659.80 ns/iter (+/- 207.72)
test benchmarks::parse_descriptor_tr_oneleaf_b_10             ... bench:      87,382.09 ns/iter (+/- 571.21)
test benchmarks::parse_descriptor_tr_oneleaf_c_20             ... bench:     175,678.96 ns/iter (+/- 653.05)
test benchmarks::parse_descriptor_tr_oneleaf_d_50             ... bench:     431,718.85 ns/iter (+/- 2,866.35)
test benchmarks::parse_descriptor_tr_oneleaf_e_100            ... bench:     883,488.25 ns/iter (+/- 6,093.25)
test benchmarks::parse_descriptor_tr_oneleaf_f_200            ... bench:   1,815,171.30 ns/iter (+/- 17,100.51)
test benchmarks::parse_descriptor_tr_oneleaf_g_500            ... bench:   4,680,035.00 ns/iter (+/- 29,164.12)
test benchmarks::parse_descriptor_tr_oneleaf_h_1000           ... bench:   9,633,127.80 ns/iter (+/- 24,993.45)
test benchmarks::parse_descriptor_tr_oneleaf_i_2000           ... bench:  19,590,854.90 ns/iter (+/- 41,516.19)
test benchmarks::parse_descriptor_tr_oneleaf_j_5000           ... bench:  53,964,958.90 ns/iter (+/- 401,618.90)
test benchmarks::parse_descriptor_tr_oneleaf_k_10000          ... bench: 115,129,663.90 ns/iter (+/- 285,490.68)
test benchmarks::parse_expression_balanced_a_0                ... bench:         170.56 ns/iter (+/- 2.89)
test benchmarks::parse_expression_balanced_b_1                ... bench:         545.43 ns/iter (+/- 20.05)
test benchmarks::parse_expression_balanced_c_2                ... bench:         856.69 ns/iter (+/- 10.27)
test benchmarks::parse_expression_balanced_d_5                ... bench:       2,118.21 ns/iter (+/- 77.34)
test benchmarks::parse_expression_balanced_e_10               ... bench:       4,339.93 ns/iter (+/- 162.23)
test benchmarks::parse_expression_balanced_f_20               ... bench:       8,707.10 ns/iter (+/- 86.91)
test benchmarks::parse_expression_balanced_g_50               ... bench:      21,837.24 ns/iter (+/- 277.08)
test benchmarks::parse_expression_balanced_h_100              ... bench:      43,450.46 ns/iter (+/- 1,057.19)
test benchmarks::parse_expression_balanced_i_200              ... bench:      85,808.12 ns/iter (+/- 1,612.74)
test benchmarks::parse_expression_balanced_j_500              ... bench:     210,495.98 ns/iter (+/- 4,124.43)
test benchmarks::parse_expression_balanced_k_1000             ... bench:     420,865.70 ns/iter (+/- 6,183.20)
test benchmarks::parse_expression_balanced_l_2000             ... bench:     849,829.65 ns/iter (+/- 18,832.70)
test benchmarks::parse_expression_balanced_m_5000             ... bench:   2,120,030.10 ns/iter (+/- 27,303.20)
test benchmarks::parse_expression_balanced_n_10000            ... bench:   4,228,137.35 ns/iter (+/- 47,938.27)
test benchmarks::parse_expression_deep_a_0                    ... bench:         162.80 ns/iter (+/- 8.18)
test benchmarks::parse_expression_deep_b_1                    ... bench:         521.99 ns/iter (+/- 6.45)
test benchmarks::parse_expression_deep_c_2                    ... bench:         845.39 ns/iter (+/- 28.31)
test benchmarks::parse_expression_deep_d_5                    ... bench:       2,061.19 ns/iter (+/- 91.73)
test benchmarks::parse_expression_deep_e_10                   ... bench:       4,147.14 ns/iter (+/- 171.97)
test benchmarks::parse_expression_deep_f_20                   ... bench:       8,401.84 ns/iter (+/- 51.62)
test benchmarks::parse_expression_deep_g_50                   ... bench:      20,530.10 ns/iter (+/- 972.39)
test benchmarks::parse_expression_deep_h_100                  ... bench:      40,175.01 ns/iter (+/- 788.46)
test benchmarks::parse_expression_deep_i_200                  ... bench:      80,477.32 ns/iter (+/- 556.42)
test benchmarks::parse_expression_deep_j_300                  ... bench:     119,681.66 ns/iter (+/- 848.63)
test benchmarks::parse_expression_deep_j_400                  ... bench:     159,537.92 ns/iter (+/- 959.15)

As you can see, again there is a performance regression, this time (I think) because we have converted a bunch of stack-based allocations into heap-based allocations. But on my local branch that includes the next several PRs, these numbers do improve (I swear). They roughly match the "master" numbers from #773 for small benchmarks, and significantly beat the "master" numbers for large benchmarks.

@apoelstra
Copy link
Member Author

There is a fuzztest failing on master, which I confirmed passes with this PR.

Copy link
Member

@sanket1729 sanket1729 left a comment

Choose a reason for hiding this comment

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

Awesome work adding the position to the Tree structure.

We can improve the "Unexpected("(1 args) while parsing Miniscript")" with the exact position where the parsing failed :O . Huge UX improvment

This includes the stringly-typed BadDescriptor :).

Nice work removing this finally.

src/expression/mod.rs Outdated Show resolved Hide resolved
src/descriptor/mod.rs Show resolved Hide resolved
@@ -64,6 +64,9 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
Pk: FromStr,
<Pk as FromStr>::Err: fmt::Display,
{
tree.verify_toplevel("sortedmulti", 1..)
Copy link
Member

Choose a reason for hiding this comment

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

Nice catch. This was missing previously

src/descriptor/tr.rs Show resolved Hide resolved
Copy link
Member

@sanket1729 sanket1729 left a comment

Choose a reason for hiding this comment

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

The only subtle/nonobvious thing maybe is that in Miniscript::from_tree
I added a call to verify_no_curly_braces which does a recursive check
for curly-braces. None of the other checks are recursive (nor do they
need to be).

From commit message of c8aa7d2
Where is the recursion?

@sanket1729
Copy link
Member

Tried to do my best careful review. But we do need fuzzing on this to gain more confidence

sanket1729
sanket1729 previously approved these changes Nov 23, 2024
Copy link
Member

@sanket1729 sanket1729 left a comment

Choose a reason for hiding this comment

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

ACK 6a8d687

Oops forgot to ack the commit

@apoelstra
Copy link
Member Author

apoelstra commented Nov 23, 2024

Tried to do my best careful review. But we do need fuzzing on this to gain more confidence

I have a fuzztest that runs against the version of 0.12 from #735. I'll publish the fuzz test once that is merged.

Also I will check on the commit message that mentions recursion -- may be the commit message is just stale.

Along the way, fix a bunch of other instances of "manual" slice
construction that can be done with try_from or from_fn. Instances
where the closure to `from_fn` would be several lines long, I left
alone, but we could revisit those later.

Fixes rust-bitcoin#774
This commit should yield no observable changes.
@apoelstra
Copy link
Member Author

Yeah, the commit message is stale. It predates my use of iter::TreeLike.

When we change the expression parser to start parsing both ()s and {}s
at once, we will need to know the parenthesis type. To return nice
errors we also need to store some position information in the Tree type.

Adding these new fields (which need to be pub to make them accessible
from descriptor/tr.rs, but which we will later encapsulate better) is
mechanical and pretty noisy, so we do it in its own commit to reduce the
size of the real "fix Taproot parsing" commit.
In the next commit we will change the expression parser to parse both
{}s and ()s as parentheses, no longer distinguishing between a "taproot"
and "non-taproot" mode. This means that all non-Taproot descriptors need
to check that curly-brace {} expressions do not appear.

While we are adding this check, we can replace the existing checks for
things like "does this start with wsh and have exactly one child" with
an encapsulated function with strongly-typed errors. This gets rid of a
couple of Error::Unexpected instances.

We change one error output (if you pass no children to a sortedmulti).
The old text is nonsensical and the new text is explicit about what is
wrong.

This change is pretty-much mechanical, though unfortunately these are
all "manual" calls to validation functions, and if I missed any, the
compiler won't give us any help in noticing. But there aren't too many.

Anyway, later on I will write a fuzz test which checks that we have not
changed the set of parseable descriptors (using normal keys, not Strings
or anything that might have braces in them, which we know we broke) and
that should catch any mistakes.

Also, similar to the last commit, this one doesn't really "do" anything
because it's still impossible to parse trees with mixed brace styles.
But in the next one, it will be possible, and we will be glad to have
moved a bunch of the diff into these prepatory commits.
We will use this error type in the next commit.

For now we will continue to use the giant global Error enum, so we add a
variant to hold the new `ParseError`. But eventually `ParseError` will
become a top-level error and `Error` will go away.
The `expression::Tree` type now parses expression trees containing both
{} and () as children. It marks which is which, and it is the
responsibility of FromTree implementors to make sure that the correct
style is used.

This eliminates a ton of ad-hoc string parsing code from
descriptor/tr.rs, including 8 instances of Error::Unexpected. It is also
the first change that preserves (sorta) a pubkey parsing error rather
than converting it to a string.

Because of rust-bitcoin#734
this inserts a call to `Descriptor::sanity_check` when parsing a string,
specifically for Taproot descriptors. This is weird and wrong but we
want to address it separately from this PR, whose goal is to preserve
all behavior.
The correct way to build a Error::ParseTree is to make an Error::Parse
containing a ParseError::Tree. Eventually when we get rid of the
top-level Error enum this will be more sensible, and we will be able to
use ? instead of this awful `.map_err(From::from).map_err(Error::parse)`
construction.

This commit rightfully belongs as part of the previous commit, but it's
noisy and mechanical so I separated it out.
This includes the stringly-typed `BadDescriptor` :).
Copy link
Member Author

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

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

On 6a8d687 successfully ran local tests

@apoelstra
Copy link
Member Author

Addressed your comments.

Copy link
Member

@sanket1729 sanket1729 left a comment

Choose a reason for hiding this comment

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

ACK 75f400f

@apoelstra apoelstra merged commit fd28e86 into rust-bitcoin:master Nov 25, 2024
30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants