人生的第一桶金 —— Nebulas DApp 開發從零開始

dduke發表於2018-05-21

前言

5月7日 00:00 - 7月2日 00:00,Nebulas(星雲) 有一個激勵計劃,開發DApp, 最高月度優秀獎勵可達 20000 NAS 價值約 120w RMB

人生的第一個一百萬,第一桶金,興不興奮, 心不心動!!~ 不管你心不心動, 反正我心動了!

第一步肯定是先註冊一個賬號了, 註冊連結

好了,看到錢就興奮不算一件壞事,不過還需要冷靜下,這120w 不是這麼好拿的,不過對於普通的開發者來說 還有一個很大的福利, 只要你成功上架一個DApp,即可獲得 100 NAS 價值 6000 RMB 這都我等來說 也算一筆不大不小的收入, 如果寫的優秀點的話,還有更多的獎項在等著,就算拿不到 120w,努力點 那個幾萬 甚至十幾 二十萬 還是有可能的。具體可以檢視官網說明

ps. 當然官方對幫忙推廣宣傳的,也有一定的獎勵,如果小夥伴們通過我上面的邀請連結進入的,並且成功上架一個DApp的話 我也是能獲取到 40 NAS,當然你自己本身的獎勵不會減少(據社群小夥伴透露,通過別人邀請連結進入的,成功上架一個DApp 的獎勵上升到110 NAS

準備工作

前言打了一波雞血, 120w 想拿到,怎麼說都要成功上架一個 DApp之後,才有這個機會。講一下準備工作吧。

  1. 首先你得會 JavaScript(TypeScript 也行),不會的小夥伴 自行學習下。
  2. 其次你得了解下 DApp 是個什麼東西?
  3. 開發流程是怎麼樣的?怎麼部署以及釋出?
  4. 去哪裡提交上架?

DApp 是個什麼東西?

其實建議自行 google 百度下,會清楚點,在這裡我做個簡單的介紹,自己的理解,可能有所出處。

DApp 即 decentralized application (去中心化應用),主要是相當於中心化應用來說的。目前的App來說,基本上都是中心化應用,有中心化的伺服器,資料儲存讀取都是跟中心化伺服器做互動。而去中心化應用,去掉的就是中心化的伺服器,才用的是區塊鏈的去中心化的資料庫。

最早應該是以太坊提出智慧合約之後才出來的一個概念,至於智慧合約,個人理解是相當於後端,資料通過智慧合約儲存在區塊鏈上。

開發流程

重頭戲來了,基友星雲鏈開發一個DApp的流程是怎麼樣的

  1. 先去星雲官網註冊賬號,註冊連結
  2. 下載官方web錢包, 並使用該web錢包建立我們自己的錢包
  3. 下載官方Chrome外掛,github上有教程
  4. 開發智慧合約,(本文會採用官方推薦的最簡單的一個例子)
  5. 部署智慧合約,(部署合約的時候需要少量的NAS, 測試鏈上的幣可以在這裡領取,正式鏈上的NAS,如果沒有渠道的話,可以聯絡我微信 xuanyuan_1, 備註請按 掘金-DApp-你的名字, 如果你是按我的邀請連結註冊的我將免費送你一點NAS幣 用於部署智慧合約。)
  6. 開發Web前端介面
  7. 部署前端介面(這塊不熟悉的,或者沒有域名的,也可以聯絡我)
  8. 提交DApp(坐等拿錢)

ps. 拿到手的是NAS,如果不想持有直接提現的話,可以去火幣等交易所提現

本文會主要講一下智慧合約,以及web前端開發兩個部分。

智慧合約

如果沒有智慧合約這個概念的話,可以把這塊理解後端的介面。星雲的智慧合約是基於 Chrome 的 V8 引擎開發的,支援 JavaScriptTypeScript。 智慧合約的執行模型如下:

人生的第一桶金 —— Nebulas DApp 開發從零開始
內建了一下 LocalContractStorage 模板來提供儲存功能,BigNumber 模組進行數值的處理,Blockchain 物件可以取得當前合約所在的塊和Transaction資訊... 具體可以參考官方的文件

寫智慧合約

直接上程式碼

"use strict";

var DictItem = function(text) {
  if (text) {
    var obj = JSON.parse(text);
    this.key = obj.key;
    this.value = obj.value;
    this.author = obj.author;
  } else {
    this.key = "";
    this.author = "";
    this.value = "";
  }
};

DictItem.prototype = {
  toString: function () {
    return JSON.stringify(this);
  }
};

var SuperDictionary = function () {
  LocalContractStorage.defineMapProperty(this, "repo", {
    parse: function (text) {
      return new DictItem(text);
    },
    stringify: function (o) {
      return o.toString();
    }
  });
};

SuperDictionary.prototype = {
  init: function () {
    // todo
  },

  save: function (key, value) {
    key = key.trim();
    value = value.trim();
    if (key === "" || value === ""){
        throw new Error("empty key / value");
    }
    if (value.length > 64 || key.length > 64){
        throw new Error("key / value exceed limit length")
    }

    var from = Blockchain.transaction.from;
    var dictItem = this.repo.get(key);
    if (dictItem){
        throw new Error("value has been occupied");
    }

    dictItem = new DictItem();
    dictItem.author = from;
    dictItem.key = key;
    dictItem.value = value;

    this.repo.put(key, dictItem);
  },

  get: function (key) {
    key = key.trim();
    if ( key === "" ) {
      throw new Error("empty key")
    }
    return this.repo.get(key);
  }
};
module.exports = SuperDictionary;
複製程式碼

上面的智慧合約就是就是官方demo裡的,吐槽一下寫這個demo的人 可能是之前寫 java 的或者是強行把 TypeScript 擼成 JavaScript。

完成可以改寫成下方形式, (為了節省篇幅把說明直接寫在註釋裡了)

// 構建一個SuperDictionary 類 ES5的寫法 可以用ES6 class的寫法也行
var SuperDictionary = function () {
  LocalContractStorage.defineMapProperty(this, "repo");
};

SuperDictionary.prototype = {
  // 這個方法比較有,初始化合約的時候 做相應的處理, 比如說 初始化的時候 繫結直接是使用者
  init: function () {
    // todo
  },
  /**
   * 儲存內容 
   * key: 關鍵字
   * vlaue: 關鍵字所對應的定義
   */
  save: function (key, value) {
    key = key.trim();
    value = value.trim();
    if (key === "" || value === ""){
        throw new Error("empty key / value");
    }
    if (value.length > 64 || key.length > 64){
        throw new Error("key / value exceed limit length")
    }
    /**
     * Blockchain.transaction.from 即本次請求的區塊鏈地址
     */
    var from = Blockchain.transaction.from;
    var dictItem = this.repo.get(key);
    // 若已經存在 則這個詞已經被搶注了 丟擲異常
    if (dictItem){
        throw new Error("value has been occupied");
    }
    // 很自信的覺得 下面的寫法是對的 沒想到測試沒通過 可怕
    // dictItem = {
    //   author: from
    //   key,
    //   value
    // }
    // 最後改成如下寫法
    dictItem = {};
    dictItem.author = from;
    dictItem.key = key;
    dictItem.value = value;
    // 儲存
    this.repo.put(key, dictItem);
  },
  // 獲取相關儲存的詞
  get: function (key) {
    key = key.trim();
    if ( key === "" ) {
      throw new Error("empty key")
    }
    return this.repo.get(key);
  }
};
module.exports = SuperDictionary;
複製程式碼

這個DApp要實現的什麼功能,其實看合約 就知道了。這是一個名為 SuperDictionary 的DApp, 主要實現的功能即為可以在這個 DApp 查詢一個詞,若這個詞沒有被人搶注,你就可以自己註冊下(比如說 搜我的大名 Duke 基本上不會有人註冊,我給它一個定義 世上最帥的人,那麼這條資訊就將永久儲存在星雲鏈上,別人再使用這個DApp 查詢 Duke 可以看到 我給他下的定義。)

星雲鏈的智慧合約有三點簡要的規範:

  1. 智慧合約程式碼必須是一個Prototype的物件;
  2. 智慧合約程式碼必須有一個init()的方法,這個方法只會在部署的時候被執行一次;
  3. 智慧合約裡面的私有方法是以_開頭的方法,私有方法不能被外部直接呼叫;

部署智慧合約

部署智慧合約有三步

  1. 檢查你的賬戶的狀態
  2. 若賬戶裡有足夠的錢來支付手續費則開始解鎖賬戶(解鎖時間為12小時)
  3. 再解鎖的期間 傳送部署BankVault合約的交易

詳情可檢視這裡

這三步都需要發一個請求出去,而且例子上的地址是 localhost 意味著 你還需要編譯安裝一個星雲鏈的程式碼,相當於成為星雲鏈的一個節點。 so trouble!!! 我只是想安靜的擼一個 DApp, 這些是什麼鬼!!!

別擔心我有招(其實官方也考慮到這點了)

到官方github 把 web版錢包 下載下來,npm install 安裝依賴,再 node server.js 執行服務。再接下來在瀏覽器中輸入 http://localhost:8080/ 即可看到如下介面

人生的第一桶金 —— Nebulas DApp 開發從零開始

人生的第一桶金 —— Nebulas DApp 開發從零開始

這樣我們就部署成功了,到此為止我們就基本上完成了,DApp後端部分的工作,我們可以開始愉快的擼前端介面了。

ps. 開發的時候,我們最好用的是測試鏈,測試鏈上的幣可以在這裡領取,但是提交

前端介面

基本上的介面,大家就自我發揮吧。主要來講一下會遇到的坑點。怎麼呼叫

官方提供了一個方法 nebPay, 但是官方並沒有把他提交到npm上去,有點憂傷,只能自己動手 佔個坑, 直接可以使用 npm install nebpay 就可以下載

最開始自己傻逼了,以為只能上傳到npm上才能用,後來發現在 package.json 直接寫 "${name}":"git+${it's github url}"也行,拿nebPay舉例即為"nebpay": "git+https://github.com/nebulasio/nebPay"

api 呼叫

前面講了前端呼叫合約的方式,具體程式碼怎麼寫呢,我簡單的封裝了下,大家可以做個參考

import NebPay from 'nebpay'
const nebPay = new NebPay()
/**
 *
 * @param {String} callFunction 呼叫合約的方法
 * @param {Array} param 請求的引數
 * @param {Boolean} needPay 是否需要支付
 */
const api = function (callFunction, param = [], needPay = false) {
  return new Promise((resolve, reject) => {
    const to = dappAddress
    const value = '0'
    const callArgs = JSON.stringify(param)
    /**
     * 如果只查詢類的請求 就不需要去支付 直接使用 nebPay 的 simulateCall 即可
     * 如果不是查詢類的 需要呼叫支付介面 使用 nebPay 的 call 呼叫
     */
    const way = needPay ? 'call' : 'simulateCall'
    nebPay[way](to, value, callFunction, callArgs, {
      listener: (res) => {
        console.log('listener', res)
        try {
          resolve(JSON.parse(res.result))
        } catch (e) {
          reject(res.result)
        }
      }
    })
  })
}
複製程式碼

顯而易見,只要用到了兩個方法,callsimulateCall, 兩者的在於是否需要修改合約裡的內容。比如查詢類的就想我們的合約裡的 get 方法,我們就用 simulateCall, 但是如我們合約裡的 save 方法就需要使用 call,會呼叫 nebulas 的 chrome 錢包外掛,需要支付少量的礦工費,這樣我們才能把我們的資訊永久儲存在星雲鏈上。

結語

一不小心囉囉嗦嗦了,寫了一堆,不知道對小夥伴們,有沒有幫助。今天(2018-05-21)已經是激勵計劃的第三週了,基本上簡單的應用都被人佔坑了,如果想要過稽核,需要多一點點創意,多一點點功能把 DApp 做的稍微飽滿點, 單人閉門造車已經很難了,有興趣的或者有好想法的小夥伴,一起組個隊一起玩,後續的機會還是有的。真獲獎了獎勵平分。 我微信及手機號為: MTg5MDY3Nzc1NzM= (加微信就好 ^_^ 請備註 掘金)


發了這篇文章之後 有不少人找我。發幾個幣給我玩玩唄。 我感覺還是有必要說明下: 部署合約需要正式鏈上的 NAS, 需要的非常少,連一分錢都不到,所以我在前面提到送一些NAS,只是為開發所需(畢竟通過交易所什麼的來即麻煩又費時費錢)。我並不是土豪,抱有其他目的的小夥伴 可以無視我了!

相關文章