<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: BTC PoW Lab</title>
    <description>The latest articles on DEV Community by BTC PoW Lab (@btcpowlab).</description>
    <link>https://dev.to/btcpowlab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4108565%2F24c32ef9-7183-4e88-a962-366894b02085.png</url>
      <title>DEV Community: BTC PoW Lab</title>
      <link>https://dev.to/btcpowlab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/btcpowlab"/>
    <language>en</language>
    <item>
      <title>A Mining-Pool Payout Promise Is Not an Accounting System</title>
      <dc:creator>BTC PoW Lab</dc:creator>
      <pubDate>Thu, 03 Sep 2026 18:29:00 +0000</pubDate>
      <link>https://dev.to/btcpowlab/a-mining-pool-payout-promise-is-not-an-accounting-system-33al</link>
      <guid>https://dev.to/btcpowlab/a-mining-pool-payout-promise-is-not-an-accounting-system-33al</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Disclosure: I operate BTC PoW Lab Pool, which is used below as a case study. This draft was prepared with AI assistance and reviewed against the live public API and project records. The pool has not found a block and has no payout history.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A percentage on a mining-pool landing page is not an accounting system.&lt;/p&gt;

&lt;p&gt;“The finder receives 85%” sounds precise. It is not enough to answer the questions that appear after a real block:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which miners were eligible at the exact block height?&lt;/li&gt;
&lt;li&gt;Which accepted shares were inside the reward window?&lt;/li&gt;
&lt;li&gt;Was the finder excluded from the community allocation?&lt;/li&gt;
&lt;li&gt;How were rounding and dust handled?&lt;/li&gt;
&lt;li&gt;Which exchange rate produced the USD estimate shown in a screenshot?&lt;/li&gt;
&lt;li&gt;Can the operator reproduce the result after a restart or database restore?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If those answers are calculated from mutable live state, two honest queries made seconds apart can disagree. A restart can make the disagreement harder to explain. A screenshot can then look like stronger evidence than the database.&lt;/p&gt;

&lt;p&gt;The fix is to treat the block as an accounting event and create an immutable snapshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate the economic identity from the connection
&lt;/h2&gt;

&lt;p&gt;A miner may use several workers, reconnect repeatedly, or run more than one device. Those are operational sessions, not necessarily separate economic participants.&lt;/p&gt;

&lt;p&gt;The payout identity should be the Bitcoin address or another explicit settlement identifier. Workers and sessions roll up into that identity. This prevents a participant from manufacturing additional reward weight by splitting one hashrate source into many worker names.&lt;/p&gt;

&lt;p&gt;The raw events should still preserve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;session ID;&lt;/li&gt;
&lt;li&gt;worker ID;&lt;/li&gt;
&lt;li&gt;payout identity;&lt;/li&gt;
&lt;li&gt;accepted difficulty;&lt;/li&gt;
&lt;li&gt;block height;&lt;/li&gt;
&lt;li&gt;server timestamp;&lt;/li&gt;
&lt;li&gt;job and extranonce identifiers;&lt;/li&gt;
&lt;li&gt;rejection reason, when applicable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aggregation should change the accounting view, not erase the evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Freeze rules and inputs together
&lt;/h2&gt;

&lt;p&gt;At block detection, the snapshot should capture more than the final totals. It should include the inputs needed to reproduce them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"block_height"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;965350&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hybrid-solo-tiered-community-7d-v5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eligibility_window_seconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;604800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"finder_identity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bc1q..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"finder_excluded"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"network_reward_sats"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"allocations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-09-03T00:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input_digest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha256:..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;rules_version&lt;/code&gt; matters because software changes. Re-running today’s code against last month’s data is not necessarily a valid historical reconstruction.&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;input_digest&lt;/code&gt; matters because it binds the snapshot to the accepted-work set used by the calculation. If a later audit imports events from backup, the digest can establish whether it reconstructed the same input.&lt;/p&gt;

&lt;h2&gt;
  
  
  Account in satoshis, display in fiat
&lt;/h2&gt;

&lt;p&gt;Settlement amounts should be integers in satoshis. Fiat values are presentation-layer estimates.&lt;/p&gt;

&lt;p&gt;A user may capture “US$ 120.20” and see “US$ 117.80” later even when the underlying reward remains exactly 158,323 sats. That is normal if the BTC/USD quote changed. The interface should show both values and explain which one is authoritative.&lt;/p&gt;

&lt;p&gt;For every allocation, persist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;exact &lt;code&gt;total_sats&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;allocation components;&lt;/li&gt;
&lt;li&gt;remainder policy;&lt;/li&gt;
&lt;li&gt;dust state;&lt;/li&gt;
&lt;li&gt;fiat quote and quote timestamp used for display;&lt;/li&gt;
&lt;li&gt;status such as &lt;code&gt;PROJECTED&lt;/code&gt;, &lt;code&gt;FROZEN&lt;/code&gt;, &lt;code&gt;PAYABLE&lt;/code&gt;, &lt;code&gt;DEFERRED_DUST&lt;/code&gt;, &lt;code&gt;BROADCAST&lt;/code&gt;, or &lt;code&gt;CONFIRMED&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Never overwrite the satoshi amount merely because the display quote changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make rounding deterministic
&lt;/h2&gt;

&lt;p&gt;If proportional weights do not divide the reward exactly, the system needs a published remainder rule. Examples include largest remainder or deterministic assignment ordered by a stable identity hash.&lt;/p&gt;

&lt;p&gt;The important part is not which reasonable rule is selected. The important part is that the rule is versioned, deterministic, and applied before the snapshot is sealed.&lt;/p&gt;

&lt;p&gt;The sum must satisfy an invariant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;finder_sats + community_sats + lab_sats + explicit_remainders
  = distributable_block_reward_sats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the invariant fails, payout preparation must fail closed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Calculation and signing are different trust boundaries
&lt;/h2&gt;

&lt;p&gt;An automatic calculator does not need access to private keys. A signer does.&lt;/p&gt;

&lt;p&gt;That difference is operationally important. A safer pipeline is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;detect a candidate block;&lt;/li&gt;
&lt;li&gt;verify it against the Bitcoin node;&lt;/li&gt;
&lt;li&gt;freeze the accounting snapshot;&lt;/li&gt;
&lt;li&gt;wait for the configured confirmation threshold;&lt;/li&gt;
&lt;li&gt;construct a batch transaction or PSBT from the frozen plan;&lt;/li&gt;
&lt;li&gt;validate outputs against the snapshot;&lt;/li&gt;
&lt;li&gt;sign in a separate, constrained environment;&lt;/li&gt;
&lt;li&gt;broadcast and record the transaction ID;&lt;/li&gt;
&lt;li&gt;reconcile every output and fee.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is also where “automatic payouts” can become custody. If community funds first arrive at an operator-controlled address, the operator controls those funds until the distribution transaction is signed. Automation reduces manual work; it does not remove the custody boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design the appeal process before the dispute
&lt;/h2&gt;

&lt;p&gt;Suppose a miner says, “I should have received more,” and sends a screenshot.&lt;/p&gt;

&lt;p&gt;The operator should be able to produce an audit bundle without editing the production database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;block and confirmation evidence;&lt;/li&gt;
&lt;li&gt;rules version;&lt;/li&gt;
&lt;li&gt;participant identity and eligibility interval;&lt;/li&gt;
&lt;li&gt;accepted-work rows or a verifiable aggregate;&lt;/li&gt;
&lt;li&gt;weight calculation;&lt;/li&gt;
&lt;li&gt;exact satoshi allocation;&lt;/li&gt;
&lt;li&gt;fiat quote metadata;&lt;/li&gt;
&lt;li&gt;snapshot digest;&lt;/li&gt;
&lt;li&gt;payout transaction and reconciliation state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The screenshot is then useful context, not the sole source of truth. It may reveal a stale UI, a changed exchange rate, a different worker aggregation, or a real accounting defect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Survive restarts and machine loss
&lt;/h2&gt;

&lt;p&gt;The snapshot and event journal should not live only on the machine running Stratum.&lt;/p&gt;

&lt;p&gt;A practical minimum is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an atomic local snapshot;&lt;/li&gt;
&lt;li&gt;an encrypted off-site copy;&lt;/li&gt;
&lt;li&gt;a manifest containing hashes and schema versions;&lt;/li&gt;
&lt;li&gt;a restore test on a separate path;&lt;/li&gt;
&lt;li&gt;documented recovery-point and recovery-time objectives.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;“Backup completed” is weaker than “backup downloaded, decrypted, hashed, and restored successfully.” Verification is part of the backup.&lt;/p&gt;

&lt;h2&gt;
  
  
  What transparency can and cannot prove
&lt;/h2&gt;

&lt;p&gt;Before its first block, a pool can prove that its rules are published, its telemetry exists, its snapshot code is deterministic, and its backups restore.&lt;/p&gt;

&lt;p&gt;It cannot prove a successful payout history that does not exist.&lt;/p&gt;

&lt;p&gt;That distinction is healthy. Engineering evidence should make future claims testable without turning preparation into a claim of completed performance.&lt;/p&gt;

&lt;p&gt;The BTC PoW Lab Pool accounting model and live limitations are public here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://btcpowlab-pool.com/model?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=phase3_targeted_outreach_2026_09&amp;amp;utm_content=auditable_snapshots" rel="noopener noreferrer"&gt;Accounting model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://btcpowlab-pool.com/status?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=phase3_targeted_outreach_2026_09&amp;amp;utm_content=auditable_snapshots" rel="noopener noreferrer"&gt;Operational status&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The broader lesson applies beyond mining: if money is distributed from changing state, freeze the rules, freeze the inputs, record exact units, and separate calculation from signing.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>backend</category>
      <category>bitcoin</category>
    </item>
  </channel>
</rss>
