NEO智能合约开发(一)不可能完成的任务

13次阅读

共计 4088 个字符,预计需要花费 11 分钟才能阅读完成。

悬赏任务
兹有如下合约
public static object Main(string method, object[] args)
{
if (Runtime.Trigger == TriggerType.Verification)
{
if (method ==“0214”)
return true;
}
return false;
}

他的 avm 如下,他是一个鉴权合约,不需要发布他。
55c56b6c766b00527ac46c766b51527ac4616168164e656f2e52756e74696d652e47657454726967676572009c6c766b52527ac46c766b52c3642a00616c766b00c30430323134876c766b53527ac46c766b53c3640e00516c766b54527ac4620f0061006c766b54527ac46203006c766b54c3616c7566
ScriptHash:0x86cf7371f5511257f682cc47be48563a3ff03f51
Address:APBUyZNkemciUQurabSQBnnma7kGGhUPPL

在 TestNet 上已经向此地址转账很多个 gas 了,谁拿走算谁的。
该任务在多个大牛集中的地方放了 24 个小时,无人拿走。称为不可能的任务名至实归。

急流勇退
这篇文字是一篇劝退文,劝你绕开鉴权合约的开发,先学习应用合约的开发。
官网(neo.org)文档的学习曲线已经不是陡峭,而是断崖式。
我采样了一番,居然没有发现有人跟随此文档顺利完成了鉴权合约的学习。
于是我怀着抱着满满的对自己学习能力的自信,去攀登这做陡峭的大山,打算学成归来再教你们如何学习鉴权归来。
我回来了,也是断崖上跳下来的。

这两笔是我从悬赏账户里面取出来的钱。
那么我成功了?部分成功,在尝试使用 NEOGUI 取这两笔钱的路上,我完全凉了。
我使用的是 NEL Thinsdk-cs 的例子钱包取出来的 (https://github.com/NewEconoLa…

完成这个任务之后,我才得出了如下结论:
建议大家绕开鉴权合约的开发,先学习应用合约的开发。
其难度主要在于需要理解的概念多,neogui 配合不足。如果你看到这里,还是毫不气馁,坚持要攀登这座大山,我们一起往后谈。
密码合约:
悬赏合约是一个密码合约
public static object Main(string method, object[] args)
{
if (Runtime.Trigger == TriggerType.Verification)
{
if (method ==“0214”)
return true;
}
return false;
}

他只有在第一个参数为 0214,并且 Runtime.Trigger==Verification 时,返回 true。
对鉴权合约来说,返回 true 这笔交易才能成立。
想起来很简单,从哪里传入这个 0214 呢?这就得把整个交易和鉴权合约这一块都说一说了。
鉴权合约与交易
鉴权合约是在交易验证阶段执行的,如果鉴权合约没有返回 true,那么这笔交易直接验证失败,无法被写入区块,也就不可能查询到这笔交易。
鉴权合约和应用合约有着本质上的不同,应用合约一定是验证成功写入的区块中执行。
NEO 交易有输入和输出。这是 UTXO 模型的事情,交易的输入是一个列表,其中每一项是对一个 UTXO 的引用。交易的输出是制造新的 UTXO。
交易的输入输出就是钱,销毁输入,制造输出,对 UTXO 迷糊的同学可以不用看了,拐回去搞清楚 UTXO。
交易包含如下内容:

输入列表
输出列表
如果是应用合约交易,还有应用合约脚本,其他交易还有些别的

这些共同构成未签名合约。
你是不是发现了,没有鉴权合约什么事情啊?鉴权合约呢?
你记得签名么?你一定知道给别人转账,要用你的私钥,对交易进行签名吧。
这其实,就是鉴权合约的一种特例。
1. 取决于一个交易有几个输入地址(也就是出钱的人),就必须有几个对应的见证人(witness)。
2. 对交易进行签名,就是添加对应转账发起人的见证人
3.NEO 是一个完整的智能合约系统,每一个见证人都是两段脚本,一段叫校验脚本,一段叫执行脚本。
以上三点是不是有些晕乎,别急,还有更晕乎的
签名详解
1.NEO 的每一个账户地址都是一段脚本,该脚本是一个两条指令的智能合约,伪代码为:
Push publickey
Syscall Checkwitness
该脚本的 hash 值就是用户地址,通常用户地址用该 hash 值加盐加验证做 base58 之后的字符串形式表达。字符串形式和 hash 值完全等价。
由此可知,NEO 的地址,就是智能合约的 hash 值。反过来也成立,NEO 每个智能合约的 hash 值,都是一个地址。
所以,我可以向一个智能合约转账,也可以从一个智能合约取钱,因为我的地址,其实也是一个智能合约地址。
2. 见证人的校验脚本就是该地址对应的智能合约,且不可修改,hash 不一样通不过校验。
3. 见证人的执行脚本是用来像校验脚本提供参数的智能合约。
所以我们再来看从我的地址给别人转账发生了什么。
1. 给别人转账,必须输入里面由来自我的地址的 utxo
2. 构造交易
3. 添加见证人,校验脚本就是我的脚本
4. 设置见证人执行脚本,他是一个一条指令的智能合约,伪代码为:
Push signdata
5. 发送包含交易数据和见证人数据的 rawdata
6. 校验交易,执行脚本 push signdata,结束,校验脚本 push 自己的 pubkey,然后 checksig,该函数两个参数,正好是 signdata 和 pubkey,检查,如果成功,交易成立。否则交易不成立。
签名是不是比你想的要复杂很多呢。
拿走悬红
搞清楚见证人和交易的关系之后,我们才可能顺利的从悬赏合约中拿走钱
那就构造一笔转账交易
输入 n 个,从悬赏合约地址里找到 utxo 做输入
输出 1,给自己的地址
输出 2 可选:可以给悬赏地址找零
见证人:校验脚本 = 悬赏合约
执行脚本 = 参数
因为参数为一个 string 一个 array
倒叙 push
伪代码为
Push0 // 加入 0
Pack // 用上面的 0 创建 array,表示空 array
Push bytes(“0214”.as bytes())//push“0214”
二进制为:00c10430323134
信息都告诉你了,那么拼个自定义合约就行了呗。
NEOGUI 不是有工具吗,F12 调出,是的,去测试吧,保证愉快。你就能理解断崖式学习曲线是怎么回事了。

而且就算你上面都做对了,你也拿不走。
我在此处纳闷了很久,然后我一行行的跟进了 NEO 底层

这有一个限制,执行脚本里面只能允许 push 指令,否则直接脚本执行失败了,鉴权合约失败,交易不成立。
我们刚才的执行脚本伪代码为
Push0 // 加入 0
Pack // 用上面的 0 创建 array,表示空 array
Push bytes(“0214”.as bytes())//push“0214”
二进制为:00c10430323134
有一个 pack,超出允许范围,交易一定失败。
那么我们知道了,鉴权合约里面是没办法引用 array 类型的参数了。
好在悬赏合约的第二个参数其实没有使用,随便推个啥就行
我们把执行脚本改为
Push0 // 加入 0
Push bytes(“0214”.as bytes())//push“0214”
二进制为:000430323134
好了,如果你很有耐心,去玩 NEOGUI 和 F12 吧。
没有发布?
你如果看了一些 NEO 智能合约的资料,你也许会发现,这个合约没发布呀。
智能合约是不需要发布的,智能合约是不需要发布的,你可以直接调用,没问题。
那么什么情况要发布呢,这个智能合约要被 appcall 调用的话,他必须被发布到链上,支付昂贵的费用。应用合约基本上都是这种,为了方便反复调用,还有内部存储。
加上所有这些,从应用合约入门,还是比鉴权合约入门简单很多。
鉴权合约不用发布。
另一个客户端是怎么回事

这是 NEL(一个 NEO 中国开发者社区 组织)
为了开发轻钱包准备的 sdk 的例子
C# 版本
https://github.com/NewEconoLa…
typescript 版本
https://github.com/NewEconoLa…
我们来演示一下,用这个例子钱包,如何更顺畅的学习鉴权合约
NEL 公众号有发布过这个钱包转账的方法
http://www.cnblogs.com/crazyl…
启动 c# 例子

点下面的 thinWallet test, 就是一個轻钱包测试了

因为我们取悬红,其实并不需要 loadkey,就是打开钱包,我们不需要任何人签名就能把钱给取了
从悬赏合约地址取得 utxo

在 Input 区域点右键,可以用智能合约增加一个 UTXO

将悬红合约 copy 进来,或者点击 loadavm 从 avm 读取
则可以看到合约的地址显示在下边
然后点 refresh utxo,可以得到宣红合约的 utxo,选一个
我们选 91.8 这个

然后看到输入有了
输出多了一个(changeback)表示是找零,我们是好青年,不全拿走
见证人(witness)也自动添加了一个(sc)是智能合约简称
加个输出,转给自己

在输出区域 右键,添加一个输出

填好转给谁,币种(gas),多少

然后输出自动调整找零
试试签名发出,发不出去,告诉你见证人的执行脚本还没配置

配置见证人

选中见证人,在见证人区域 右键

黄色是校验脚本,他就是悬赏合约本身,不可以修改
红色是执行脚本的配置,我们用一个 json 替代不直观的配置
String 加了点规则
(str) 开头表示这是个字符串
(int) 开头表示这是个 biginteger
还有 (bin)(int160)(int256)
很好懂吧。

点击 Gencode 就生成了执行脚本,但是我们已知,带 Array 的执行脚本不允许,改一下。

好,点 ok

回来点签名并广播

Done,成功,
得到一个交易 id 对话框
交易成功

随便去哪里查,都可以看到悬红里的钱已经取出了。
写在最后
悬红里还留了很多钱,留给那些想要探索的人,请不要一次取完。
作者:李剑英
原文转自:https://www.cnblogs.com/crazy…

正文完
 0