DAPP: sistema de votación de contrato inteligente Ethereum (solidez) + fondo java (springboot + mybatis + web3j + thymeleaf)

1. Antecedentes del proyecto

Para consolidar el conocimiento relacionado con blockchain que hemos aprendido recientemente, dedicamos unos días a desarrollar un conjunto de sistemas de votación basados ​​en contratos inteligentes de Ethereum que se pueden aplicar de manera práctica .

2. Selección técnica

  1. Redacción inteligente de contratos: solidez
  2. Entorno de cadena privada: ganache-cli
  3. Interfaz: motor de plantilla de hojas de tomillo
  4. Backend: springboot + mybatis
  5. Paquete jar de dependencia principal: web3j

El marco general del proyecto es el siguiente (debido a que el contenido del front-end es pequeño y solo se usa para mostrar funciones básicas, vue no se usa en el proceso de desarrollo real):
Inserte la descripción de la imagen aquí

3. Código de contrato de solidez

pragma solidity ^ 0.4.26;
 
contract Ballot {
    string public name; //投票的名称,name of the Ballot
    address public chairman; //合约拥有者的地址
    bool public closed; // 记录投票是否结束
 
    // 获胜票数比例
    uint public proportion; // 获胜时得票数占总票数的最低比例, 例如50%就赋值为50
    uint public totalVotes; // 总票数
 
    // 加投票权集合, 表示哪些人有投票权
    address[] voters;
    struct Proposal { // 候选人信息的结构体
        bytes32 name;
        uint voteCount;  // 候选人的得票数
    }
    Proposal[] public proposals;  // 候选人的结构体(可变长)数组
    mapping(address => bool) voteRecords; // 投票者是否投票(默认false)
    uint[] winningProposals = [0];
    bytes32[] winningProposalsName; // 记录winning候选人名字的数组
 
    constructor(string _name, bytes32[] _proposals, uint _proportion, address[] _voters) public { // 合约的构造函数
        chairman = msg.sender; // 记录合约的拥有者
        closed = false; // 合约默认处于打开
        name = _name; // 投票的名称,如 "选举学生会主席"
        for(uint i = 0; i < _proposals.length; i++) {
            proposals.push(Proposal({
                name: _proposals[i],
                voteCount: 0
            }));
        }
        proportion = _proportion;
        voters = _voters;
        totalVotes = voters.length;
    }
 
 
    function setChairman(address _chairman) external { // 更换合约拥有者时用
        chairman = _chairman;
    }
 
    function vote(uint proposal) public { //给候选人投票, 需传入候选人的序号及投票者的地址
        address voterAddress = msg.sender;
        require(!closed, "the ballot is already closed."); // 保证合约没有关闭,即投票没有结束
        // 看投票者的地址是否在合法名单中
        bool legal = false;
        for(uint i = 0; i < voters.length; i++){
            if(voters[i] == voterAddress){
                legal = true;
                break;
            }
        }
        require(legal, "the voter is illeagal!");
        require(proposal < proposals.length, "the prosal is invalid!");
        require(!voteRecords[voterAddress], "Already voted."); // 保证投票者没有投过票
        voteRecords[voterAddress] = true;
 
        proposals[proposal].voteCount += 1; // 候选人得票数加一
    }
 
    function closeBallot() public { // 关闭投票
        require(chairman == msg.sender, "only the chairman can close the ballot."); // 只有拥有者可以关闭投票
        closed = true;
    }
 
    function getWinningProposals() internal { //统计投票的获胜者
        winningProposals.length = 0;
        uint winningVoteCount = 0;
        for(uint i = 0; i < proposals.length; i++) {
            if(proposals[i].voteCount * 100 / totalVotes >= proportion) {
                winningProposals.push(i);
            }
        }
        if(winningProposals.length == 0){
        for(i = 0; i < proposals.length; i++){
            if(proposals[i].voteCount > winningVoteCount){
                winningVoteCount = proposals[i].voteCount;
            }
        }
        for(i = 0; i < proposals.length; i++){
            if(proposals[i].voteCount == winningVoteCount){
                winningProposals.push(i);
            }
        }
    }
    }
 
    function winnerName() public view returns (bytes32[]) { // 返回得票数最高的候选人的名字
        require(closed, "only when the ballot is closed can you examine the winner");
        getWinningProposals();
        for(uint i = 0; i < winningProposals.length; i++){
            winningProposalsName.push(proposals[winningProposals[i]].name);
        }
        return winningProposalsName;
    }
 
    function getProposalNumber() public view returns (uint){
        return proposals.length;
    }
}

4. Pantalla de función

1. Interfaz de lista de votantes

  1. Haga clic en "iniciar una encuesta" en la esquina superior izquierda para crear una nueva encuesta;
  2. En la lista de votación existente, puede votar por votos inconclusos;
  3. Solo el propietario del contrato puede rescindir la votación y este proceso requiere la entrada de la verificación de la firma de la clave privada.
    Inserte la descripción de la imagen aquí

2. Agregar página de votación

Puede crear un nuevo voto en esta página y debe proporcionar una clave privada, implementar y registrarse como propietario del contrato.
Inserte la descripción de la imagen aquí

3. Ver el número de votos y la página de votación.

Debe ingresar la firma de la clave privada al votar, y cada dirección de cuenta solo puede votar una vez.
Inserte la descripción de la imagen aquí

4. Tablas de bases de datos

Para simplificar el diseño, no se diseña un contrato de recolección de votos, pero se usa la base de datos mysql para almacenar datos, esta operación no filtrará información del bloque.
Inserte la descripción de la imagen aquí

5. Dirección del código fuente del proyecto

Dirección de github del código fuente del proyecto

Dado que este proyecto es solo para aprendizaje y consolidación, hay muchas redundancias y deficiencias en el código, pero se han implementado las funciones básicas y no hay especificación de código, espero que lo entiendas cuando lo leas.

Supongo que te gusta

Origin blog.csdn.net/qq_45656248/article/details/114447375
Recomendado
Clasificación