区块链作业3生成通过两个线性方程组的解赎回的交易

作业要求

(a)生成可通过以下两个线性方程组的解x,y)赎回的交易:
x+y= (StudentID of First Half)和x-y= (StudentID of Second Half)
[为确保存在整数解,请更改右侧两个数字的最后一位,使数字都是偶数或都是奇数]。
(b)赎回交易。赎回脚本应尽可能小。也就是说,一个有效的scriptSig应该是简单地将两个整数x和y发送到堆栈中。确保在scriptPubKey中使用了OP_ADDOP_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_EQUALVERIFYOP_EQUAL用了OP_NUMEQUALVERIFYOP_NUMEQUAL
翻看python-bitcoinlib的源码,一开始只看到了OP_NUMEQUALVERIFYOP_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之类的,那个函数也看了下定义之类的没有看得很清楚,因为函数里又调了别的函数。不过肯定是那个函数的锅。(浪费了我一份币子,还好当时分了十份)

猜你喜欢

转载自blog.csdn.net/weixin_44190459/article/details/109634739