Make a packed .spkg self-describe every network it supports - #882
Open
maoueh wants to merge 1 commit into
Open
Conversation
Densify Package.networks at resolution time so that every network entry carries an explicit initialBlock for every module, and an explicit params value for every module accepting one. A consumer such as substreams.dev can then describe what a package does on each of its networks without reimplementing the module-graph derivation. This also fixes modules that inherit their initial block being frozen to whichever network was active when the package was packed. computeInitialBlock had already replaced their UNSET marker before the package was marshalled, and on re-read ApplyNetwork only overrides modules named explicitly under 'networks:', so a package packed on mainnet and run with --network sepolia silently kept mainnet start blocks for every derived module. Densification names them all, leaving nothing to inherit. Packages published before this need a repack: the authored-versus-derived distinction is not recoverable from the artifact. Warn in pack, registry publish and registry verify when a network name is not a known Firehose network registry ID or alias, or is an alias resolving to several networks. Never an error, so private and unlisted chains keep publishing. Add --network to 'substreams info', matching run and gui, so an .spkg can be inspected as any network it declares. Summarize its Networks section to one line per network, since the expanded form now grows with modules x networks, and add --expand-networks for the full listing. Sort that output, which iterated Go maps directly. Fix ApplyNetwork setting its 'found' flag unconditionally inside the module loop, which made the "did you mean?" suggestion unreachable and silently ignored an initialBlock naming a module that does not exist. Delete the plans/ folder and gitignore it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A published
.spkgdoes not let a consumer such as substreams.dev describe the networks a package supports. Three defects sit behind that.Derived initial blocks were frozen at pack time.
substreams packruns the fullReader.Read()pipeline before marshalling, socomputeInitialBlockhad already replaced everyUNSETmarker with a value derived for the packing network, and that value went into the artifact. On re-read the damage was invisible:ApplyNetworkonly touches modules named explicitly undernetworks:, andcomputeInitialBlockskips any module whose initial block is no longerUNSET. Every module inheriting its start block stayed pinned to the packing network. Reproduced on a two-module package wheremod2consumesmod1, withmainnet.mod1 = 200andsepolia.mod1 = 400:Params escaped this only by accident:
validateNetworksforces every network to declare the same param keys, so no param was ever left to inherit.The networks map was too sparse to describe anything.
Package.networksis packaged (field 13, contrary to first impressions), but held only the authored overrides. A site rendering a package page could not answer "what ismod2's start block on base?" without reimplementingcomputeInitialBlockand the module graph.Network names were unvalidated. Nothing checked
network:or thenetworks:keys against the Firehose network registry, so a typo published silently and consumers had no reliable key to map a package onto a real chain.What changed
Densified networks map
densifyNetworksexpands every network entry so each module carries an explicitinitialBlock, and each module accepting params carries an explicitparamsvalue. No proto change — a dense map is just more explicit overrides than old readers used to see.Per network: restore the authored initial blocks, apply that network's overrides, run
computeInitialBlock, record the result for every module. Modules are restored afterwards, so the resolution that follows is unaffected. Params record the network's override when it has one and the module's carried value otherwise; modules without aparamsinput are skipped, sinceApplyParamsrejects them.It runs inside
ApplyPackageTransformations, betweenvalidateNetworksandApplyNetwork, and always rather than only onpack— it needs each module's authored initial block, and theUNSETmarker is destroyed bycomputeInitialBlocklater in that same function. Running it in the shared pipeline also keepspack,info,runandguiin agreement. Idempotent on an already-dense package.The frozen-initial-block defect disappears as a consequence: once every module is named,
ApplyNetworkoverrides them all and nothing is left to inherit. Cost is roughly 3 KB for a 20-module package supporting 10 networks.Network-name warnings
New warning in
warnIncompletePackage, already wired intopack,registry publishandregistry verify. Each network name is looked up in the Firehose network registry: no match warns it is not a known registry ID or alias, several matches warn the alias is ambiguous and names the candidates, exactly one match is silent even when the name is an alias (eth-mainnet→mainnet). Warning only, never an error, so private and unlisted chains keep publishing. The lookup is injected as a parameter so the behaviour is tested against a fixture rather than the registry's live content.substreams info--network, to inspect a package as any network it declares.runandguialready had the flag; without it an.spkgcould only ever be read as its default network.--expand-networks, to list the per-module values. TheNetworkssection is otherwise summarized to one line per network, since the expanded form now grows with modules × networks.ApplyNetworkdead codeIts
foundflag was set unconditionally inside the module loop, making the "did you mean?" suggestion unreachable, so aninitialBlocknaming a nonexistent module was silently ignored. Densification makes the check moot for our own writes, but the function is exported. Its message also saidparam for modulewhile reporting an initial block.Compatibility
New CLI, old
.spkg— the defect persists for already-published packages. The authored-versus-derived distinction was destroyed at their pack time and is not recoverable from the artifact; repacking from source fixes them.Old CLI, new
.spkg— works. The sparse-map code path reads a dense map unmodified.Worth a second look before merge
Densification derives initial blocks for every declared network, not just the active one, so a package consistent on
mainnetand inconsistent onsepolianow fails atsubstreams pack.For:
substreams run --network sepoliaalready fails today with the same error, so packing surfaces it earlier, where it is cheap to fix. Against:computeInitialBlockwalks all modules regardless of the requested output module, so a package whosesepoliainconsistency sits in a branch nobody streams on that network used to pack fine and now will not. The alternative is to skip and warn about a network that fails derivation instead of failing the whole pack.Testing
Built test-first throughout.
densifyNetworksis covered for derived blocks, authored blocks, effective params, modules without a params input, the synthesized default-network entry, idempotency, and the conflicting-blocks error. The reported bug has a round-trip regression test that packs a package, re-reads it under a network override and asserts the derived module followed.renderNetworksand the network-name warnings have table tests. Existingreader_test.goexpectations were updated to the densified values.Full suite green,
go vetclean.