安裝ganache-cli
ganache-cli是以太坊節點仿真器軟件ganache的命令行版本,可以方便開發者快速進行以太坊DApp的開發與測試。
npm install -g ganache-cli
啓動
~$ ganache-cli
啓動選項
- -a 或 --accounts: 指定啓動時要創建的測試賬戶數量。
- -e 或 --defaultBalanceEther: 分配給每個測試賬戶的ether數量,默認值爲100。
- -b 或r --blockTime: 指定自動挖礦的blockTime,以秒爲單位。默認值爲0,表示不進行自動挖礦。
- -d 或 --deterministic: 基於預定的助記詞(
mnemonic
)生成固定的測試賬戶地址。 - -n 或 --secure: 默認鎖定所有測試賬戶,有利於進行第三方交易簽名。
- -m 或 --mnemonic: 用於生成測試賬戶地址的助記詞。
- -p 或 --port: 設置監聽端口,默認值爲8545。
- -h 或 --hostname: 設置監聽主機,默認值同NodeJS的
server.listen()
。 - -s 或 --seed: 設置生成助記詞的種子。.
- -g 或 --gasPrice: 設定Gas價格,默認值爲20000000000。
- -l 或 --gasLimit: 設定Gas上限,默認值爲90000。
- -f 或 --fork: 從一個運行中的以太坊節點客戶端軟件的指定區塊分叉。輸入值應當是該節點旳HTTP地址和端口,例如
http://localhost:8545
。 可選使用@標記來指定具體區塊,例如:http://localhost:8545@1599200
。 - -i 或 --networkId:指定網絡id。默認值爲當前時間,或使用所分叉鏈的網絡id。
- --db: 設置保存鏈數據的目錄。如果該路徑中已經有鏈數據,ganache-cli將用它初始化鏈而不是重新創建。
- --debug:輸出VM操作碼,用於調試。
- --mem:輸出ganache-cli內存使用統計信息,這將替代標準的輸出信息。
- --noVMErrorsOnRPCResponse:不把失敗的交易作爲RCP錯誤發送。開啓這個標誌使錯誤報告方式兼容其他的節點客戶端,例如geth和Parity。
特殊選項
- --account: 指定賬戶私鑰和賬戶餘額來創建初始測試賬戶。可多次設置:
$ ganache-cli --account="<privatekey>,balance" [--account="<privatekey>,balance"]
注意私鑰長度爲64字符,必須使用0x前綴的16進制字符串。賬戶餘額可以是整數,也可以是0x前綴的17進制字符串,單位爲wei。
使用--account選項時,不會自動創建HD錢包。
- -u 或 --unlock: 解鎖指定賬戶,或解鎖指定序號的賬戶。可以設置多次。當與--secure選項同時使用時,這個選項將改變指定賬戶的鎖定狀態:
$ ganache-cli --secure --unlock "0x1234..." --unlock "0xabcd..."
也可以指定一個數字,按序號解鎖賬號:
$ ganache-cli --secure -u 0 -u 1
安裝Truffle
1、下載官網Nodejs12版本
2、解壓到對應目錄下,並改名爲node
3、配置環境變量
gedit ~/.bashrc
export NODE_HOME=/opt/node
export PATH=$PATH:$NODE_HOME/bin
export NODE_PATH=$NODE_HOME/lib/node_modules
保存後
source ~/.bashrc
4、安裝Truffle
$ npm install -g truffle
結束後進入truffle命令行即成功
合約項目
1、創建項目路徑
mkdir auction_dapp
cd auction_dapp
truffle unbox webpack
rm constracts/ConvertLib.sol constracts/MetaCoin.sol
2、創建EcommerceStore.sol文件,編寫滿足需求的合約
pragma solidity ^0.4.17;
contract EcommerceStore{
enum ProductStatus{Open, Sold, Unsold}
enum ProductCondition{New, Used}
uint public productIndex;
mapping (uint => address) productIdInstore;
mapping (address => mapping(uint => Product)) stores;
struct Bid{
address bidder;
uint productId;
uint value;
bool revealed;
}
struct Product{
uint id;
string name;
string category;
string imageLink;
string descLink;
uint auctionStartTime;
uint auctionEndTime;
uint startPrice;
address highestBidder;
uint highestBid;
uint secondHighestBid;
uint totalBids;
ProductStatus status;
ProductCondition condition;
mapping(address => mapping(bytes32 => Bid)) bids;
}
function constructor() public{
productIndex = 0;
}
function addProductToStore(string _name,string _category, string _imageLink, string _descLink
,uint _auctionStartTime,uint _auctionEndTime,uint _startPrice,uint _productCondition)public{
require(_auctionStartTime < _auctionEndTime);
productIndex += 1;
Product memory product = Product(productIndex,_name,_category,_imageLink,_descLink,_auctionStartTime,_auctionEndTime,_startPrice,0,0,0,0,ProductStatus.Open,ProductCondition(_productCondition));
stores[msg.sender][productIndex] = product;
productIdInstore[productIndex] = msg.sender;
}
function getProduct(uint _productId) public view returns(uint, string, string, string, string, uint, uint, uint, ProductStatus, ProductCondition){
Product memory product = stores[productIdInstore[_productId]][_productId];
return (product.id,product.name,product.category,product.imageLink, product.descLink,product.auctionStartTime,product.auctionEndTime,product.startPrice,product.status, product.condition);
}
function bid(uint _productId,bytes32 _bid) payable public returns(bool){
Product storage product = stores[productIdInstore[_productId]][_productId];
require(now >= product.auctionStartTime);
require(now <= product.auctionEndTime);
require(msg.value > product.startPrice);
require(product.bids[msg.sender][_bid].bidder == 0);
product.bids[msg.sender][_bid] = Bid(msg.sender, _productId,msg.value,false);
product.totalBids += 1;
return true;
}
function revealBid(uint _productId, string _amount, string _secret) public{
Product storage product = stores[productIdInstore[_productId]][_productId];
require(now > product.auctionEndTime);
bytes32 sealedBid = sha3(_amount,_secret);
Bid memory bidInfo = product.bids[msg.sender][sealedBid];
require(bidInfo.bidder > 0);
require(bidInfo.revealed == false);
uint refund;
uint amount = stringToUint(_amount);
if(bidInfo.value < amount){
refund = bidInfo.value;
}else{
if(address(product.highestBidder) == 0){//first time
product.secondHighestBid = product.highestBid;
product.highestBidder.transfer(product.highestBid);
product.highestBidder = msg.sender;
product.highestBid = amount;
refund = bidInfo.value - amount;
}else{
if(amount > product.highestBid){
product.secondHighestBid = product.highestBid;
product.highestBid = amount;
product.highestBidder = msg.sender;
}else if(amount > product.secondHighestBid){
product.secondHighestBid = amount;
refund = bidInfo.value;
}else{
refund = amount;
}
}
}
product.bids[msg.sender][sealedBid].revealed = true;
if (refund > 0) {
msg.sender.transfer(refund);
}
}
function highestBidderInfo(uint _productId) view public returns (address, uint, uint) {
Product memory product = stores[productIdInstore[_productId]][_productId];
return (product.highestBidder, product.highestBid, product.secondHighestBid);
}
function totalBids(uint _productId) view public returns (uint) {
Product memory product = stores[productIdInstore[_productId]][_productId];
return product.totalBids;
}
function stringToUint(string s)pure private returns(uint){
bytes memory b = bytes(s);
uint result = 0;
for (uint i = 0; i < b.length; i++) {
if (b[i] >= 48 && b[i] <= 57) {
result = result * 10 + (uint(b[i]) - 48);
}
}
return result;
}
}
3、將EcommerceStore.sol拷貝到項目的contracts目錄下,將本來存在的ConvertLib.sol和MetaCoin.sol刪除,保留Migration.sol和新合約EcommerceStore.sol
4、回到auction_dapp目錄下,修改對應的truffle-config.js文件
development:{
host: "127.0.0.1",
port: 8545,
network_id: "*", //network的廣泛選擇性
}
compilers: {
solc: {
version: "0.4.17", // 與編寫的合約版本相同
}
}
5、truffle編譯
cd contracts
truffle compile
生成的結果到build/constracts下的json文件中
6、truffle部署相應的合約,前提是ganache-cli必須已經啓動
//是否重新部署
truffle migrate (--reset)
7*啓動控制檯類似於私鏈geth的使用
truffle console