Bytom DAPP Development Notes (3): DAPP demo front-end source code analysis

Time:2020-6-28

This chapter will analyze the front-end source code of DAPP demo provided by the original official, analyze the whole demo process, and then add personal opinions and solutions to the pits encountered in the development process.

A brief introduction of savings and dividend contract

For the convenience of understanding, here is a brief introduction to the content of the savings and dividend contract. For details, you can see the details of the savings and dividend contract. As the name implies, after saving, when a certain time is reached, the principal and interest will be returned in proportion. Therefore, the demo splitsaving(savings) andprofit(withdrawal) two pages. The content of this chapter is for the submission of contract transactions, so it is only for the description of savings page.

Instructions for use of DAPP demo

Official demo address

Bytom DAPP Development Notes (3): DAPP demo front-end source code analysis

1) The premise of access is to use chrome to open the official demo address, install bycoin plug-in, and search in the app store;

2) After installing bycoin, you need to initialize user information, create or import backup files to restore users;

3) Fill in the specified asset quantity and click OK;

Bytom DAPP Development Notes (3): DAPP demo front-end source code analysis

4) Pop up the special page for contract transaction, fill in the password and click confirm;

5) View transaction flow

Bytom DAPP Development Notes (3): DAPP demo front-end source code analysis

Front end source code analysis

Source code: source code of savings and dividend contract front-end (the content of this chapter is the latest version of the code on July 10, 2019)

Bytom DAPP Development Notes (3): DAPP demo front-end source code analysis

The front-end code is based on the front-end framework react, which is easy to read. The structure is as above. Let’s take a look at Bytom DAPP demo1srccompo as a saving page nentslayoutsaveindex.jsx

//Method after submission
    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) Received the amount of the input box, as well as the address of the current user;

2) Prompt content after success;

3) Prompt content after failure;

Next toFixedLimitDepositmethod

export function FixedLimitDeposit(amount, address) {
  const object = { 
    address: address,
    amount: amount,
    parameter: [amount, address]
  }
  return submitContract(listDepositUTXO, createContractTransaction, updateDatatbaseBalance, object)  //####### 1.
}

1) The three methods passed in are listdepositutxo (to find all utxos of the current contract), createcontracttransaction (to create the contract parameters before submission), and updatedatatbasebalance (to update the submission list of users)

Enter dapp-demo1srccom entslayoutsaveaction.js OfsubmitContractmethod

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) First, call listdepositutxo to get the information of all utxos currently saved and locked, which will be explained in detail later;

2) Call the createcontracttransaction method to assemble the corresponding information parameters of the contract;

3) After selecting the utxo to be used, call updateutxo to tell the buffer server that the utxo has been used, change the state, and prevent others from calling;

4) Execution window.bytom.send_ advanced_ Transaction method, referring to plug-in wallet API, is a high-level transaction method. This is the native method of bycoin plug-in, which calls up the transaction submission page to let the user enter the password;

5) After the transaction is confirmed, call updatedatatbasebalance to submit the data to the backend;


Let’s see api.js OflistDepositUTXOMethod: write all the interfaces that interact with the buffer server to this file:

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)
}

It is obvious that the / list utxos method of bufferserver is called in the end. It is very simple and worth mentioning

1) According toprogram(contract code) andasset(asset ID) to find utxo, in fact, the bottom layer here calls the official blockcenter interface, which will be explained in detail later;

Continue to look at dapp-demo1srccompn entslayoutsaveaction.js Createcontracttransaction method of

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
      })
    }
  })
}

This method is more complicated. Let’s go step by step

Let’s take a look here7) , the final returned content is input, output, args, utxo, which corresponds to the input, output, args in the send transaction page, as shown in Figure K

Bytom DAPP Development Notes (3): DAPP demo front-end source code analysis
(Figure K)

As mentioned in the previous chapter, all transactions over the original chain must have a conservation of mass theorem. The sum of input and output corresponds to each other. The execution method in the contract transaction must have parameters. Here, args represents the incoming parameters, and utxo represents the ID of utxo

1) Set the minimum value

2) Matchsutxo, according to the above content, just passedlistDepositUTXOGet the list of all available utxos. At this time, select a utxo of at least an amount greater than or equal to the amount entered by the user;

3) Contractarguments, building args, is the parameter of the method in the contract;

4) Usually, the contract transaction will have its own asset input, contract utxo input, here is the input of utxo to be unlocked;

5) This is the input of wallet assets;

6) As mentioned in the previous chapter, when unlocking a contract, the corresponding results must be calculated according to the logic in the contract, so the logic here is the same as that in the contract, and the detailed description of the savings and dividend contract is shown in the figure below;

Bytom DAPP Development Notes (3): DAPP demo front-end source code analysis

The judgment logic is the same. The structure of plug-in wallet interface mentioned in the previous chapter is different, but the principle is the same.

Finally, let’s look at srccompon entslayoutsaveaction.js OfupdateDatatbaseBalancemethod

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)
}

The same is to call buffer server. Here is to call the update balance method to submit the successful transaction to the backend.

Summary

The content and methods of DAPP demo front-end code are introduced above. Apart from the complexity of plug-in API calls, other common application logic calls are mainly understoodConservation of massThe rest is about data audit. It’s very simple.


Pit encountered

Readers with application development should be able to understand the core of the problem at once. Now I’m talking about the pit;

1) Utxo lock interface is easy to be brushed; if a developer knows this interface and swipes the utxo of your interface lock application, the application will be paralyzed for a long time;

Solution: this should be considered from the application aspect, such as adding some one-time verification codes to the interface, adding refer monitoring, adding authorization and other ways, and adding transaction monitoring to the back end to maintain the state of utxo in various situations, which is abstract and complex, but it is necessary;

2) Concurrency problem; same as 1) even if I am a normal user, after I choose a utxo to unlock, I actually tell the back end to lock through the HTTP interface and set it upEnter password page(Figure K). At this time, if the user does not enter the password and do not submit it, the utxo will not be unlocked on the original link, but the buffer server will be locked.

Solution: the back-end source code is locked for a period of time. If it is not used, it will be unlocked on a regular basis. This situation also requires monitoring and judgment of the application to maintain the status of all utxos. I suggest that when issuing a contract,Send multiple utxo lock-in contracts, there will be more utxos available. At this time, some students ask whether TPS is not the same. If the students use excessive coins, they will know that the blockchain transaction does not pay much attention to TPS, and the transaction of hot coins must be more than 60-100 blocks before a transaction can be determined. This depends on how the application developers judge and choose.

3) The user’s transaction information interface is easy to be swiped; just like 1) after the transaction is completed, I submit data directly through the HTTP interface. I swipe wildly, isn’t it a billionaire;

Solution: if you want the user’s transaction information to generate transaction bills, you can directly use the plug-in interface, but you need to filter it through the contract code. The author monitors all transactions in the blockchain browser and enters the database transaction table, so that you can monitor all transactions at all times.

4) Prone to chain errors; Here DAPP demo sends a utxo of a contract. If a user submits a transaction, a new utxo will be generated, but the utxo has not been confirmed yet. The list utxo interface of the buffer server will put the unidentified utxo to solve the concurrency problem. But as a developer, I know the code of the contract and write a transaction freely. Although it will definitely fail, it will take time At this time, the buffer server also returns the utxo that has definitely failed to the front end, and it has been chained to generate a bunch of transactions, which is easy to generate chained failures.

Solution: 1) I’ve discussed with the former official boss. The best solution is to set a password for the contract itself. The input parameters must be encrypted with incode according to the password. When the contract itself is interpreted, decode and verify it to ensure that the parameters in and out are official, so no one will attack… But the conclusion is, for the time being Contract engine of the original chain is not supported.

2) It is necessary to hide the contract logic, and other people cannot call malicious occupation, for example, the front-end code is confused, or the args parameter is the back-end generation. In addition, it is suggested that the contract logic can be masked by encrypting the build transaction interface parameter of the original blockcenter.

PS: This is the author’s reflection on the above problems. There is a better solution. Welcome to discuss it together.

summary

This content mainly talks about the source code analysis of the front-end code, as well as the logic pit in the design. The specific solution should be communicated and discussed with the official developers. The transaction of the blockchain originally does not pursue large concurrency, but it also needs certain concurrency. In Chapter 4, the author makes some personal opinions and suggestions according to the content of the buffer server in view of the above problems 。