Skip to content

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 apoelstra force-pushed the 2024-11--expression-2 branch from 3a20537 to 6a8d687 Compare November 13, 2024 16:05
@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.

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

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
@apoelstra apoelstra deleted the 2024-11--expression-2 branch December 18, 2024 00:46
heap-coder added a commit to heap-coder/rust-miniscript that referenced this pull request Sep 27, 2025
…be non-recursive

75f400f86579b6c6047822fac1de5fccfb25fa67 error: remove two more variants which were redundant with threshold errors (Andrew Poelstra)
cdac32e22dd443ef7ae8671652c4b0cea5164515 error: remove 3 now-unused variants from the global Error enum (Andrew Poelstra)
ccb9c7089e2e7d125cf16a00fd2e5a4b8ec97990 expression: drop Error::ParseTree variant (Andrew Poelstra)
0b6fcf4833996c88b4989ab8acbbb6c721d0f5bd expression: unify Taproot and non-Taproot parsing (Andrew Poelstra)
360ed59411a58349b890cca8b59556ea2e574581 Introduce `error` module with single `ParseError` enum in it. (Andrew Poelstra)
179dc87cf8249d9fc9e18ac778e988f579ea5657 expression: move some ad-hoc validation from descriptor module (Andrew Poelstra)
f5dcafd36e9834055e012b5e1b34a5a2d38b29b2 expression: start tracking parenthesis-type and string position (Andrew Poelstra)
853a01af9515466b5a99edca711b8007e68a0d1c expression: rewrite parser to be non-recursive (Andrew Poelstra)
20066bdb185a90d2e470413d9b229b35a348ab0f checksum: use array::from_fn (Andrew Poelstra)
df75cbc362165fe8d139e2b7b48e15f5f9feac76 update fuzz/README.md to use hex crate (Andrew Poelstra)

Pull request description:

  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..)

ACKs for top commit:
  sanket1729:
    ACK 75f400f86579b6c6047822fac1de5fccfb25fa67

Tree-SHA512: 8c535f420f39cf565900adb938f7a30c24cfc93fe30f09268f1b2d70fff5d7dc1f06ca0a3972c118f4e6889b107040feeab849b22e74bd8355f816a9dd3d4448
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