Context
bee master at 253ecd81. Affects every release since the v0.2 codec.
Summary
pkg/manifest/mantaray/node.go::Add defers setting n.refBytesSize until the first non-empty entry is added. Bee itself calls Add with an empty entry at pkg/api/bzz.go:266 (swarm.ZeroAddress.Bytes() is nil) for the root metadata. If that node then accumulates forks, MarshalBinary writes refBytesSize = 0 while the fork bodies still carry full-width refs, and UnmarshalBinary at pkg/manifest/mantaray/marshal.go:280 silently drops them on reload.
mantaray-js documents this with a FIXME in src/node.ts; downstream Rust consumers hit it in the wild.
Repro
n := mantaray.New()
n.SetObfuscationKey(mantaray.ZeroObfuscationKey)
for _, p := range [][]byte{[]byte("foo"), []byte("bar")} {
_ = n.Add(ctx, p, nil, map[string]string{"k": "v"}, ls) // empty entry
}
_ = n.Save(ctx, ls)
_, err := mantaray.NewNodeRef(n.Reference()).LookupNode(ctx, []byte("foo"), ls)
// err == ErrNotFound — fork silently dropped
Expected
Round-trip preserves the trie.
Proposed fix
Infer refBytesSize at the top of MarshalBinary when Add never set it — from the node's own entry width if present, else the first child fork's saved ref width. PR with patch + regression test (TestPersistDirectoryOnlyAdds) to follow.
AI Disclosure
Context
bee master at
253ecd81. Affects every release since the v0.2 codec.Summary
pkg/manifest/mantaray/node.go::Adddefers settingn.refBytesSizeuntil the first non-empty entry is added. Bee itself callsAddwith an empty entry atpkg/api/bzz.go:266(swarm.ZeroAddress.Bytes()isnil) for the root metadata. If that node then accumulates forks,MarshalBinarywritesrefBytesSize = 0while the fork bodies still carry full-width refs, andUnmarshalBinaryatpkg/manifest/mantaray/marshal.go:280silently drops them on reload.mantaray-js documents this with a FIXME in
src/node.ts; downstream Rust consumers hit it in the wild.Repro
Expected
Round-trip preserves the trie.
Proposed fix
Infer
refBytesSizeat the top ofMarshalBinarywhenAddnever set it — from the node's own entry width if present, else the first child fork's saved ref width. PR with patch + regression test (TestPersistDirectoryOnlyAdds) to follow.AI Disclosure