Skip to content

feat(header): BlockInfo timeslot + epoch-mark length prefix + preimage-hash extrinsic commitment (GP v0.8.0) (#1014)#1031

Merged
YCC3741 merged 3 commits into
feat/reporting-1016-workcontext-fieldsfrom
feat/header-1014-recenthistory-v080
Jul 15, 2026
Merged

feat(header): BlockInfo timeslot + epoch-mark length prefix + preimage-hash extrinsic commitment (GP v0.8.0) (#1014)#1031
YCC3741 merged 3 commits into
feat/reporting-1016-workcontext-fieldsfrom
feat/header-1014-recenthistory-v080

Conversation

@HanaYukii

Copy link
Copy Markdown
Contributor

Part of #1012 · Closes #1014

Stacked on #1027 (← #1026). Base is feat/reporting-1016-workcontext-fields; review only the #1014 commit here. Retarget to 1012-update-to-v080 as the stack merges.

What — three consensus-visible v0.8.0 changes

# change GP ref
1 BlockInfo (recent history) gains a 4-byte timeslot between state_root and reported; the appended item carries H_t eq:recenthistoryspec, eq:recenthistorydef, C(3)
2 EpochMark's validator-key sequence is now length-prefixed (var{k}); was fixed-length encodeepochmark (serialization.tex)
3 Extrinsic hash: preimages component becomes p = E(var[(E4(s), blake(d))]) — each blob committed by its Blake2b hash, replacing the full C.15 encoding header.tex

Everything else in the issue is already aligned (verified against the v0.7.2→v0.8.0 tex diff): epoch/winning-tickets marker presence+content rules, the ancestors requirement, and the author-index bound are semantically unchanged.

Changes

  • types.BlockInfo + Encode / Decode / UnmarshalJSON (+ jam_types struct kept in sync; reflection registries stay on v0.7.x per feat(work-package): align GP v0.8.0 work packages and bundles #1015 precedent)
  • EpochMark.Encode/Decode — emit/read the length prefix (decode still validates it equals ValidatorsCount)
  • block_serialization.go — new p() helper (mirrors g()) used by CreateExtrinsicHash; full-block serialization (C.15) unchanged — only the hash commitment changes
  • recent_history.NewItem takes the block slot; both STF call sites pass block.Header.Slot

Tested

  • TestEncodeBlockInfo_V080Timeslot, TestEncodeEpochMark_V080LengthPrefix (new) — round-trip + byte-offset asserts
  • TestExtrinsicHashPreimagesComponent_V080 (new) — count prefix + E4 requester + blake(blob), empty case
  • go build / go vet / gofmt clean; internal/types, recent_history, safrole, statistics, store, extrinsic, input/jam_types green
  • ⏭️ v0.7.x vector fallout skipped until official v0.8.0 vectors land (Update to v0.8.0 #1012): history + safrole STF modes (v080IncompatibleModes), all traces (embed full serialized state), and the matching unit vector tests (skipV080VectorIncompat + per-test skips)
  • ℹ️ Pre-existing, unrelated: internal/header (TestCreateParentHash / TestCreateExtrinsicHash) and internal/blockchain (TestGetGenesisBlock / TestGetGenesisState) fail identically on the pristine 1012-update-to-v080 base (verified at 6d93ac4) — stale v0.7.x fixtures, untouched here

…hash extrinsic commitment (GP v0.8.0 #1014)

Three consensus-visible changes from GP v0.8.0:

- BlockInfo (recent history, eq:recenthistoryspec / C(3)): add a 4-byte
  timeslot between state_root and reported; NewItem now takes the block
  slot (H_t per eq:recenthistorydef) and both STF call sites pass it.
- EpochMark (encodeepochmark): the validator-key sequence is now
  length-prefixed (var{k}); decode validates the prefix still equals
  ValidatorsCount. Reflection registries stay on v0.7.x per #1015 precedent.
- Extrinsic hash (header.tex): the preimages component becomes
  p = E(var[(E4(s), blake(d))]) -- each preimage blob committed by its
  Blake2b hash -- replacing the full C.15 encoding. New p() helper in
  block_serialization.go, mirroring g(). Full-block serialization (C.15)
  is unchanged; only the hash commitment changes.

Round-trip unit tests assert the new byte offsets. v0.7.x vector fallout
(history + safrole STF modes, all traces) is skipped until official v0.8.0
vectors land; marker presence/content rules are unchanged in v0.8.0 and
keep their existing tests.
…r-1014-recenthistory-v080

# Conflicts:
#	internal/types/encode_test.go

@yu2C yu2C left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Summary

Thanks for the v0.8.0 wire-format updates (BlockInfo timeslot, EpochMark length prefix, preimage-hash extrinsic commitment). The codec round-trip unit tests look correct.

One architectural suggestion around the new p() helper in block_serialization.go — please address before merge if possible.


Issue Verification

Test Status Evidence
go test ./internal/recent_history/... -count=1 PASS (skipped vectors) TestRecentHistoryTestVectors skipped pending v0.8.0 vectors
go test ./internal/stf/... -count=1 -run Header PASS (no tests) internal/stf has no test files
TestEncodeBlockInfo_V080Timeslot PASS codec round-trip
TestEncodeEpochMark_V080LengthPrefix PASS codec round-trip
TestExtrinsicHashPreimagesComponent_V080 PASS p() byte layout

Linked issues: #1014 (Part of #1012)


internal/utilities/block_serialization.go

[SUGGESTION] Move p() into internal/types/encode.go

p() is only called from CreateExtrinsicHash (used by validate_header.go and header_controller.go). It does not participate in block wire serialization (BlockSerialization still uses C.15 via ExtrinsicPreimageSerialization).

The v0.8.0 extrinsic-hash preimages component (header.tex p = E(var[(E4(s), blake(d))])) is intentionally not the same as PreimagesExtrinsic.Encode (C.15: E4(s) + length-prefixed blob). That distinction is correct — please do not change the existing Encode/Decode.

However, placing p() in block_serialization.go (alongside deprecated hand-rolled *Serialization helpers) makes it look like legacy code. The same file already has this split:

  • C.15 block wiretypes.PreimagesExtrinsic.Encode / Decode
  • Extrinsic-hash componentp() (hash-only, no decode)

Please move the extrinsic-hash encoding into internal/types/encode.go as a separately named method, e.g.:

// EncodeForExtrinsicHash implements header.tex p =
// E(var[(E4(s), blake(d)) for (s, d) in E_P]).
// NOT the C.15 block-wire encoding; see PreimagesExtrinsic.Encode.
func (p *PreimagesExtrinsic) EncodeForExtrinsicHash(e *Encoder) error { ... }

Then have CreateExtrinsicHash call that method via the shared encoder, and remove the private p() helper. (Same pattern could apply to g() in a follow-up, but p() is in scope for this PR.)

Why encode.go?

  • types.go — struct definitions only
  • encoder.go — low-level Encoder machinery
  • encode.go — per-type encode methods ✅
  • decode.go — no decode needed for hash-only commitment

internal/utilities/extrinsic_hash_v080_test.go

[SUGGESTION] Merge test into block_serialization_test.go

Please drop the standalone extrinsic_hash_v080_test.go and move TestExtrinsicHashPreimagesComponent_V080 into block_serialization_test.go alongside the other serialization tests. If p() moves to types, rename the test accordingly (e.g. TestPreimagesExtrinsic_EncodeForExtrinsicHash_V080 in internal/types/encode_test.go).


Files reviewed (no issues)

  • internal/types/types.go, decode.go, encode.go, unmarshal_json.go — BlockInfo timeslot, EpochMark length prefix ✅
  • internal/recent_history/recent_history_controller.goNewItem passes block.Header.Slot
  • internal/input/jam_types/jam_types.go — struct sync ✅
  • testdata/reader.go — v0.8.0 skip lists updated ✅

Severity: 0 CRITICAL · 2 SUGGESTION · 0 NIT

@HanaYukii

Copy link
Copy Markdown
Contributor Author

Thanks @yu2C — both suggestions applied in HEAD:

  • p()types.PreimagesExtrinsic.EncodeForExtrinsicHash (encode.go), doc comment spelling out it is the header.tex extrinsic-hash component and NOT the C.15 wire encoding (which is untouched). One wrinkle vs the sketch: types cannot import utilities/hash (that package imports types), so the method uses x/crypto/blake2b directly — same primitive Blake2bHash wraps. Added a small Encoder.EncodeFunc so CreateExtrinsicHash can run the alternate encoding through the pooled encoder; the private p() is gone. (g() can migrate the same way in a follow-up, as you noted.)
  • Test moved to internal/types/encode_test.go as TestPreimagesExtrinsic_EncodeForExtrinsicHash_V080; extrinsic_hash_v080_test.go deleted.

…review follow-up, #1014)

Address yu2C's review on #1031:

- The v0.8.0 extrinsic-hash preimages component now lives in
  internal/types/encode.go as PreimagesExtrinsic.EncodeForExtrinsicHash
  (header.tex p = E(var[(E4(s), blake(d))])), clearly separated from the
  C.15 block-wire Encode which is unchanged. Uses x/crypto/blake2b
  directly (utilities/hash imports types, so types cannot import it).
- New Encoder.EncodeFunc runs an alternate encoding against the pooled
  buffer; CreateExtrinsicHash uses it and the private p() helper in
  block_serialization.go is removed.
- Test moved to internal/types/encode_test.go and renamed
  TestPreimagesExtrinsic_EncodeForExtrinsicHash_V080; the standalone
  utilities test file is dropped.
@YCC3741
YCC3741 merged commit 60dc3a6 into feat/reporting-1016-workcontext-fields Jul 15, 2026
YCC3741 pushed a commit that referenced this pull request Jul 15, 2026
…review follow-up, #1014)

Address yu2C's review on #1031:

- The v0.8.0 extrinsic-hash preimages component now lives in
  internal/types/encode.go as PreimagesExtrinsic.EncodeForExtrinsicHash
  (header.tex p = E(var[(E4(s), blake(d))])), clearly separated from the
  C.15 block-wire Encode which is unchanged. Uses x/crypto/blake2b
  directly (utilities/hash imports types, so types cannot import it).
- New Encoder.EncodeFunc runs an alternate encoding against the pooled
  buffer; CreateExtrinsicHash uses it and the private p() helper in
  block_serialization.go is removed.
- Test moved to internal/types/encode_test.go and renamed
  TestPreimagesExtrinsic_EncodeForExtrinsicHash_V080; the standalone
  utilities test file is dropped.
HanaYukii added a commit that referenced this pull request Jul 15, 2026
…review follow-up, #1014)

Address yu2C's review on #1031:

- The v0.8.0 extrinsic-hash preimages component now lives in
  internal/types/encode.go as PreimagesExtrinsic.EncodeForExtrinsicHash
  (header.tex p = E(var[(E4(s), blake(d))])), clearly separated from the
  C.15 block-wire Encode which is unchanged. Uses x/crypto/blake2b
  directly (utilities/hash imports types, so types cannot import it).
- New Encoder.EncodeFunc runs an alternate encoding against the pooled
  buffer; CreateExtrinsicHash uses it and the private p() helper in
  block_serialization.go is removed.
- Test moved to internal/types/encode_test.go and renamed
  TestPreimagesExtrinsic_EncodeForExtrinsicHash_V080; the standalone
  utilities test file is dropped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants