DApp入門(僅后端)
- 引言
- 環境
- 初始化nmp
- 創建私鏈
- 撰寫合約
- 編譯合約
- 部署合約
- 控制臺互動
引言
最近在學區塊鏈,做了個簡單的投票DApp,僅包含后端,主要學習一下與合約的互動,因為程序中踩了無數的坑,特此記錄,
環境
geth version 1.10.14-unstable-99be62a9-20211220
nodejs version v10.13.0
初始化nmp
進入專案檔案
npm init
npm install web3@0.20.7
npm install solc@0.4.22
創建私鏈
撰寫genesis.json檔案,這個檔案是geth官網給的PoA協議的模板,直接復制過來即可,
{
"config": {
"chainId": 15,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"clique": {
"period": 5,
"epoch": 30000
}
},
"difficulty": "1",
"gasLimit": "8000000",
"extradata": "0x0000000000000000000000000000000000000000000000000000000000000000E35586d5C0e2f41938A005546f83c1B23798ca130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"alloc": {
"E35586d5C0e2f41938A005546f83c1B23798ca13": { "balance": "3000000000000000000000" },
"f41c74c9ae680c1aa78f42e5647a62f353b7bdde": { "balance": "4000000000000000000000" }
}
}
初始化私鏈
geth init --datadir data genesis.json
啟動私鏈
geth --datadir ./data --nodiscover --http --http.api personal,eth,net,web3 --allow-insecure-unlock --dev --networkid 15 console 2>output.log
這里面的引數是我踩了許多坑最終確定的,–nodiscover代表不要尋找peer nodes(不加的話會一直刷peer nodes),–allow-insecure-unlock可以使得其他控制臺能夠訪問到http.api,在 dev 模式下,啟動節點后,系統默認提供一個開發者賬號,這個賬號會作為當前的 coinbase 賬號,在 keystore 目錄下也有對應的加密私鑰檔案,這個賬戶里會有很多很多的錢,可以用來轉賬,同時每發生一筆交易,都會自動挖礦上傳區塊,console打開控制臺,日志寫到output.log里,
現在私鏈就已經成功啟動啦,可以另開一個視窗實時查看日志,
tail -f output.log
回到原來的視窗,在控制臺上輸入eth.accounts可以查看賬戶,dev模式下應該是有一個默認賬戶,也就是accounts[0],里面有很多錢,
> eth.accounts
["0x3c9487d9680666e181d75e48adbafce7c9111fe5"]
下面創建一個新的賬戶
> personal.newAccount()
Passphrase:
Repeat passphrase:
"0xe40ec1d1dd73bd9045f5a2c98f9c8807665823f8"
往這個賬戶里轉一些錢用于創建合約
> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:web3.toWei(2,'ether')})
"0xe3ed27f27dd02bc8f72dc59ff415269f07a21e765f5ec9c9ed8cc6233779fcc7"
> eth.getBalance(eth.accounts[1])
2000000000000000000
撰寫合約
這里面我直接copy了一個solidity模板,一個很簡單的投票合約,存盤為Voting.sol
pragma solidity ^0.4.22;
contract Voting {
mapping (bytes32 => uint8) public votesReceived;
bytes32[] public candidateList;
constructor(bytes32[] candidateNames) public {
candidateList = candidateNames;
}
function totalVotesFor(bytes32 candidate) view public returns (uint8) {
require(validCandidate(candidate));
return votesReceived[candidate];
}
function voteForCandidate(bytes32 candidate) public {
require(validCandidate(candidate));
votesReceived[candidate] += 1;
}
function validCandidate(bytes32 candidate) view public returns (bool) {
for(uint i = 0; i < candidateList.length; i++) {
if (candidateList[i] == candidate) {
return true;
}
}
return false;
}
}
編譯合約
輸入node打開nodejs控制臺,
> Web3 = require('web3')
> web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
> code = fs.readFileSync('Voting.sol').toString()
> solc = require('solc')
> compiledCode = solc.compile(code)
部署合約
Execute this in your node console:
> abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface)
> VotingContract = web3.eth.contract(abiDefinition)
> byteCode = compiledCode.contracts[':Voting'].bytecode
> deployedContract = VotingContract.new(['Alice','Bob','Cary'],{data: '0x'+byteCode, from:
web3.eth.accounts[1], gas: 4700000})
##注意那個'0x'如果不加會有如下報錯
Error: invalid argument 0: json: cannot unmarshal hex string without 0x prefix into Go struct field TransactionArgs.data of type hexutil.Bytes
at Object.InvalidResponse (/home/dyj/project-block/project/node_modules/web3/lib/web3/errors.js:38:16)
at RequestManager.send (/home/dyj/project-block/project/node_modules/web3/lib/web3/requestmanager.js:61:22)
at Eth.send [as sendTransaction] (/home/dyj/project-block/project/node_modules/web3/lib/web3/method.js:145:58)
at ContractFactory.new (/home/dyj/project-block/project/node_modules/web3/lib/web3/contract.js:228:33)
##如果報錯說未授權的問題,需要給account解鎖
Error: authentication needed: password or unlock
at Object.InvalidResponse (/home/dyj/project-block/project/node_modules/web3/lib/web3/errors.js:38:16)
at RequestManager.send (/home/dyj/project-block/project/node_modules/web3/lib/web3/requestmanager.js:61:22)
at Eth.send [as sendTransaction] (/home/dyj/project-block/project/node_modules/web3/lib/web3/method.js:145:58)
at ContractFactory.new (/home/dyj/project-block/project/node_modules/web3/lib/web3/contract.js:228:33)
##解鎖
>web3.personal.unlockAccount(web3.eth.accounts[1],'your password')
>deployedContract = VotingContract.new(['Alice','Bob','Cary'],{data: '0x'+byteCode, from:
web3.eth.accounts[1], gas: 4700000})
以上合約就部署成功了,但是問題又沒有完全解決,此時如果直接呼叫deployedContract.address會回傳undefined
> deployedContract.address
undefined
明明已經挖礦了,在區塊鏈上可以看到合約資訊,但是合約地址就是undefined,找了各種論壇,終于找到了原因,可能是因為賬戶授權過期了,由于解決程序比較玄學,放下原貼,
https://ethereum.stackexchange.com/questions/10542/address-is-undefined-after-deploying-a-smart-contract

基于此,重新unlock一下,再部署,然后挖礦,挖礦成功后,應該就能看到address,(雖然是dev環境啟動的,但是這里仍需要手動挖一下,)
關于挖礦,在console里輸入
>miner.start()
##看下日志,挖出來之后
>miner.stop()
控制臺互動
接下來就可以使用合約地址呼叫合約了
> contractInstance = VotingContract.at(deployedContract.address)
'0xeb5cfe629990e8ec7d8e468913e97a6f4ed15899323fab5b2d88ac0cf35232d3'
> contractInstance.voteForCandidate('Alice', {from:web3.eth.accounts[1]})
##此時如果查看Alice的票數發現是0
> contractInstance.totalVotesFor.call('Alice').toLocaleString()
'0'
##問題的原因還是在于沒有挖礦,miner成功后,重新查看
> contractInstance.totalVotesFor.call('Alice').toLocaleString()
'1'
以上就完成了后端的互動,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/390406.html
標籤:區塊鏈
下一篇:PCA主成分分析(降維)
