# Coinbase 期限规则(亦即"输出锁定高度")
*阅读其它语言版本: [English](../coinbase_maturity.md), [Korean](coinbase_maturity_KR.md).*
coinbase 输出(区块奖励和手续费)为“锁定”,需要有 1440 个确认(也就是经过约 24 小时在链上加上区块)才能到期花费。这是为了防止之后如果出现链上回滚的情况下,降低撤销之后交易的风险。
比特币也有类似设计,挖矿奖励需要经过 100 个确认(比特币出块时间为十分钟,Grin 出块时间为 60 秒)方可花费。
Grin 在交易池和区块验证管道中强行使用 coinbase 期限。包含花费 coinbase 输出的输入交易只有在 coinbase 完全到期(根据目前链高度和生成 coinbase 输出区块的高度)后才可以添加到交易池。同理,如果区块中包含花费 coinbase 输出的输入交易,根据含有输入的区块高度和最初生成 coinbase 输出区块的高度,若 coinbase 未到期,则区块无效。
期限规则*仅*适用于 coinbase 输出。普通交易输出的有效锁定高度为零。
输出包括 -
* 特征(目前为 coinbase 和 非 coinbase)
* 秘诺 (commitment) `rG+vH`
* 范围证明
若要花费普通交易输出,需要满足两个条件。我们需要证明此输出之前并未花费,并证明输出所有权。
Grin 交易包含下列信息 -
* 一组输入。每个输入对应一个之前花费的输出。
* 一组新的输出包括 -
* 值 `v` 和盲因子(密钥) `r` 以曲线相乘,并算出总和 `rG+vH`。
* 表明 `v` 并非为负数的范围证明。
* 公开的明确交易费。
* 一个签名。用额外盲因子值(全部输出加交易费减去输出)并将其用作私钥来计算。
我们可以寻找目前输出组中的秘诺来证明输出未花费。输出组具有权威性;若某个输出存在于输出组中,我们便知晓其并未花费。若某输出在输出组中不存在,我们便知道这一输出要么不存在,要么就是之前存在但现在已被花费(我们不会确知是哪种情况)。
可通过验证交易签名来证明所有权。*只有*交易之和为零*且*知道 `v` 和 `r` 的情况下方可对交易签名。
知道 `v` 和 `r` 便可(通过秘诺)特别确认输出。而且可以通过验证原始 coinbase 交易上的签名来证明输出所有权。
Grin 不允许在输出组中重复的秘诺同时存在。但只要输出被花费,就会从输出组中移除,且将复制的秘诺重新添加到输出组。不推荐这一操作,但 Grin 必须在不违反网络共识的情况下解决这一问题。
几个因素会让这一情况变复杂 -
1. 两个区块可获得相同奖励,尤其是空块的情况下,但有转账费的非空块也有可能。
1. 非 coinbase 输出可与 coinbase 有相同值。
1. 矿工可重复使用私钥(但不建议)。
Grin 不允许在输出组中重复的秘诺同时存在。但输出组特指特别的链分叉。有可能在不同并发分叉同时存在重复的*类似的* 秘诺。这些重复的秘诺可能到期“锁定高度”不同,且在不同分叉中可花费。
* 区块 B1 上确认的输出 O1,在高度 h1(分叉 f1 上)可花费
* 区块 B2 上确认的输出 O1',在高度 h2(分叉 f2 上)可花费
复杂之处是根据分叉链上区块含有输入 I1,I1 就可花费 O1 或 O1'。特别是 I1 有可能在一条分叉上而不是在另一个分叉上的特定区块高度有效。
换言之,一个秘诺有可能指向多个输出,所有输出可能有不同区块高度。我们*还得*必须确保正确识别确实花费了哪个输出,还有根据目前的链状态正确执行 coinbase 到期规则。
按 coinbase 到期规则在指定区块高度锁定的 coinbase 输出无法独自识别,无法以秘诺单独安全花费 -
* coinbase 输出的来源区块
鉴于此,我们可验证区块高度,并推理出输出的“锁定高度”(1000 以上区块)。
## 全存档节点
全存档节点就是个简单任务,用来识别输出来自哪个区块。全存档节点储存以下数据 -
* 链上所有区块的全区块数据
* 区块所有输出数据
我们可以轻易查看链上所有区块,找到含有自己关注的输出区块。
问题是我们需要用没有全区块数据的节点怎么办(修剪节点、非全存档节点)。[哪种节点?]
如果我们没有全区块数据怎么验证 coinbase 期限?
## 非存档节点
[术语?这些节点术语是什么?]
节点不一定有全区块数据。修剪节点或许只储存以下数据(请参考修剪文档)-
* 区块头部链。
* 所有交易内核。
* 所有未花费输出。
* 输出 MMR 和范围证明 MMR
数据组经过极简处理,那么如何知道一个输出来自哪个区块?
我们知道了多个输出(多个分叉、潜在不同锁定高度)可以有*相同*秘诺,为具体识别花费的输出还需要在输出中提供哪些额外信息?
进一步讲 - 我们是否可以在不存取所有输出数据的情况下完成识别?是否可以只使用输出 MMR?
### 推荐方法
维护一个索引映射秘诺来定位输出 MMR。
如果对指定的秘诺索引中没有项目,或在输出 MMR 中没有项目,即可知道输出不可花费(要么之前已花费或从未存在)。
如果在输出 MMR 中找到一个项目,便知道在输出组中有可花费输出存在,但我们不知道是否正确。我们不知道其是否为 coinbase 输出,以及区块来源高度。
如果输出 MMR 中保存的哈希值包括秘诺和输出特征,而且我们需要输入提供秘诺和特征,那便可进行下步验证 -
* 输出存在于输出 MMR 中(根据秘诺),和
* MMR中的哈希值与输入中的输出数据匹配
有了这一步就可以知道输出是否为 coinbase 输出,还是基于指定功能的普通交易输出。除非输入特征与原始输出特征匹配,否则哈希值会不匹配。
普通的非 coinbase 输出就到此为止。我们知道输出目前可花费,无需再查看锁定高度。
对于 coinbase 输出,可以继续验证区块高度和期限。验证过程需要确认产生输出的区块。我们无法确定区块本身,但需要输入来指定区块(哈希值),之后可以根据区块头部的默克尔根证明区块完全准确。
[待确定 - 默克尔证明概览及如何根据区块头部默克尔根利用这些证明包容性]
总结 -
输出 MMR 根据 `秘诺|特征`(只有秘诺不够)储存输出哈希值。
不需要在生成输出哈希值中包含范围证明。
若要花费输出,我们需要 -
* `r` 和 `v` 构建秘诺和证明所有权
输出必须提供 -
* 秘诺(查询 MMR 中的输出)
* 输出特征(依赖`特征|秘诺`的输出 MMR 哈希值)
* 在原始区块中显示包含输出的默克尔证明
* 原始区块的区块哈希
* [待确定 - 根据默克尔证明维护索引?]
通过秘诺和特征确定正确的输出目前是否未花费。通过区块和输出特征确定锁定高度(如有)。