# 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 不允许在输出组中重复的秘诺同时存在。但输出组特指特别的链分叉。有可能在不同并发分叉同时存在重复的*类似的* 秘诺。这些重复的秘诺可能到期“锁定高度”不同，且在不同分叉中可花费。

* 区块 B<sub>1</sub> 上确认的输出 O<sub>1</sub>，在高度 h<sub>1</sub>（分叉 f<sub>1</sub> 上）可花费
* 区块 B<sub>2</sub> 上确认的输出 O<sub>1</sub>'，在高度 h<sub>2</sub>（分叉 f<sub>2</sub> 上）可花费

复杂之处是根据分叉链上区块含有输入 I<sub>1</sub>，I<sub>1</sub> 就可花费 O<sub>1</sub> 或 O<sub>1</sub>'。特别是 I<sub>1</sub> 有可能在一条分叉上而不是在另一个分叉上的特定区块高度有效。

换言之，一个秘诺有可能指向多个输出，所有输出可能有不同区块高度。我们*还得*必须确保正确识别确实花费了哪个输出，还有根据目前的链状态正确执行 coinbase 到期规则。

按 coinbase 到期规则在指定区块高度锁定的 coinbase 输出无法独自识别，无法以秘诺单独安全花费 -

* coinbase 输出的来源区块

鉴于此，我们可验证区块高度，并推理出输出的“锁定高度”（1000 以上区块）。

## 全存档节点

全存档节点就是个简单任务，用来识别输出来自哪个区块。全存档节点储存以下数据 -

* 链上所有区块的全区块数据
* 区块所有输出数据

我们可以轻易查看链上所有区块，找到含有自己关注的输出区块。

问题是我们需要用没有全区块数据的节点怎么办（修剪节点、非全存档节点）。[哪种节点？]

如果我们没有全区块数据怎么验证 coinbase 期限？

## 非存档节点

[术语？这些节点术语是什么？]

节点不一定有全区块数据。修剪节点或许只储存以下数据（请参考修剪文档）-

* 区块头部链。
* 所有交易内核。
* 所有未花费输出。
* 输出 MMR 和范围证明 MMR

数据组经过极简处理，那么如何知道一个输出来自哪个区块？

我们知道了多个输出（多个分叉、潜在不同锁定高度）可以有*相同*秘诺，为具体识别花费的输出还需要在输出中提供哪些额外信息？

进一步讲 - 我们是否可以在不存取所有输出数据的情况下完成识别？是否可以只使用输出 MMR？

### 推荐方法

维护一个索引映射秘诺来定位输出 MMR。

如果对指定的秘诺索引中没有项目，或在输出 MMR 中没有项目，即可知道输出不可花费（要么之前已花费或从未存在）。

如果在输出 MMR 中找到一个项目，便知道在输出组中有可花费输出存在，但我们不知道是否正确。我们不知道其是否为 coinbase 输出，以及区块来源高度。

如果输出 MMR 中保存的哈希值包括秘诺和输出特征，而且我们需要输入提供秘诺和特征，那便可进行下步验证 -

* 输出存在于输出 MMR 中（根据秘诺），和
* MMR中的哈希值与输入中的输出数据匹配

有了这一步就可以知道输出是否为 coinbase 输出，还是基于指定功能的普通交易输出。除非输入特征与原始输出特征匹配，否则哈希值会不匹配。


普通的非 coinbase 输出就到此为止。我们知道输出目前可花费，无需再查看锁定高度。

对于 coinbase 输出，可以继续验证区块高度和期限。验证过程需要确认产生输出的区块。我们无法确定区块本身，但需要输入来指定区块（哈希值），之后可以根据区块头部的默克尔根证明区块完全准确。

[待确定 - 默克尔证明概览及如何根据区块头部默克尔根利用这些证明包容性]

总结 -

输出 MMR 根据 `秘诺|特征`（只有秘诺不够）储存输出哈希值。

不需要在生成输出哈希值中包含范围证明。

若要花费输出，我们需要 -

* `r` 和 `v` 构建秘诺和证明所有权

输出必须提供 -

* 秘诺（查询 MMR 中的输出）
* 输出特征（依赖`特征|秘诺`的输出 MMR 哈希值）
* 在原始区块中显示包含输出的默克尔证明
* 原始区块的区块哈希
  * [待确定 - 根据默克尔证明维护索引？]

通过秘诺和特征确定正确的输出目前是否未花费。通过区块和输出特征确定锁定高度（如有）。