NEO智慧合約開發(一)不可能完成的任務

瘋光無線發表於2018-02-07

懸賞任務

茲有如下合約

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. 輸入列表
  2. 輸出列表
  3. 如果是應用合約交易,還有應用合約指令碼,其他交易還有些別的

這些共同構成未簽名合約。

 

你是不是發現了,沒有鑑權合約什麼事情啊?鑑權合約呢?

 

你記得簽名麼?你一定知道給別人轉賬,要用你的私鑰,對交易進行簽名吧。

這其實,就是鑑權合約的一種特例。

 

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對話方塊

 

交易成功

隨便去哪裡查,都可以看到懸紅裡的錢已經取出了。

 

寫在最後

懸紅裡還留了很多錢,留給那些想要探索的人,請不要一次取完。

相關文章