以太坊web3開發初步學習


以太坊web3開發初步學習

此文是對https://learnblockchain.cn/2018/04/15/web3-html/的學習再理解。

以太坊智能合約通過使用web3.js前端和智能合約交互。web3.js是以太坊官方的js API, 用戶可以通過web3.js提供的API通過http或者IPC與
本地的或者遠程的以太坊節點進行交互。
主要有以下幾種庫

web3-eth //主要用來與以太坊和智能合約交互
web3-shh //用於控制whisper協議和p2p通信以及廣播
web3-utils // 包含與DApp有關的功能

web3和geth(以太坊客戶端)通信使用的是JSON—RPC協議。

首先以一個最基礎的solidity合約舉例:

pragma solidity ^0.4.21;

contract InfoContract {

   string fName;
   uint age;

   function setInfo(string _fName, uint _age) public {
       fName = _fName;
       age = _age;
   }

   function getInfo() public constant returns (string, uint) {
       return (fName, age);
   }
}

web3 provider是指自定義節點,例如私有測試網絡。
Injected web3 連接到嵌入頁面的web3,比如連接到MetaMask。
Javascript VM是本地的js虛擬機環境,僅用於練習合約編寫。

接着就是安裝web3。web3安裝好之后創建UI前端,包括了輸入框。
<script>標簽中間寫web.js的代碼和智能合約進行交互。

<script>
    if (typeof web3 !== 'undefined') {
        web3 = new Web3(web3.currentProvider);
    } else {
        // set the provider you want from Web3.providers
        web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));
    }
</script>

該腳本意思為,如果web3已被定義,就創建web3對象。否則就手動指定provider。
provider就是錢包,通過RPC web3和錢包進行連接。

一旦連接錢包,接下來便可以設置以太坊賬戶。

web3.eth.defaultAccount = web3.eth.accounts[0];//選擇第一個賬戶。

賬戶設置好之后,web3通過ABI調用合約函數,通過Remix中出現的ABI,

info.getInfo(function(error, result){//info是某地址的合約
    if(!error)
        {
            $("#info").html(result[0]+' ('+result[1]+' years old)');
            console.log(result);
        }
    else
        console.error(error);
});

$("#button").click(function() {//setInfo是info合約的函數,點擊button后設置了name和age的值
    info.setInfo($("#name").val(), $("#age").val());
});

最終,合約向以太坊中輸入了name和age。

小結

以太坊智能合約,本質上就像一個類庫, 類庫的方法用於操作和更新類庫中的狀態變量,這些方法需要外部用戶來調用。外部用戶調用ABI的時候往往會向其中輸入參數。
這些參數用於更新合約的全局變量。 所以說智能合約的本質是不可篡改的數據庫。智能合約的核心就是其狀態變量。
其實智能合約本質就是一個難以篡改的數據庫。稱之為合約實際上真是誤導人。

其他知識點

$("#xxid")是id選擇器。jquery的知識。
https://www.cnblogs.com/jokerjason/p/7404649.html

solidity的事件

區塊鏈是打包一系列交易的區塊組成的鏈條,每一條交易會包含0到多個日志記錄,日志就代表着合約所觸發的事件。
DAPP的應用,如果監聽了某事件,當事件發生時,會進行回調。日志和事件在合約內無法被訪問,而只能被外部監聽。
事件的定義:

event EventName(address bidder, uint amount)

該用法和定義函數式一樣的,並且在事件合約中同樣可以被繼承。

事件監聽有什么用?

定義一個事件,

event Instructor(string name, uint age); //接收兩個參數

在setInfo函數中,觸發Instructor事件。

function setInfo(string _fName, uint _age) public{
  fName = _fName;
  age = _age;
  emit Instructor(_fName, _age);//這是setInfo的參數。
}

emit表示觸發動作。 setInfo函數執行時會觸發該事件。在web3前端輸入name和age之后,觸發Instructor事件
在web3部分引用事件監聽器

var instructorEvent = info.Instructor();

再寫一個回調函數, 這樣,代碼更新后,再在瀏覽器上點擊update info,便會回調

instructorEvent.watch(function(error, result) {//該函數有兩個返回值,result便是setInfo的返回值。
        if (!error)
            {
                $("#info").html(result.args.name + ' (' + result.args.age + ' years old)');//這里寫的是形參。
            } else {
                console.log(error);
            }
    });

說白了, event變量寫好后,在某個函數中聲明,觸發的時候, web3如果監聽了它,且寫了一個watch函數,便可以得到監聽的參數。
這些參數拿到之后再輸出到頁面上,從而完成更新。

solidity的事件和日志

var options = { 
    fromBlock: 0,
    address: web3.eth.defaultAccount, //地址
    topics: ["0x0000000000000000000000000000000000000000000000000000000000000000", null, null]
};
web3.eth.subscribe('logs', options, function (error, result) {
    if (!error)
        console.log(result);
})
    .on("data", function (log) {
        console.log(log);
    })
    .on("changed", function (log) {
});

solidity局部變量無法使用映射類型。

有兩個函數,funcA和funcB, 在funcA中聲明了一個變量C,funcA調用B且C作為B的參數,但是總是報錯。
后來查資料發現對memory 類型的映射賦值,會報錯。https://blog.csdn.net/qq_33764491/article/details/80403603
原因在於solidity的映射的實現是通過

solidity枚舉類型

和C語言枚舉類型的寫法一樣。

enum weekday{
  sun,mon,tue,wed,the,fri,sat;
}
// weekday.sun 來引用枚舉值。

注意,"}"后面沒有分號。 使用枚舉的時候要是xxx.xxx格式。

solidity異常通知

一共有三種,

assert(bool condition), //如果條件不滿足,拋出異常,合約中斷,一般使用於內部錯誤
require(bool condition) //如果條件不滿足,拋出異常,合約中斷, 用於函數參數輸入的判斷和外部函數使用
require(bool condition, string message) //會拋出日志
revert() //回滾, 合約中斷, 回滾狀態改變
revert(string, reason) //提供一個回滾說明

監控器檢測到異常之后,要用哪類通知呢?
這里選擇了assert(bool condition)

assert(Parse_acceptword_to_wordset(accept_word, wset) != RETURNID.ACCEPT_WORD_FORMAT_WRONG);

solidity比較字符串大小

幾乎能搜到的寫法都是錯誤的。不知道是由於solidity的abi庫改變了還是別的原因。查看文檔發現,要得到字符串的hash值,必須先調用abi.encodePacked()

keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))

文檔建議最好使用bytes來代替string,這樣最節省gas。

solidity無法使用while(1)

while(1)用法錯誤,應該使用while(true)

solidity的日志

事件是給solidity使用的,於是會有一種比較特殊的方案。

對外訪問,在函數的函數名xx()之后添加

solidity日志(Event)的使用方法。
在DAPP的應用中,如果監聽了某事件,當某事件發生時,會進行回調。 但是日志在合約內是無法被訪問的,即使是創建日志的合約。

event eventName(address bidder, uint amount)//

使用web3.js和日志進行交互,如果它發生了錯誤。

首先要定義一個事件,該事件要能夠和合約進行觸發
參考資料 https://www.cnblogs.com/tinyxiong/p/9045274.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM