Patch: cross-shard, staking, rewards, consensus and the VM - #5124
Open
GheisMohammadi wants to merge 37 commits into
Open
Patch: cross-shard, staking, rewards, consensus and the VM#5124GheisMohammadi wants to merge 37 commits into
GheisMohammadi wants to merge 37 commits into
Conversation
GheisMohammadi
force-pushed
the
fix/mainpatch
branch
from
August 18, 2026 16:11
e9914c7 to
0ae80da
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is a patch. No new features, no protocol redesign, no storage format changes. It is a set of independent corrections found during a review of the cross-shard/receipt path, the staking and delegation flow, reward distribution, EPoS and quorum, view change, and the EVM.
Severity
Fixes
senderKeySanityChecksverified only that a VIEWCHANGE message was self-signed, not that the key was in the committee.GetM3Bitmapaggregates every stored signature but returns a bitmap covering committee members only, so a non-member signature left the M3 aggregate unverifiable against the bitmap-derived key and no NEWVIEW could be accepted for that viewID.decider().Participants().delegatorSlashApplyDebtdivides bytotalExternalStake. Delegation entries persist after a full undelegation, so a validator can carry external delegators whose snapshot stake sums to zero.votepower.Computedivides each slot's effective stake byroster.TotalEffectiveStake, which can be zero.ValidateCXReceiptsProofindexesCXShardHashesbylen(ShardIDs). The two are independent RLP lists on a gossip message.TxTypeis transaction-scoped but consulted on every transfer inCallandcreate, so nested value transfers during aSubtractionOnlytransaction were debited without being credited.VerifyAndDelegateFromMsgfetches a fresh deep copy of the wrapper per index entry. Two entries naming the same validator each consumed the same undelegating tokens, and only the last write survived.HMYSlotCount == 0,ourPercentagestays 0 whiletheirPercentageonly reachesexternalPercent, so the "give diff to last staked voter" balancing step assigned the entire Harmony vote share to one member.externalPercentto 1 when there are no Harmony slots.QuoandRoundIntboth round, so per-delegator shares can sum above the pool.rewardPoolwent negative and the remainder branch was skipped.RemoveUnlockedUndelegations, an entry matchingmaxRateApplieswas dropped from the list without being added tototalWithdraw.To == nilproduced aCXReceiptthat RLP-encodes but fails to decode, soReadCXReceiptserrored andCXMerkleProofsilently skipped that shard, invalidating every proof from the same source block.CallCodeandDelegateCalldispatch to precompiles without the value transferCallperforms, while still passing acontract.Value()from the calling frame, so the cross-shard precompile spent the balance held at its own address.CALLvia aDirectCallOnlymarker.VerifyIncomingReceiptsran only fromValidateNewBlock.insertChainapplied incoming receipts without the spent-marker,ToShardID, merkle proof or source-shard signature checks.VerifyAndCollectRewardsFromDelegationand the redelegation loop indexedwrapper.Delegationsby an offset from the node-local delegation index without checkingDelegatorAddress.AddPendingReceiptsadmitted a proof whose validation failed withMsgNoShardStateFromDB, which is reachable for any header epoch without a stored shard state, andproposeReceiptsProofrequeued it indefinitely.current + 1and cap requeues.CXReceiptsProof.CopywroteCommitSigintoCommitBitmap.Block.Body()andReadBlockboth go throughCopy, so persisted bodies no longer matchedIncomingReceiptHash.AddRewardindexedcurValidator.Delegations[i]by snapshot position with no length check.CallandCallCodenull it out;DelegateCallandStaticCallexecuted it as bytecode.CreateValidatorFromNewMsgverified every BLS proof of possession beforeSanityCheckappliedMaxBLSPerValidator, and this runs inTxPool.validateStakingTxbefore acceptance.checkDuplicateFieldsloaded every wrapper in the validator list even when the message supplied neither an identity nor slot keys.evm.StakeMsgswas not rolled back on frame revert, unlikeCXReceipt, and was returned fromApplyTransactioneven on failed execution.StakeMsgsat all five frames.Finaliselogged and skipped a wrapper whoseSanityCheckfailed, leavingstateValidatorsand the persisted code out of sync.VerifyAndCollectRewardsFromDelegationtested emptiness withtotalRewards.Int64(), which reads only the low 64 bits.Sign().MayBalanceMigrationcalled.Root()on the result ofGetBlockByHashwithout a nil check.ContainsEmptyFielddereferenced the receiver after thecxp == nilshort-circuit.append(val.SlotPubKeys[0:0], ...)aliases the caller's backing array rather than copying.msgPayload[0]was read before checking the payload length.if i < 0on auint64loop variable is unreachable.GetVMConfigreturned&bc.vmConfig, so a caller setting a tracer would mutate the config block processing reads.Epochs
StrictStateValidationEpochgates all 14 rows markedGated: Yes.Testing
Every fix has a test that fails without the change and passes with it.
Packages verified:
core,core/vm,core/state,core/types,consensus,consensus/quorum,consensus/votepower,core_test,node/harmony,internal/chain,internal/params,staking/types,staking/slash,staking/effective,staking/availability,hmy.