【AICon】探索八个行业创新案例,教你在教育、金融、医疗、法律等领域实践大模型技术! >>> 了解详情
写点什么

揭秘比特币和区块链(五):深入理解比特币交易的脚本

  • 2017-01-11
  • 本文字数:3040 字

    阅读完需:约 10 分钟

本文作者为火币区块链研究中心技术专家廖雪峰,他有十年软件开发经验,精通 Java/Python/Ruby/Visual Basic/Objective C/Lisp 等编程语言,对开源框架有深入研究,著有《Spring 2.0 核心技术与最佳实践》一书,并有多个业余开源项目托管在 GitHub。本文中廖雪峰详细地介绍了比特币及比特币区块链的相关知识。

另外,想快速了解并掌握区块链技术的同学,可以购买极客时间出品的『深入浅出区块链』专栏。专栏立足于区块链技术,带你形成完整的区块链知识体系。作者还会手把手教你构建自己的迷你区块链,把你真正带进区块链的世界。

在比特币区块链中,每一个区块都指向上一个区块,这些通过 SHA256 计算的区块哈希链就是比特币账本不可篡改的基础。

在一个区块中,比特币系统用交易(Transaction)来表示一笔比特币交易。一个区块包含至少一笔交易。这些 Transaction 的 Hash 通过 Merkle Tree 计算出所有交易的 Merkle Hash,并被包含至区块 Hash 中,从而实现交易的不可修改。

如果我们仔细观察每一笔交易,可以发现,除了第一笔交易是矿工的挖矿所得外,每一笔交易都拥有一个或多个输入(TxIn),以及一个或多个输出(TxOut):

第一笔矿工挖矿的收入交易通常被称为 Coinbase,它没有输入,所以 TxIn 的 Hash 总是被标记为 00000000…0000

其他的交易,任何一个 TxIn 都会唯一追溯到区块链上在本区块之前的某个交易 Hash,以及索引:

通过交易 Hash 和索引(从 0 开始),即可唯一确定一个未花费的交易输出——UTXO(Unspent Transaction Output)。这样,每一个 Tx Input 都和之前的某个 Tx Output 关联了起来。

我们假设在上一笔交易中,Bob 给 Alice 支付了 0.15 个 BTC。

由于比特币并没有账户的概念,这一笔交易的输出并没有写上 Alice 的名字,也没有写上 Alice 的公钥。

那么,Alice 想要花费这 0.15 个 BTC,她应该如何证明自己拥有这个 UTXO,并且,其他人无法假冒 Alice 来花费这个 UTXO 呢?

答案是比特币的交易创建的输出其实并非一个简单的公钥地址,而是一个脚本。在 Bob 给 Alice 支付 0.15 个 BTC 的这个交易中,Bob 创建的输出脚本类似:

复制代码
OP_DUP OP_HASH160 abcd1234...9876 OP_EQUALVERIFY OP_CHECKSIG

其中,abcd1234…9876 是 Alice 的公钥 Hash。整个脚本的意思是,谁能够提供一个签名和一个公钥,让这个脚本运行通过,谁就能花费这笔交易的 1.5 个 BTC。

由于创建签名只能使用 Alice 的私钥,非 Alice 的私钥创建的签名将无法通过这个脚本的验证,所以,其他人无法假冒 Alice 来花费这笔输出。

一旦 Alice 提供了一个签名和自己的公钥,她实际上已经创建了另一笔交易来花费这个输出。

所有人都可以验证 Alice 创建的这个新交易是否有效。如果有效,该交易就会被矿工打包进新的区块,从而成为区块链上不可更改的一部分。

我们以著名的 Pizza Transaction 为例,来验证一个交易是否是有效的。

在交易 cca75078…4d79 中,唯一的 TxIn 输入提供的 sigScript 是:

复制代码
8b4830450221009908144ca6539e09512b9295c8
a27050d478fbb96f8addbc3d075544dc41328702
201aa528be2b907d316d2da068dd9eb1e23243d9
7e444d59290d2fddf25269ee0e0141042e930f39
ba62c6534ee98ed20ca98959d34aa9e057cda01c
fd422c6bab3667b76426529382c23f42b9b08d78
32d4fee1d6b437a8526e59667ce9c4e9dcebcabb

该 sigScript 实际上由两部分构成:

签名:30450221…ee0e01(71 字节 +1 字节签名类型),实际签名是去掉最后一个字节 01 的 30450221…ee0e,签名类型是 SIGHASH_ALL(0x01)。

公钥:042e930f…cabb(65 字节)

为了验证该交易是否有效,我们首先要根据 TxIn 所声明的 Previous Output Hash:a1075db5…d48d 和索引 0 找到上一笔交易的输出:

https://webbtc.com/tx/a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d

这笔交易输出的脚本是:

复制代码
1976a91446af3fb481837fadbb421727f9959c2d32a3682988ac

比特币的脚本由一系列指令和数据构成,每个指令占用一个字节,数据由数据头部的长度决定。上述二进制脚本翻译后的比特币指令如下:

复制代码
OP_DUP OP_HASH160 46af3fb481837fadbb421727f9959c2d32a36829 OP_EQUALVERIFY OP_CHECKSIG

现在,我们有了签名,公钥和脚本:

复制代码
sig: 30450221...ee0e01
pubkey: 042e930f...cabb
OP_DUP OP_HASH160 46af3fb46829 OP_EQUALVERIFY OP_CHECKSIG

就可以运行这个脚本来验证交易是否有效。

比特币脚本被设计成以栈来运行的虚拟机指令,它只有有限的几种指令,并且故意被设计成没有循环、条件跳转,所以,比特币脚本不是图灵完备的语言。

比特币脚本的执行非常简单。我们首先要准备一个空栈,然后把签名和公钥入栈:

紧接着,我们就可以执行 TxOut 的脚本:

复制代码
OP_DUP OP_HASH160 46af3fb481837fadbb421727f9959c2d32a36829 OP_EQUALVERIFY OP_CHECKSIG

首先执行 OP_DUP,这条指令把栈顶的元素复制一份,所以结果变成:

紧接着执行 OP_HASH160,它对栈顶元素计算 SHA256/RipeMD160,实际上是计算公钥 Hash,所以运行结果变成:

接下来的指令实际上是一个数据,我们直接把数据入栈:

然后,执行 OP_EQUALVERIFY,这条指令会比较栈顶的两个元素是否相等,如果不等,整个脚本就执行失败了,如果相等,脚本会继续执行,所以运行结果变成:

最后,执行指令 OP_CHECKSIG,这条指令会验证签名。首先,我们根据签名类型 SIGHASH_ALL(0x01)对整个交易进行验证。验证方法是:

把当前 Transaction 的所有 TxIn 的 scriptSig 去掉(红色部分),并把当前 TxIn 的 scriptSig 替换为 UTXO 的 script(蓝色部分),调整长度字段(绿色部分):

最后加上小端序 4 字节的签名类型 0x01(灰色部分),计算两次 SHA256,我们得到:

复制代码
c2d48f45…2669

现在,使用 ECDSA 算法对签名进行验证:

复制代码
boolean ecdsa_verify_signature(byte[] message, byte[] signature, byte[] pubkey)

根据签名的验证结果,我们即可确认该交易是否有效。

由于引入了脚本,我们可以看到,比特币实际上通过编程脚本实现了一个严格以计算机程序验证为基础的数字货币所有权的转移机制。由于计算机程序的可扩展性,比特币支付其实并不限定在必须支付给某一个公钥地址。利用脚本,我们可以构造出各种支付条件,例如,多重签名验证条件:

复制代码
2 <public-key1> <public-key2> <public-key3> 3 OP_CHECKMULTISIGN

这种提供多个公钥地址,并且需要多个签名验证的多重签名脚本,允许在 M 个签名种至少给出 N 个签名即可使用。上述脚本允许提供 3 个公钥地址中的任意两个有效签名。

当我们把比特币托管在某个第三方的在线钱包中时,就可以使用多重签名来保证只有自己和第三方钱包共同签名后才可动用输出,这样保证了黑客在攻击了第三方钱包后也无法花掉用户的比特币。

通过 OP_CHECKLOCKTIMEVERIFY,我们可以指定一个交易的锁定时间,在此之前,该交易输出无法被花掉。这个指令其实实现了支付宝的 7 天资金锁定然后再支付给卖家的功能。

还有一些交易并没有指定一个公钥 Hash,例如,这个交易的脚本如下:

复制代码
OP_HASH256 6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000 OP_EQUAL

它的意思是说,谁能够提供一个数据,它的 SHA256 是 6fe28c0a…0000,谁就可以花费这笔交易。

(注:该交易已经被花费了,有人找到了符合条件的数据)

从比特币的脚本,我们可以看到,基于区块链的数字货币支付实际上是数字货币所有权的安全转移。如果我们把金融资产或者实物资产以数字化的形式登记在区块链上,通过脚本就可以安全实现各种条件下的所有权转移,这正是智能合约在区块链上的应用。

出处:火币区块链研究中心。转载需注明来源!

2017-01-11 16:0216922

评论

发布
暂无评论
发现更多内容

ORACLE进阶(十三)using实现简化连接查询

No Silver Bullet

oracle 7月月更 using

Qt | 显示网络图片 QNetworkAccessManager

YOLO.

网络 图片 qt 7月月更

js对象的key到底加不加引号?

南极一块修炼千年的大冰块

7月月更

微服务项目中,Spring Security 比 Shiro 强在哪?

冉然学Java

编程 微服务架构 spring security Java’

双目立体匹配之代价聚合

秃头小苏

7月月更

Python|数据可视化——超星学习通助手后台数据的可视化处理

AXYZdong

Python 7月月更

不习惯的Vue3起步三 の computed和watch

空城机

vue3.2 7月月更

利用ECS服务器搭建安防视频监控平台

DS小龙哥

7月月更

羊城“论剑”!大湾区百家AI企业共话如何打牢人工智能“长链”的发展根基

Geek_2d6073

CSS 中 ::before 和 ::after 伪元素的几个实际用途

南城FE

CSS 前端 伪元素 7月月更

使用Gitlab Jenkins Docker建立CI部署方案

沃德

程序员 jenkins 7月月更

阿里云机器学习平台PAI与华东师范大学论文入选SIGIR 2022

阿里云大数据AI技术

Transformer 机器学习/深度学习

Spring Cloud源码分析之Eureka篇第八章:服务注册名称的来历

程序员欣宸

Java spring SpringCloud Eureka 7月月更

作用域与作用域链

是乃德也是Ned

JavaScript 前端 7月月更

MFC|自绘Static控件

中国好公民st

c++ 7月月更

面试突击64:了解 HTTP 协议吗?

王磊

Java 面试题

【C语言】进阶指针Four

謓泽

7月月更

更贴心、更好学的Python自动化办公教程!

博文视点Broadview

CSS Houdini:用浏览器引擎实现高级CSS效果

vivo互联网技术

CSS 前端 引擎 css动画

Git .ignore 文件规则不生效

攻城狮杰森

git IDEA 协同开发 7月月更

Python+JS逆向哪里多?必然是登录逻辑,投资界登录pwd参数解析

梦想橡皮擦

Python 7月月更

一站式 DevOps 平台,让开发大不同

SoFlu软件机器人

浅入浅出Mybatis(一)

ES_her0

7月月更

打造“拉动式”企业培训管理方案,释放人才潜能

明道云

tidb-dm报警DM_sync_process_exists_with_error排查

TiDB 社区干货传送门

故障排查/诊断

麒麟v10上部署TiDBv5.1.2生产环境的最佳实践

TiDB 社区干货传送门

实践案例 安装 & 部署

百花齐放的家居行业联盟,三翼鸟率先撬动三个赛点

脑极体

低代码实现探索(四十四)检查器待研究

零道云-混合式低代码平台

文盘Rust -- 给程序加个日志

TiDB 社区干货传送门

开发语言

滴-EventBus快速使用介绍-新手考驾照

芝麻粒儿

android EventBus 7月月更

iOS中的多态

NewBoy

ios 前端 移动端 iOS 知识体系 7月月更

揭秘比特币和区块链(五):深入理解比特币交易的脚本_语言 & 开发_廖雪峰_InfoQ精选文章