feat: add RootHashPadded for fixed-height subtree composition#121
Merged
Conversation
Contributor
👋 Thanks, @ordishs!This pull request comes from a fork. For security, our CI runs in a restricted mode.
Thanks for contributing to bsv-blockchain/go-subtree! 🚀 |
2 tasks
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.
Summary
Adds
Subtree.RootHashPadded(targetHeight int) (*chainhash.Hash, error)— a method that computes the subtree's merkle root and then lifts it to a caller-specified height by repeatedly hashing the root with itself (H(prev, prev)per phantom level). This is bitcoin's "duplicate-last-when-odd" rule applied to phantom slots above the actual leaves.The motivation is to make subtree-root composition produce the same merkle root as building a single big merkle tree over all leaves, even when the last subtree is partial. Today, combining a complete subtree's root with a partial subtree's un-padded root yields a different value than the bitcoin merkle root over the same transactions —
RootHashPaddedcloses that gap. Consumer (Teranode) intends to use it for block validation where one block carries multiple fixed-height subtrees and the final one may be incomplete.What's in the PR
errors.go: two new sentinels —ErrTargetHeightTooSmall,ErrNotPowerOfTwoLeafCount.subtree.go: theRootHashPaddedmethod, placed adjacent toRootHash.subtree_padded_test.go: seven tests covering the happy path, no-lift, empty-subtree, both error paths, an 8+2-leaves big-tree equivalence check, and a block-scale 258-tx (256+2 composition) equivalence check.Purely additive — no existing behaviour changes.
Preconditions enforced by RootHashPadded
len(Nodes)must be a power of two (or zero) → otherwiseErrNotPowerOfTwoLeafCount.targetHeight >= ceil(log2(len(Nodes)))→ otherwiseErrTargetHeightTooSmall.(nil, nil)(matchingRootHash's nil-for-empty contract; guarded by a//nolint:nilnildirective with explanation).Test plan
go test -race -count=1 ./...— 76 tests pass, 0 failuresgo vet ./...— cleangolangci-lint run --new-from-rev=master— 0 issuesgo build ./...— cleanNote on archive status
I see the master README now carries an archive notice pointing to the go-stack monorepo. Happy to redirect this to go-stack if maintainers prefer — let me know. Submitting here first since (a) the repo isn't actually archived yet and (b) downstream consumers' go.mod still points here.