From 2e471587aa0a8c9117d8854d26e9ceee13d0dd86 Mon Sep 17 00:00:00 2001 From: frstrtr Date: Mon, 13 Jul 2026 17:54:39 +0000 Subject: [PATCH] dash(S8): get_work() consumer capstone -- fuse NodeCoinState::select_work() template source + assemble_work_job_targets() The embedded get_work chain was fully wired but had NO production consumer: NodeCoinState::select_work() (embedded template when the 4-leg reception wire (#693/#694) has populated the node bundle, else the retained dashd getblocktemplate fallback) and assemble_work_job_targets() (per-miner job-target arithmetic) each existed and were unit-tested, but nothing fused them into a single miner-facing entry. Only the test suites ever called select_work(). Add dash::stratum::get_work() (src/impl/dash/stratum/get_work.hpp): the first non-test caller of the embedded arm. It sources the base block template off the node-held NodeCoinState -- NO direct dashd poll on the hot path when the bundle is populated -- and assembles the job targets over whichever template arm ran. dashd_fallback stays REQUIRED and is invoked ONLY on a set-gap (unpopulated / invalidated bundle): the always-reachable safety + [GBT-XCHECK] cross-check arm, never removed. test_dash_get_work (4/4) pins the fused contract, seeding mirrored exactly from test_dash_node_embedded_wire (no fabricated oracle values): * set-gap routes DashdFallback (invoked once) and still assembles targets; * populated routes Embedded WITHOUT invoking the fallback, byte-equal to a direct build_embedded_workdata() over the node's own held state; * job targets are identical across both template sources; * on_invalidate (reorg) demotes back to the fallback. Registered in both build.yml --target allowlists. STRICTLY single-coin (src/impl/dash/ + test only), SAFE-ADDITIVE. --- .github/workflows/build.yml | 4 +- src/impl/dash/stratum/get_work.hpp | 66 ++++++++ test/CMakeLists.txt | 11 ++ test/test_dash_get_work.cpp | 258 +++++++++++++++++++++++++++++ 4 files changed, 337 insertions(+), 2 deletions(-) create mode 100644 src/impl/dash/stratum/get_work.hpp create mode 100644 test/test_dash_get_work.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec919c425..91353ee43 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -102,7 +102,7 @@ jobs: core_test sharechain_test share_test btc_share_test \ test_threading test_weights \ test_header_chain test_mempool test_template_builder \ - test_doge_chain test_compact_blocks test_dash_x11_kat test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate test_dash_work_source test_dash_node_coin_state test_dash_coin_state_maintainer test_dash_node_embedded_wire test_dash_node_reception_wire \ + test_doge_chain test_compact_blocks test_dash_x11_kat test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate test_dash_work_source test_dash_node_coin_state test_dash_coin_state_maintainer test_dash_node_embedded_wire test_dash_node_reception_wire test_dash_get_work \ test_multiaddress_pplns test_pplns_stress \ test_hash_link test_decay_pplns \ test_pplns_consensus \ @@ -252,7 +252,7 @@ jobs: test_threading test_weights \ test_header_chain test_mempool test_template_builder \ test_doge_chain test_compact_blocks test_dash_x11_kat \ - test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate test_dash_work_source test_dash_node_coin_state test_dash_coin_state_maintainer test_dash_node_embedded_wire test_dash_node_reception_wire \ + test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm test_dash_coinbase_parity test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate test_dash_work_source test_dash_node_coin_state test_dash_coin_state_maintainer test_dash_node_embedded_wire test_dash_node_reception_wire test_dash_get_work \ test_hash_link test_decay_pplns \ test_pplns_consensus \ test_v36_script_sorting test_v36_cross_impl_refhash \ diff --git a/src/impl/dash/stratum/get_work.hpp b/src/impl/dash/stratum/get_work.hpp new file mode 100644 index 000000000..b8554e0ae --- /dev/null +++ b/src/impl/dash/stratum/get_work.hpp @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +#pragma once + +/// Phase C-TEMPLATE step 9 (capstone): the fused dash get_work() consumer. +/// +/// Every prior slice landed one HALF of get_work in isolation: +/// * select_dash_work() / NodeCoinState::select_work() (work_source.hpp, +/// node_coin_state.hpp, #672/#673) -- the TEMPLATE source: prefer the +/// locally-assembled embedded template (build_embedded_workdata, oracle +/// parity vs frstrtr/p2pool-dash getwork(), older-than-v35) when the +/// node-held coin-state bundle is populated by the 4-leg reception wire +/// (#693/#694), else the RETAINED dashd getblocktemplate fallback; +/// * assemble_work_job_targets() (work_job_targets.hpp) -- the per-miner +/// JOB-TARGET arithmetic (work.py:368-426). +/// +/// Nothing fused them: no production (non-test) caller ever ran +/// NodeCoinState::select_work() to source a template AND assembled the miner +/// job over it -- the two halves were exercised only by their own unit KATs. +/// get_work() is that single miner-facing entry point -- the +/// "DASHWorkSource::get_work()" the stratum headers reference as future work. +/// +/// CONTRACT (matches the S8 embedded-arm invariants): +/// * the hot path reads the node-held NodeCoinState -- NO direct dashd poll +/// when the bundle is populated (the embedded arm assembles locally); +/// * dashd_fallback is REQUIRED and is invoked ONLY on a set-gap +/// (unpopulated / invalidated bundle) -- the always-reachable safety path +/// and the [GBT-XCHECK] cross-check, NEVER removed; +/// * the job-target assembly is a pure transform of caller inputs and rides +/// on top of EITHER template source unchanged. +/// +/// STRICTLY single-coin: src/impl/dash/ only, no bitcoin_family / src/core +/// reach beyond the shared uint256/DashWorkData types the halves already use. + +#include // NodeCoinState, WorkSelection, WorkSource +#include // DashWorkData +#include // assemble_work_job_targets, WorkJobTargets, WorkJobTargetInputs + +#include +#include + +namespace dash::stratum { + +/// The miner-facing result of get_work(): which arm sourced the template, the +/// selected block template itself, and the assembled stratum job targets. +struct GetWork { + coin::WorkSource source{coin::WorkSource::DashdFallback}; + coin::DashWorkData work; + WorkJobTargets targets; +}; + +/// Fused get_work(): source the base block template off the node-held +/// coin-state (embedded when populated, retained dashd fallback on a set-gap) +/// and assemble the per-miner job targets over it. dashd_fallback is REQUIRED +/// -- it is the always-reachable safety/cross-check arm and is only invoked +/// when the embedded bundle is unavailable. +inline GetWork get_work( + const coin::NodeCoinState& coin_state, + const std::function& dashd_fallback, + const WorkJobTargetInputs& job_in) +{ + coin::WorkSelection sel = coin_state.select_work(dashd_fallback); + WorkJobTargets targets = assemble_work_job_targets(job_in); + return GetWork{ sel.source, std::move(sel.work), targets }; +} + +} // namespace dash::stratum diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b50e46172..76a88f367 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -559,6 +559,17 @@ if (BUILD_TESTING AND GTest_FOUND) ) target_link_libraries(test_dash_node_embedded_wire PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining c2pool_storage pool) # OBJECT-lib SCC direct-naming (#22/#39) gtest_add_tests(test_dash_node_embedded_wire "" AUTO) + # get_work() consumer capstone: fuses NodeCoinState::select_work() (embedded + # template source) with assemble_work_job_targets(); same OBJECT-lib SCC. + add_executable(test_dash_get_work test_dash_get_work.cpp) + target_link_libraries(test_dash_get_work PRIVATE + GTest::gtest_main GTest::gtest + dash_x11 core + nlohmann_json::nlohmann_json + ${Boost_LIBRARIES} + ) + target_link_libraries(test_dash_get_work PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining c2pool_storage pool) # OBJECT-lib SCC direct-naming (#22/#39) + gtest_add_tests(test_dash_get_work "" AUTO) # Reception wire (legs 1-3): interfaces::Node reception Events -> # CoinStateMaintainer. Proves the wire_*_ingest() subscriptions fold off the diff --git a/test/test_dash_get_work.cpp b/test/test_dash_get_work.cpp new file mode 100644 index 000000000..f7ad8f34f --- /dev/null +++ b/test/test_dash_get_work.cpp @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +/// Phase C-TEMPLATE step 9 -- fused dash get_work() consumer KAT. +/// +/// get_work() (src/impl/dash/stratum/get_work.hpp) is the single miner-facing +/// entry that FUSES the two halves prior slices landed separately: +/// * template source -- NodeCoinState::select_work() (#672/#673), populated +/// by the 4-leg reception wire (#693/#694); +/// * job-target math -- assemble_work_job_targets() (work_job_targets.hpp). +/// +/// This suite pins the fused contract end-to-end: +/// * a set-gap (unpopulated node bundle) routes the RETAINED dashd fallback +/// (invoked exactly once) AND still assembles the job targets; +/// * a populated bundle routes WorkSource::Embedded WITHOUT invoking the +/// dashd fallback (no direct daemon poll on the hot path), and reproduces +/// EXACTLY the DashWorkData a direct build_embedded_workdata() over the +/// node's OWN held state yields; +/// * the assembled job targets are IDENTICAL across both template sources -- +/// the arithmetic is a pure transform that rides on top of either arm; +/// * an on_invalidate() (reorg) demotes back to the fallback. +/// +/// Seeding mirrors test_dash_node_embedded_wire.cpp EXACTLY (same projection), +/// and every "expected" value is an independent recomputation -- no fabricated +/// oracle constants. Rig-free: default-constructed NodeImpl, no io_context. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using dash::coin::DashWorkData; +using dash::coin::WorkSource; +using dash::coin::MNState; +using dash::coin::MutableTransaction; +using dash::coin::build_embedded_workdata; +using dash::stratum::GetWork; +using dash::stratum::get_work; +using dash::stratum::WorkJobTargetInputs; +using dash::stratum::WorkJobTargets; +using dash::stratum::assemble_work_job_targets; +using ::core::coin::UTXOViewCache; +using ::core::coin::Outpoint; +using ::core::coin::Coin; +using ::bitcoin_family::coin::TxIn; +using ::bitcoin_family::coin::TxOut; + +static constexpr uint8_t DASH_PUBKEY_VER = 76; +static constexpr uint8_t DASH_P2SH_VER = 16; +static constexpr uint32_t H = 2'400'000; + +static uint256 raw256(uint8_t base) { + uint256 h; + std::array p{}; + for (size_t i = 0; i < 32; ++i) p[i] = static_cast(base + i); + std::memcpy(h.data(), p.data(), 32); + return h; +} + +static std::vector p2pkh_script(uint8_t hashseed) { + std::vector s{0x76, 0xa9, 0x14}; + for (int i = 0; i < 20; ++i) s.push_back(static_cast(hashseed + i)); + s.push_back(0x88); s.push_back(0xac); + return s; +} + +static MutableTransaction make_spend(const uint256& prev, uint32_t idx, + int64_t out_value, uint32_t salt) { + MutableTransaction tx; + tx.version = 1; tx.type = 0; tx.locktime = salt; + TxIn in; in.prevout.hash = prev; in.prevout.index = idx; + in.sequence = 0xffffffffu; + tx.vin.push_back(in); + TxOut o; o.value = out_value; + tx.vout.push_back(o); + return tx; +} + +static std::vector> single_mn(const std::vector& payout) { + MNState s; + s.isValid = true; + s.nRegisteredHeight = 2'300'000; + s.nLastPaidHeight = 0; + s.scriptPayout.m_data = payout; + return {{raw256(0x01), s}}; +} + +static DashWorkData fallback_sentinel() { + DashWorkData w; + w.m_height = 0xDEADBEEFu; + w.m_bits = 0x1a2b3c4du; + return w; +} + +static void expect_workdata_eq(const DashWorkData& a, const DashWorkData& b) { + EXPECT_EQ(a.m_version, b.m_version); + EXPECT_EQ(a.m_previous_block, b.m_previous_block); + EXPECT_EQ(a.m_height, b.m_height); + EXPECT_EQ(a.m_coinbase_value, b.m_coinbase_value); + EXPECT_EQ(a.m_bits, b.m_bits); + EXPECT_EQ(a.m_curtime, b.m_curtime); + EXPECT_EQ(a.m_mintime, b.m_mintime); + EXPECT_EQ(a.m_payment_amount, b.m_payment_amount); + EXPECT_EQ(a.m_tx_hashes, b.m_tx_hashes); + EXPECT_EQ(a.m_tx_fees, b.m_tx_fees); + EXPECT_EQ(a.m_txs.size(), b.m_txs.size()); +} + +// A fixed, non-degenerate per-miner job-target input. share_info_bits_target +// sits inside the sane band; a positive local_hash_rate exercises the +// None-path pseudoshare modulation. Reused verbatim across every case so the +// assembled targets are directly comparable. +static WorkJobTargetInputs sample_job_inputs() { + WorkJobTargetInputs in; + in.share_info_bits_target.SetHex("00000000ffff0000000000000000000000000000000000000000000000000000"); + in.sane_target_min.SetHex ("0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + in.sane_target_max.SetHex ("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + in.have_desired_pseudoshare = false; + in.local_hash_rate = 1.0e6; // 1 MH/s -> real None-path cap + return in; +} + +static void expect_targets_eq(const WorkJobTargets& a, const WorkJobTargets& b) { + EXPECT_EQ(a.min_share_target, b.min_share_target); + EXPECT_EQ(a.share_target, b.share_target); +} + +// ════════════════════════════════════════════════════════════════════════ +// Set-gap: unpopulated node bundle -> dashd fallback, targets still assembled. +// ════════════════════════════════════════════════════════════════════════ +TEST(DashGetWork, GapRoutesFallbackAndAssemblesTargets) { + dash::NodeImpl node; + ASSERT_FALSE(node.coin_state().populated()); + + const auto job_in = sample_job_inputs(); + const WorkJobTargets reference_targets = assemble_work_job_targets(job_in); + + int calls = 0; + GetWork gw = get_work(node.coin_state(), + [&]{ ++calls; return fallback_sentinel(); }, job_in); + + EXPECT_EQ(gw.source, WorkSource::DashdFallback); + EXPECT_EQ(calls, 1); // fallback invoked exactly once + EXPECT_EQ(gw.work.m_height, 0xDEADBEEFu); // and its template returned verbatim + expect_targets_eq(gw.targets, reference_targets); // job assembled regardless +} + +// ════════════════════════════════════════════════════════════════════════ +// Populated: embedded arm, no dashd poll, byte-equal to a direct build. +// ════════════════════════════════════════════════════════════════════════ +TEST(DashGetWork, PopulatedRoutesEmbeddedNoDashdPoll) { + UTXOViewCache utxo(nullptr); + uint256 prev = raw256(0x77); + utxo.add_coin(Outpoint(prev, 0), Coin(100'000, {}, /*height=*/1, /*cb=*/false)); + + auto payout = p2pkh_script(0x30); + const uint256 prev_hash = raw256(0xAB); + const uint32_t bits = 0x1b104be3u; + const uint32_t mtp = 1'700'000'000u; + const uint32_t curtime = 1'700'000'123u; + const uint32_t version = 0x20000000u; + + dash::NodeImpl node; + node.coin_state().mempool().set_utxo(&utxo); + + node.coin_state_maintainer().on_mn_list_update(single_mn(payout)); + ASSERT_TRUE(node.coin_state_maintainer().on_mempool_tx( + make_spend(prev, 0, 90'000, /*salt=*/1))); + node.coin_state_maintainer().on_new_tip( + H - 1, prev_hash, bits, mtp, DASH_PUBKEY_VER, DASH_P2SH_VER, curtime, version); + ASSERT_TRUE(node.coin_state().populated()); + + DashWorkData reference = build_embedded_workdata( + H - 1, prev_hash, node.coin_state().mnstates(), node.coin_state().mempool(), + bits, mtp, DASH_PUBKEY_VER, DASH_P2SH_VER, curtime, version); + + const auto job_in = sample_job_inputs(); + const WorkJobTargets reference_targets = assemble_work_job_targets(job_in); + + int calls = 0; + GetWork gw = get_work(node.coin_state(), + [&]{ ++calls; return fallback_sentinel(); }, job_in); + + EXPECT_EQ(gw.source, WorkSource::Embedded); + EXPECT_EQ(calls, 0); // NO dashd poll on the hot path + expect_workdata_eq(gw.work, reference); // oracle-parity template preserved + expect_targets_eq(gw.targets, reference_targets); +} + +// ════════════════════════════════════════════════════════════════════════ +// The job-target arithmetic is identical across BOTH template sources. +// ════════════════════════════════════════════════════════════════════════ +TEST(DashGetWork, JobTargetsRideEitherTemplateSource) { + const auto job_in = sample_job_inputs(); + + // Gap arm. + dash::NodeImpl gap_node; + GetWork gap = get_work(gap_node.coin_state(), + [&]{ return fallback_sentinel(); }, job_in); + ASSERT_EQ(gap.source, WorkSource::DashdFallback); + + // Populated arm. + UTXOViewCache utxo(nullptr); + uint256 prev = raw256(0x77); + utxo.add_coin(Outpoint(prev, 0), Coin(100'000, {}, 1, false)); + dash::NodeImpl hot_node; + hot_node.coin_state().mempool().set_utxo(&utxo); + hot_node.coin_state_maintainer().on_mn_list_update(single_mn(p2pkh_script(0x30))); + ASSERT_TRUE(hot_node.coin_state_maintainer().on_mempool_tx(make_spend(prev, 0, 90'000, 1))); + hot_node.coin_state_maintainer().on_new_tip( + H - 1, raw256(0xAB), 0x1b104be3u, 1'700'000'000u, + DASH_PUBKEY_VER, DASH_P2SH_VER, 1'700'000'123u, 0x20000000u); + ASSERT_TRUE(hot_node.coin_state().populated()); + GetWork hot = get_work(hot_node.coin_state(), + [&]{ return fallback_sentinel(); }, job_in); + ASSERT_EQ(hot.source, WorkSource::Embedded); + + // Same inputs -> same job targets, independent of which arm sourced work. + expect_targets_eq(gap.targets, hot.targets); +} + +// ════════════════════════════════════════════════════════════════════════ +// Demote: on_invalidate() (reorg) drops back to the dashd fallback. +// ════════════════════════════════════════════════════════════════════════ +TEST(DashGetWork, InvalidateDemotesToFallback) { + dash::NodeImpl node; + node.coin_state_maintainer().on_mn_list_update(single_mn(p2pkh_script(0x30))); + node.coin_state_maintainer().on_new_tip( + H - 1, raw256(0xAB), 0x1b104be3u, 1'700'000'000u, + DASH_PUBKEY_VER, DASH_P2SH_VER); + ASSERT_TRUE(node.coin_state().populated()); + + node.coin_state_maintainer().on_invalidate(); + ASSERT_FALSE(node.coin_state().populated()); + + const auto job_in = sample_job_inputs(); + int calls = 0; + GetWork gw = get_work(node.coin_state(), + [&]{ ++calls; return fallback_sentinel(); }, job_in); + + EXPECT_EQ(gw.source, WorkSource::DashdFallback); + EXPECT_EQ(calls, 1); + EXPECT_EQ(gw.work.m_height, 0xDEADBEEFu); +}