教程区块链区块链技术ch1717.8 安全与测试:防重复投票与权限控制验证

本页目录

投票系统的核心安全需求:一人一票、结果不可篡改、计票透明。


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

评论加载中…

发表评论

0/2000