下面我将通过一个简单的智能合约开发案例,详细说明使用Solidity进行智能合约开发的过程。我们将开发一个基本的投票系统,用户可以为候选人投票,并且投票结果会被记录在区块链上。
案例介绍:简单投票系统
1. 设置开发环境
安装工具
- Node.js:用于运行JavaScript代码。
- Truffle:Solidity开发框架。
- Ganache:本地区块链模拟器。
- MetaMask:用于与dApp进行交互的加密钱包。
npm install -g truffle
npm install -g ganache-cl
2. 创建Truffle项目
mkdir SimpleVoting
cd SimpleVoting
truffle init
3. 编写智能合约
在contracts
目录下创建一个新的文件Voting.sol
:
// Voting.sol
pragma solidity ^0.8.0;
contract Voting {
struct Candidate {
uint id;
string name;
uint voteCount;
}
mapping(address => bool) public voters;
mapping(uint => Candidate) public candidates;
uint public candidatesCount;
event votedEvent(uint indexed candidateId);
constructor() {
addCandidate("Alice");
addCandidate("Bob");
}
function addCandidate(string memory _name) private {
candidatesCount++;
candidates[candidatesCount] = Candidate(candidatesCount, _name, 0);
}
function vote(uint _candidateId) public {
require(!voters[msg.sender], "You have already voted");
require(_candidateId > 0 && _candidateId <= candidatesCount, "Invalid candidate ID");
voters[msg.sender] = true;
candidates[_candidateId].voteCount++;
emit votedEvent(_candidateId);
}
}
4. 编写迁移脚本
在migrations
目录下创建一个新的文件2_deploy_contracts.js
:
// 2_deploy_contracts.js
const Voting = artifacts.require("Voting");
module.exports = function (deployer) {
deployer.deploy(Voting);
};
5. 配置Truffle
修改truffle-config.js
,配置开发网络:
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*" // 匹配任何网络id
}
},
compilers: {
solc: {
version: "0.8.0"
}
}
};
6. 启动Ganache
ganache-cli
7. 部署智能合约
在新的终端窗口中执行以下命令:
truffle migrate --network development
8. 编写前端代码
创建client
目录,并在其中初始化一个React应用:
npx create-react-app client
cd client
npm install web3
在client/src
目录下创建一个文件Voting.js
,编写前端交互代码:
// Voting.js
import React, { useEffect, useState } from "react";
import Web3 from "web3";
import Voting from "./contracts/Voting.json";
const VotingApp = () => {
const [account, setAccount] = useState("");
const [candidates, setCandidates] = useState([]);
const [voted, setVoted] = useState(false);
useEffect(() => {
const loadBlockchainData = async () => {
const web3 = new Web3(Web3.givenProvider || "http://localhost:8545");
const accounts = await web3.eth.requestAccounts();
setAccount(accounts[0]);
const networkId = await web3.eth.net.getId();
const deployedNetwork = Voting.networks[networkId];
const contract = new web3.eth.Contract(Voting.abi, deployedNetwork && deployedNetwork.address);
const candidatesCount = await contract.methods.candidatesCount().call();
const candidatesArray = [];
for (let i = 1; i <= candidatesCount; i++) {
const candidate = await contract.methods.candidates(i).call();
candidatesArray.push(candidate);
}
setCandidates(candidatesArray);
const hasVoted = await contract.methods.voters(accounts[0]).call();
setVoted(hasVoted);
// Listen for voted event
contract.events.votedEvent({}, (error, event) => {
console.log(event);
setCandidates((prevCandidates) =>
prevCandidates.map((candidate) =>
candidate.id === event.returnValues.candidateId
? { ...candidate, voteCount: parseInt(candidate.voteCount) + 1 }
: candidate
)
);
setVoted(true);
});
};
loadBlockchainData();
}, []);
const vote = async (candidateId) => {
const web3 = new Web3(Web3.givenProvider || "http://localhost:8545");
const networkId = await web3.eth.net.getId();
const deployedNetwork = Voting.networks[networkId];
const contract = new web3.eth.Contract(Voting.abi, deployedNetwork && deployedNetwork.address);
await contract.methods.vote(candidateId).send({ from: account });
};
return (
<div>
<h2>Voting DApp</h2>
<p>Your account: {account}</p>
<h3>Candidates</h3>
<ul>
{candidates.map((candidate) => (
<li key={candidate.id}>
{candidate.name} - {candidate.voteCount} votes
{!voted && <button onClick={() => vote(candidate.id)}>Vote</button>}
</li>
))}
</ul>
</div>
);
};
export default VotingApp;
9. 运行前端应用
确保在client
目录下,启动前端应用:
npm start
总结
通过上述步骤,我们创建了一个简单的投票系统,包括智能合约的编写、部署以及前端的交互。在实际项目中,可以根据需求进一步完善和扩展功能,例如用户身份验证、投票计时器等。在开发过程中,注重代码的安全性和最佳实践,可以确保智能合约的可靠性和安全性。
评论前必须登录!
注册