傳送門: 柏鏈項目學院java
這是一個基於go語言編寫的,自動化測試以太坊智能合約的開發框架,使用此框架,能夠自動化的部署合約,自動測試合約內的功能函數。你也發現了,本框架模擬的是truffle框架,可是徹底是基於go語言編寫,並且以太坊的客戶端須要使用私鏈或者測試鏈。c++
本課程是指導開發者如何經過go語言來實現這樣一個測試框架。git
go語言環境安裝本文再也不詳細說明,如下咱們介紹其餘環境安裝。github
這個其實教程不少,搜索引擎都能搜到,也能夠去官網查看!官網安裝說明golang
solidity智能合約須要編譯,若是使用remix環境,在線編譯器就幫咱們作了,如今咱們須要在命令行實現,那須要本身安裝solc編譯器,以後藉助安裝geth自帶的abigen可執行程序,能夠輕鬆的搞定solidity智能合約的編譯,將sol文件編譯爲go文件。shell
下載solidity,這個由以太坊官方提供編程
git clone https://github.com/ethereum/solidity
此代碼由c++編寫實現,使用cmake進行編譯,若是沒有cmake須要安裝一個。json
brew install cmake
sudo apt-get install cmake
開始solidity代碼ubuntu
cd solidity mkdir build cd build cmake .. && make
再將可執行文件solc拷貝到系統$PATH的某個路徑下app
cp solc/solc /usr/local/bin/
當把工具準備好以後,咱們就能夠來嘗試編譯智能合約了。那麼首先,咱們得有一個智能合約。下面的例子是一個模擬銀行業務的智能合約。
pragma solidity^0.5.0; contract pdbank { address public owner; mapping(address=>uint256) public balances;//紀錄每一個帳戶餘額 uint256 public totalAmount; string public bankName;//銀行名稱 //構造函數 constructor(string memory _bankName) public { owner = msg.sender; bankName = _bankName; } //充值 function deposit() public payable { //do nothing totalAmount += msg.value; balances[msg.sender] += msg.value; } //提現 function withdraw(uint256 _amount) public payable { if(balances[msg.sender] > _amount) { balances[msg.sender] -= _amount; msg.sender.transfer(_amount); totalAmount -= _amount; } } }
如何編譯它呢?查看如下abigen的幫助!
yekaideMacBook-Pro:~ yk$ abigen -h Usage of abigen: -abi string Path to the Ethereum contract ABI json to bind, - for STDIN -bin string Path to the Ethereum contract bytecode (generate deploy method) -exc string Comma separated types to exclude from binding -lang string Destination language for the bindings (go, java, objc) (default "go") -out string Output file for the generated binding (default = stdout) -pkg string Package name to generate the binding into -sol string Path to the Ethereum contract Solidity source to build and bind -solc string Solidity compiler to use if source builds are requested (default "solc") -type string Struct name for the binding (default = package name)
咱們來新建一個工程:gosolkit
cd $GOPATH/src/ mkdir gosolkit cd gosolkit
建立一個sol目錄,用於存放智能合約
mkdir sol
建立pdbank.sol文件,編輯智能合約文件,將上述合約代碼填入其中。
yekaideMacBook-Pro:sol yk$ cat pdbank.sol pragma solidity^0.5.0; contract pdbank { address public owner; mapping(address=>uint256) public balances;//紀錄每一個帳戶餘額 uint256 public totalAmount; string public bankName;//銀行名稱 //構造函數 constructor(string memory _bankName) public { owner = msg.sender; bankName = _bankName; } //充值 function deposit() public payable { //do nothing totalAmount += msg.value; balances[msg.sender] += msg.value; } //提現 function withdraw(uint256 _amount) public payable { if(balances[msg.sender] > _amount) { balances[msg.sender] -= _amount; msg.sender.transfer(_amount); totalAmount -= _amount; } } }
編譯代碼,注意使用sol與pkg參數,type參數這裏不啓用(type在編譯abi文件時使用,若是是源文件不需使用type)
yekaideMacBook-Pro:sol yk$ abigen -sol pdbank.sol -pkg main -out pdbank.go yekaideMacBook-Pro:sol yk$ ls -lrt total 48 -rw-r--r-- 1 yk staff 766 3 20 09:31 pdbank.sol -rw------- 1 yk staff 16915 3 20 09:33 pdbank.go
能夠去欣賞一下這個go代碼了!
這裏說的調用固然就是用go語言來調用智能合約。
首先來看發佈,咱們要在go語言代碼中找到帶Deploy開頭的函數,很開心,咱們找到了DeployPdbank。這個就是部署合約的函數,找到它,咱們就能夠部署合約了,那麼就先研究這個函數如何使用!
func DeployPdbank(auth *bind.TransactOpts, backend bind.ContractBackend, _bankName string) (common.Address, *types.Transaction, *Pdbank, error)
參數說明
返回值
咱們先來考慮身份設置,須要帳戶地址以及私鑰,私鑰=keystore+password。
須要用到的工具包和函數:
編寫部署合約的代碼
func CallDeployPdbank() error { //連接到以太坊節點 cli, err := ethclient.Dial("http://localhost:8545") if err != nil { fmt.Println("failed to dial geht", err) return err } //建立身份,須要私鑰 auth, err := bind.NewTransactor(strings.NewReader(keydata), "123") if err != nil { fmt.Println("faild to NewTransactor", err) return err } //部署合約 addr, ts, pb, err := DeployPdbank(auth, cli, "yekai") if err != nil { fmt.Println("failed to deploy pdbank", err) return err } //測試查詢銀行名 name, _ := pb.BankName(nil) fmt.Println("addr=", addr.Hex(), "name=", name, ts.Hash().Hex()) return nil }
能夠測試,執行結果發現:
yekaideMacBook-Pro:sol yk$ go run main.go pdbank.go addr= 0x625CC53E4660660eD94D90D263D1D793d453DE33 name= 0xc36f59cd82317ab14d49c5490cdbe6654a7f30ddc5eb5d208b277ac01fc2b4b3
也就是說name並無獲取成功,這是由於以太坊屬於異步開發,剛剛部署不會當即生效,因此當即獲取會失敗!
再編寫一個查詢銀行名字的
func CallBankName() error { cli, err := ethclient.Dial("http://localhost:8545") if err != nil { fmt.Println("failed to dial geht", err) return err } defer cli.Close() //將以前部署的合約地址拿過來 pb, err := NewPdbank(common.HexToAddress("0x625cc53e4660660ed94d90d263d1d793d453de33"), cli) //因爲查看銀行名稱不須要消耗gas,因此不用指定身份 name, _ := pb.BankName(nil) fmt.Println("bank name is", name) return err }
再編寫一個存款的函數調用
func CallDeposit() error { //連接到以太坊節點 cli, err := ethclient.Dial("http://localhost:8545") if err != nil { fmt.Println("failed to dial geht", err) return err } defer cli.Close() //建立身份,須要私鑰 auth, err := bind.NewTransactor(strings.NewReader(keydata), "123") if err != nil { fmt.Println("faild to NewTransactor", err) return err } pb, err := NewPdbank(common.HexToAddress("0x625cc53e4660660ed94d90d263d1d793d453de33"), cli) //存款須要攜帶金錢 auth.Value = big.NewInt(10000001) //存款須要亮明身份 ts, err := pb.Deposit(auth) if err != nil { fmt.Println("failed to deposit", err) return err } fmt.Println(ts.Hash().Hex()) return err }