中本聪致迈克·赫恩:关于比特币合约、序列号和高频交易(2011 年 3 月 9 日)
首次公开证据
打开首次公开证据希望你一切都好。我终于让所有律师都满意了,可以用 Google 的名义、采用 Apache 2 许可证发布 BitCoinJ:
它还不完整——尤其是尚未正确处理区块链分叉——但其余部分正在补上。我在文档和注释上投入了大量精力,希望它能让那些无法理解或构建当前代码的新受众接触到比特币。接下来一两个月,我会补完一些缺失的较大部分,以实现完整的客户端模式。
这真是个好消息!只按客户端需求进行干净的重写,可以甩掉很多复杂性,而且也向 Java 开发者敞开了大门。
我知道你现在很忙,但希望你能抽时间回答我的几个问题。
我很乐意回答任何问题。
在实现完整 SPV 的过程中,我在考虑向协议添加一条 getmerklebranch 消息。它会返回一组 {blockhash, branch} 对
那就是 CMerkleTx。
给定交易哈希,这样就能在一笔广播交易被纳入区块之前验证它,而无须存储完整链。你觉得这种方法好吗?
我不明白。默克尔分支把一笔交易关联回一个区块,而只有当该区块展现出工作量证明时,这才有意义。关联回一个尚未求解的区块什么也证明不了。
网络节点能够验证 0-conf 交易,是因为它们拥有完整的交易索引,所以它们可以:
- 对照依赖项验证签名。
- 断言它们尚未看到另一笔花费,因为它们知道所有现存交易。
你说的是用于该交易依赖项的 CMerkleTx 吗?那可以做到第 1) 点,但做不到第 2) 点。
如果你不了解所有现存交易,我不知道该如何做到第 2) 点。你只能依赖对其他节点的信任。可以把这种信任分散到多个节点上。节点只会转发它们认可为有效的交易。如果你从所连接的所有节点那里都收到一笔交易的 inv 消息,它们就是在证明该交易有效,而且是它们看到的第一笔花费。
另外,我最近一直在考虑探索不同的交易类型,比如为测试网移除 IsStandard() 检查。
非常好的想法。在 -testnet 上绝对应该允许这样做。
很明显,你从一开始就对交易作了大量思考,而不只是简单地转移币,但遗憾的是,这些内容既没有写进论文,也没有记录在代码中。托管、多方支付等都很有意思,我想知道你是否可以找个时间整理一份清单,列出我们能用脚本语言实现哪些想法。
最后,允许替换交易的代码已被禁用,但注释没有说明原因。这只是为了缩小攻击面、降低复杂性,还是有更深层的原因?
只是为了缩小攻击面。它无助于提高交易费。一笔交易从 nLockTime 开始变为有效。无法让一笔交易到某个时间后停止有效;一笔交易只要曾经变为有效,就必须永远保持有效。
请看这些讨论帖:
http://www.bitcoin.org/smf/index.php?topic=1786.msg22119#msg22119
http://www.bitcoin.org/smf/index.php?topic=2181.msg28729#msg28729
我还没有完全理解为什么序列号是交易输入的属性,而不是交易本身的属性。
这是为了合约。一笔尚未记录的开放交易可以一直被替换,直到 nLockTime。它可能包含多方的付款。每个输入的所有者都为自己的输入签名。要写入新版本,每个人都必须签署一个更高的序列号(参见 IsNewerThan)。输入所有者签名时是在说:“如果每个人都投入自己的钱,而且输出是这样,我就同意把钱投入其中。”SignatureHash 中还有其他选项,例如 SIGHASH_SINGLE,意思是:“只要这一个输出(也就是我的)符合我的要求,我就同意,至于你如何处理其他输出,我不在乎。”如果用较高的 nSequenceNumber 写入这一点,该方就可以退出谈判,只保留这一项条件;或者签署 SIGHASH_NONE,彻底退出。
各方可以使用 OP_CHECKMULTISIG 创建一笔 nSequenceNumber 更高的交易,要求一部分参与方签名才能完成签署,从而创建一个预先商定的默认选项。各方把这笔交易留作备用,必要时相互传递,直到它获得足够多的签名。
nLockTime 的一种用途,是一组参与方之间的高频交易。他们可以在全体一致同意的情况下不断更新一笔交易。付钱的一方会第一个签署下一个版本。如果某一方不再同意变更,那么最后的状态将在 nLockTime 时被记录。如果需要,可以在每个版本之后准备一笔默认交易,使 n-1 方能够把不响应的一方排除出去。中间交易不需要广播。只有最终结果会被网络记录。就在 nLockTime 之前,各方和几个见证节点会广播它们所见过的序列号最高的交易。
英文原文
展开英文原文
I hope you are doing well. I finally got all the lawyers happy enough to release BitCoinJ under the Google name using the Apache 2 license:
It's incomplete - notably it doesn't properly handle block chain splits yet - but the rest is coming. I put a lot of work into documentation and comments so hopefully it'll open up BitCoin to a new audience who weren't able to understand/build the current code. Over the next month or two I'll be finishing off some of the bigger missing pieces for a full client-mode implementation.
That's great news! Much complexity can be left behind in a clean rewrite with only client requirements, and it opens it to Java developers too.
I know you are busy right now but I'm hoping you can find time to answer a few questions I had.
I'm happy to answer any questions.
As part of doing full SPV I'm thinking of adding a getmerklebranch message to the protocol. This would return a set of {blockhash, branch} pairs
That's a CMerkleTx
given tx hashes, so allowing verification of a broadcast transaction before it was incorporated into a block without storing the full chain. Does that approach sound good to you?
I don't understand. A merkle branch links a tx back to a block, which only has significance if the block exhibits proof-of-work. Linking back to an as-yet unsolved block proves nothing.
Network nodes are able to verify 0-conf txes because they have the complete tx index, so they can:
- verify signatures against dependencies.
- say that they haven't seen another spend yet, because they know about every tx in existence.
Are you talking about CMerkleTxes for the tx's dependencies? That would get part 1), but not part 2).
If you don't know about all txes in existence, I don't know how to do 2). You could only rely on trusting other nodes for that. That trust can be distributed over multiple nodes. Nodes only relay transactions they accept as valid. If you receive inv messages for a tx from all the nodes you're connected to, they're attesting that it's valid and the first spend they saw.
Also, I've been thinking of exploring different transaction types lately, eg by removing the IsStandard() checks for the testnet.
Very good idea. That should definitely be allowed on -testnet.
It's clear you put a lot of thought into transactions beyond simply moving coins around up front, but unfortunately none of it was in the paper or documented in the code. Escrow, multi-pay and so on are all interesting but I was wondering if you could compile a list of ideas for things we can do with the scripting language at some point.
Finally, the code that allows for transaction replacement has been disabled but the comment doesn't say why. Is this just to reduce the attack surface/complexity or is there a deeper reason?
Just to reduce surface area. It wouldn't help with increasing tx fee. A tx starts being valid at nLockTime. It wouldn't work to have a tx that stops being valid at a certain time; once a tx ever becomes valid, it must stay valid permanently.
See these threads:
http://www.bitcoin.org/smf/index.php?topic=1786.msg22119#msg22119
http://www.bitcoin.org/smf/index.php?topic=2181.msg28729#msg28729
I haven't fully understood why sequence numbers are a property of the tx inputs rather than the tx itself.
It's for contracts. An unrecorded open transaction can keep being replaced until nLockTime. It may contain payments by multiple parties. Each input owner signs their input. For a new version to be written, each must sign a higher sequence number (see IsNewerThan). By signing, an input owner says "I agree to put my money in, if everyone puts their money in and the outputs are this." There are other options in SignatureHash such as SIGHASH_SINGLE which means "I agree, as long as this one output (i.e. mine) is what I want, I don't care what you do with the other outputs.". If that's written with a high nSequenceNumber, the party can bow out of the negotiation except for that one stipulation, or sign SIGHASH_NONE and bow out completely.
The parties could create a pre-agreed default option by creating a higher nSequenceNumber tx using OP_CHECKMULTISIG that requires a subset of parties to sign to complete the signature. The parties hold this tx in reserve and if need be, pass it around until it has enough signatures.
One use of nLockTime is high frequency trades between a set of parties. They can keep updating a tx by unanimous agreement. The party giving money would be the first to sign the next version. If one party stops agreeing to changes, then the last state will be recorded at nLockTime. If desired, a default transaction can be prepared after each version so n-1 parties can push an unresponsive party out. Intermediate transactions do not need to be broadcast. Only the final outcome gets recorded by the network. Just before nLockTime, the parties and a few witness nodes broadcast the highest sequence tx they saw.