-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: opt-in way to allow empty list of roots in CAR headers #461
Conversation
This needs @rvagg 's eyes. The issue has never been the technical implementation. The problem, according to @rvagg, is that aspects of Filecoin dealmaking depend on this not being empty and are indirectly using go-car to validate the root CID is not empty. I'm not 100% clear this is still a serious issue but it requires some audit of ecosystem code. |
car.go
Outdated
if len(ch.Roots) == 0 { | ||
return nil, fmt.Errorf("empty car, no roots") | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💭 maybe we could add new NewCarReader
that takes variadic CarReaderOptions
(similar to what we already have for *Writer
) and have option that adjust empty-roots behavior (error or noop), and switch to that explicit constructor in boxo/kubo/caboose?
func NewCarReader(r io.Reader, opts ...CarReaderOption) (*CarReader, error) {
// create the CarReader
cr := &CarReader{reader: r}
// apply the options
for _, opt := range opts {
opt(cr)
}
// return the CarReader
return cr, nil
}
And CarReaderOption
for this PR could be something like
func WithErrorOnEmptyRoots(flag bool) CarReaderOption {
return func(cr *CarReader) {
cr.errorOnEmptyRoots = flag
}
}
And error only when flag is true.
The original NewCarReader
would always call with true, so no change in default behavior:
func NewCarReader(r io.Reader) (*CarReader, error) {
return NewCarReader(r, WithErrorOnEmptyRoots(true))
}
This way:
- we don't need to worry about breaking Filecoin and can ship this without impacting existing users
- have a useful primitive for customizing parser behavior going forward
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the PR to use this pattern. Does this look reasonable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm.. your version was breaking API change and removed tests, probably not what we want 🙃
I've pushed bigger refactor in 67151fc – it maintains backward API compatibility, so the old code like Filecoin one will work the same.
At the same time the new code can switch to NewCarReaderWithOptions
to define explicit behavior, and even Filecoin can slowly migrate to that too, once empty roots are validated elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this allows us to keep backward compatibility and explicitly enable both behaviors, which means code that expects error can be migrated into implicit flag over time
car_test.go
Outdated
}, { | ||
"{version:1}", | ||
"0aa16776657273696f6e01", | ||
"empty car, no roots", | ||
"", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should keep this test, we need to have test for both root present and no root, to guard the behavior. Restored in 67151fc + added explicit test for WithErrorOnEmptyRoots(true|false)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is this no longer need explicit in-depth approval from @rvagg because we no longer make breaking change to API and we do not change the default behavior.
Disabling error on empty roots is opt-in via new constructor, which is backward-compatible and imo we could ship this as go-car v0.7.0.
cc @willscott @rvagg @aschmahmann @aarshkshah1992 – any concerns?
@lidel did you see my one comment on your commit? you keep the state of the header check on the reader, even though it's only used in the constructor.
|
@willscott I did not see it. In the future, please drop comments like this on PRs for visibility 🙏 I made a concious decision to remove Other flags will modify Reader behavior beyond the header. For example, we could add |
I guess this is OK, although we did say that we weren't going to touch the v0 package anymore. I do have a |
@rvagg - but we have continued to update v1. - e.g with the updated use of go-merkledag / etc. I think we do this now so we can move forward, rather than blocking on not having a good interface for reading this type of car |
Allow reading a car even when roots is empty