Skip to content

limit fromTransientStore results to the selected collection config - #5651

Open
Nussu06 wants to merge 1 commit into
hyperledger:mainfrom
Nussu06:pvtdata-transient-config-match
Open

Nussu06 wants to merge 1 commit into
hyperledger:mainfrom
Nussu06:pvtdata-transient-config-match

Conversation

@Nussu06

@Nussu06 Nussu06 commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Type of change

  • Bug fix

Description

When a peer serves a private data pull for a block it has not committed yet, dataRetriever.fromTransientStore in gossip/privdata/dataretriever.go appends the write sets of every transient store entry for the requested txID, but keeps the collection config of only one entry (highest EndorsedAt, ties go to whichever entry is iterated last). puller.filterNotEligible then checks the requesting peer against that one config.

Any channel member peer can add transient store entries through a gossip private data push (GossipStateProviderImpl.privateDataMessage), and the collection config in that message is stored as sent, with EndorsedAt 0. On a peer that received the real private data by dissemination (also EndorsedAt 0), a channel member outside the collection can push a few entries for the same txID whose config lists its own org as a member, then send a pull request for that digest with a BlockSeq above the victim's ledger height to force the transient store path. When one of its entries is iterated last, eligibility is checked against the forged config and the response carries the real private write set as well.

The config selection is unchanged. The function now only returns write sets from entries whose collection config is equal to the selected one, so data stored under one policy is never released under another. When all entries share the same config, which is the normal case, the result is the same as before.

Additional details

Reproduced with a scratch test that used the real transient store, dataRetriever and puller.filterNotEligible: with one legitimate entry and 10 pushed entries, the non-member received the private data in 18 of 20 runs before the change and 0 of 20 after. Added TestNewDataRetriever_TransientStoreEntriesWithDifferentConfigs, which fails on the current code because both write sets are returned. go test ./gossip/privdata/... ./gossip/state/... and golangci-lint run ./gossip/privdata/... pass locally.

The endorsing peer itself is not affected, since its own entry has a non-zero EndorsedAt and always wins the selection. The ledger path (fromLedger) uses config history and is not affected either.

Related issues

None

fromTransientStore merged the private write sets of every transient
store entry for a txID but kept the collection config of only one of
them, and the puller checks the requesting peer against that config.
Entries pushed over gossip carry a config supplied by the sending peer,
so a channel member outside the collection could push an entry whose
config names its own org and then pull the real private data for the
same txID before the block is committed.

Only return the write sets stored under the selected config.

Signed-off-by: nussaiba shaikh <nussaibah@bugqore.com>
@Nussu06
Nussu06 requested a review from a team as a code owner October 27, 2026 19:38
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.

1 participant