libp2p / libp2p/go-libp2p

Need a record validator interface that handles equality

Open
#701 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
6.9k
Forks
1.3k
Avg merge
13d 21h
Merged PRs (30d)
1

Description

The libp2p record validator interface has the function Select(key string, values [][]byte) (int, error)

Unfortunately, there's no way to figure out if given two records are the same using just the interface if we rely on the contract specified alone.

Some failed examples:

  • bytes.Equal(record1, record2) as done in go-libp2p-pubsub-router and go-ipns
    • This fails because certain serialization formats (e.g. Protocol Buffers) do not guarantee that the same record will serialize the same way twice.
  • Select(key, {record1, record2}) == Select(key, {record2, record1} == 0
    • Unfortunately, the only relevant specification on the interface is that we return the "best" record and that it be "stable". While stable is generally pretty well defined to mean that calling the same function with exactly the same inputs will produce the same results, "best" has no real restrictions especially when it comes to two equal value.
      • The public key record just returns 0 for all records which might convince us that record1 == record2 even though they're totally different
      • I might choose to use bytes.Equal to return the "better" of two equal records internally even though they're actually equal.

Thankfully there are a number of ways to fix this of which a few are below:

  1. Add a SelectMany(key string, values [][]byte) that returns an array of equal values (either [][]byte or []int)
  2. Add an Equals(key string, record1 []byte, record2 []byte) that will help in a more limited use case
  3. Specify that if multiple values are equal we must return the index of the 1st value

Options that involve changing the interface are more painful if there are lots of consumers of the interface. However, we could work around this by creating a new interface that with a struct that wraps the old one into a new one, or by utilizing go's ability to specify interfaces where they're used instead of globally.

Options that involve changing the contract on the interface can be easier. However, it may lead to undetected problems as people who think they've implemented the interface turn out to have not implemented it properly.

@raulk @Stebalien what do you think? This may lead to wasted bandwidth in go-libp2p-pubsub-router unless we address this.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the validator interface in validator.go and compare its Select contract with the usages in go-libp2p-pubsub-router's pubsub.go and go-ipns's record.go. Review the proposed equality approaches and determine which interface or contract change maintainers accept; done means the equality behavior is specified and affected consumers are addressed.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
networking
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.