@@ -91,10 +91,11 @@ TEMPLATE
9191code CLASS::set_code (const tx_link& tx_fk, const transaction& tx) NOEXCEPT
9292{
9393 // This is the only multitable write query (except initialize/genesis).
94- using namespace system ;
94+
9595 if (tx.is_empty ())
9696 return error::tx_empty;
9797
98+ using namespace system ;
9899 using ix = linkage<schema::index>;
99100 const auto & ins = tx.inputs_ptr ();
100101 const auto & ous = tx.outputs_ptr ();
@@ -105,24 +106,31 @@ code CLASS::set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT
105106 // ========================================================================
106107 const auto scope = store_.get_transactor ();
107108
109+ // If dirty we must guard against duplicates.
110+ const auto dirty = store_.is_dirty ();
111+
108112 // Allocate contiguously and store inputs.
109113 input_link in_fk{};
110- if (!store_.input .put_link (in_fk, table::input::put_ref{ {}, tx }))
114+ if (!store_.input .put_link (in_fk,
115+ table::input::put_ref{ {}, tx }))
111116 return error::tx_input_put;
112117
113118 // Allocate contiguously and store outputs.
114119 output_link out_fk{};
115- if (!store_.output .put_link (out_fk, table::output::put_ref{ {}, tx_fk, tx }))
120+ if (!store_.output .put_link (out_fk,
121+ table::output::put_ref{ {}, tx_fk, tx }))
116122 return error::tx_output_put;
117123
118124 // Allocate and contiguously store input links.
119125 ins_link ins_fk{};
120- if (!store_.ins .put_link (ins_fk, table::ins::put_ref{ {}, in_fk, tx_fk, tx }))
126+ if (!store_.ins .put_link (ins_fk,
127+ table::ins::put_ref{ {}, in_fk, tx_fk, tx }))
121128 return error::tx_ins_put;
122129
123130 // Allocate and contiguously store output links.
124131 outs_link outs_fk{};
125- if (!store_.outs .put_link (outs_fk, table::outs::put_ref{ {}, out_fk, tx }))
132+ if (!store_.outs .put_link (outs_fk,
133+ table::outs::put_ref{ {}, out_fk, tx }))
126134 return error::tx_outs_put;
127135
128136 // Create tx record.
@@ -148,41 +156,54 @@ code CLASS::set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT
148156 return error::tx_point_allocate;
149157
150158 for (const auto & in: *ins)
151- if (!store_.point .put (ins_fk++, in->point (), table::point::record{}))
159+ if (!store_.point .put (ins_fk++, in->point (),
160+ table::point::record{}))
152161 return error::tx_null_point_put;
153162 }
154163 else
155164 {
156- // Expand synchronizes keys with ins_fk, entries dropped into same offset.
165+ // Expand synchronizes keys with ins_fk, entries set into same offset.
157166 // Allocate contiguous points (at sequential keys matching ins_fk).
158167 if (!store_.point .expand (ins_fk + inputs))
159168 return error::tx_point_allocate;
160169
161- // Collect duplicates to store in duplicate table.
162- std::vector<chain::point> twins{};
163- auto ptr = store_.point .get_memory ();
164-
165- // This must be set after tx.set and before tx.commit, since searchable and
166- // produces an association to tx.link, and is also an integral part of tx.
167- for (const auto & in: *ins)
170+ // Must be set after tx.set and before tx.commit, since searchable and
171+ // produces association to tx.link, and is also an integral part of tx.
172+ if (dirty)
168173 {
169- bool duplicate{};
170- if (!store_.point .put (duplicate, ptr, ins_fk++, in->point (),
171- table::point::record{}))
172- return error::tx_point_put;
173-
174- if (duplicate)
175- twins.push_back (in->point ());
174+ // Collect duplicates to store in duplicate table.
175+ std::vector<chain::point> twins{};
176+ auto ptr = store_.point .get_memory ();
177+ for (const auto & in: *ins)
178+ {
179+ bool duplicate{};
180+ if (!store_.point .put (duplicate, ptr, ins_fk++, in->point (),
181+ table::point::record{}))
182+ return error::tx_point_put;
183+
184+ if (duplicate)
185+ twins.push_back (in->point ());
186+ }
187+
188+ ptr.reset ();
189+
190+ // As few duplicates are expected, duplicate domain is only 2^16.
191+ // Return of tx_duplicate_put implies link domain has overflowed.
192+ for (const auto & twin: twins)
193+ if (!store_.duplicate .exists (twin))
194+ if (!store_.duplicate .put (twin, table::duplicate::record{}))
195+ return error::tx_duplicate_put;
176196 }
197+ else
198+ {
199+ auto ptr = store_.point .get_memory ();
200+ for (const auto & in: *ins)
201+ if (!store_.point .put (ptr, ins_fk++, in->point (),
202+ table::point::record{}))
203+ return error::tx_point_put;
177204
178- ptr.reset ();
179-
180- // As few duplicates are expected, the duplicate domain is only 2^16.
181- // Return of tx_duplicate_put implies that the link domain has overflowed.
182- for (const auto & twin: twins)
183- if (!store_.duplicate .exists (twin))
184- if (!store_.duplicate .put (twin, table::duplicate::record{}))
185- return error::tx_duplicate_put;
205+ ptr.reset ();
206+ }
186207 }
187208
188209 // Commit address index records (hashmap).
@@ -361,8 +382,6 @@ code CLASS::set_code(const block& block, const header_link& key,
361382
362383 code ec{};
363384 auto fk = tx_fks;
364-
365- // Each tx is set under a distinct transactor.
366385 for (const auto & tx: *block.transactions_ptr ())
367386 if ((ec = set_code (fk++, *tx)))
368387 return ec;
0 commit comments