我们在本章开始时发现,交易的“幕后”看起来与钱包、区块链浏览器和其他面向用户的应用程序中呈现出来的非常不同。 前几章中的许多简单而熟悉的概念,如比特币地址和余额,似乎都没有出现在交易结构中。 我们看到交易本身并不包含比特币地址,而是通过锁定和解锁比特币离散值的脚本进行操作。 余额也不存在于这个系统中的任何地方,但是每个钱包应用程序都明明白白地显示了用户钱包的余额。

    现在,我们已经探讨了比特币交易中实际包含的内容,我们可以研究如何从交易的看似原始的组件中派生出更高级别的抽象。

    我们再来看看Alice的交易在一个常用的区块浏览器(下图6-8)中呈现的:

    6.6_比特币地址,余额和其他抽象 - 图1

    图6-8 Alice与Bob咖啡馆的交易

    在交易的左侧,区块链浏览器将Alice的比特币地址显示为“发送者”。其实这个信息本身并不在交易中。当区块链浏览器检索到交易时,它还检索在输入中引用的上一个交易,并从该旧交易中提取第一个输出。在该输出内是一个锁定脚本,将UTXO锁定到Alice的公钥哈希(P2PKH脚本)。区块链浏览器提取公钥哈希,并使用Base58Check编码对其进行编码,以生成和显示表示该公钥的比特币地址。

    同样,在右侧,区块链浏览器显示了两个输出:第一个到Bob的比特币地址,第二个到Alice的比特币地址(作为找零)。为了创建这些比特币地址,区块链浏览器再次从每个输出中提取锁定脚本,将其识别为P2PKH脚本,从中提取公钥哈希。最后,区块链浏览器使用Base58Check重新编码公钥哈希,生成和显示比特币地址。

    如果点击Bob的比特币地址,区块链浏览器将显示Bob的比特币地址的余额,如下图6-9:

    6.6_比特币地址,余额和其他抽象 - 图2

    图6-9 Bob的比特币地址的余额

    区块链浏览器显示了Bob的比特币地址的余额。但是比特币系统中却没有“余额”的概念。这里显示的余额其实是由区块链浏览器按如下方式构建出来的:

    为了构建“总收入”数量,区块链浏览器首先解码比特币地址的Base58Check编码,检索编码在地址内的Bob公钥的160位哈希值。然后,区块链浏览器搜索交易数据库,使用包含Bob公钥哈希的P2PKH锁定脚本查找输出。通过汇总所有输出的值,区块链浏览器就得出了接收总额。

    构建当前余额(显示为“最终余额”)需要更多的工作。区块链浏览器保持一个单独的数据库,即UTXO集,其中保存着当前未被使用的输出。为了维护这个数据库,区块链浏览器必须实时监控比特币网络中出现的未经确认的交易,添加新创建的UTXO,删除已用UTXO。这是一个复杂的过程,依赖于在交易传播过程中跟踪交易,以及与比特币网络保持共识,以确保跟随正确的主链。区块链浏览器有时也会出现未能保持同步,导致其对UTXO集的跟踪扫描不完整或不正确。

    区块链浏览器从UTXO集中,汇总引用Bob的公钥哈希的所有未花费输出的金额,就得出显示给用户的“最终余额”数值。

    为了生成这张画面,得到这两个“余额”,区块链浏览器必须索引和搜索数十、数百甚至数十万的交易。

    总之,通过钱包应用程序,区块链浏览器和其他比特币用户界面呈现给用户的信息通常由更高级别的抽象组成,这些抽象是通过搜索许多不同的交易、检查其内容和操作其中包含的数据而派生出来的。通过呈现这种简单的比特币交易视图(类似于从一个发送者到一个接收者的银行支票),这些应用程序必须抽象出许多潜在的细节。它们主要关注常见的交易类型:每个输入上具有SIGHASH_ALL签名的P2PKH交易。因此,虽然比特币应用程序以易于阅读的方式呈现所有了80%以上的交易,但有时候会被偏离规范的交易困扰。对于包含更复杂的锁定脚本,或不同SIGHASH标志,或多个输入和输出的交易,这种抽象就显得简单和不足。

    每天都有数百个不包含P2PKH输出的交易在区块链上被确认。 区块链浏览器经常向他们发出红色警告信息,表示无法解码地址。以下链接包含最近不能完全解码的“奇怪交易”:https://blockchain.info/strange-transactions.

    正如我们将在下一章中看到的,这些并不一定是奇怪的交易。它们是包含比常见的P2PKH更复杂的锁定脚本的交易。接下来我们将学习如何解码和理解更复杂的脚本及其支持的应用程序。