一笔比特币交易的本质是数据结构交易被验证为无效

资讯 7个月前 manoon
0

比特币交易比特币系统中最重要的部分。根据比特币系统的设计原则,系统的任何其他部分都是为了保证比特币交易能够在比特币网络中产生、传播和验证,并最终加入到全球比特币交易账本(Bitcoin Blockchain)中。比特币交易的本质是数据结构,这些数据结构包含了比特币交易参与者的价值转移信息。比特币区块链是一个全球复式账本。每笔比特币交易都是比特币区块链上的公共记录。

比特币交易在比特币网络中的传播

一旦比特币交易被发送到连接到比特币网络的任何节点,该交易将被该节点验证。如果交易被验证为有效,则该节点会将交易传播给连接到该节点的其他节点;同时,交易发起方会收到交易有效并被接受的返回消息。如果交易被验证为无效,节点将拒绝接受交易,同时向交易发起者返回交易被拒绝的消息。

比特币网络是一个点对点网络,这意味着每个比特币节点都连接到其他一些比特币节点(这些其他节点是在点对点协议启动时发现的)。整个比特币网络形成了一个松散连接的“蜘蛛网”,没有固定的拓扑结构,也没有任何结构——这使得所有节点的地位都是平等的。比特币交易相关信息(包括交易和区块)从每个节点传播到与其相连的其他节点。一个刚刚被验证并传递给比特币网络中任何节点的交易,会被发送到三到四个相邻节点,每个相邻节点都会将交易发送给三到四个邻居。节点。以此类推,在几秒钟内,有效交易将像指数传播的波一样在网络中传播,

交易结构

比特币交易是一种包含输入输出值的数据结构。该数据结构包含用于将资金从初始点(输入值)转移到目标地址(输出值)的代码信息。比特币交易的输入输出值与账号或身份信息无关。它们应该理解为被特定秘密信息锁定的一定数量的比特币。只有所有者或知道秘密信息的人才能解锁。交易的数据结构如下:

一笔比特币交易的本质是数据结构交易被验证为无效

下面详细介绍交易数据结构中的输入和输出。

交易输出

交易输出是一个UTXO比特币交易过程,一个UTXO主要包括

一笔比特币交易的本质是数据结构交易被验证为无效

锁定脚本会将输出锁定到特定的比特币地址,从而将一定数量的比特币的所有权转移给新的所有者。

具体输出结构如下:

一笔比特币交易的本质是数据结构交易被验证为无效

您可以使用 blockchain.info API 在特定地址查找 UTXO:

一笔比特币交易的本质是数据结构交易被验证为无效

上述查询中,地址变量的意思是查询与该地址相关的UTXO。在查询结果中,uspent_outputs 对应一个 UTXO 数组。可以看出这个地址只有一个相关的UTXO。结果中重要字段的含义:

交易输入

假设有如下交易,需要从一个地址向另一个地址转账0.5BTC:

# -*- coding:utf-8 -*-
# 使用贪心算法从UTXO列表中选择输出。
from sys import argv
class OutputInfo:
   def __init__(self, tx_hash, tx_index, value):
       self.tx_hash = tx_hash
       self.tx_index = tx_index
       self.value = value
   def __repr__(self):
       return "<%s:%s with %s Satoshis>" % (self.tx_hash, self.tx_index,  self.value)
# 为了发送,从未花费的输出列表中选出最优输出。
# 返回输出列表,并且把其他的改动发送到改变地址。
def select_outputs_greedy(unspent, min_value):
   # 如果是空的话认为是失败了。
   if not unspent: return None
   # 分割成两个列表。
   lessers = [utxo for utxo in unspent if utxo.value < min_value]
   greaters = [utxo for utxo in unspent if utxo.value >= min_value]
   key_func = lambda utxo: utxo.value
   if greaters:
       # 非空。寻找最小的greater。
       min_greater = min(greaters)
       change = min_greater.value - min_value
       return [min_greater], change
   # 没有找到greaters。重新尝试若干更小的。
   # 从大到小排序。我们需要尽可能地使用最小的输入量。
   lessers.sort(key=key_func, reverse=True)
   result = []
   accum = 0
   for utxo in lessers:
       result.append(utxo)
       accum += utxo.value
       if accum >= min_value:
           change = accum - min_value
           return result, "Change: %d Satoshis" % change
   # 没有找到。
   return None, 0
def main():
   unspent = [
       OutputInfo("ebadfaa92f1fd29e2fe296eda702c48bd11ffd52313e986e99ddad9084062167", 1,  8000000),
       OutputInfo("6596fd070679de96e405d52b51b8e1d644029108ec4cbfe451454486796a1ecf", 0, 16050000),
       OutputInfo("b2affea89ff82557c60d635a2a3137b8f88f12ecec85082f7d0a1f82ee203ac4", 0,  10000000),
       OutputInfo("7dbc497969c7475e45d952c4a872e213fb15d45e5cd3473c386a71a1b0c136a1", 0, 25000000),
       OutputInfo("55ea01bd7e9afd3d3ab9790199e777d62a0709cf0725e80a7350fdb22d7b8ec6", 17, 5470541),
       OutputInfo("12b6a7934c1df821945ee9ee3b3326d07ca7a65fd6416ea44ce8c3db0c078c64", 0, 10000000),
       OutputInfo("7f42eda67921ee92eae5f79bd37c68c9cb859b899ce70dba68c48338857b7818", 0, 16100000),
   ]
   if len(argv) > 1:
       target = long(argv[1])
   else:
       target = 55000000
   print "For transaction amount %d Satoshis (%f bitcoin) use: " % (target, target/ 10.0**8)
   print select_outputs_greedy(unspent, target)
if __name__ == "__main__":
   main()

在上面的代码中,模拟了一个比特币地址对应的UTXO列表。目标代表要输出的比特币的大小。select_outputs_greedy 方法使用贪心算法从这个列表中获取比特币的目标大小。

运行这段代码的结果是:

([<7dbc497969c7475e45d952c4a872e213fb15d45e5cd3473c386a71a1b0c136a1:0 with 25000000 Satoshis>, 
<7f42eda67921ee92eae5f79bd37c68c9cb859b899ce70dba68c48338857b7818:0 with 16100000 Satoshis>, 
<6596fd070679de96e405d52b51b8e1d644029108ec4cbfe451454486796a1ecf:0 with 16050000 Satoshis>],
'Change: 2150000 Satoshis') 

输出集包含三个UTXO,总值是0.5715BTC,我们的目标是0.55BTC,所以输出也有一个Change:0.0215BTC,表示change。

当本次模拟交易完成后,将输出中的三个UTXO从数据库中删除,生成两个新的UTXO:一个是目标大小0.55BTC,另一个是变化0.0215BTC . 因此,在整个交易中,未花费中满足条件的三个UTXO构成三个交易输入,target和Change size的UTXO构成两个交易输出。

上例交易中选择了三个UTXO。一旦选择了一个 UTXO,钱包就会为每个 UTXO 生成一个解锁脚本。这个解锁脚本包括:

选定的 UTXO 加上解锁脚本构成了交易输入。交易输入的具体数据结构如下:

一笔比特币交易的本质是数据结构交易被验证为无效

一笔比特币交易的本质是数据结构交易被验证为无效

从结构上可以看出,一个交易输入包括:

解锁脚本和锁定脚本

比特币的交易验证引擎依赖两种类型的脚本来验证比特币交易:锁定脚本和解锁脚本。

每个比特币客户端通过同时执行锁定和解锁脚本来验证交易。对于比特币交易中的每个输入,验证软件首先检索输入指向的 UTXO。该 UTXO 包含一个锁定脚本,用于定义支出条件。接下来,验证软件将读取包含在尝试花费此 UTXO 的输入中的解锁脚本并执行这两个脚本。

在之前的比特币客户端中,解锁和锁定脚本以链式存在并依次执行。出于安全考虑,比特币开发者在 2010 年修改了这个功能——因为存在“允许异常解锁脚本将数据压入堆栈并污染锁定脚本”的漏洞。在当今的比特币世界中比特币交易过程,这两个脚本在堆栈传递时分别执行。

比特币交易脚本语言是一种基于反向波兰符号的基于堆栈的执行语言。它主要有以下几个操作

OP_DUP的操作是将栈顶的数据复制到栈顶

一笔比特币交易的本质是数据结构交易被验证为无效

将栈顶的两个数据出栈,比较它们是否相等,如果为真则进行下一个入栈操作,如果为假则整个验证过程失败

OP_HASH160 弹出栈顶数据,进行哈希运算,然后将结果压入栈中

OP_CHECKSIG 弹出栈顶的两个数据,进行比较,将结果压入栈中

具体规则如下:

一笔比特币交易的本质是数据结构交易被验证为无效

锁定脚本

OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG

可以看出整个锁定脚本中唯一的变量是发送者的公钥哈希

一笔比特币交易的本质是数据结构交易被验证为无效

解锁脚本

交易验证

运行解锁脚本 + 锁定脚本 => TRUE

交易验证

比特币网络收到交易输入后,会对该交易进行验证,验证通过后,会生成交易输出。在交易输入中,UTXO 属于发送方,在交易输出中,UTXO 属于接收方。

栈结构的主要运行规则如下:

那么,比特币交易验证的过程如下:

一笔比特币交易的本质是数据结构交易被验证为无效

一笔比特币交易的本质是数据结构交易被验证为无效

当验证通过时,将生成相应的交易输出,将比特币从一个所有者转移到另一个所有者。

版权声明:manoon 发表于 2021-10-24 8:59:55。
转载请注明:一笔比特币交易的本质是数据结构交易被验证为无效 | 198区块链导航

暂无评论

暂无评论...