Skip to content

Conversation

@StephenButtolph
Copy link
Contributor

@StephenButtolph StephenButtolph commented Dec 1, 2025

Why this should be merged

Part of #4621

This allows VM implementations an alternative to the gossip.BloomFilter implementation. By using this implementation, users do not need to manage a bloom filter on their own.

How this works

Provides a generic implementation similar to the implementations in the X-chain and the P-chain.

To speed up development, this PR does not include migrating the existing VMs to this new implementation.

How this was tested

Updated the integration test of the gossip package to utilize the simplified API.

Need to be documented in RELEASES.md?

No.

Copy link
Member

@JonathanOppenheimer JonathanOppenheimer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Someone else more knowledgeable should also review.

Base automatically changed from bloom-count-noop to master December 1, 2025 21:04
Copy link
Contributor

@ARR4N ARR4N left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for me to re-review the requested changes.

// is later modified.
salt := b.salt
return bloomBytes, salt[:]
func (b *BloomFilter) BloomFilter() (*bloom.Filter, ids.ID) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my understanding: why ids.ID? It seems like an odd overloading of the meaning of a type.

Copy link
Contributor

@joshua-kim joshua-kim Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there was a reason in the old code - I think we just went with hash = ids.ID. It would probably make more sense to make a type alias for salt or just use plain []byte

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I returned an array rather than a slice to avoid needing to do the copy.. It could just be [32]byte... We just typically use ids.ID throughout the repo for these... We could probably clean it up later

}

// PushGossiperSet exposes whether hashes are still included in a set.
type PushGossiperSet interface {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(subjective) I understand (and agree with) the abstraction of the different set types, but their names feel unintuitive to me. Although they're named for how they're used, I think it would make more sense for them to be named for what they do. This, for example, could be a MembershipVerber (perhaps Reporter or Checker).

If you plan on coming back to this code later then I think it's better to just add a TODO so we don't block SAE on this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added TODOs

Comment on lines 27 to 28
// This value should always be at least as large as the number of items that
// can be iterated over with a call to Iterate.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please elaborate on scenarios in which one might expect Iterate to yield fewer items.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reworded it to say it should be equal... Really it just must not be smaller.


// Add one to expectedResetCount to account for the initial creation
// of the bloom filter.
require.Equal(tt.expectedResetCount+1, testutil.ToFloat64(bs.metrics.ResetCount))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
require.Equal(tt.expectedResetCount+1, testutil.ToFloat64(bs.metrics.ResetCount))
require.Equal(tt.expectedResetCount+1, testutil.ToFloat64(bs.metrics.ResetCount), "number of resets")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious on the rationale for these logs in require - isn't this generally self documenting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also don't find the logs useful, but adding them doesn't matter to me

require.Equal(tt.expectedResetCount+1, testutil.ToFloat64(bs.metrics.ResetCount))
b, h := bs.BloomFilter()
for _, expected := range tt.expected {
require.True(bloom.Contains(b, expected[:], h[:]))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
require.True(bloom.Contains(b, expected[:], h[:]))
require.Truef(bloom.Contains(b, expected[:], h[:]), "%T.Contains(%#x)", bloom, expected)

Also, assert is more appropriate for testing set membership, to provide a full picture and avoid whack-a-mole debugging. Just saying 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know people talk about whack-a-mole debugging... I have never experienced it myself

// that were not included in the filter.
type PullGossiperSet[T Gossipable] interface {
// Add adds a value to the set. Returns an error if v was not added.
Add(v T) error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I noticed we use this throughout the PR but did we intend to use v here? Should this be t?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I felt like v for value was pretty normal


// Add one to expectedResetCount to account for the initial creation
// of the bloom filter.
require.Equal(tt.expectedResetCount+1, testutil.ToFloat64(bs.metrics.ResetCount))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious on the rationale for these logs in require - isn't this generally self documenting?

Copilot AI review requested due to automatic review settings December 3, 2025 16:12
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces gossip.BloomSet, a new implementation that simplifies bloom filter management by wrapping a Set implementation and automatically handling bloom filter creation, resetting, and synchronization. This eliminates the need for VM implementations to manually manage bloom filters.

Key changes:

  • Adds BloomSet as a generic wrapper that manages bloom filters for any Set implementation
  • Deprecates the existing BloomFilter type in favor of BloomSet
  • Updates interface definitions to separate concerns between handlers, push gossip, and pull gossip

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
network/p2p/gossip/set.go Implements new BloomSet wrapper with automatic bloom filter management
network/p2p/gossip/set_test.go Adds comprehensive tests for BloomSet including concurrency testing
network/p2p/gossip/gossip.go Moves Gossipable and Marshaller definitions, adds new interface types for pull/push gossipers
network/p2p/gossip/handler.go Updates to use new HandlerSet interface instead of full Set
network/p2p/gossip/bloom.go Deprecates existing BloomFilter implementation and updates method signatures
network/p2p/gossip/gossipable.go Removes file (definitions moved to gossip.go)
network/p2p/gossip/gossip_test.go Updates tests to use BloomSet and refactors test doubles
network/p2p/gossip/bloom_test.go Updates to use new BloomFilter() method signature
vms/platformvm/network/gossip.go Updates to implement new BloomFilter() method signature
vms/avm/network/gossip.go Updates to implement new BloomFilter() method signature
graft/coreth/plugin/evm/eth_gossiper.go Updates to implement new interfaces and method signature
graft/coreth/plugin/evm/atomic/txpool/mempool.go Updates to implement new interfaces and method signature
graft/coreth/plugin/evm/gossip/handler.go Updates to use new HandlerSet interface
graft/coreth/plugin/evm/tx_gossip_test.go Simplifies test to use new gossip utilities
graft/coreth/plugin/evm/atomic/vm/tx_gossip_test.go Simplifies test to use new gossip utilities
go.mod Updates dependency versions

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +17 to +19
DefaultMinTargetElements = 1000
DefaultTargetFalsePositiveProbability = .01
DefaultResetFalsePositiveProbability = .05
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we expose these under a single DefaultBloomSetConfig? It seems like it would make discoverability easier

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it this way so that the defaults can't be changed (As we can't expose a const DefaultBloomSetConfig).

@StephenButtolph StephenButtolph added this pull request to the merge queue Dec 3, 2025
Merged via the queue into master with commit 39b7456 Dec 3, 2025
40 checks passed
@StephenButtolph StephenButtolph deleted the implement-set-with-bloom-filter branch December 3, 2025 17:11
@github-project-automation github-project-automation bot moved this to Done 🎉 in avalanchego Dec 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done 🎉

Development

Successfully merging this pull request may close these issues.

5 participants