@@ -33,12 +33,85 @@ namespace database {
3333
3434// Address (natural-keyed).
3535// ----------------------------------------------------------------------------
36- // Pushing into vectors is more efficient than precomputation of size.
3736
37+ // private/static
3838TEMPLATE
39- code CLASS::get_address_outputs (const std::atomic_bool& cancel,
39+ template <typename Functor>
40+ inline code CLASS::parallel_address_transform (const std::atomic_bool& cancel,
41+ outpoints& out, const output_links& links, Functor&& functor) NOEXCEPT
42+ {
43+ constexpr auto parallel = poolstl::execution::par;
44+
45+ std::atomic_bool fail{};
46+ std::vector<outpoint> outpoints (links.size ());
47+ std::transform (parallel, links.begin (), links.end (), outpoints.begin (),
48+ [&functor, &fail](const auto & link) NOEXCEPT
49+ {
50+ return functor (link, fail);
51+ });
52+
53+ out.clear ();
54+ if (fail) return error::integrity;
55+ if (cancel) return error::canceled;
56+ for (auto & outpoint: outpoints)
57+ {
58+ if (cancel) return error::canceled;
59+ if (outpoint.point ().index () != point::null_index)
60+ out.insert (std::move (outpoint));
61+ }
62+
63+ return error::success;
64+ }
65+
66+ // protected
67+ TEMPLATE
68+ code CLASS::to_address_outputs (const std::atomic_bool& cancel,
69+ output_links& out, const hash_digest& key) const NOEXCEPT
70+ {
71+ // Pushing into the vector is more efficient than precomputation of size.
72+ out.clear ();
73+ for (auto it = store_.address .it (key); it; ++it)
74+ {
75+ if (cancel)
76+ return error::canceled;
77+
78+ table::address::record address{};
79+ if (!store_.address .get (it, address))
80+ return error::integrity;
81+
82+ out.push_back (address.output_fk );
83+ }
84+
85+ return error::success;
86+ }
87+
88+ // protected
89+ TEMPLATE
90+ code CLASS::get_address_outputs_turbo (const std::atomic_bool& cancel,
4091 outpoints& out, const hash_digest& key) const NOEXCEPT
4192{
93+ out.clear ();
94+ output_links links{};
95+ if (const code ec = to_address_outputs (cancel, links, key))
96+ return ec;
97+
98+ return parallel_address_transform (cancel, out, links,
99+ [this , &cancel](const auto & link, auto & fail) NOEXCEPT
100+ {
101+ if (cancel || fail) return outpoint{};
102+ auto outpoint = get_spent (link);
103+ fail = (outpoint.point ().index () == point::null_index);
104+ return outpoint;
105+ });
106+ }
107+
108+ TEMPLATE
109+ code CLASS::get_address_outputs (const std::atomic_bool& cancel,
110+ outpoints& out, const hash_digest& key, bool turbo) const NOEXCEPT
111+ {
112+ if (turbo && store_.turbo ())
113+ return get_address_outputs_turbo (cancel, out, key);
114+
42115 out.clear ();
43116 for (auto it = store_.address .it (key); it; ++it)
44117 {
@@ -55,10 +128,35 @@ code CLASS::get_address_outputs(const std::atomic_bool& cancel,
55128 return error::success;
56129}
57130
131+ // protected
58132TEMPLATE
59- code CLASS::get_confirmed_unspent_outputs (const std::atomic_bool& cancel,
133+ code CLASS::get_confirmed_unspent_outputs_turbo (const std::atomic_bool& cancel,
60134 outpoints& out, const hash_digest& key) const NOEXCEPT
61135{
136+ out.clear ();
137+ output_links links{};
138+ if (const code ec = to_address_outputs (cancel, links, key))
139+ return ec;
140+
141+ return parallel_address_transform (cancel, out, links,
142+ [this , &cancel](const auto & link, auto & fail) NOEXCEPT
143+ {
144+ if (cancel || fail || !is_confirmed_unspent (link))
145+ return outpoint{};
146+
147+ auto outpoint = get_spent (link);
148+ fail = (outpoint.point ().index () == point::null_index);
149+ return outpoint;
150+ });
151+ }
152+
153+ TEMPLATE
154+ code CLASS::get_confirmed_unspent_outputs (const std::atomic_bool& cancel,
155+ outpoints& out, const hash_digest& key, bool turbo) const NOEXCEPT
156+ {
157+ if (turbo && store_.turbo ())
158+ return get_confirmed_unspent_outputs_turbo (cancel, out, key);
159+
62160 out.clear ();
63161 for (auto it = store_.address .it (key); it; ++it)
64162 {
@@ -76,10 +174,46 @@ code CLASS::get_confirmed_unspent_outputs(const std::atomic_bool& cancel,
76174 return error::success;
77175}
78176
177+ // protected
79178TEMPLATE
80- code CLASS::get_minimum_unspent_outputs (const std::atomic_bool& cancel,
179+ code CLASS::get_minimum_unspent_outputs_turbo (const std::atomic_bool& cancel,
81180 outpoints& out, const hash_digest& key, uint64_t minimum) const NOEXCEPT
82181{
182+ out.clear ();
183+ output_links links{};
184+ if (const code ec = to_address_outputs (cancel, links, key))
185+ return ec;
186+
187+ return parallel_address_transform (cancel, out, links,
188+ [this , &cancel, minimum](const auto & link, auto & fail) NOEXCEPT
189+ {
190+ if (cancel || fail || !is_confirmed_unspent (link))
191+ return outpoint{};
192+
193+ uint64_t value{};
194+ if (!get_value (value, link))
195+ {
196+ fail = true ;
197+ return outpoint{};
198+ }
199+
200+ if (value < minimum)
201+ return outpoint{};
202+
203+ auto outpoint = get_spent (link);
204+ fail = (outpoint.point ().index () == point::null_index);
205+ return outpoint;
206+ });
207+ }
208+
209+ TEMPLATE
210+ code CLASS::get_minimum_unspent_outputs (const std::atomic_bool& cancel,
211+ outpoints& out, const hash_digest& key,
212+ uint64_t minimum, bool turbo) const NOEXCEPT
213+ {
214+ if (turbo && store_.turbo ())
215+ return get_minimum_unspent_outputs_turbo (cancel, out, key, minimum);
216+
83217 out.clear ();
84218 for (auto it = store_.address .it (key); it; ++it)
85219 {
@@ -106,10 +240,10 @@ code CLASS::get_minimum_unspent_outputs(const std::atomic_bool& cancel,
106240
107241TEMPLATE
108242code CLASS::get_confirmed_balance (const std::atomic_bool& cancel,
109- uint64_t & balance, const hash_digest& key) const NOEXCEPT
243+ uint64_t & balance, const hash_digest& key, bool turbo ) const NOEXCEPT
110244{
111245 outpoints outs{};
112- if (code ec = get_confirmed_unspent_outputs (cancel, outs, key))
246+ if (code ec = get_confirmed_unspent_outputs (cancel, outs, key, turbo ))
113247 {
114248 balance = zero;
115249 return ec;
0 commit comments