diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-02 07:15:45 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-02 07:15:45 +0000 |
| commit | f094dc2f95df213f8c89d1d6f25dc864062623ae (patch) | |
| tree | 06e9ac2db31590b2c9803e51f326105806d611d9 /src/test_rvaccept.cpp | |
| parent | e4f898c4a6b9900553c64b9804889b5fdae3e55f (diff) | |
pool: refuse to build a job whose coinbase would burn the subsidy
GetKeyFromPool() returns an empty vector when the wallet is encrypted
and locked, and when key generation itself fails. RebuildJob() fed
whatever came back straight into the coinbase, and CScript::operator<<
serialises an empty vector as a zero-length push, so the template's
coinbase script became `<empty> OP_CHECKSIG` -- satisfiable by nobody.
Every block the pool's miners found against such a job burned its whole
subsidy: the coins exist and can never move, while QueuePayouts records
the full obligation and the miners are then paid out of coin that block
never contributed. An operator who locks the wallet overnight while the
miners keep finding blocks pays twice for every one of them.
BitcoinMiner has exactly this guard ("no wallet key available for
coinbase; mining stopped"); this builder was missed. Mirror it: log the
reason and return false before any job state is touched. Every caller
already treats a false return as "no job this round" -- the submit
handler and the new-block path log a warning and leave gHaveJob false,
the no-job watchdog goes on retrying every few seconds, and the
periodic nTime refresh keeps broadcasting the old job, whose key was
drawn while the wallet could still produce one. Once the wallet can
hand out a key again the next retry issues a spendable job unprompted.
Diffstat (limited to 'src/test_rvaccept.cpp')
0 files changed, 0 insertions, 0 deletions