Skip to content
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

Refactor BlockHeader #228

Merged
merged 2 commits into from
Nov 22, 2024
Merged

Refactor BlockHeader #228

merged 2 commits into from
Nov 22, 2024

Conversation

lukechampine
Copy link
Member

This unifies v1 and v2 block headers and promotes BlockHeader from gateway to types. It also changes how V2 block IDs are computed.

I had previously omitted the ParentID from the v2 block "header," because it is incorporated into the Commitment field (via the hash of the parent consensus.State). This left the first 32 bytes of the 80-byte hash preimage unused, so I filled them with a distinguisher string.

However, after reflecting on how headers are actually used in the Syncer, I think it's better to include the ParentID after all, even if it's slightly redundant and not strictly necessary. Here's my reasoning, in the form of a dialogue:

  • 🤔 Foo: Imagine a peer sends you a v2 header, claiming that they have found the next block. You hash the header and verify that, indeed, it meets the proof-of-work target. You therefore stop mining the current block and begin mining the next one. Unbeknownst to you, this header does not attach to the old block! Now you are wasting hashrate until you detect this deception. If the header contained the ParentID, you could check that it matched your current block before abandoning it.
  • 🤨 Bar: Including the ParentID doesn't prevent this class of attack, because the purported block could be invalid for other reasons that aren't detectable from the header alone. For example, it could have missing signatures. Moreover, this attack requires the attacker to expend a lot of hashrate; why wouldn't they use that hashrate to mine a valid block instead?
  • 🤔 Foo: Aha, but that's where the ParentID is different! You don't need to expend a lot of hashrate mining a purposefully-invalid block; instead, you can reuse the header of a recently-mined block. That header will (probably) still have sufficient proof-of-work to meet the current target, so it will pass the initial validation check.
  • 🤨 Bar: Okay, but one of the first checks you perform when receiving a relayed header is "have I seen this block before?" So if you try to cheat by reusing a recent block, it will simply be ignored.
  • 🤔 Foo: ...fine, granted. But there's basically no downside to include the ParentID anyway. We weren't using that space anyway (but we need to preserve it, for miner compatibility), it's occasionally useful, and you don't need to twist your brain into knots convincing yourself that the system is still secure without it.
  • 🤨 Bar: ...sure, whatever.

Copy link
Member

@ChrisSchinnerl ChrisSchinnerl left a comment

Choose a reason for hiding this comment

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

I don't mind this change but we need an upgrade path that is not a panic due to the changed encoding. We can't stable release renterd (or any node software really) with the new core consensus if every update of the core dependency potentially causes a panic and requires manual user interaction.

@lukechampine
Copy link
Member Author

I'm not sure I follow. Do you mean that this change breaks existing v2 testnets? Or that SiaFoundation/coreutils#116 breaks existing consensus.dbs?

@n8maninger
Copy link
Member

n8maninger commented Nov 21, 2024

I think the primary concern is that a few other recent PRs broke existing consensus.db over anything specific to this PR or SiaFoundation/coreutils#116. I agree with your comment here: https://github.com/SiaFoundation/coreutils/pull/116/files#r1837380099 that neither of these should cause a new issue.

We do currently have a problem in the apps that use the coreutils chain db where we can't release an update without requiring manual intervention on the consensus database. It's been a particular pain on our test nodes that auto update 😅. That probably doesn't need to be tackled in either of these open PR, but it will need to be solved in a follow up at some point soon as we're looking to push out v2.0.0 EoY.

hostd-test  | panic: error decoding *chain.supplementedBlock: encoded object contains invalid length prefix (3632516464492651565 elems > 408 bytes left in stream)
hostd-test  |
hostd-test  | goroutine 112 [running]:
hostd-test  | go.sia.tech/coreutils/chain.check(...)
hostd-test  |   go.sia.tech/[email protected]/chain/db.go:197
hostd-test  | go.sia.tech/coreutils/chain.(*dbBucket).get(0x0?, {0xc000746c80?, 0x1ddfd80?, 0x0?}, {0x1831080, 0xc000952f00})
hostd-test  |   go.sia.tech/[email protected]/chain/db.go:222 +0x1c5
hostd-test  | panic: error decoding *chain.supplementedBlock: encoded object contains invalid length prefix (3632516464492651565 elems > 408 bytes left in stream)

@n8maninger
Copy link
Member

n8maninger commented Nov 21, 2024

It does look like we'll break syncing on Anagami since the V2BlockHeader encoding is changing, but I think that's acceptable.

@lukechampine
Copy link
Member Author

Fair, I have been pretty cavalier about consensus changes lately. 😅 I'll try to rein it in as we approach release.

And yeah, changes to network stuff are less bothersome, since they'll resolve themselves once enough people update.

@n8maninger n8maninger merged commit 611d481 into master Nov 22, 2024
9 checks passed
@n8maninger n8maninger deleted the v2-header branch November 22, 2024 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

3 participants