Sorry, I was careless with the use of `>=` there. You are correct, forks form a tree. For this proposal, every leaf must be assigned a unique `nForkId`. The relationship between `nForkId` is irrelevant (e.g. which number is bigger), as long as they are unique. Transactions are only valid IFF `nForkId` matches exactly the `nForkId` of the software validating it. As described above, the transaction doesn't even contain `nForkId`, and the node surely is not starting to guess which one it could be. 

OK, but then it seems to me you have a dilemma for, eg, your LN commitment tx.  You either give it the specific nForkId of the fork it's created on - making it invalid on all other forks (eg, any future "non-contentious upgrade" HF that replaces that fork).  Or you give it nForkId 0 - which has the "BCH tx valid on Segwit2x (& vice versa)" flaw.

It may make sense to revise your proposal to incorporate Luke's OP_CHECKBLOCKATHEIGHT, and make the fork ID a (block height, hash) pair rather than just a number.  But I still think the idea of fork-specific addresses is a keeper!


On Tue, Nov 14, 2017 at 8:49 AM, Mats Jerratsch <mats@blockchain.com> wrote:

But I like the 'old' idea of putting the hash of a block that MUST be on the chain that this txn can eventually be added to. If the hash is not a valid block on the chain, the txn can't be added.

It means you can choose exactly which forks you want to allow your txn on, pre-fork for both, post-fork for only one, and gets round the issue of who gets to decide the nForkid value.. since you don't need one. Also, all the old outputs work fine, and LN not an issue.

I'm missing why this scheme would be better ?

I do agree that solutions like `SIGHASH_BLOCKCOMMIT` are superior in the sense that they are very difficult to circumvent. However, a fork could also follow the original chain in SPV mode and allow transactions protected with these mechanism. Since it's fundamentally impossible to disallow transactions in future projects, the goal shouldn't be to make this overly complicated. 

Furthermore, this schema is not just adding replay protection. It makes transacting safer overall (due to a dedicated address format per fork) and allows light clients to differentiate between multiple forks. In the past three months, at least $600k has been lost by users sending BCH to a BTC address [1].

Thanks for the clarification.  How would a tx specify a constraint like "nForkId>=1"?  I was thinking of it just as a number set on the tx.

Whether the transaction is replay protected or not is specified by setting a bit in the `SigHashId`. If this bit is set, then the signature *preimage* MUST have `nForkId` appended. `nForkId` is not part of the final transaction, someone who wants to verify the transaction must know which `nForkId` it was created with. 

If the bit isn't set, it means `nForkId=0`, which allows other forks to validate the signature.

Also note that since forks form a partial order, but IDs (numbers) form a total order, ">=" will miss some cases.  Eg, suppose BCH had forked with nForkId 2, and then you set up a LN funding tx on BCH with nForkId>=2, and then Segwit2x forked (from BTC!) with nForkId 3.  The BCH funding tx would be valid on Segwit2x.  This is more of a fundamental problem than a bug - to avoid it you'd have to get into stuff like making each fork reference its parent-fork's first block or something, someone has written about this...

Sorry, I was careless with the use of `>=` there. You are correct, forks form a tree. For this proposal, every leaf must be assigned a unique `nForkId`. The relationship between `nForkId` is irrelevant (e.g. which number is bigger), as long as they are unique. Transactions are only valid IFF `nForkId` matches exactly the `nForkId` of the software validating it. As described above, the transaction doesn't even contain `nForkId`, and the node surely is not starting to guess which one it could be. 

[1]