Skip to content

update#431

Open
itsmylife44 wants to merge 3073 commits into
Snipa22:masterfrom
MoneroOcean:master
Open

update#431
itsmylife44 wants to merge 3073 commits into
Snipa22:masterfrom
MoneroOcean:master

Conversation

@itsmylife44

Copy link
Copy Markdown

No description provided.

@bobbieltd

Copy link
Copy Markdown
Contributor

It is the biggest pull request in one hit that I have ever seen in Github. 🙈 To the moon 🚀.

@LegolasGChief

Copy link
Copy Markdown

These changes will work on latest snipa pool if I add them? what is best way to implement them? it will work for Aeon still? I am worried about DB changes

@bobbieltd

Copy link
Copy Markdown
Contributor

It works with Aeon, of course. Aeon is a sibling of Monero, much simpler than other coins.
itismylife44 already use MoneroOcean codes for his graft pool + NiceHash to test pool. Impressive. Very serious person ! Bring my popcorn and watch how his pool is going 😎
in bocca al lupo !

Correct the misspelling in the human-readable subject/body of the
sendAdminFyi block-submit-failure messages. The throttle/dedup keys
(first argument) are unchanged, so notification behavior is identical.
Call the script_utils factory like the other user_/manage_ scripts
instead of relying on the static createCli.init property. Behavior is
identical since both resolve cli.init to initMini.init.
Remove unreachable `|| 0` fallback on miner.lastShareTime; Date.now()/1000
is always a positive number so the fallback is dead.

Reorder the success path in block_reward_fix_common.js to close the cursor
before committing the txn, matching the file's error/not-found paths and the
dominant manage_scripts convention.
…on NaN

A login like "wallet+abc" set miner.difficulty = Number("abc") = NaN; the
min/max clamps are no-ops on NaN, so it reached the BigInt difficulty math
during the new-block broadcast and threw an uncaught RangeError that killed
the pool worker (an unauthenticated remote crash from any stratum client).
Fall back to the starting difficulty when the suffix is not a finite positive
number. Numeric suffixes are unaffected.
createBtcRpc.getAnyBlockHeaderByHash only checked that result.tx was a
non-empty array, then parseBtcReward did 'for (const vout of block.tx[0].vout)'
unguarded. A malformed/partial BTC-style daemon reply (tx[0] lacking vout, via
reorg/resync/pruned/non-standard coinbase) threw an uncaught TypeError in the
daemon-reply callback, crashing the block_manager into a payout crash-loop for
RTM/RVN. Treat such a reply as a verify error (callback(true, body)) like the
other error paths; valid replies are unaffected.
These daemon-reply callbacks run inside res.on('end') with no try/catch and no
process-level handler, so a malformed/partial reply threw an uncaught exception
that crashed the pool/block_manager process:
- createCryptonoteRpc: JSON.parse(body.result.json) + miner_tx.vout deref had
  no guard -> wrap in try/catch and validate miner_tx.vout before use.
- Erg: accessed body.blockTransactions.transactions after only checking body.header.
- Xtm main/T: accessed body.result.header.* / body.result.metadata.* after only
  checking body.result.
Each now returns a verify error (callback(true, body)) on a malformed reply,
matching the existing error paths. Well-formed replies are unaffected.
user_delete removed balance rows unconditionally, so deleting an account whose balance
row has pending_batch_id set (reserved by an in-flight payout batch) would make the
payment finalizer's reserved-row UPDATE mismatch and wedge payout recovery. Add the same
pending_batch_id guard user_balance_move already has: refuse the delete (even under
--force) when the row is reserved, and tell the operator to retry after the batch
settles. Adds a regression test.
Flat config (eslint.config.js) for a CommonJS Node backend: sourceType
"commonjs", ecmaVersion 2023, globals.node, ignoring node_modules plus
the gitignored .cache (downloaded third-party miner code) and
test-artifacts dirs. Adds "lint": "eslint ." and eslint/globals devDeps.
Code fixes: underscore-prefixed unused catch bindings/args and a few
unused local helpers, and dropped one unused destructured import.
Relaxed rules to match existing prevalent style: no-prototype-builtins,
no-useless-escape, no-regex-spaces, no-control-regex,
no-constant-binary-expression off; no-empty set to allowEmptyCatch.
Adds a "pretest" npm script that runs "npm run lint" so eslint executes
automatically before the test suite.
…ables

Restore the six rules that were previously relaxed/disabled in
eslint.config.js, addressing each violation in a behavior-preserving way:

- no-empty (was allowEmptyCatch:true -> "error"): every intentionally
  empty best-effort catch block now carries an explanatory comment
  describing why the error is swallowed (code fix; no inline disables).
- no-prototype-builtins (was off -> "error"): obj.hasOwnProperty(...)
  calls rewritten to Object.hasOwn(...) / Object.prototype.hasOwnProperty.call(...)
  (code fix).
- no-useless-escape (was off -> "error"): removed a provably redundant
  backslash escape in the email-validation regex character class (code fix).
- no-regex-spaces (was off -> "error"): literal multi-space runs in
  email-body assertion regexes rewritten with explicit { N } quantifiers
  preserving the exact match (code fix).
- no-control-regex (was off -> "error"): the one intentional ANSI
  escape-stripping regex keeps the control char and gets a scoped
  // eslint-disable-next-line no-control-regex (inline disable).
- no-constant-binary-expression (was off -> "error"): statically-constant
  "x || 0" guards simplified to their constant value (code fix).

npx eslint . exits 0.
Adds no-throw-literal, default-case-last, no-unused-expressions, no-var,
no-else-return, prefer-const, eqeqeq ({null:"ignore"}), no-implicit-coercion,
object-shorthand, prefer-template, no-shadow, no-param-reassign. Bulk applied via
eslint --fix; manual behavior-preserving fixes for the eqeqeq/no-shadow/
no-param-reassign sites.

Also fixes a bug the no-param-reassign rewrite introduced in createMiner: the
parameter `agent` was replaced by `const normalizedAgent`, but miner.proxy,
miner.xmrig_proxy and applyNiceHashDiff still read the raw, un-normalized `agent`
(behavior diverges when an agent string exceeds the 255-char retention cap). They
now read normalizedAgent, restoring the prior behavior.

Tests: 495 pass / 0 fail.
sendUntilSuccess retried a failed share/block POST via setImmediate -- a tight
next-tick loop. When the central shareHost is down but its host is up (ECONNREFUSED,
the typical outage) each of the ~cpus*32 held send-queue slots reconnects as fast as
the event loop runs, pinning the pool master's CPU core and flooding the dead endpoint
with connection attempts while the queue backs up unboundedly. Retry on a fixed 1s
delay instead: still retries until success (no share dropped), but paced so an outage
cannot spin the CPU or flood the endpoint. Adds a test that the retry is delayed.
isStorableShare only checked typeof share.raw_shares === "number", which
accepts NaN/Infinity. raw_shares is a proto float, and wire NaN/Infinity
decode to JS numbers that pass that check, then flow into the cumulative
totalHashes/roundHashes accumulators and poison pool stats and the PPLNS
round-share denominator. Tighten the guard to Number.isFinite (strictly
tighter; unchanged for all valid finite hashrate values) so a malformed
frame is dropped like an out-of-range blockHeight already is. Add a
regression test asserting NaN/Infinity frames are dropped, the valid frame
is still stored, and no non-finite stat is written.
… cleanup)

A prior change made createTaskQueue.oldest() return pending[0]. The sole caller is the
remote share-verify stale-task cleanup (lib/coins/index.js), whose queue is fed with
unshift() -- so pending[0] is the NEWEST task, not the oldest. Under sustained share
submission the head stays fresh, so the cleanup early-returns and never removes expired
tasks, leaking queued verification tasks and per-wallet miner_address_verify counters
until memory / share-processing availability degrades (reachable via public submissions
when verify_shares_host is set).

Track a monotonic enqueueOrder per task and return the minimum from oldest(), so it is
correct regardless of push (FIFO tail) vs unshift (priority front). Adds a regression
test for the push+unshift ordering.
…crash)

resolveErgSubmittedBlockHash dereferenced body.powSolutions.pk with no guard when
err === null. A non-error but malformed/partial header (missing powSolutions) from the
daemon/relay threw a TypeError inside the setTimeout callback -- no surrounding try/catch,
no process-level uncaughtException handler -- crashing the block-submit confirm path (ERG
is a relayed coin; a crash here can stall/lose a found block). Treat a missing solution as
"not our block" (same sentinel as the err!==null branch).
…d loss)

ETH-family block headers carry no confirmations/topoheight, and the daemon returns
non-canonical blocks by hash (verified against the live ETC daemon: getBlockByHash of an
uncle / non-canonical hash returns the block). So an orphaned found block -- not canonical
and not referenced as an uncle within the inclusion window -- came back from
getAnyBlockHeaderByHash non-null with error=null: neither checkOrphans (mo_altblockmanager)
nor isAltblockOrphanResponse (block_manager) detected it (both key off confirmations /
topoheight === -1), and the height-fallback is gated behind a non-null error. The orphan
was then traded to XMR and paid to miners for a block that earned nothing on-chain.

Mark the true-orphan fallthrough with confirmations = -1, the sentinel both consumers
already recognise, so it is invalidated instead of paid. The canonical (hash === canonical)
and uncle (createEthUncleReward) branches return earlier and are untouched, so valid blocks
and uncles are never misflagged (ETC uncle-inclusion distance <= 7 is inside the +-8 scan
window). Verified against the live ETC daemon; full suite green.
Follow-up to the ETC-orphan fix, after a same-class sweep + live-daemon verification:

- ERG (factories.js createErgRpc.getAnyBlockHeaderByHash): like ETC, the Ergo node serves
  forked/orphaned blocks by id with HTTP 200 and no orphan marker, and this handler had no
  canonical comparison at all, so an orphaned ERG found block returned as a clean success and
  was paid. Now compares against the single canonical id at the block's height and marks a
  non-canonical block confirmations=-1; ambiguous lookups fall through to the valid path.

- Cryptonote alts (xla/ryo/zeph/sal/arq/ccx + XMR alt blocks): monerod get_block_header_by_hash
  returns an orphaned block non-null with orphan_status=true (verified vs the live XMR daemon:
  13 alt chains present; alt header orphan_status=true, main=false), but isAltblockOrphanResponse
  only checked topoheight/confirmations/error -> the orphan passed and was paid. Added
  orphan_status===true to the check.

Valid blocks unaffected (orphan_status=false; ERG marks only a confirmed-different canonical id).
Full suite green.
mom v0.7.0 benchmarks the active GPU algos (autolykos2/etchash/kawpow/pearl) at startup by
default (bench_algo_params=1); those aren't in MOM_NO_BENCH_ALGOS, so the "no-bench" live
config still ran slow (and on some Intel Xe GPUs unstable) DAG benchmarks before mining. Set
bench_algo_params=0 to skip benchmarking and go straight to the pool job.
…drop an accepted block

submitEthBlock confirms acceptance on eth_submitWork===true, then resolveEthSubmittedBlockHash
waited 30s and did a SINGLE ethBlockFind to discover the on-chain hash. If the daemon was
down/slow/restarting in that window, ethBlockFind/ethBlockCheck return null, the function
returned the zero-hash, and share_blocks dropped the already-accepted (on-chain) block
uncredited (admin FYI only, no retry). Compounds with monitorNodes' daemon restarts.

ethBlockFind is read-only/idempotent, so retry it a bounded number of times
(ETH_BLOCK_RESOLVE_ATTEMPTS=10 x 30s) before falling back to the zero-hash. Single-attempt
success is unchanged.

Limits (option A, in-memory): retry state is not durable, so a pool restart inside the window
still loses the in-flight block; outages longer than ~5 min still fall back to the zero-hash
drop; a genuine orphan is dropped after the retries instead of immediately. A durable fix
(persist the pending resolution) was deferred. + tests (transient-recover, exhausted-fallback).
Suite green.
…ropping a refind (R14, partial)

Main blocks are keyed by height, so saveResolvedBlock treated ANY existing blockDB[height] entry
as a duplicate (hash-blind). After a reorg orphans block A at height N (unlocker sets valid=false)
and the pool finds canonical block C at N, saveResolvedBlock saw the slot occupied and dropped C
-> lost block, miners unpaid.

Now: same hash -> genuine duplicate (unchanged); different hash but the recorded block was
orphaned (valid===false) -> replace the orphan tombstone with the new valid block; a different
still-valid block -> still "duplicate" (cannot hold two at one height key). Normal one-block-per-
height operation is unchanged. The remaining two-still-valid-at-one-height window needs the full
fix (height in the Block value + forward-probe, like AltBlock) -- tracked as R14 option 1. Suite green.
…c236fe / b31b6ed)

Adds the coverage the cons-review flagged as missing for three money-path fixes:
- basics.js: eth-family getAnyBlockHeaderByHash tags a true orphan (not canonical, no uncle
  reference) with confirmations=-1; erg getAnyBlockHeaderByHash tags a true orphan (a
  different canonical id occupies the height) with confirmations=-1.
- block_jobs.js: saveResolvedBlock replaces an orphaned (valid=false) same-height block with
  the canonical refind, and keeps an existing still-valid block (treated as duplicate).
Tests-only; no production code change.
The workerMax check pre-incremented (++count <= workerMax), so an over-limit login that is rejected
still bumped the count; that worker never connects, so it is never decremented and the count drifts
up over time until legitimate miners under the real limit are wrongly rejected. Check before
incrementing (intent of refactor ef46e97 was only to bound worker count). Suite green.
…unt leak, long_runner key-0 resume, template one-shot

- manage_scripts/exchange_recovery_cache_common.js: key buildBlockLookup by the LMDB `_key` the
  callback yields, not the non-existent block.id (was always NaN -> lookup 100% broken).
- lib/pool/miner_registry.js: check proxy worker count before incrementing so a rejected over-limit
  login doesn't leak the count (twin of the protocol.js 302d649 fix).
- lib/long_runner.js: compare goToRange() !== false in the reverse-resume branch so an LMDB key
  value of 0 isn't mis-treated as "not found" (mirrors the forward branch).
- lib/pool/templates.js: make the header-fetch-error reschedule one-shot (requireTrue) like the
  success path, so a bootstrap (undefined repeating) call can't spawn a second poll loop.
- factories.js + protocol.js: fix 'extranoces' -> 'extranonces' miner-facing typo (+ test).
Suite green (504 pass).
…r guard/import, collapse duplicate coinHashFactor branches (behavior-preserving, eslint+tests green)
…(skip cycle, not crash)

createBlockTemplate (RtmBlockTemplate/RavenBlockTemplate) runs inside the daemon-RPC reply callback,
which jsonRequest invokes OUTSIDE its try/catch — so any template-build throw (malformed bits/version/
previousblockhash, too-many/unparseable txs) propagated uncaught and could crash the process. Wrap the
build in try/catch and, on failure, log + return like a no-result reply so the pool skips that template
cycle and retries next poll. Suite 504/504.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants