懸賞任務
茲有如下合約
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/NewEconoLab/neo-thinsdk-cs)
完成這個任務之后,我才得出了如下結論:
建議大家繞開鑒權合約的開發,先學習應用合約的開發。
其難度主要在於需要理解的概念多,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/NewEconoLab/neo-thinsdk-cs
typescript版本
https://github.com/NewEconoLab/neo-thinsdk-ts
我們來演示一下,用這個例子錢包,如何更順暢的學習鑒權合約
NEL公眾號有發布過這個錢包轉賬的方法
http://www.cnblogs.com/crazylights/p/8338117.htm
啟動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對話框
交易成功
隨便去哪里查,都可以看到懸紅里的錢已經取出了。
寫在最后
懸紅里還留了很多錢,留給那些想要探索的人,請不要一次取完。