投票系统的核心安全需求:一人一票、结果不可篡改、计票透明。
17.8.1 防重复投票
rust
// 已在 17.3 中实现
// has_voted: Vec<Pubkey> — 每个地址只能出现一次
pub fn cast_vote(ctx: Context<CastVote>, option_index: u8) -> Result<()> {
let vote_account = &mut ctx.accounts.vote_account;
let voter = *ctx.accounts.voter.key;
// 防重复投票检查
if vote_account.has_voted.contains(&voter) {
return Err(VoteError::AlreadyVoted.into());
}
vote_account.votes[option_index as usize] += 1;
vote_account.has_voted.push(voter);
Ok(())
}| 攻击 | 防御 | 验证方式 |
|---|---|---|
| 重复投票 | has_voted 数组检查 | 单元测试:同一地址两次投票返回错误 |
| 过期后投票 | end_time 检查 | 时间旅行测试:模拟过期后调用 |
| 无效选项 | 索引范围检查 | 边界测试:option_index 超范围 |
| 非创建者关闭 | 签名地址 == creator 检查 | 权限测试:其他地址关闭失败 |
17.8.2 测试用例
typescript
// tests/vote.ts
import * as anchor from '@coral-xyz/anchor';
import { expect } from 'chai';
import { Vote } from '../target/types/vote';
describe('vote', () => {
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.Vote as anchor.Program<Vote>;
let voteAccount: anchor.web3.Keypair;
// 测试用例
it('可创建投票', async () => {
voteAccount = anchor.web3.Keypair.generate();
await program.methods
.createPoll('最喜欢的编程语言?', ['Rust', 'Go', 'TypeScript'], ...)
.accounts({ ... })
.signers([voteAccount])
.rpc();
const account = await program.account.voteAccount.fetch(voteAccount.publicKey);
expect(account.question).to.equal('最喜欢的编程语言?');
expect(account.options).to.deep.equal(['Rust', 'Go', 'TypeScript']);
});
it('可投票', async () => {
await program.methods.castVote(0)
.accounts({ voteAccount: voteAccount.publicKey, voter: provider.wallet.publicKey })
.rpc();
const account = await program.account.voteAccount.fetch(voteAccount.publicKey);
expect(account.votes[0]).to.equal(1);
});
it('不能重复投票', async () => {
try {
await program.methods.castVote(1)
.accounts({ voteAccount: voteAccount.publicKey })
.rpc();
expect.fail('应抛出错误');
} catch (e: any) {
expect(e.toString()).to.include('AlreadyVoted');
}
});
it('过期后不能投票', async () => { /* 时间旅行测试 */ });
});17.8.3 测试金字塔
graph TD
Unit[单元测试: Anchor test 本地验证器] --> Integration[集成: 前后端联调]
Integration --> Devnet[devnet 部署测试]
Devnet --> Mainnet[主网观察模式]
, 前往 → 17.9 部署 |*
评论
0评论加载中…