为了实现上一篇文章中说的“计数器合约”,需要介绍BSV上的高级语言sCrypt,并解释如何用sCrypt实现这个合约。 sCrypt和BSV脚本的关系就像C语言和汇编语言的关系。通过sCrypt VS Code插件,可以把sCrypt编译成BSV脚本语言,还可以在VSCode中进行调试。 sCrypt语言实现的“计数器合约”代码如下。一会我们会详细分析。 关键问题:旧TX的合约output被花费时要检查新TX的output是否符合规则,但旧TX并不知道新TX的output,那怎么检查呢? 解决方案倒也不复杂,在花费旧TX output时,把新TX output作为解锁参数告诉旧TX的output脚本,让脚本对该参数做分析和检查,如果符合条件才允许花费。 逻辑部分的主要检查两个条件: 新TX output脚本的逻辑部分与旧TX output脚本的逻辑部分一样。 满足了新TX的output只能是“计数器”合约,不能是其他类型(如P2PKH)output的需求。 新TX output脚本的数据部分比旧TX output脚本的数据部分的值大1。 满足了每次执行(花费)合约,计数器值加1且只加1的需求。 首先,分析参数声明。 这一行的关键是两个输入参数,这两个输入参数就是花费(执行)合约output时提供的解锁参数,包含在了新TX的input中。 合约的原理很简单,关键是如何保证解锁参数的真实性。因为解锁参数在构造新TX时是可以随意输入的,那么如何保证 你一定会好奇这两行代码到底是如何保证数据真实的,这是合约最精妙的地方,我会在下一篇文章里专门解释。 总之,如果数据不真实,那么脚本就会返回失败,UTXO不能被花费,也就是说合约不能被执行。 前面提到,新TX output脚本的逻辑部分与旧TX一样,只是数据部分的值增加了1。所以,把旧TX output脚本 再把 前面已经从 这样,整个合约就完成了。这个合约已经部署在了BSV的测试网络上:0, 1, 2 … 没看明白再看一遍吧。 下一篇我们将填上这篇中挖的坑:如何保证 参考资料:contract Counter { public function increment(bytes sighashPreimage, int amount) { Tx tx = new Tx(); require(tx.validate(sighashPreimage)); int len = length(sighashPreimage); bytes hashOutputs = sighashPreimage[len - 40 : len - 8]; bytes scriptCode = Util.readVarint(sighashPreimage[104:]); int scriptLen = length(scriptCode); int counter = unpack(scriptCode[scriptLen - 1 :]); bytes scriptCode_ = scriptCode[: scriptLen - 1] ++ num2bin(counter + 1, 1); Sha256 hashOutputs_ = hash256(num2bin(amount, 8) ++ Util.writeVarint(scriptCode_)); require(hashOutputs == hashOutputs_); } }
合约原理
代码分析
increment
函数的内容就是“计数器合约”output中的脚本内容,编译后可以分两部分:
解锁参数
public function increment(bytes sighashPreimage, int amount)
amount
参数不关键,先忽略。重点看sighashPreimage
参数。这个参数实际上是一系列数据的集合,其中包括了两个重要数据:
检查sighashPreimage参数真实性
sighashPreimage
参数中的两个重要数据是真实的(一定与新TX实际的output数据hash
、旧TX实际的output脚本
完全相同),而不是随意输入的假数据呢?下面这两行代码就是做这个检查的:Tx tx = new Tx(); require(tx.validate(sighashPreimage));
解析sighashPreimage参数
int len = length(sighashPreimage); bytes hashOutputs = sighashPreimage[len - 40 : len - 8]; bytes scriptCode = Util.readVarint(sighashPreimage[104:]); int scriptLen = length(scriptCode); int counter = unpack(scriptCode[scriptLen - 1 :]);
sighashPreimage
的结构是固定的,按固定结构从中解析出:新TX output hash值hashOutputs
、旧TX output脚本scriptCode
,然后再从scriptCode
中取出最后一个字节,这就是旧TX中计数器的值,存在变量counter
里。计算符合合约规则的新output hash值
bytes scriptCode_ = scriptCode[: scriptLen - 1] ++ num2bin(counter + 1, 1); Sha256 hashOutputs_ = hash256(num2bin(amount, 8) ++ Util.writeVarint(scriptCode_));
scriptCode
的逻辑部分保留,把数据部分counter
加1,并放到逻辑部分后面,这就是符合合约规则的新TX output脚本了。第一行代码就是这个作用,新脚本存在了变量scriptCode_
中。scriptCode_
与新TX output的satoshis数量amount
合并在一起做sha256 hash,就得到了新TX output的hash值hashOutputs_
。这里仍然暂时忽略对amount
参数的解释。检查计算出的hash值与实际的新TX output的hash值是否一致
require(hashOutputs == hashOutputs_);
sighashPreimage
参数中解析出了实际的新TX output hash值hashOutputs
,也计算出了符合合约规则的预期hash值hashOutputs_
。只要比较这两个值是否相等,就可以确定实际的TX output是否符合规则。如果不符合规则,那么旧TX的UTXO就无法被花费。看明白了吗?
sighashPreimage
参数的真实性。
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算