Repository navigation
Conversation
Recheck received block witness authorization under the Manager lock after pending state is reset, so concurrent permission changes and pending transactions cannot authorize block admission. Keep witness validation before advertisement broadcast and defer sync validation to Manager. Update the shutdown target only after witness authorization succeeds.
|
[MUST] Witness authorization needs to be checked against the block’s actual parent state. The new Manager check can reject a valid competing branch. A and B are children of P, whose witness permission authorizes K1. A contains a K1 → K2 rotation, while B is signed by K1. B can reach ingress while A is still being processed and has not yet executed its permission-update transaction. The ingress check therefore still reads K1 and correctly accepts B’s signature. A then finishes and commits before B acquires the Manager lock. B is now a fork block, and There is also a related pre-existing ingress limitation: Please validate authorization against the actual parent state, defer/retry blocks when that state is unavailable, and add regression coverage for both sequences. |
SeriousCoding789
left a comment
There was a problem hiding this comment.
I agree with adding the witness-signature check inside Manager.pushBlock: checking against committed state after the pending session is reset fixes the pending-state problem. My concern is with removing it from the sync network layer. After this change the in-Manager check is the only witness-signature check on the sync path, and it runs only after work the old check used to avoid.
-
Work moves into the critical section. A sync block is only buffered on receipt and validated later on the sync handler thread. At base, a block with a bad witness signature was rejected in
validBlockbeforeprocessBlock. With this PR it first enterspushBlock: it raisesblockWaitLock(Manager.java:1241, which makespushTransactioncallers wait), takes the Manager monitor that block production also uses (:1243), runsgetVerifyTxs(:1259) and resets the pending session (:1265), so all pending transactions are re-queued and executed again. Only then is it rejected at:1270. The sender still gets aBAD_BLOCKdisconnect and a 1-hour ban, but that limit is per IP, so it can be repeated from many addresses. -
The check in front of
consensus.receiveBlockbecomes the only guard.consensus.receiveBlock(:1274) acts on the block's witness address (duplicate-producer detection for this node's SR keys), so it should only see blocks whose signature has been verified. Today the new check runs right before it. But the fix for the fork-state issue in the comment above (validate against the block's parent state, defer when that state is unavailable) would likely skip or defer the check for some fork blocks at this point. Without a sync-layer check, those blocks would reachconsensus.receiveBlockandkhaosDb.pushwith no witness-signature check at all. -
Runtime exceptions are no longer wrapped.
validateSignaturecan throw unchecked exceptions on malformed input, e.g. a witness signature shorter than 65 bytes while strict ECDSA validation is off (sanitize()only trims overlong signatures). The old network wrapper turned any exception intoBLOCK_SIGN_INVALID. InsidepushBlockthey now escape unwrapped, skipfailProcessBlock, and are logged with a full stack trace on every attempt. -
Known block ids (minor).
BlockIdcovers only the raw header, and both thefreshBlockIdshortcut (TronNetDelegate.java:272) and the "already exist" return (Manager.java:1252-1254) run before the new check. A sync copy of a known block with a garbage signature now returns success instead ofBAD_BLOCK.
Restoring the old sync check unchanged would bring back the pending-state false rejections this PR fixes; on the sync path that means banning an honest peer. So rather than reverting, I'd suggest keeping a sync-layer pre-check that does not depend on pending state:
- before
processBlock, a state-free check that the witness signature has a valid length and a signer can be recovered (same strictness asvalidateSignature), rejected withBAD_BLOCKon failure; this cannot reject a valid block; - if the fork-state fix defers validation for some blocks, making sure a block reaches
consensus.receiveBlockonly after its signature has been verified, or movingreceiveBlockafter the deferred validation.
It might also be worth converting runtime exceptions from validateSignature into ValidateSignatureException inside pushBlock, and adding tests for: a garbage-signature sync block with a non-empty pending pool, a short witness signature with strict ECDSA off, and a known block id carrying a garbage signature.
What does this PR do?
Recheck received block witness authorization under the Manager lock after pending state is reset, so concurrent permission changes and pending transactions cannot authorize block admission. Keep witness validation before advertisement broadcast and defer sync validation to Manager. Update the shutdown target only after witness authorization succeeds.
Why are these changes required?
This PR has been tested by:
Follow up
Extra details