@@ -125,3 +125,97 @@ TEST(DgbEmbeddedTxSelect, UnknownFeeTxExcluded)
125125 EXPECT_EQ (sel.total_fees , 0u );
126126 EXPECT_TRUE (sel.transactions .empty ());
127127}
128+
129+ // ---------------------------------------------------------------------------
130+ // CONFORMANCE: selection ORDER + weight-cap skip semantics.
131+ //
132+ // p2pool consumes the daemon GBT transactions[] in the order Core emits it --
133+ // ancestor-feerate descending (CreateNewBlock). The embedded shaper must emit
134+ // the same ordering so the share's tx set and any p2pool-side fee accounting
135+ // line up. get_sorted_txs_with_fees walks m_feerate_index, a
136+ // std::multimap<double,uint256,std::greater<double>> -> highest feerate first.
137+ // These pin that ordering and the weight-cap skip (a `continue`, NOT a `break`:
138+ // a high-feerate tx that overflows the cap is skipped while a lighter,
139+ // lower-feerate tx further down can still be packed).
140+ // ---------------------------------------------------------------------------
141+
142+ namespace {
143+
144+ // A tx with `n` outputs (each tagged distinct via index), to vary weight.
145+ MutableTransaction wide_tx (uint32_t index, int n_outputs)
146+ {
147+ MutableTransaction tx;
148+ tx.version = 1 ;
149+ tx.locktime = 0 ;
150+ TxIn in;
151+ in.prevout .hash .SetNull ();
152+ in.prevout .index = index;
153+ in.sequence = 0xffffffff ;
154+ tx.vin .push_back (in);
155+ for (int i = 0 ; i < n_outputs; ++i) {
156+ TxOut out;
157+ out.value = 1000 + i;
158+ tx.vout .push_back (out);
159+ }
160+ return tx;
161+ }
162+
163+ uint32_t tx_weight (const MutableTransaction& tx)
164+ {
165+ uint32_t base = 0 , wit = 0 , weight = 0 ;
166+ dgb::coin::compute_tx_weight (tx, base, wit, weight);
167+ return weight;
168+ }
169+
170+ } // namespace
171+
172+ // transactions[] are emitted highest-feerate-first (equal weight -> by fee).
173+ TEST (DgbEmbeddedTxSelect, EmitsFeerateDescendingOrder)
174+ {
175+ Mempool pool;
176+ MutableTransaction lo = tagged_tx (10 , 0 ); // fee 300 -> lowest feerate
177+ MutableTransaction mid = tagged_tx (20 , 1 ); // fee 600
178+ MutableTransaction hi = tagged_tx (30 , 2 ); // fee 900 -> highest feerate
179+ // Insert out of feerate order to prove the index, not arrival, drives order.
180+ ASSERT_TRUE (pool.add_tx (mid));
181+ ASSERT_TRUE (pool.add_tx (lo));
182+ ASSERT_TRUE (pool.add_tx (hi));
183+ pool.set_tx_fee (compute_txid (lo), 300 );
184+ pool.set_tx_fee (compute_txid (mid), 600 );
185+ pool.set_tx_fee (compute_txid (hi), 900 );
186+
187+ auto source = make_mempool_tx_source (pool, /* max_weight=*/ 4'000'000 );
188+ const auto sel = source ();
189+
190+ ASSERT_EQ (sel.transactions .size (), 3u );
191+ EXPECT_EQ (sel.transactions [0 ][" txid" ], compute_txid (hi).GetHex ());
192+ EXPECT_EQ (sel.transactions [1 ][" txid" ], compute_txid (mid).GetHex ());
193+ EXPECT_EQ (sel.transactions [2 ][" txid" ], compute_txid (lo).GetHex ());
194+ EXPECT_EQ (sel.total_fees , 1800u );
195+ }
196+
197+ // Weight cap skips an over-cap high-feerate tx but still packs a lighter one
198+ // below it (skip-not-break). total_fees reflects only the packed tx.
199+ TEST (DgbEmbeddedTxSelect, WeightCapSkipsHeavyButPacksLighter)
200+ {
201+ Mempool pool;
202+ MutableTransaction heavy = wide_tx (0 , /* n_outputs=*/ 40 ); // large weight
203+ MutableTransaction light = tagged_tx (50 , 1 ); // single output
204+ ASSERT_TRUE (pool.add_tx (heavy));
205+ ASSERT_TRUE (pool.add_tx (light));
206+ pool.set_tx_fee (compute_txid (heavy), 10'000'000 ); // huge fee -> top feerate
207+ pool.set_tx_fee (compute_txid (light), 100 ); // low feerate, low weight
208+
209+ const uint32_t w_heavy = tx_weight (heavy);
210+ const uint32_t w_light = tx_weight (light);
211+ ASSERT_GT (w_heavy, w_light) << " test needs heavy strictly heavier than light" ;
212+
213+ // Cap exactly fits `light` but not `heavy`: heavy is first (top feerate),
214+ // overflows -> skipped; light follows and fits.
215+ auto source = make_mempool_tx_source (pool, /* max_weight=*/ w_light);
216+ const auto sel = source ();
217+
218+ ASSERT_EQ (sel.transactions .size (), 1u );
219+ EXPECT_EQ (sel.transactions [0 ][" txid" ], compute_txid (light).GetHex ());
220+ EXPECT_EQ (sel.total_fees , 100u );
221+ }
0 commit comments