作业要求
(a)生成可通过以下两个线性方程组的解x,y)赎回的交易:
x+y= (StudentID of First Half)和x-y= (StudentID of Second Half)
[为确保存在整数解,请更改右侧两个数字的最后一位,使数字都是偶数或都是奇数]。
(b)赎回交易。赎回脚本应尽可能小。也就是说,一个有效的scriptSig
应该是简单地将两个整数x和y发送到堆栈中。确保在scriptPubKey
中使用了OP_ADD
和OP_SUB
。
实现思路
这个作业看起来就像是让你解个方程,然后验证一下你解的方乘对不对。(不过要是真的用这样脚本交易比特币那自己币子不是别人想用就随便用了嘛ORZ)
已经说了解锁脚本就是x和y,那么首先压入栈里的就是x和y,那接下就要验证x和y是不是方乘的解。
首先先把xy复制一遍,因为需要验证两个方程得用两边,就用到了OP_2DUP
,它的定义是这样的,所以能把栈顶两个元素赋值
elif sop == OP_2DUP:
check_args(2)
v1 = stack[-2]
v2 = stack[-1]
stack.append(v1)
stack.append(v2)
然后就把x和y加起来,用OP_ADD
脚本,它在执行的时候会把x和ypop
掉然后再把结果push
进栈里
接着拿这个result
和原方程里的值比较是否一致,这里之所以使用的是OP_EQUALVERIFY
,是因为它不会产生一个返回值,而使用OP_EQUAL
会在栈里留下一个ture值没法处理
elif sop == OP_EQUALVERIFY:
check_args(2)
v1 = stack[-1]
v2 = stack[-2]
if v1 == v2:
stack.pop()
stack.pop()
然后差不多和前面一样的思路,先得到一个减的结果,然后和方程里的值比较,用OP_EQUAL
验证,在栈里留下一个true值,这里可以看到并不是直接返回一个false或者true,而是返回的\x01
或者,应该是和true或者false一样的功能,为空是false,不为空是ture
elif sop == OP_EQUAL:
check_args(2)
v1 = stack.pop()
v2 = stack.pop()
if v1 == v2:
stack.append(b"\x01")
else:
stack.append(b"")
实现脚本
加锁脚本
OP_2DUP
OP_ADD
<StudentID of First Half>
OP_EQUALVERIFY
OP_SUB
<StudentID of Second Half>
OP_EQUAL
解锁脚本
<X> #解方程的得到的xy值
<y>
脚本运行过程
完整的脚本
<X>
<y>
-----
OP_2DUP
OP_ADD
<StudentID of First Half>
OP_EQUALVERIFY
OP_SUB
<StudentID of Second Half>
OP_EQUAL
运行过程
NULL #起始状态,栈内为空
<x> #x压栈
<x><y> #y压栈
<x><y><x><y> #OP_2DUP复制栈顶及栈顶下一个元素并压栈
<x><y><add_result> #OP_ADD弹出xy并且将xy相加的结果压栈
<x><y><add_result><stuid first> #学号前四位压栈
<x><y> #OP_EQUALVERIFY验证两个内容是否相等,相等则将其弹出
<sub_result> #OP_SUB弹出xy并且将xy相减的结果压栈
<sub_result><stuid second> #学号后三位压栈
ture #OP_EQUAL验证栈内的两个数值是否相等然后将true压栈
掉进去的坑
没有用OP_EQUALVERIFY
和OP_EQUAL
用了OP_NUMEQUALVERIFY
和OP_NUMEQUAL
翻看python-bitcoinlib的源码,一开始只看到了OP_NUMEQUALVERIFY
和OP_NUMEQUAL
elif opcode == OP_NUMEQUAL:
bn = long(bn1 == bn2)
stack.pop()
stack.pop()
stack.append(bitcoin.core._bignum.bn2vch(bn))
elif opcode == OP_NUMEQUALVERIFY:
bn = long(bn1 == bn2)
if not bn:
err_raiser(VerifyOpFailedError, opcode)
else:
# No exception, so time to pop the stack
stack.pop()
stack.pop()
return
看似是没有什么大问题的,不过OP_NUMEQUAL
里并没有直接把bn
压栈,反而是调用了一个函数bitcoin.core._bignum.bn2vch
,里面有bignum
而且bn
类型为long
,调用的函数可能对bn做了处理导致最后没有办法得到ture之类的,那个函数也看了下定义之类的没有看得很清楚,因为函数里又调了别的函数。不过肯定是那个函数的锅。(浪费了我一份币子,还好当时分了十份)