SwiftHTML & CSSSolidityDesenvolvimento de JogosSolana/Rust
15.11.2024

Aula 038: Implementando Sistemas de Votação On-Chain

Nesta aula, vamos explorar como implementar um sistema de votação on-chain usando Rust e a blockchain Solana. Sistemas de votação são cruciais para aplicações descentralizadas (dApps), pois permitem que os participantes tomem decisões de maneira confiável. Este tutorial oferecerá uma implementação simples, guiando você na criação de um contrato de votação que permite aos usuários criar enquetes e votar nelas.

Configurando Seu Ambiente

Antes de começarmos, certifique-se de que você tenha o seguinte configurado:

  1. Rust e Cargo: Garanta que Rust e Cargo estejam instalados em sua máquina. Você pode instalá-los no site oficial do Rust.

  2. Solana CLI: Instale as ferramentas de linha de comando da Solana seguindo as instruções de instalação no site oficial da Solana.

  3. Anchor Framework: Usaremos o framework Anchor para simplificar o desenvolvimento de contratos inteligentes na Solana. Instale-o utilizando:

    cargo install --git https://github.com/coral-xyz/anchor.git --tag v0.26.0 anchor-cli --locked
  4. Crie um Novo Projeto: Inicie um novo projeto Anchor executando:

    anchor init sistema_de_votacao_on_chain
    cd sistema_de_votacao_on_chain

Entendendo o Design do Sistema de Votação

Nosso sistema de votação permitirá que os usuários:

  1. Criem uma enquete com uma pergunta única e múltiplas opções.
  2. Votem em uma opção específica da enquete.
  3. Recuperem os resultados da enquete.

Estruturas de Dados

Definiremos duas estruturas de dados: Enquete e Voto.

use anchor_lang::prelude::*;

#[account]
pub struct Enquete {
    pub pergunta: String,
    pub opcoes: Vec<String>,
    pub votos: Vec<u32>,
    pub proprietario: Pubkey,
}

#[account]
pub struct Voto {
    pub eleitor: Pubkey,
    pub id_enquete: Pubkey,
    pub index_opcao: usize,
}

Neste exemplo:

  • Enquete contém a pergunta, as opções possíveis, o número de votos para cada opção e a chave pública do proprietário.
  • Voto registra quem votou, em qual enquete e qual opção foi selecionada.

Implementando a Criação da Enquete

Vamos implementar a função para criar uma enquete:

#[program]
mod sistema_de_votacao_on_chain {
    use super::*;

    pub fn criar_enquete(ctx: Context<CriarEnquete>, pergunta: String, opcoes: Vec<String>) -> Result<()> {
        let enquete = &mut ctx.accounts.enquete;
        enquete.pergunta = pergunta;
        enquete.opcoes = opcoes.clone();
        enquete.votos = vec![0; opcoes.len()]; // Inicializa os votos para cada opção
        enquete.proprietario = *ctx.accounts.usuario.key;

        Ok(())
    }
}

#[derive(Accounts)]
pub struct CriarEnquete<'info> {
    #[account(init, payer = usuario, space = 8 + 64 + 4 * 32)]
    pub enquete: Account<'info, Enquete>,
    #[account(mut)]
    pub usuario: Signer<'info>,
    pub system_program: Program<'info, System>,
}

Explicação

  • A função criar_enquete inicializa uma nova conta de Enquete com a pergunta e as opções fornecidas.
  • O vetor votos é inicializado com zero para cada opção.
  • A estrutura CriarEnquete gerencia as contas envolvidas na transação.

Implementando a Funcionalidade de Votação

Agora, vamos implementar a função que permite que os usuários votem:

pub fn registrar_voto(ctx: Context<RegistrarVoto>, index_opcao: usize) -> Result<()> {
    let enquete = &mut ctx.accounts.enquete;
    let eleitor = &ctx.accounts.eleitor;

    require!(index_opcao < enquete.opcoes.len(), CustomError::EscolhaInvalida);

    enquete.votos[index_opcao] += 1;

    let voto = &mut ctx.accounts.voto;
    voto.eleitor = *eleitor.key;
    voto.id_enquete = *enquete.key;
    voto.index_opcao = index_opcao;

    Ok(())
}

#[derive(Accounts)]
pub struct RegistrarVoto<'info> {
    #[account(mut)]
    pub enquete: Account<'info, Enquete>,
    #[account(init, payer = eleitor, space = 8 + 8 + 32 + 4)]
    pub voto: Account<'info, Voto>,
    #[account(mut)]
    pub eleitor: Signer<'info>,
    pub system_program: Program<'info, System>,
}

Explicação

  • A função registrar_voto atualiza a contagem de votos para a opção selecionada e armazena a escolha do eleitor.
  • Verificamos se o índice da opção é válido e gerenciamos as contas por meio da estrutura RegistrarVoto.

Recuperando os Resultados da Enquete

Por fim, vamos implementar uma função para recuperar os resultados atuais de uma enquete:

pub fn obter_resultados_enquete(ctx: Context<ObterResultadosEnquete>) -> Result<ResultadosEnquete> {
    let enquete = &ctx.accounts.enquete;

    Ok(ResultadosEnquete {
        pergunta: enquete.pergunta.clone(),
        opcoes: enquete.opcoes.clone(),
        votos: enquete.votos.clone(),
    })
}

#[derive(Accounts)]
pub struct ObterResultadosEnquete<'info> {
    pub enquete: Account<'info, Enquete>,
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct ResultadosEnquete {
    pub pergunta: String,
    pub opcoes: Vec<String>,
    pub votos: Vec<u32>,
}

Explicação

  • A função obter_resultados_enquete permite que os usuários consultem o estado atual da enquete.
  • Ela retorna a pergunta da enquete, as opções disponíveis e o número de votos por opção.

Conclusão

Parabéns! Você implementou um sistema básico de votação on-chain usando Rust na blockchain Solana. Agora você pode criar enquetes, registrar votos e recuperar resultados, tudo armazenado de forma segura on-chain.

Em aulas futuras, considere adicionar recursos como:

  • Datas de expiração para enquetes.
  • Autenticação de usuários para evitar votos duplicados.
  • Interface aprimorada para uma melhor interação.

Isso fornece uma base sólida para sua aplicação de votação descentralizada. Boa programação!

Did you like this article? Rate it from 1 to 5:

Thank you for voting!