区块链学习笔记及总结【二】

区块链总述

区块链是比特币的核心技术,在比特币系统里用来记录有序且带有时间戳的交易记录。主要用于防止(double spend)双花攻击和篡改以前的交易记录。

这里需要注意是防止篡改,不是防止更改。实际上区块链某些情况还鼓励更改,比如不合法的区块写入的时候。由于只承认最长合法链,对于那些没有在最长合法链的区块来说,他们就是被修改了。

总的来说,区块链是一个不需要外力的自稳定系统(在大部分算力在好人手里的情况下)。整个区块体现的是绝大部分参与者的意志。当然这绝大部分的标准在不同系统设计里就有不同的标准了,在比特币系统里就是绝大部分的算力。

需要注意的是比特币去中心化后还是不能阻止团体的出现。在虽然团体要操控整个系统还是很难的。要阻止团体出现就要另外设计机制,可能是类似欺诈游戏(一部动漫感觉还不错)里的少数决的机制吧,不过最后好像还是不可避免要组队。

另外比特币追求的公平性不是绝对的公平,而是一种线性的公平。打个比方就是我的算力是你的两倍,那我的收益应该也是你的两倍,而不能又放大效应,就是为了不能出现马太效应—— 富者愈富,穷者愈穷。

当然上面这段主要是我自己主观的看法,不一定对。下面是有关bitcoin的总结

区块链简介

比特币中的每个完整节点都独立存储一个区块链,该区块链仅包含由该节点验证的区块。 当多个节点在其区块链中都有相同的区块时,它们被认为达成了共识,也就是逻辑上的公共账本。 这些节点为维护共识而遵循的验证规则称为共识规则。一个好的去中心化系统要对共识规则有放大作用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2oApcObg-1642693109129)(bitcoin.assets/en-blockchain-overview-16426818607191.svg)]

上图显示了区块链的简化版本。 一个块(block)被收集到一个块的交易数据部分。 每个交易的副本都经过哈希处理,然后对哈希进行配对、哈希、再次配对和再次哈希,直到剩下一个哈希,即默克尔树Merkle tree的默克尔根Merkle root

默克尔根存储在区块头中。 每个块还存储前一个块头的散列,将块链接在一起。 这确保了在不修改记录它的块和所有后续块的情况下不能修改事务。

交易也被链接在一起。 比特币钱包软件给人的印象是,比特币 是从钱包发送到钱包的,但比特币其实是从一个交易转移到另一个交易。 每笔交易都会花费之前在一笔或多笔交易中收到的 比特币,因此一笔交易的输入是前一笔交易的输出。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g4DDmE1f-1642693109130)(https://developer.bitcoin.org/_images/en-transaction-propagation.svg)]

单个交易可以创建多个输出,就像发送到多个地址的情况一样,但是特定交易的每个输出只能在区块链中用作一次输入。 任何后续的引用都是禁止的双重花费——尝试花费相同的 比特币 两次。

输出与 交易标识符 (TXID)是已签名交易的哈希值。

由于特定交易的每个输出只能使用一次,因此区块链中包含的所有交易的输出可以分为 交易输出(UTXO)或已用的交易输出。 为了使付款有效,它只能使用 UTXO 作为输入。

视为 交易费用 创建包含该交易的区块的 例如,在上图中,每笔交易花费的费用比从其组合输入中收到的少 10,000 聪,实际上支付了 10,000 聪的交易费用。

工作量证明

上面的匿名节点共同维护的 网络 ,因此比特币要求每个区块都证明在其创建过程中投入了大量的工作,以确保想要修改过去区块的坏节点必须好节点更努力地工作。想要向区块链添加新区块。

将块链接在一起 使得 在不修改所有后续块的情况下无法修改任何块中包含的事务。 导致了修改特定区块的成本随着添加到区块链中的新区块的个数增加而增加,从而放大了工作量证明的效果。

工作量证明 利用了加密哈希的不可预测性。 一个好的密码散列算法将任意数据转换成一个看似随机的数字。 如果以任何方式修改数据并重新运行哈希,就会产生一个新的看似随机的数字,因此无法修改数据以使哈希数可预测。

为了证明你做了一些额外的工作来创建一个块,你必须创建一个不超过某个值的块头的哈希。 例如,如果最大可能散列值为2255,通过生成小于2255的哈希值,可以证明你最多尝试了两种组合。。

一样具有挑战性时,才会将新区块添加到区块链中 难度 与共识协议预期 每 2,016 个块, 网络 使用存储在每个块头中的时间戳来计算最后 2,016 个块中的第一个和最后一个块生成之间经过的秒数。 理想值是 1,209,600 秒(两周)。

如果生成 2,016 个块的时间少于两周,则预期难度值会按比例增加(最多300%),因此如果以相同的速度检查哈希,则接下来的 2,016 个块应该需要恰好两周时间才能生成。如果生成块的时间超过两周,则预期难度值会因同样的原因成比例地降低(最小 75%)。

块头提供了几个易于修改的字段,例如专用的 nonce 字段,因此获得新的哈希不需要等待新的交易。 此外,仅对 80 字节的区块头进行哈希处理以进行工作量证明,因此在一个区块中包含大量交易数据不会因额外的 I/O 而减慢哈希处理速度,而添加额外的交易数据只需要重新计算默克尔树中的祖先哈希。

区块高度和分叉

任何成功将区块头散列到低于目标阈值的值的比特币矿工都可以将整个区块添加到区块链中(假设该区块是合法的)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uFrkYRK4-1642693109131)(bitcoin.assets/en-blockchain-fork-16426834035843.svg)]

多个区块可以具有相同的区块高度,这在两个或多个矿工大致同时生产一个区块时很常见。 这会在区块链中创建一个明显的 分叉 ,如上图所示。

当矿工在区块链末端同时产生区块时,每个节点单独选择接受哪个区块。 在没有其他考虑的情况下,如下所述,节点通常使用他们看到的第一个块。

两条链同时竞争最长合法链,网络里的节点选择自己认同的最长合法区块往下挖。最终,算力大的一条链胜出,分歧消除。

该区块仅连接到一个竞争的同时开采的区块。 这使得前叉的那一侧比另一侧更坚固。 假设一个分叉只包含有效块,正常的节点总是遵循最困难的链来重新创建和丢弃较短分叉

如果不同的矿工在不同的目的下工作,那么长期分叉是可能的,例如一些矿工努力扩展区块链,同时其他矿工试图通过 51% 的攻击来修改交易历史。

交易数据

每个区块必须包含一个或多个交易。 这些交易中的第一个必须是 coinbase 交易,也称为铸币交易,它应该收集和花费区块奖励(包括区块补贴和该区块中包含的交易支付的任何交易费用)。

coinbase 交易的 UTXO 有一个特殊条件,即它不能被花费(用作输入)至少 100 个区块。 这暂时阻止了矿工从一个块中花费交易费用和块奖励,该块在块链分叉后可能会被回滚(因此 coinbase 交易被破坏)。

区块不需要包含任何coinbase基交易,但矿工几乎总是会包含额外的交易以收取交易费用。

所有交易,包括 coinbase 交易,都以二进制原始交易格式编码成块。

对原始交易格式进行哈希处理以创建交易标识符 (txid)。 从这些 txid 中, 默克尔树通过将每个 txid 与另一个 txid 配对然后将它们散列在一起来构建 如果有奇数个 txid,则没有兄弟节点的 txid 将使用其自身的副本进行散列。

生成的散列本身每个都与另一个散列配对并一起散列。 任何没有兄弟节点的哈希都与自身进行哈希。 重复该过程,直到只剩下一个哈希,即默克尔根。

例如,如果交易只是加入(而不是散列),五交易默克尔树看起来像下面的文本图:

       ABCDEEEE .......Merkle root
      /        \
   ABCD        EEEE
  /    \      /
 AB    CD    EE .......E is paired with itself
/  \  /  \  /
A  B  C  D  E .........Transactions

merkle 树允许客户端通过从块头获取 merkle 根和来自完整对等点的中间哈希列表来验证交易是否包含在块中。 完整的对等点不需要被信任:伪造区块头的成本很高,并且中间哈希不能被伪造,否则验证将失败。

例如,要验证交易 D 是否已添加到块中,SPV 客户端除了 merkle 根外,只需要 C、AB 和 EEEE 哈希的副本; 客户不需要了解任何其他交易。 如果这个区块中的五个交易都处于最大大小,下载整个区块将需要超过 500,000 个字节——但下载三个哈希加上区块头只需要 140 个字节。

共识规则变更

为了保持共识,所有全节点都使用相同的共识规则来验证区块。 但是,有时会更改共识规则以引入新功能。 当新规则实施时,可能会有一段时间非升级节点遵循旧规则而升级节点遵循新规则,从而产生两种可能的情况

  1. 遵循新共识规则的块被升级节点接受,但被未升级节点拒绝。 例如,在一个区块中使用了一个新的交易特征:升级的节点理解该特征并接受它,但未升级的节点拒绝它,因为它违反了旧规则。
  2. 违反新共识规则的区块被升级节点拒绝,但被未升级节点接受。 例如,在一个区块中使用了滥用交易功能:升级节点拒绝它,因为它违反了新规则,但未升级节点接受它,因为它遵循旧规则。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DZ0865Rr-1642693109132)(bitcoin.assets/en-hard-fork-16426847269895.svg)]

在第一种情况下,被未升级节点拒绝,从那些未升级节点获取区块链数据的挖掘软件拒绝与从升级节点获取数据的挖掘软件构建在同一条链上。 这会创建永久不同的链——一个用于未升级的节点,一个用于升级的节点——称为硬分叉。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CqeoWhCv-1642693109134)(https://developer.bitcoin.org/_images/en-soft-fork.svg)]

在第二种情况下,升级节点拒绝,如果升级节点控制大部分算力,则可以防止区块链永久分叉。 这是因为,在这种情况下,未升级节点将接受与升级节点相同的所有区块作为有效区块,因此升级节点挖的链下聚集了更多算力,非升级节点最终将接受升级节点挖出的最长的链为最长合法链。 这称为软分叉。

交易

每笔交易都由几个部分构成,这些部分既可以实现简单的直接支付,也可以实现复杂的交易。

为简单起见,假设 coinbase 交易不存在。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-00ddyeSP-1642693109136)(bitcoin.assets/en-tx-overview-16426849841618.svg)]

上图显示了比特币交易的主要部分。 每笔交易至少有一个输入和一个输出。 每个 输入花费支付给先前输出的 比特币。 每个输出作为未使用的交易输出 (UTXO) 等待之后的输入花费它。 当你的比特币钱包告诉你有 10,000 比特币余额时,这实际上意味着你有 10,000 比特币 在一个或多个 UTXO 中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NLAmQDVU-1642693109138)(bitcoin.assets/en-tx-overview-spending.svg)]

输出具有一个所在事务位置的索引号,同时还有一个以 satoshis 为单位的金额,它的支付条件由pubkey script脚本给出。 任何能够满足该 脚本条件的人都可以花费这个输出里的比特币。

输入使用交易标识符(txid)和 输出索引号(通常称为输出向量的“vout”)来标识要花费的特定输出。 它还有一个签名脚本signature script,用来和匹配pubkey script

下图通过显示 Alice 用于向 Bob 发送交易以及 Bob 稍后用于花费该交易的工作流程来帮助说明如何使用这些功能。 Alice 和 Bob 都将使用最常见的标准 Pay-To-Public-Key-Hash (P2PKH) 交易类型。 P2PKH 让 Alice 将 satoshis 花费到一个典型的比特币地址,然后让 Bob 使用一个简单的加密 密钥对 。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0nQ2pyYu-1642693109139)(bitcoin.assets/en-creating-p2pkh-output.svg)]

Bob 必须首先生成一个私钥/ 公钥对 ,然后 Alice 才能创建第一笔交易。 比特币使用椭圆曲线数字签名算法 ( ECDSA ) 和 secp256k1 曲线; secp256k1 私钥 是 256 位随机数据。 该数据的副本被确定性地转换为 secp256k1 公钥。 因为以后可以可靠地重复转换,所以不需要存储公钥。

然后对公钥(pubkey)进行加密散列。 这个公钥哈希也可以在以后可靠地重复,因此也不需要存储。 散列缩短和混淆了公钥,使手动转录更容易,并为防止意外问题提供安全性。

Bob 将公钥散列提供给 Alice作为收款地址。这些地址是 base58 编码的字符串,包含地址版本号、散列和校验和。 该地址可以通过任何介质传输,并且可以进一步编码为另一种格式,例如包含bitcoin:url的二维码。

一旦 Alice 获得地址并将其解码回标准哈希,她就可以创建第一笔交易。 她创建了一个标准的 P2PKH 交易输出,其中包含指令,如果任何人能够证明他们控制与 Bob 的散列公钥对应的私钥,就可以使用该输出。

Alice 广播交易并将其添加到区块链中。 bitcoin网络把它作为一个未支用的交易输出(UTXO)存起来。

一段时间后,当 Bob 决定花费 UTXO 时,他必须创建一个输入来引用 Alice 创建交易的哈希 (txid)用来说明比特币的来源,以及她使用的索引号 。 然后他必须创建一个 签名脚本 ——一组满足 Alice 在前一个输出的公钥脚本中放置的条件的数据参数。

公钥脚本和签名脚本将 secp256k1 公钥和签名与条件逻辑相结合,创建可编程的授权机制。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qUgJI9Qq-1642693109139)(bitcoin.assets/en-unlocking-p2pkh-output.svg)]
对于 P2PKH 样式的输出,Bob 的签名脚本将包含以下两条数据:

  1. 他的完整(未散列)公钥,因此 pubkey 脚本可以检查它的散列值是否与 Alice 提供的 pubkey 散列值相同。
  2. secp256k1 签名 通过使用 ECDSA 加密公式将某些交易数据(如下所述)与 Bob 的私钥组合 这让 pubkey 脚本验证 Bob 拥有创建公钥的私钥。

Bob 的 secp256k1 签名不仅证明 Bob 控制着他的私钥; 它还使他的交易中的非签名脚本部分是无法篡改的,因此 Bob 可以通过 p2p网络 传播

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q5PlwTIN-1642693109140)(bitcoin.assets/en-signing-output-to-spend.svg)]

如上图所示,Bob 签名的数据包括前一笔交易的 txid 和 输出索引、前一笔输出的 pubkey 脚本、Bob 创建的让下一个接收者花费这笔交易的输出的 pubkey 脚本,以及要兑换的 satoshis 数量。 本质上,除了签名脚本之外,整个交易都是经过签名的,其中包含完整的公钥和 secp256k1 签名。

在将他的签名和公钥放入签名脚本后,Bob 通过 点对点网络 。 每个节点和矿工在进一步广播交易或尝试将其包含在新的交易块中都会独立验证交易。

P2PKH 脚本验证

验证过程需要评估签名脚本和公钥脚本。 在 P2PKH 输出中,pubkey 脚本是:

OP_DUP OP_HASH160 <PubkeyHash> OP_EQUALVERIFY OP_CHECKSIG

花费者的签名脚本被评估并作为脚本开头的前缀。 在 P2PKH 交易中,签名脚本包含 secp256k1 签名 (sig) 和完整公钥 (pubkey),创建以下串联:

<Sig> <PubKey> OP_DUP OP_HASH160 <PubkeyHash> OP_EQUALVERIFY OP_CHECKSIG

脚本语言是一种 类似 Forth 的 基于堆栈的语言,故意设计为无状态且不是图灵完备的。 无状态确保一旦将交易添加到区块链中,就没有条件使其永久不可花费。 图灵不完备性(特别是缺少循环和goto)使脚本语言更不灵活且更可预测,从而大大简化了安全模型。

为了测试交易是否有效,签名脚本和公钥脚本操作一次执行一项,从 Bob 的签名脚本开始,一直到 Alice 的公钥脚本结束。 下图显示了标准 P2PKH pubkey 脚本的运行过程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wXIJz5oK-1642693109142)(bitcoin.assets/en-p2pkh-stack.svg)]

  • 签名(来自 Bob 的签名脚本)被push到一个空堆栈。 因为它只是数据,所以除了将它添加到堆栈之外什么都没有做。 公钥(也来自签名脚本)被推送到签名之上。

  • 从 Alice 的 pubkey 脚本中,OP_DUP操作被执行。 OP_DUP将当前位于其顶部的数据的副本推送到堆栈中——在这种情况下,创建 Bob 提供的公钥的副本。

  • 接下来执行的操作OP_HASH160将当前位于其顶部的数据的哈希值(在本例中为 Bob 的公钥)压入堆栈。

  • 然后 Alice 的 pubkey 脚本推送 Bob 在第一笔交易中为她提供的 pubkey 散列。 此时,堆栈顶部有两个 Bob 的 pubkey 散列副本。

  • Alice 的 pubkey 脚本执行OP_EQUALVERIFYOP_EQUALVERIFY相当于执行 OP_EQUAL后跟 OP_VERIFY

    OP_EQUA 检查堆栈顶部的两个值; 在这种情况下,它检查从 Bob 提供的完整公钥生成的公钥哈希是否等于 Alice 在创建交易 #1 时提供的公钥哈希。 OP_EQUAL 弹出(从堆栈顶部删除)它比较的两个值,并用比较结果替换它们:falsetrue

    OP_VERIFY检查堆栈顶部的值。 如果值为 false ,则立即终止并且交易验证失败。 否则,它将 true从堆栈中弹出。

  • 最后,Alice 的公钥脚本执行 OP_CHECKSIG,它检查 Bob 提供的签名与他也提供的现已验证的公钥。 如果签名与公钥匹配并且是使用需要签名的所有数据生成的, OP_CHECKSIG会将值 true 入堆栈顶部。

如果 false 不在堆栈顶部,则交易有效。

P2SH 脚本

Pubkey 脚本需要由对脚本的作用不感兴趣的消费者创建的。

为了这个问题, pay-to-script-hash( P2SH) 被发明,目的是让花钱的人创建一个pubkey脚本,其中包含第二个脚本的散列,即赎回脚本(Redeem script)。

下图所示的基本 P2SH 工作流程看起来与 P2PKH 工作流程几乎相同。 Bob 使用他想要的任何脚本创建赎回脚本,对赎回脚本进行散列,并将赎回脚本散列提供给 Alice。 Alice 创建了一个 P2SH 样式的输出,其中包含 Bob 的赎回脚本哈希。

当 Bob 想要花费输出时,他会在签名脚本中提供他的签名以及完整的(序列化的)赎回脚本。确保赎回脚本的散列和signatrue里的hash一样,然后它会像处理pubkey脚本一样处理赎回脚本,如果赎回脚本没有返回 false,则让 Bob 花费输出。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F4DkVB7J-1642693109143)(https://developer.bitcoin.org/_images/en-unlocking-p2sh-output.svg)]

赎回脚本的哈希与公钥哈希具有相同的属性,因此只需稍作改动即可将其转换为标准比特币地址格式,以将其与标准地址区分开来。 这使得收集 P2SH 样式地址与收集 P2PKH 样式地址一样简单。 散列仍然会隐藏赎回脚本中的公钥,因此 P2SH 脚本与 P2PKH 公钥散列一样安全。

标准交易

从 Bitcoin Core 0.9 开始,标准的 pubkey 脚本类型是

  • Pay To Public Key Hash (P2PKH)
  • Pay To Script Hash (P2SH)
  • Multisig
  • Pubkey
  • Null Data

P2PKH

P2PKH 是最常见的公钥脚本形式,用于将交易发送到一个或多个比特币地址。

Pubkey script: OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Signature script: <sig> <pubkey>

P2SH

P2SH 用于将交易发送到脚本哈希。 每个标准公钥脚本都可以用作 P2SH 兑换脚本,不包括 P2SH 本身。 从 Bitcoin Core 0.9.2 开始,P2SH 交易可以包含任何有效的兑换脚本,使 P2SH 标准更加灵活,并允许对许多新颖和复杂的交易类型进行试验。 P2SH 最常见的用途是标准的多重签名公钥脚本,其次是 开放资产协议

用于 P2SH 的另一个常见的redeemScript 是将文本数据存储在区块链上。

Pubkey script: OP_HASH160 <Hash160(redeemScript)> OP_EQUAL
Signature script: <sig> [sig] [sig...] <redeemScript>

只要脚本哈希与赎回脚本匹配,此脚本组合对于没有P2SH 功能的旧节点看起来就完美无缺。 但是新节点将对赎回脚本进行进一步的验证。 他们将从签名脚本中提取赎回脚本,对其进行解码,并且执行它。因此,要赎回 P2SH 交易,除了正确的赎回脚本外,支出者还必须提供有效的签名或答案。

最后一步类似于 P2PKH 或 P2Multisig 脚本中的验证步骤,其中签名脚本的初始部分<sig> [sig] [sig..]充当 P2PKH/P2Multisig 中的“签名脚本”,而赎回脚本充当“公钥脚本”。

Multisig

虽然已经有 P2SH 用于多重签名,但此基本脚本可用于在使用 UTXO 之前需要多个签名。

在称为 m-of-n 的多重签名公钥脚本中, m最小 必须匹配公钥数, n数量 提供的公钥数。

由于原始比特币实现中的一个差错,OP_CHECKMULTISIG从堆栈中消耗的值比 指示的值多一个 m ,因此 中的 列表 secp256k1 签名脚本 签名 必须以一个额外的 OP_0

签名脚本必须以与相应公钥出现在 pubkey 脚本或兑换脚本中的顺序相同的顺序提供签名。 详见 “OP_CHECKMULTISIG” 中的描述。

Pubkey script: <m> <A pubkey> [B pubkey] [C pubkey...] <n> OP_CHECKMULTISIG
Signature script: OP_0 <A sig> [B sig] [C sig...]

虽然它不是一个单独的交易类型,但这是一个具有 2-of-3 的 P2SH 多重签名:

Pubkey script: OP_HASH160 <Hash160(redeemScript)> OP_EQUAL
Redeem script: <OP_2> <A pubkey> <B pubkey> <C pubkey> <OP_3> OP_CHECKMULTISIG
Signature script: OP_0 <A sig> <C sig> <redeemScript>

Pubkey

公钥输出是 P2PKH 公钥脚本的简化形式,但它们不如 P2PKH 安全,因此它们通常不再用于新交易。

Pubkey script: <pubkey> OP_CHECKSIG
Signature script: <sig>

Null Data

Null Data 在 默认中继和挖掘的 交易类型 Bitcoin Core 0.9.0 及更高版本中 将任意数据添加到不可使用的 pubkey 脚本中,完整节点不必将其存储在其 UTXO 数据库中。 最好使用Null Data事务而不是其他事务,因为其他事务不能被自动删除;

Pubkey Script: OP_RETURN <0 to 40 bytes of data>(Null data scripts cannot be spent, so there's no signature script.)

锁定时间和序列号

所有签名哈希类型签名的一件事是交易的 locktime 。 (在比特币核心源代码中称为 nLockTime。)锁定时间表示可以将交易添加到区块链的最早时间。

Locktime 允许签名者创建仅在未来生效的时间锁定交易,让签名者有机会改变主意。

如果任何签名者改变主意,他们可以创建一个新的非锁定时间交易。 新交易将使用与锁定与时间交易的输入相同的输入。 如果在时间锁过期之前将新交易添加到区块链中,因为输入相同,这会使锁定时间交易与新交易冲突,从而达到取消交易的目的。

交易费用和

交易根据签名交易的总字节大小支付费用。 每字节的费用是根据当前对开采区块的空间需求计算的,费用随着需求的增加而上涨。交易费用是给比特币矿工的, 因此最终由每个矿工选择他们将接受的最低交易费用。

由于每笔交易都会花费未使用的交易输出 (UTXO),并且由于一个 UTXO 只能使用一次,所以UTXO 的全部价值必须全部作为交易费用花费或提供给矿工。 很少有人会拥有与他们想要支付的金额完全匹配的 UTXO,因此大多数交易都包含有找零输出。

理论上可以重用与 UTXO 中使用的相同的 P2PKH 公钥哈希或 P2SH 脚本哈希,但是出于安全性,通常更改输出来发送到新的 P2PKH 或 P2SH 地址。

避免密钥重用

在交易中,花费者和接收者各自向对方透露交易中使用的所有公钥或地址。 这允许任何一个人使用公共区块链来跟踪涉及另一个人的相同公钥或地址的过去和未来的交易。

如果经常重复使用相同的公钥,就像人们使用比特币地址(散列公钥)作为静态支付地址时发生的那样,其他人可以轻松跟踪该人的接收和消费习惯,包括他们在已知地址中控制了多少 比特币。

更好的方法是,在接受付款或创建零钱输出时使用新的公钥,可以与稍后讨论的其他技术(例如 CoinJoin 或 merge avoidance),从而使单独使用区块链来可靠地跟踪用户的方式变得极其困难

交易延展性(Transaction Malleability)

交易延展性为拒绝服务攻击敞开了大门。 签名脚本包含 secp256k1 签名,该签名无法自行签名,从而允许攻击者对交易进行非功能性修改而不会使其无效。 例如,攻击者可以将一些数据添加到签名脚本中,这些数据将在处理之前的公钥脚本之前被删除(保证可以匹配之前的公钥脚本)。

尽管这些修改是非功能性的——因此它们不会改变交易使用的输入或支付的输出——但它们会改变交易的计算哈希值。 由于每个交易都使用哈希作为交易标识符(txid)链接到先前的交易,因此修改后的交易将不会具有其创建者所期望的 txid。

对于大多数旨在立即添加到区块链的比特币交易来说,这不是问题。 但是,如果在将交易添加到区块链之前花费了交易的输出,这确实会成为一个问题。

比特币开发人员一直在努力降低标准交易类型之间的交易延展性,这些努力的一个成果是 BIP 141:隔离见证 ,它由比特币核心支持并于 2017 年 8 月激活。当不使用隔离见证时,新交易不应该依赖于尚未添加到区块链中的先前交易,尤其是在大量 satoshis 处于危险之中的情况下。

交易延展性也会影响支付跟踪。 Bitcoin Core 的 RPC 接口让您可以通过交易的 txid 跟踪交易——但如果由于交易被修改而导致 txid 发生变化,则交易可能会从网络消失。

交易应由其作为输入花费的交易输出 (UTXO) 进行跟踪,因为在不使交易无效的情况下无法更改它们。

如果交易似乎确实从 网络中消失并且需要重新发出,则以让丢失的交易无效的方式重新发出它(即发一个冲突的交易)。一种始终有效的方法是确保重新发出的付款花费与丢失的交易有相同输入。

合约

合约是使用去中心化比特币系统来执行金融协议的交易。 比特币合约通常可以被设计成最大限度地减少对外部代理的依赖,例如法院系统,这大大降低了在金融交易中与未知实体打交道的风险。

托管和仲裁

客户 Charlie想从商人Bob那里购买产品,但他们都不信任对方,因此他们使用合同来帮助确保 Charlie得到他的商品,而Bob得到他的付款。

一个简单的合约可以说 Charlie 将花费 satoshis 到一个输出上,只有在 Charlie 和 Bob 都签署了花费它的输入时才能花费这个输出。 这意味着除非 Charlie得到他的商品,否则Bob不会得到报酬,但 Charlie不能得到商品并保留他的付款。

如果出现争议,这个简单的合约没有多大帮助,因此 Bob 和 Charlie 寻求 Alice的帮助来创建一个 托管合约 。 Charlie将他的 satoshis 用于输出,只有三个人中有两个人签署输入才能使用。 现在,如果一切正常,Charlie 可以向 Bob 付款,如果出现问题,Bob 可以 退还 Charlie 的钱,或者如果有争议,Alice 可以仲裁并决定谁应该获得 satoshis。

为了创建多重签名 ( multisig ) 输出,他们每个人都给其他人一个公钥。 然后 Bob 创建以下 P2SH 多重签名 兑换脚本:

OP_2 [A's pubkey] [B's pubkey] [C's pubkey] OP_3 OP_CHECKMULTISIG

(未显示将公钥压入堆栈的操作码。)

OP_2OP_3将实际数字 2 和 3 压入堆栈。 OP_2指定需要2个签名才能签名; OP_3指定提供 3 个公钥(未散列)。 这是一个 2-of-3 多重签名公钥脚本,更一般地称为 m-of-n 公钥脚本(其中 m 是所需的 最小 匹配签名, n数量 提供的公钥

Bob 将赎回脚本交给 Charlie,Charlie 检查以确保包括他的公钥和 Alice 的公钥。 然后他对赎回脚本进行哈希处理以创建一个 P2SH 赎回脚本并将 satoshis 支付给它。 Bob 看到付款被添加到区块链中并运送商品。

不幸的是,商品在运输过程中会受到轻微损坏。 Charlie 想要全额 退款,但 Bob 认为 10% 的 退款就足够了。 他们求助于Alice来解决这个问题。 Alice 要求 Charlie 提供照片证据以及 Bob 创建并由 Charlie 检查的赎回脚本的副本。

在查看证据后,Alice 认为 40% 的退款就足够了,因此她创建并签署了一个包含两个输出的交易,一个将 60% 的 satoshis 用于 Bob 的公钥,另一个将剩余的 40% 用于 Charlie 的公钥.

在签名脚本中,Alice 将她的签名和 Bob 创建的未散列序列化赎回脚本的副本放入。 她将不完整交易的副本提供给 Bob 和 Charlie。 他们中的任何一个都可以通过添加他的签名来完成它,以创建以下签名脚本:

OP_0 [A's signature] [B's or C's signature] [serialized redeem script]

当交易被广播到 网络 时,每个节点检查签名脚本与 Charlie之前支付的 P2SH 输出,确保赎回脚本与之前提供的赎回脚本哈希匹配。 然后执行赎回脚本,将两个签名用作输入数据。 假设赎回脚本通过验证,两个交易输出在 Bob 和 Charlie 的钱包中显示为可消费余额。

但是,如果 Alice 创建并签署了一项他们都不同意的交易,例如将所有 satoshis 都花给自己,Bob 和 Charlie 可以找到一个新的仲裁员并签署一项交易,将 satoshis 用于另一个 2-of-3 多重签名赎回脚本哈希,这个包括来自第二个仲裁员的公钥。 这意味着 Bob 和 Charlie 永远不必担心他们的仲裁员会窃取他们的钱。

资源: BitRated 在 GNU AGPL 许可的网站上使用 HTML/JavaScript 提供多重签名仲裁服务接口。

小额支付渠道

Alice 还兼职为 Bob 主持论坛帖子。 每次有人在 Bob 繁忙的论坛上发帖时,Alice 都会浏览该帖子以确保它不是冒犯性的或垃圾邮件。 Bob 经常忘记付钱给她,所以 Alice 要求在她批准或拒绝每个帖子后立即付款。 Bob 说他不能这样做,因为数百笔小额支付将花费他数千聪的交易费用,因此 Alice 建议他们使用 小额支付渠道

Bob 向 Alice 索要她的公钥,然后创建了两个交易。 第一笔交易向 P2SH 输出支付 100 毫比特币,其 2-of-2 多重签名赎回脚本需要 Alice 和 Bob 的签名。 这是债券交易。 广播此交易将使 Alice 持有毫比特币作为人质,因此 Bob 暂时将此交易保密并创建第二个交易。

在锁定时间强制执行 24 小时延迟后,第二笔交易将第一笔交易的所有毫比特币(减去交易费用)花还给 Bob。 这是 退款 交易。 Bob 不能自己对 退款 交易进行签名,所以他将其交给 Alice 进行签名,如下图所示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fUcsv8Zc-1642693109144)(bitcoin.assets/en-micropayment-channel.svg)]

Alice 检查 退款 交易的锁定时间是否为未来 24 小时,对其进行签名,并将其副本返回给 Bob。 然后她向 Bob 询问债券交易,并检查 退款 交易是否花费了债券交易的输出。 她现在可以将债券交易广播到 网络 ,以确保 Bob 必须等待时间锁定到期,然后才能进一步花费他的毫比特币。 到目前为止,Bob 实际上并没有花任何钱,除了可能的小额交易费用,他将能够 退款 在 24 小时内 退款

现在,当 Alice 做了一些价值 1 毫比特币的工作时,她要求 Bob 创建并签署一个新版本的 退款 交易。 交易的第二个版本花费 1 毫比特币给 Alice,另外 99 个还给 Bob; 它没有锁定时间,因此Alice可以随时签名并使用它。 (但她不会立即这样做。)

Alice和Bob重复这些工作和支付步骤,直到Alice完成当天的工作,或者直到时间锁定即将到期。 Alice签署了 退款 交易的最终版本并将其广播,支付给她自己并将剩余的余额退还给Bob。 第二天,当 Alice 开始工作时,他们创建了一个新的 小额支付通道

如果 Alice 在时间锁到期之前未能广播一个版本的 退款 交易,Bob 可以广播第一个版本并获得全额 退款 。 这就是 小额支付渠道 最适合小额支付的原因之一——如果 Alice 的互联网服务在接近时间锁定到期时中断了几个小时,她可能会被骗取付款。

交易的延展性,在上面的交易部分讨论,是限制 小额支付渠道 。 如果有人使用交易延展性来打破两笔交易之间的联系,即使她没有做任何工作,Alice也可以扣押Bob的 100 毫比特币。

对于较大的支付,比特币交易费用占总交易价值的百分比非常低,因此通过立即广播的单独交易来保护支付更有意义。

资源: bitcoinj 一套 完整的小额支付功能、一个示例实现和 一个教程 所有这些都在 Apache 许可下。

CoinJoin

Alice担心她的隐私。 她知道每笔交易都会添加到公共区块链中,因此当 Bob 和 Charlie 向她付款时,他们每个人都可以轻松追踪这些 satoshis,以了解她支付的比特币地址、支付了多少,以及她可能还剩下多少 satoshis。

Alice 不是罪犯,她只是想合理地否认她在哪里花费了她的 satoshis 以及她还剩下多少,所以她在她的计算机上启动了 Tor 匿名服务,并以“AnonGirl”的身份登录 IRC 聊天室。

聊天室里还有“Nemo”和“Neminem”。 他们集体同意在彼此之间转移 satoshis,因此除了他们之外没有人可以可靠地确定谁控制了哪些 satoshis。 但是他们面临着一个两难的境地:谁先将他们的 satoshis 转移给另外两个化名的人之一? 如下图所示的 CoinJoin 式合约使这个决定变得容易:他们创建一个单一的交易,同时完成所有支出,确保他们中的任何一个都不能窃取其他人的 satoshis。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nEIfgD3o-1642693109145)(https://developer.bitcoin.org/_images/en-coinjoin.svg)]

每个贡献者都会查看他们的未使用交易输出 (UTXO) 集合,寻找他们可以花费的 100 毫比特币。 然后,他们各自生成一个全新的公钥,并将 UTXO 详细信息和公钥哈希提供给协调者。 在这种情况下,主持人是 AnonGirl; 她创建了一个交易,将每个 UTXO 用于三个相同大小的输出。 一个输出用于每个贡献者的公钥哈希。

AnonGirl 然后使用 SIGHASH_ALL确保没有人可以更改输入或输出详细信息。 她将部分签名的交易交给 Nemo,Nemo 以同样的方式签署他的输入并将其传递给 Neminem,Neminem 也以同样的方式签署。 Neminem 然后将交易广播到比特币 点对点网络 ,将所有毫比特币混合在一个交易中。

正如您在插图中看到的那样,除了 AnonGirl、Nemo 和 Neminem 之外,任何人都无法自信地确定谁收到了哪些输出,因此他们每个人都可以合理地推诿他们的输出。

现在,当 Bob 或 Charlie 试图通过区块链跟踪 Alice 的交易时,他们也会看到 Nemo 和 Neminem 进行的交易。 如果 Alice 再做几个 CoinJoin,Bob 和 Charlie 可能不得不猜测数十或数百人进行的哪些交易实际上是由 Alice 进行的。

Alice 的 satoshis 的完整历史仍在区块链中,因此有决心的调查员可以与加入 AnonGirl Coin 的人交谈,以找出她的 satoshis 的最终来源,并可能将 AnonGirl 揭示为 Alice。 但是对于任何随便浏览区块链历史的人,Alice 获得了合理的否认。

上述 CoinJoin 技术需要参与者支付少量 satoshis 来支付交易费用。 另一种技术,购买者 CoinJoin,实际上可以节省他们的聪并同时改善他们的隐私。

AnonGirl 在 IRC 聊天室等待,直到她想购买。 她宣布她打算花费 satoshis 并等到其他人想要购买,可能来自不同的商人。 然后他们以与以前相同的方式组合输入,但将输出设置为单独的商家地址,因此没有人能够仅从区块链历史中找出其中一个人从商家那里购买了什么。

由于无论如何他们都必须支付交易费用才能进行购买,因此 AnonGirl 和她的共同消费者无需支付任何额外费用——但因为他们通过组合多笔交易减少了开销,节省了字节,他们可能能够支付较小的总交易费用,为每个人节省了少量的聪。

当前工作实施: 截至今天,2018 年, JoinMarket Wasabi Wallet 是比特币的可操作 CoinJoin 实施。

JoinMarket 风格的 CoinJoins 与上述方案的不同之处在于将参与者分为两部分:做市商和做市商。 做市商正在将他们的 CoinJoin 意向发布到 IRC 房间,并等待市场接受者接受他们的报价。 当接受者出现时,它会选择一组制造商并与他们创建共享交易,同时支付少量费用。 与上述方案不同,这是自动发生的。

Wasabi Wallet 风格的 CoinJoins 称为 Chaumian CoinJoins。 它使用 CoinJoin 协调器,各种对等方可以在其中注册。 当预定数量的参与者注册时,CoinJoin-round 开始。在该方案中,Chaumian 盲签名用于防止协调者和对等方了解哪些输出对应于哪些输入。 Chaumian CoinJoin 的一个示例是以下交易: 8fee07b90f26e85e22e87da13e1618cd9eeaf98f3f3774273c9307cd40ff98e8

猜你喜欢

转载自blog.csdn.net/qq_45256489/article/details/122612347
今日推荐