该文档描述了用于验证 Taproot Asset (资产)转移的虚拟机执行环境,该环境使用 asset_script_version
版本 1。
forked from bitcoin/bips
bip-tap
搜索此仓库
/
复制路径
BlameMore 文件操作
BlameMore 文件操作
和
bip-tap vm: specify that minting transition witnesses must be verified
2023年10月16日
bd3cdc1 · 2023年10月16日
打开提交详情
292 行 (226 loc) · 14.1 KB
/
顶部
预览
代码
Blame
292 行 (226 loc) · 14.1 KB
复制原始文件
下载原始文件
大纲
编辑和原始操作
BIP: ???
Layer: Applications
Title: Taproot Asset Script v1
Author: Olaoluwa Osuntokun <laolu32@gmail.com>
Comments-Summary: No comments yet.
Comments-URI: https://git
Status: Draft
Type: Standards Track
Created: 2021-12-10
License: BSD-2-Clause
## 目录<br>Permalink: 目录<br>- 摘要<br>- 版权<br>- 动机<br>- 设计 <br> - 规范 <br> - 映射输入<br> - 映射输出<br> - 验证状态转换<br>- 测试向量<br>- 向后兼容性<br>- 参考实现 |
本文档描述了虚拟机执行环境,用于验证使用
asset_script_version
为 1 的 Taproot Asset 转账。
本文档中描述的执行环境是 BIP 341 和 342 中定义的 taproot 验证规则的略微修改版本。给定一个 Taproot Asset,
一个或多个要花费的 Taproot Asset 叶子(输入)和要创建的资产叶子,将创建一个“虚拟”taproot 比特币交易。这个交易
是一个 1 输入 1 输出的交易,它使用 merkle sum tree 提交到输入和输出集。完成此映射后,验证将正常进行。
本文档基于 2-clause BSD 许可。
Taproot Asset 覆盖允许使用几乎任意的虚拟机来验证系统内的转账。为了缩小协议的初始版本范围,我们描述了一种利用现有比特币脚本虚拟机的方法,允许我们继承一组基线的表达能力,同时允许实施者重用现有的工具和库。
Taproot Asset asset_script_version
1 将 Taproot Asset 输入和输出集映射到“虚拟”比特币交易。
输入和输出集使用普通的 merkle sum tree 提交到单个 1 输入 1 输出的交易中
(TODO(roasbeef): 这里完全没有包含非包含吗??)。
通过 augmented merkle tree 的 merkle-sum 不变量,验证者能够通过断言已提交的输入总和等于已提交的输出总和来强制执行资产的非膨胀。一旦验证了此不变量,执行将按照 BIP 341+342 验证规则正常恢复,并附加可能导致验证提前失败的执行前检查。
单个 1 输入 1 输出的交易用于将 Taproot Asset 状态转换状态压缩为恒定大小的交易。给定一个 Taproot Asset 承诺(存在于 taproot 输出中)及其有效的 opening,先前的资产 ID 集被压缩为单个输入,并且当前的 split_commitment
用于压缩输出状态。
状态转换验证可能在单个交易中采用一个或多个资产叶子(叶子存在于不同的输出中)。当存在单个叶子时,状态转换中没有发生拆分,或者该资产是 collectible。当指定两个或更多叶子时,除一个叶子之外的所有叶子都是由于 Taproot Asset 层级的拆分事件而产生的拆分。在这种情况下,拆分承诺证明以及创建拆分的状态转换的有效性都经过验证。
输入映射仅针对指定 prev_asset_witnesses
的状态转换执行。
给定一组输入,每个输入都由 prev_asset_input
标识,输入承诺(用作先前的输出)的构建方式如下:
prev_asset_witnesses
字段中标识的每个 Taproot Asset 输入 c_i:
split_commitment
,则需要在序列化步骤之前将其删除。prev_outpoint || prev_asset_id || prev_asset_script_key
标识)。
prev_asset_witnesses
的输出叶子的副本,以及以下修改:
asset_script_key
应设置为等于该 group key。这确保状态转换验证在验证花费时使用 group key。asset_script_key
字段应为空白。这将使状态转换验证短路,从而允许铸造不支持发行的资产。prev_id_identifier
,值为序列化的叶子,总和值为叶子中包含的资产金额。input_root
和总和值 input_asset_sum
。通过上述例程,我们将输入集映射到 MS-SMT 树,该树还提交到任何给定资产的总花费金额。在验证期间,由于可能存在多个输入 witness,因此在验证期间,每个输入的 asset_witness
都用作初始 witness 堆栈。
请注意,我们在此统一输入承诺中没有映射 relative_lock_time
字段。相反,我们将在验证/签名过程中映射此字段,这将启用每个输入相关的相对和绝对锁定时间的存在。
以下算法实现了完全状态转换验证所需的输入映射:
make_virtual_input(prev_inputs: map[PrevOut]TaprootAssetLeaf) -> (MerkleSumRoot, TxIn):
input_smt = new_ms_smt()
for prev_out, taproot_asset_leaf in prev_inputs:
leaf_bytes = taproot_asset_leaf.serialize_tlv()
input_smt.insert(key=prev_out, value=leaf_bytes, sum_value=taproot_asset_leaf.amt)
input_root = input_smt.root()
virtual_txid = sha256(input_root.hash || input_root.sum_value)
# We only only bind the virtual txid here. Below we'll modify the input
# index based on the ordering of this SMT.
# 我们只在这里绑定虚拟 txid。 下面我们将根据此 SMT 的排序修改输入索引。
return input_root, NewTxIn(NewOutPoint(txid=virtual_txid), nil)
输出映射仅针对指定 prev_asset_witnesses
的状态转换执行。
给定一个 Taproot Asset 输出,以及其 split_commitment_root
中包含的任何关联输出,输出承诺的构建方式如下:
amt
字段的总和,换句话说,split_commitment_root
的最后 4 个字节。split_commitment_root
值的前 32 个字节。sha256(asset_key_family || asset_id || asset_script_key)
。如果未指定 asset_key_family
字段,则应使用 32 个字节的零来代替。以下算法实现了完全状态转换验证所需的输出映射:
make_virtual_txout(leaf: TaprootAssetLeaf) -> (MerkleSumRoot, TxOut):
match leaf.asset_type:
case Normal:
tx_out = NewTxOut(
pk_script=[OP_1 OP_DATA_32 leaf.split_commitment_root.hash],
value=leaf.split_commitment_root.sum_value,
)
return leaf.split_commitment_root, tx_out
case Collectible:
output_smt = new_ms_smt()
output_smt.insert(
key=sha256(leaf.asset_key_family || leaf.asset_id || leaf.asset_script_key)
value=leaf.serialize_tlv(),
sum_value=1,
)
witness_program = output_smt.root_hash()
tx_out = NewTxOut(
pk_script=[OP_1 OP_DATA_32 witness_program],
value=1,
)
return output_smt.root, tx_out
如果状态转换指定了 prev_asset_witnesses
字段,那么
一旦输入和输出集映射到我们的虚拟比特币交易(创建一个具有单个输入和输出的 v2 比特币交易),
验证将按照 BIP 341+342 正常进行,并进行以下修改:
input_asset_sum
不完全等于 output_asset_sum
,则验证必须失败。prev_asset_witnesses
集中的每个 prev_input
:
asset_type
没有映射到花费该输入的 Taproot Asset 叶子的 asset_type
,则验证必须失败。prev_id_identifier
字段的字典索引。asset_script_key
,映射到 v1 segwit witness program (taproot)。amt
字段。relative_lock_time
字段,则将序列号设置为该字段。lock_time
,则将交易的锁定时间设置为该叶子的锁定时间。SIGHASH_DEFAULT
评估。asset_script_key
为空白,则 asset_group_key
必须为空白,并且所有 witness 必须为空白。在这种情况下,验证成功,因为这只是没有 emission 的资产的创建/minting 交易。asset_id
值不相同,则验证必须失败。
asset_family_key
字段。relative_lock_time
字段,如果引用的 TLV 叶子的输入 age 小于 relative_lock_time
,则验证必须失败。lock_time
字段,如果包含交易的区块的区块高度小于 lock_time
,则验证必须失败。我们在此级别显式地实现锁定时间语义,因为比特币本身的上下文中的序列和锁定时间字段是从将新区块连接到主链末尾的 PoV 进行验证的。
否则,如果状态转换仅指定 split_commitment_proof
,则:
split_commitment_proof
且没有显式输入,则必须提供并验证输出的有效包含证明。以下算法实现了顶级 Taproot Asset 叶子以及通过拆分承诺创建的叶子的验证:
verify_taproot_asset_state_transition(leaf: TaprootAssetLeaf, leaf_split: TaprootAssetLeaf) -> bool
if is_valid_issuance_txn_no_group_key(leaf):
return true
if leaf_split is not None:
if leaf is None:
return false
if !verify_split_commitment(leaf.split_commitment_root,
leaf_split.split_commitment_proof):
return false
input_smt, tx_in = make_virtual_input(leaf.prev_inputs)
output_smt, tx_out = make_virtual_txout(leaf)
if input_smt.sum_value != output_smt.sum_value:
return false
virtual_tx_template = NewTx([tx_in], [tx_out])
for input in range leaf.prev_inputs:
if input.asset_type != leaf.asset_type:
return false
match input.asset_id:
case AssetID:
if input.asset_id != leaf.asset_id:
return false
case KeyFamily:
if input.asset_key_family != leaf.asset_key_family:
return false
virtual_tx = virtual_tx_template.clone()
if !parse_valid_schnorr_sigs(input.asset_witness):
return false
virtual_tx.tx_in[0].witness = input.asset_witness
virtual_tx.tx_in[0].prev_out.index = input_smt.leaf_index_of(input)
prev_pk_script = OP_1 OP_DATA_32 input.asset_script_key
input_value = input.amt
if input.relative_lock_time != 0:
virtual_tx.tx_in[0].sequence = relative_lock_time
input_age = conf_input_age(input)
if num_confs(input) < input_age:
return false
if input.lock_time != 0:
virtual_tx.lock_time = leaf.lock_time
block_height = env.block_height()
if block_height < virtual_tx.lock_time:
return false
vm = new_script_vm(
prev_pk_script=prev_pk_script, tx=virtual_tx, input_index=0,
input_amt=input_value,
)
if !vm.Execute():
return false
return true
验证状态转换 的测试向量可以在这里找到:
测试向量由 Taproot Assets GitHub 仓库中的单元测试 自动生成。
github.com/lightninglabs/taproot-assets/tree/main/vm
- 原文链接: github.com/Roasbeef/bips...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!