深入探讨IC如何实现直接集成BTC
文章来自于|IC Wiki
投稿、转载请联系|DfinitySZ小助手
BTC是一种基于P2P开源协议的数字货币,BTC使用未使用交易输出/UTXO的账户模型,即为交易创建输出。这些输出用作其他交易的输入,从而创建新的交易输出,一个UTXO总是会被一个交易消耗掉。
注解:在BTC等加密货币中,未使用的交易输出 (UTXO) 是电子货币的抽象化概念。每个UTXO类似于硬币,并以其各自的货币持有一定数量的价值。每个 UTXO 代表一个所有权链,实现为数字签名链,其中所有者签署消息(交易),将其 UTXO 的所有权转移到接收者的公钥。
众所周知,作为数据黄金储备的BTC对智能合约的不支持大大削弱了其在应用场景上的构想空间。2021年9月7日,DFINITY基金会发布了一项对于区块链发展具有里程碑意义的提案——为BTC创建智能合约。即为在无需额外的信任假设情况下,通过IC底层技术直接集成BTC,这种集成将实现在IC上使用BTC原生支持任何服务(IC Canister/智能合约可以直接在BTC链上持有、发送、接收比特币),这将开辟无穷无尽的应用场景。
这种直接集成需要完成以下工程内容:
Canister拥有BTC地址;
Canister可以访问它们控制的地址的UTXO集;
Canister可以安全地签署BTC交易;
Canister可以向BTC网络提交交易事务。
IC与BTC集成的无需信任方面是实现一个阈值ECDSA协议,该协议允许子网根据Canister请求的秘密共享私钥计算ECDSA签名。使用此协议,每个Canister都可以“控制”一组无限的可派生 ECDSA密钥并为其获取签名。这使得Canister能够以安全的方式直接在BTC链上接收、持有和转移比特币。要实现Canister接收的输入交易和相关的UTXO,它需要访问与BTC地址相关的UTXO集,IC的解决方案是直接从BTC网络中摄取BTC区块,并相应验证它们。
IC<>BTC集成架构
关于实现IC直接集成BTC的架构上需要在IC协议栈的每一层进行更改或添加相应组件。
BTC集成架构概述
如上图所示BTC Canister在执行层作为副本一部分实现的虚拟容器,它公开了用于查询UTXO集和提交交易的API 。BTC地址的UTXO集由API get_utxos公开;BTC地址的余额通过get_balance方法公开;使用send_transaction方法发送BTC交易。Canister使用这三种方法与BTC区块链交互并检索其状态。
BTC Caniste为UTXO集提供服务时需要将BTC区块从BTC网络的节点拉入IC中,摄取区块中的交易输入和输出,并且由BTC Canister维护一组未使用的交易输出 (UTXO),此类实现需要一个跨IC协议栈所有层的架构,且还包括副本外部的新组件。
BTC Canister维护一组最近的BTC区块(例如,宽度为144个区块的跨度)、BTC网络的UTXO 集以及Canister提交的一组的输出交易的表示。UTXO集和最近的区块用于响应Canister的UTXO 查询。
在副本之外,有一个BTC适配器,它一个沙盒操作系统级进程,它使用BTC的对等发现协议(Bitcoin's peer discovery protocol)随机连接到多个BTC网络节点。BTC适配器同步BTC网络的区块头和区块。此外,BTC适配器还维护BTC网络区块的最新视图,并根据请求向 IC 协议栈提供区块。
在IC协议轮中,作为共识层核心组件的活跃区块制造者向网络层请求新的BTC区块。网络层负责检索BTC Canister的部分状态,包括BTC Canister维护的最近BTC区块头以及输出交易。这两个项目都用作向BTC适配器发送BTC区块请求的参数。BTC适配器将接收到的区块哈希与其最近的BTC网络视图相匹配,如果它持有一个区块是通过哈希表示区块之一的后继区块,则返回该区块。此外,它还将请求中收到的交易添加到队列中,以便将输出交易异步提交到BTC网络。如果BTC适配器返回一个区块,则由区块制造者将其放入提议的IC区块中。
假设在当前的IC协议轮次中已经提出了一个包含BTC区块的IC块,这个IC区块会像往常一样被gossiped到子网节点,这需要经过共识层的公证和最终确定过程。公证过程针对BTC集成进行了扩展:每个副本会根据预期的哈希值及其时间戳对IC块中包含的BTC区块执行确定性的有效性检查。至关重要的是只有在保证区块将被所有诚实副本成功验证的情况下,区块制造者才可以提议区块,否则子网的共识可能会失败。
一旦具有BTC区块有效负载的IC区块成功被验证,最终确定过程将继续进行,且无需更改。一旦区块最终确定,BTC有效负载需要在消息路由层中提取,发布到相应的子网队列中以执行。当BTC区块到达执行层时,它由执行层的BTC Canister执行:区块被验证,其交易和交易的输入和输出被提取,BTC区块链的UTXO集和网络视图将相应更新。
创建BTC交易需要为每个用作交易输入的UTXO计算一个 ECDSA 签名。Canister可以从作为专用ECDSA签名子网的一部分实施的阈值ECDSA API请求ECDSA 签名。创世将部署一个这样的子网,如果需求增加,未来将可能会提供多个签名子网。图1以简化的方式显示了阈值ECDSA功能,它是支持Btcoin的子网中一部分,而不是位于单独的子网中。使用阈值 ECDSA API 允许Canister请求 ECDSA 签名,该签名由ECDSA子网中的副本/节点 基于秘密共享私钥联合计算。使用BIP-32密钥派生的泛化,使每个Canister都可以访问它控制的无限组阈值ECDSA密钥。
技术细节
如上一节所述,Canister与(虚拟)BTC容器交互以利用BTC集成 API。BTC Canister依赖于BTC适配器,它是与BTC网络交互的组件。在本节中,提供了有关各个组件的技术细节,从BTC适配器自下而上开始。
注意:一些技术细节并未在IC<>集成BTC的开发者预览版中实现,这将在下一节中讨论。例如,不执行几个有效性检查。这些遗漏对于本地测试环境来说并不重要。
BTC适配器
BTC适配器与BTC网络交互以获取区块头和区块,并发布由Canister发起的BTC交易。
连接到比特币节点
默认情况下,BTC适配器连接到8个随机选择的比特币节点,但连接数是可配置的,为了确保每个副本的BTC适配器以高概率连接到不同的随机集,BTC适配器会向种子节点查询地址,直到它确认收到至少1000个地址,并从这些地址中随机选择节点,直到所需数量的已建立连接。根据官方测试数据表明,这个过程每个副本的BTC适配器会连接到大部分不同的地址。
状态
BTC适配器旨在维持以下状态:
所有区块头。
区块缓存
用于广播但尚未传输到BTC节点的输出交易的缓存。
创世之初,BTC适配器没有任何区块头,且缓存是空的。
BTC适配器在运行
当BTC适配器启动时,它会连接到BTC节点并开始从创世中拉入区块头,直到它赶上区块。对于每个下载的区块头,BTC适配器执行以下检查:解析区块头格式是否正确。根据难度目标,区块头中的哈希工作就足够了。
在收到来自BTC Canister的消息之前,缓存一直是空的。BTC Canister会定期发送一个最近区块头的哈希列表,它拥有完整的区块(包含所有交易)。
有关发送区块头哈希的详细信息参考下述有关BTC Canister概述部分。
BTC适配器会检查它在具有最多哈希工作的链(通常是最长的链)上是否有任何区块头,假设其哈希不在接收列表中,表明BTC Canister还没有接收到相应的区块。如果BTC适配器在其缓存中包含扩展BTC Canister中当前链的一些丢失区块时,它将以包含下一个缺失区块的消息进行响应,包括相应的区块头,最大为2 MB。这个上限意味着对于大小通常超过1MB的最近区块,只返回一个区块(和块头)。在一条消息中发送多个区块的能力对于更快地摄取旧块很有效,因为它们要小得多。
如果BTC适配器的缓存中没有丢失的区块,它会立即返回一条空消息,以免延迟共识。在准确了解BTC Canister的状态后,BTC适配器会下载下一个丢失的区块,以便在BTC Canister的未来请求中将它们打包到返回消息中。由于BTC适配器不跟踪交易,它无法验证接收到的区块中交易中的有效性。为了防止向BTC Canister发送无效块垃圾邮件,它会执行一些基本检查:
它是否可以被解析为一个正确的BTC区块;
Merkle树根哈希对应于相应区块头中的哈希。
一旦接收到的一组区块头哈希表明BTC Canister已接收到区块,区块会从缓存中删除。
当BTC适配器接收到输出交易时,它们将被放置在交易缓存中,并被广播给BTC网络。当交易被传输到连接的比特币节点,交易会从缓存中删除。
通过共识
从技术来说,只要复制品被选为下一个(IC)区块制造商,则会查询复制品的BTC适配器以获取BTC区块。当BTC适配器的响应包含一个或多个区块时,共识层会调用一个函数来检查BTC区块的有效性,然后再将它们放入IC块中。确保有效性检查机制对于所有副本的结果是否一致非常重要。因此,有效性检查必须是确定性函数,即不能考虑本地时间和BTC适配器的本地可用状态等因素。执行以下有效性检查:
区块头是格式正确,即为它可以被解析为一个正确的区块头;
该区块是格式正确,即为它可以被解析为一个正确的BTC区块;
Merkle树根哈希对应于相应区块头中的哈希。
同样,交易在这个阶段还没有得到验证。
一旦 IC区块通过共识(和消息路由),BTC区块(和相应的区块头)就会被提供给BTC Canister以供摄取。
BTC Canister
BTC Canister是一个虚拟Canister,类似于管理Canister,这意味着它在其它Canister看来就像一个常规Canister,但实际上它是副本的一部分。BTC集成API通过BTC Canister提供,以便其它Canister能够集成BTC功能。
管理容器概述:
https://smartcontracts.org/docs/interface-spec/index.html#ic-management-canister
状态
BTC Canister存储以下状态:
从创世到某个区块高度h的完整 UTXO 集;
包括从高度h开始的区块头的区块;
输出交易集。
由于BTC Canister不存储交易的完整历史,它必须决定何时可以安全地丢弃一个区块,从而只依赖于它维护的UTXO集中的信息。
由于存在长期分叉的风险,BTC Canister不使用确认计数来确定何时丢弃区块。相反,它使用了一个稍微复杂的概念,称之为稳定性/stability:简单来说如果在有一定数量的后续区块后,一个区块是稳定的,降低了该区块将来被丢弃的风险,并且任何其他分叉的尖端也至少落后相同数量的区块。更正式地说,如果h(b)表示自创世以来区块b的前导块的数量,d(b)表示从区块b开始的最长后继路径的长度,则稳定性定义如下。
定义(δ-stability):对于参数δ>0,如果以下条件成立,一个区块是δ-stability
d(b)≥δ
∀b'∈B,h(b')=h(b):d(b)-d(b')≥δ
BTC Canister配置了144的稳定性阈值δ,如果没有分叉,BTC Canister将所有区块保留大约一天(平均每 10 分钟一个区块)。一旦一个区块变得δ-stable,交易就会被应用到UTXO集,并且该区块被丢弃。因此,稳定性用于定义上述状态描述提到的截止区块高度h,所有稳定性低于阈值的区块都被认为是不稳定的。
运行中的BTC Canister
当从BTC适配器请求更新时,BTC Canister向BTC适配器发送一条包含所有不稳定区块哈希值的消息,BTC适配器使用哈希来确定BTC Canister丢失了哪些区块(如果有)。当从BTC适配器接收区块和区块头时,会对每个区块/区块头执行以下有效性检查:
区块头格式是否正确,即为它可以被解析为一个正确的区块头;
根据难度目标,使用区块头中的哈希工作就足够了;
区块头指向一个已知的前任;
该区块格式是否正确,即它可以被解析为一个正确的BTC区块;
Merkle树根哈希对应于相应区块头中的哈希;
所有交易都是有效的,即签名是正确的,只有未使用的输出被消耗。
如果验证成功,则将该区块添加到不稳定区块列表中。此外,如果一个区块因此变为δ-stable,则 UTXO 集会根据该区块中的交易进行更新,并丢弃该区块。
BTC Canister公开了以下API:
get_utxos:该函数返回固定BTC地址的未使用交易输出 (UTXO)
get_balance:该函数返回给定比特币地址的余额。
send_transaction:该函数将给定的交易发送到比特币网络。
有关 API 的详细信息可以在下述链接中找到:
https://github.com/dfinity/bitcoin-developer-preview
在响应具有可选min_confirmations参数的get_utxos和get_balance调用时,BTC Canister会考虑 UTXO 状态以及至少具有请求的最小确认数的不稳定块中所有交易。换句话说,在从UTXO集合中提取相关的未使用输出后,会解析不稳定的区块以找到额外的未使用输出。此外,如果有交易消耗任何收集的输出,则输出将被丢弃,因为它们被视为已消耗。
为了减少由于分叉导致的不一致的风险,确认被保守地计算,再次使用δ-stability一个块的稳定性计数是最大的δ,因此区该块是δ-stability确定交易确认次数的过程如下:最大区块高度被识别为在这个高度只有一个区块。考虑到第一步中确定区块的不稳定区块链,一个区块中交易的确认次数定义为该区块的稳定性/stability计数加1。
虽然这条规则可能看起来很复杂,但它有几个不错的属性:如果没有分叉,则每笔交易的确认次数正是所期望的:一旦交易进入一个区块,它就有一个确认,如果有随后的区块,它会有两个确认,以此类推。但是,如果存在多个高度相似的竞争分叉,则确认数量将保持在较低水平,直到一条链占上风,此时确认数量开始增加。简而言之,该规则旨在确保大量确认意味着即使存在竞争分叉,交易也不会被撤消的可能性。
当BTC Canister接收到输出交易,且交易通过验证检查时,它会将交易转发到BTC适配器。如上所述,BTC Canister会缓存交易,并在交易未出现在区块中时定期重新提交。一旦交易出现在区块中或在24小时后过期,该交易就会被删除。
开发者预览
2022年2 月3日发布的IC<>BTC开发者预览版是BTC集成功能的早期版本,它旨在供开发者针对预览版API部署智能合约并提供反馈,以便根据社区反馈对最终版本的API进行优化。
开发者预览版API仅作为本地开发环境(Canister SDK)的一部分提供,BTC网络将被替换为单个本地运行的bitcoind节点,虽然这不是与BTC主网或测试网集成,但这是在本地开发环境运行的最佳选择,开发者可以完全控制该节点以进行BTC智能合约开发测试。
开发者预览版通过 APIget_utxos、get_balance和send_transaction使该功能的所有BTC相关逻辑可用,但此版本与IC协议栈的集成被简化了:它没有使用与IC协议层的自定义集成。在共识层中,添加了一个 Adapter Shim作为外部组件,通过查询调用将 Adapter 连接到常规IC协议栈和入口消息。开发者预览版的开发者需要在其本地环境(Canister SDK )之上安装该版本和启动它。BTC容器公开为Wasm/WebAssembly容器,而不是作为副本一部分实现的虚拟容器,就像最终版本中的管理容器一样。
必看周刊
生态精选
寻宝回顾
精彩活动
联系我们
t.me/DfinitySZ
dfisz.com
twitter.com/DfinitySZ
twitter.com/DfinitySZCN
reddit.com/user/DfinityShenZhen