Bytom Dapp 開發(fā)筆記(三):Dapp Demo前端源碼分析

本章內容會針對比原官方提供的dapp-demo,分析里面的前端源碼囱修,分析清楚整個demo的流程,然后針對里面開發(fā)過程遇到的坑王悍,添加一下個人的見解還有解決的方案破镰。

儲蓄分紅合約簡述

為了方便理解,這里簡單說說儲蓄分紅合約的內容压储,具體可以查看儲蓄分紅合約詳細說明鲜漩,儲蓄分紅,顧名思義就是儲蓄之后渠脉,當達到一定的時間宇整,按照比例返回本息這樣的意思,所以demo中拆分成saving(儲蓄)與profit(提現(xiàn))兩個頁面芋膘,本章內容是針對合約交易的提交鳞青,所以只針對儲蓄頁面說明。

比原官方Dapp-demo使用說明

比原官方demo地址

1)訪問的前提需要用chrome打開比原官方demo地址为朋,同時安裝bycoin插件臂拓,在應用商店搜索就行;

2)安裝完bycoin,需要初始化用戶信息,新建或者導入備份文件去恢復用戶孙乖;

3)填寫指定資產(chǎn)數(shù)量妇斤,點擊確定;

4)彈出合約交易專用頁面漱挚,填寫密碼,點擊確認;

5)查看交易流水

前端源代碼分析

源碼 : 儲蓄分紅合約前端源代碼 (本章內容講解的是 2019年7月10號 最新版的代碼)

前端代碼是基于前端框架react去做的坊饶,很容易讀懂,結構如上殴蓬,我們來看看作為儲蓄頁面(saving)Bytom-Dapp-Demo1\src\components\layout\save\index.jsx

//提交后的方法
    FixedLimitDeposit(amount, address) //####### 1.
      .then(()=> {
          //####### 2.
          this.refs.btn.removeAttribute("disabled");
          this.setState({
            error:'',
            msg:`Submit success!!! you spent ${amount} deposite asset,and gain ${amount} billasset.`
          })
        }).catch(err => {
          //####### 3.
          this.refs.btn.removeAttribute("disabled");
          this.setState({
            error:err,
            msg: ''
          })
        })

1)接收了輸入框的金額匿级,還有當前用戶的地址;

2)成功后提示內容;

3)失敗后提示內容痘绎;

接下來到FixedLimitDeposit方法

export function FixedLimitDeposit(amount, address) {
  const object = { 
    address: address,
    amount: amount,
    parameter: [amount, address]
  }
  return submitContract(listDepositUTXO, createContractTransaction, updateDatatbaseBalance, object)  //####### 1.
}
  1. 傳入三個方法體分別是 listDepositUTXO(查找當前合約所有的UTXO)津函, createContractTransaction(創(chuàng)建提交前的合約參數(shù)),updateDatatbaseBalance(更新用戶的提交列表)

進入Dapp-Demo1\src\components\layout\save\action.js 的 submitContract方法

return new Promise((resolve, reject) => {
    //list available utxo
    return listDepositUTXO().then(resp => { //####### 1.

      //create the Contract Transaction
      return createContractTransaction(resp, amount, address).then(object =>{ //####### 2.
        const input = object.input
        const output = object.output
        const args = object.args

        const utxo = object.utxo

        //Lock UTXO
        return updateUtxo({"hash": utxo}) //####### 3.
          .then(()=>{

            //Transactions
            return window.bytom.send_advanced_transaction({input, output, gas: GetContractArgs().gas*100000000, args}) //####### 4.
              .then((resp) => {
                  //Update Balance
                  return updateDatatbaseBalance(resp, ...updateParameters).then(()=>{//####### 5.
                    resolve()
                  }).catch(err => {
                    throw err
                  })
              })
              .catch(err => {
                throw err.message
              })
          })
          .catch(err => {
            throw err
          })
      }).catch(err => {
        throw err
      })
    }).catch(err => {
      reject(err)
    })
  })
  1. 首先調用listDepositUTXO 拿到當前節(jié)約鎖定的所有UTXO的信息孤页,待會詳細說明尔苦;

2)調用 createContractTransaction 方法,組裝好合約的對應信息參數(shù)散庶;

3)選取要使用的 UTXO后蕉堰,調用updateUtxo 告訴bufferserver ,該UTXO已經(jīng)被使用悲龟,更改狀態(tài)屋讶,防止其他人調用了;

4)執(zhí)行window.bytom.send_advanced_transaction方法须教,參考插件錢包API皿渗,是高級交易方法,這個是bycoin插件的原生方法轻腺,調起 提交交易的頁面乐疆,讓用戶輸入密碼;

5)交易確認后贬养,調用 updateDatatbaseBalance 提交數(shù)據(jù)到后端挤土;


再來看看api.js的listDepositUTXO 方法,所有與bufferserver交互的接口全部寫到這個文件里面:

function listDepositUTXO() {
  return listDappUTXO({//****** 1.
    "program": GetContractArgs().depositProgram,   
    "asset": GetContractArgs().assetBill,         
    "sort": {
      "by":"amount",
      "order":"desc"
    }
  })
}

//Api call from Buffer server
export function listDappUTXO(params)
{
  let url
  switch (window.bytom.net){
    case "testnet":
      url = "/dapptestnet/list-utxos"
      break
    default:
      url = "/dapp/list-utxos"
  }
  return post(url, params).then(resp => resp.data)
}

很明顯最終是調用bufferserver的/list-utxos方法误算,非常簡單仰美,值得一提的是

1)里面的結構體根據(jù)program(合約代碼)與asset(資產(chǎn)ID)去查找UTXO,這里其實底層是調用官方的blockcenter接口的儿礼,后面會細說咖杂;

繼續(xù)看看Dapp-Demo1\src\components\layout\save\action.js 的createContractTransaction方法

function createContractTransaction(resp, amount, address){
  return new Promise((resolve, reject) => {
    //utxo pre calculation
    const limit = GetContractArgs().radio * 100000000   //****** 1.
    if (resp.length === 0) {
      reject( 'Empty UTXO info, it might be that the utxo is locked. Please retry after 60s.')
    } else if (amount < limit) {
      reject( `Please enter an amount bigger or equal than ${limit}.`)
    }

    const result = matchesUTXO(resp, amount) //****** 2.
    const billAmount = result.amount
    const billAsset = result.asset
    const utxo = result.hash

    //contract calculation
    if (amount > billAmount) {
      reject('input amount must be smaller or equal to ' + billAmount + '.')
    } else {
      const input = []
      const output = []

      const args = contractArguments(amount, address) //****** 3.
      
      input.push(spendUTXOAction(utxo)) //****** 4.
      input.push(spendWalletAction(amount, GetContractArgs().assetDeposited)) //****** 5.

      if (amount < billAmount) { //****** 6.
        output.push(controlProgramAction(amount, GetContractArgs().assetDeposited, GetContractArgs().profitProgram))
        output.push(controlAddressAction(amount, billAsset, address))
        output.push(controlProgramAction((BigNumber(billAmount).minus(BigNumber(amount))).toNumber(), billAsset, GetContractArgs().depositProgram))
      } else {
        output.push(controlProgramAction(amount, GetContractArgs().assetDeposited, GetContractArgs().profitProgram))
        output.push(controlAddressAction(billAmount, billAsset, address))
      }

      resolve({ //****** 7
        input,
        output,
        args,
        utxo
      })
    }
  })
}

這個方法比較復雜,我們一步一步來

這里先看看 7)蚊夫,最終返回的內容是 input诉字、 output、 args知纷、 utxo壤圃, 跟發(fā)送交易頁面里面的input、 output琅轧、 args對應起來埃唯,如 圖K

(圖K)

上一章說過,所有比原鏈的交易都要存在質量守恒定理鹰晨,input與output的總和要相對應,合約交易里面執(zhí)行方法必須需要參數(shù),這里的args就代表傳入的參數(shù)模蜡,utxo是代表 utxo的id

1)做一下限制漠趁,設置最少值

2)matchesUTXO ,根據(jù)上面的內容忍疾,剛剛已經(jīng)通過listDepositUTXO 拿到所有可用的UTXO列表闯传,這個時候要根據(jù)用戶輸入的數(shù)額amount,選擇一個起碼 大于或等于的 amount 的UTXO出來卤妒;

3)contractArguments 甥绿,構建args,就是合約里面方法的參數(shù)则披;

4)通常合約交易會有自己資產(chǎn)的input共缕,合約UTXO的input,這里是要解鎖的utxo的input士复;

5)這個是錢包資產(chǎn)的input图谷;

  1. 上一章內容說過,解鎖合約的交易阱洪,必須根據(jù)合約里面的邏輯便贵,計算出對應的結果,所以這里的邏輯跟合約里面邏輯是一樣的冗荸,儲蓄分紅合約詳細說明 如圖承璃;

判斷邏輯一樣,這里插件錢包跟上一章說的pc錢包接口的結構有所不同蚌本,但是原理一樣盔粹。

最后我們看看src\components\layout\save\action.js 的updateDatatbaseBalance 方法

function updateDatatbaseBalance(resp, amount, address){
 return updateBalances({
    "tx_id": resp.transaction_hash,
    address,
    "asset": GetContractArgs().assetDeposited,
    "amount": -amount
  }).then(()=>{
    return updateBalances({
      "tx_id": resp.transaction_hash,
      address,
      "asset": GetContractArgs().assetBill,
      "amount": amount
    })
  }).catch(err => {
    throw err
  })
}


export function updateBalances(params)
{
  let url
  switch (window.bytom.net) {
    case "testnet":
      url = "/dapptestnet/update-balance"
      break
    default:
      url = "/dapp/update-balance"
  }
  return post(url, params)
}

同樣是調用bufferserver,這里是調用update-balance方法魂毁,把成功后的交易提交到后端玻佩。

小結

上面介紹了dapp-demo前端代碼的內容,介紹了里面的方法席楚,除了插件api的調用比較復雜外咬崔,其他都是普通的應用邏輯調用,主要理解了質量守恒定理烦秩,剩下的都是對數(shù)據(jù)審核數(shù)據(jù)的問題垮斯,非常簡單。


遇到的坑

有應用開發(fā)的讀者應該一下子就能理解到問題核心吧只祠,我現(xiàn)在在說說里面的坑兜蠕;

1) UTXO鎖定接口容易被刷; 假如我一個開發(fā)人員知道這個接口抛寝,狂刷你這個接口狂鎖應用的UTXO熊杨,這樣應用長期都會癱瘓狀態(tài)曙旭;

解決方案:這個應該從應用方面去考慮,譬如接口加一些一次性的驗證碼晶府,加refer的監(jiān)控桂躏,加授權之類的方式,后端加上交易監(jiān)控川陆,去維持著各種情況UTXO的狀態(tài)剂习,比較抽象,而且比較復雜较沪,不過這是必須的鳞绕;

2)并發(fā)問題;跟1)一樣尸曼,就算我是一個正常用戶们何,選擇了一個UTXO解鎖后,居然通過http接口告訴后端去鎖定骡苞,調起 輸入密碼頁面 (圖K)垂蜗,這個時候如果用戶不輸入密碼不提交,在比原鏈上該UTXO是沒有被解鎖解幽,但是bufferserver會卻鎖住了贴见。

解決方案: 后端源碼是鎖定一段時間,如果沒有使用躲株,則定期解鎖出來片部,這種情況也是需要應用的監(jiān)控判斷,維護所有utxo的狀態(tài)霜定,個人建議在發(fā)合約的時候档悠,發(fā)多筆UTXO鎖定合約,可用的UTXO就會變多望浩,這個時候有些同學問辖所,TPS豈不是也一樣不高,如果用過火幣的同學就知道了磨德,區(qū)塊鏈交易本來就不太注重TPS缘回,而且火幣的交易必須要超過60-100個區(qū)塊,才確定一筆交易典挑,這個看應用開發(fā)者如何去判斷酥宴,取舍。

3)用戶交易信息接口容易被刷您觉;跟1)一樣拙寡,交易完成后,直接通過http接口去提交數(shù)據(jù)琳水,我狂刷肆糕,豈不是億萬富翁....般堆;

解決方案:想要用戶的交易信息,生成交易賬單擎宝,可以直接用插件的接口郁妈,不過要通過合約編碼去篩選出來,筆者是通過監(jiān)控區(qū)塊鏈瀏覽器所有交易绍申,進入數(shù)據(jù)庫交易表的方式,這樣可以時時刻刻監(jiān)控所以交易顾彰。

4)容易產(chǎn)生鏈式錯誤极阅; 這里dapp-demo發(fā)的是一個合約的UTXO,假如用戶提交交易之后會產(chǎn)生新的UTXO涨享,但是這個UTXO還沒有確認的筋搏,bufferserver的list-utxo接口會把還沒有確認的UTXO,從而解決并發(fā)問題厕隧,但是我一個開發(fā)人員奔脐,知道合約的編碼,隨便寫個交易提交了吁讨,雖然肯定會失敗髓迎,但是需要時間,這個時候bufferserver也把這個肯定失敗的UTXO返回過來前端建丧,一直鏈式產(chǎn)生一堆交易排龄,很容易產(chǎn)生鏈式失敗。

解決方案:1)這里我跟比原官方的老大深深討論過翎朱,最優(yōu)方案當然是合約本身設置一個密碼橄维,輸入?yún)?shù)必須要根據(jù)這個密碼去加incode密過,傳入合約交易參數(shù)拴曲,合約本身在解釋的時候争舞,再decode解密驗證,保證出入的參數(shù)是官方的澈灼,這樣就不會有人攻擊.....不過結論是竞川,暫時比原鏈的合約引擎不支持。

2)一定要隱藏好合約邏輯蕉汪,其他人就沒辦法去惡意調用惡意占用流译,例如前端代碼混淆,或者args參數(shù)是后端生成者疤,另外建議比原的blockcenter的build-transaction接口參數(shù)可以加密這樣福澡,去掩蓋合約邏輯。

PS:這是筆者對于以上問題的思考驹马,有更好的解決方案革砸,歡迎一起討論除秀。

總結

這種內容主要說了前端代碼的源碼分析,還有設計上的邏輯坑算利,具體的解決方案應該跟官方的開發(fā)人員溝通還有討論册踩,區(qū)塊鏈的交易本來不追求大并發(fā),但是也需要一定的并發(fā)性效拭,筆者在第四章才根據(jù)bufferserver內容暂吉,在針對上面的問題,做出一些個人見解還有建議缎患。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末慕的,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子挤渔,更是在濱河造成了極大的恐慌肮街,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件判导,死亡現(xiàn)場離奇詭異嫉父,居然都是意外死亡,警方通過查閱死者的電腦和手機眼刃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門绕辖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鸟整,你說我怎么就攤上這事引镊。” “怎么了篮条?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵弟头,是天一觀的道長。 經(jīng)常有香客問我涉茧,道長赴恨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任伴栓,我火速辦了婚禮伦连,結果婚禮上,老公的妹妹穿的比我還像新娘钳垮。我一直安慰自己惑淳,他們只是感情好,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布饺窿。 她就那樣靜靜地躺著歧焦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪肚医。 梳的紋絲不亂的頭發(fā)上绢馍,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天向瓷,我揣著相機與錄音,去河邊找鬼舰涌。 笑死猖任,一個胖子當著我的面吹牛,可吹牛的內容都是我干的瓷耙。 我是一名探鬼主播朱躺,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼哺徊!你這毒婦竟也來了室琢?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤落追,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后涯肩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轿钠,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年病苗,在試婚紗的時候發(fā)現(xiàn)自己被綠了疗垛。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡硫朦,死狀恐怖贷腕,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情咬展,我是刑警寧澤泽裳,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站破婆,受9級特大地震影響涮总,放射性物質發(fā)生泄漏。R本人自食惡果不足惜祷舀,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一瀑梗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧裳扯,春花似錦抛丽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至哟忍,卻和暖如春狡门,著一層夾襖步出監(jiān)牢的瞬間陷寝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工其馏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凤跑,地道東北人。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓叛复,卻偏偏與公主長得像仔引,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子褐奥,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內容

  • 從目前已經(jīng)發(fā)布的DAPP來看咖耘,DAPP架構大致可以分成3種類型:插件錢包模式、全節(jié)點錢包模式和兼容模式撬码。 插件錢包...
    比原鏈Bytom閱讀 813評論 0 0
  • 簡介 這章的內容詳細分析一下涉及智能合約Dapp的整個開發(fā)流程儿倒,注意是涉及只能合約,如果你只要一些基本轉BTM功能...
    比原鏈Bytom閱讀 462評論 1 0
  • OmniTool開發(fā)包適用于為PHP應用快速增加對Omni Layer/USDT數(shù)字資產(chǎn)的支持能力呜笑,即支持使用自有...
    編程狂魔閱讀 1,642評論 0 1
  • 以太坊(Ethereum ):下一代智能合約和去中心化應用平臺 翻譯:巨蟹 夫否、少平 譯者注:中文讀者可以到以太坊愛...
    車圣閱讀 3,761評論 1 7
  • 1、“如果你在管教孩子的過程中感覺到痛苦叫胁,那么你的方法一定是錯的凰慈。” * 思考:有哪些時候我覺得管教孩子很痛苦驼鹅? ...
    歐米伽泥奏凱閱讀 663評論 0 2