cómo construir una mejor democracia en menos de 100 líneas de código [cerrado]

Hola amigos, después de tres días de investigación y mucha ayuda de la comunidad, resolví mi problema con el contrato inteligente del código de democracia siguiendo este tutorial: https://blog.ethereum.org/2015/12/04/ethereum-in-practice -parte-2-cómo-construir-una-mejor-democracia-en-bajo-100-líneas-de-código/

Tengo el bloqueo llamado "Valor de retorno de las llamadas de bajo nivel no utilizadas": Valor de retorno de las llamadas de bajo nivel no utilizadas

Así que resuelvo el problema con el consejo de Rob Hitchens y hago mi código así

pragma solidity 0.4.8;
contract token { mapping (address => uint256) public balanceOf; }

/* The democracy contract itself */
contract Democracy {

    /* Contract Variables and events */
    uint public minimumQuorum;
    uint public debatingPeriodInMinutes;
    Proposal[] public proposals;
    uint public numProposals;
    token public sharesTokenAddress;

    event ProposalAdded(uint proposalID, address recipient, uint amount, string description);
    event Voted(uint proposalID, bool position, address voter);
    event ProposalTallied(uint proposalID, int result, uint quorum, bool active);

    struct Proposal {
        address recipient;
        uint amount;
        string description;
        uint votingDeadline;
        bool openToVote;
        bool proposalPassed;
        uint numberOfVotes;
        bytes32 proposalHash;
        Vote[] votes;
        mapping (address => bool) voted;
    }

    struct Vote {
        bool inSupport;
        address voter;
    }

    /* modifier that allows only shareholders to vote and create new proposals */
    modifier onlyShareholders {
        if (sharesTokenAddress.balanceOf(msg.sender) == 0) throw;
        _;
    }

    /* First time setup */
    function Democracy(token sharesAddress, uint minimumSharesForVoting, uint minutesForDebate) {
        sharesTokenAddress = token(sharesAddress);
        if (minimumSharesForVoting == 0 ) minimumSharesForVoting = 1;
        minimumQuorum = minimumSharesForVoting;
        debatingPeriodInMinutes = minutesForDebate;
    }

    /* Function to create a new proposal */
    function newProposal(address beneficiary, uint etherAmount, string JobDescription, bytes transactionBytecode) onlyShareholders returns (uint proposalID) {
        proposalID = proposals.length++;
        Proposal p = proposals[proposalID];
        p.recipient = beneficiary;
        p.amount = etherAmount;
        p.description = JobDescription;
        p.proposalHash = sha3(beneficiary, etherAmount, transactionBytecode);
        p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
        p.openToVote = true;
        p.proposalPassed = false;
        p.numberOfVotes = 0;
        ProposalAdded(proposalID, beneficiary, etherAmount, JobDescription);
        numProposals = proposalID+1;
    }

    /* function to check if a proposal code matches */
    function checkProposalCode(uint proposalNumber, address beneficiary, uint etherAmount, bytes transactionBytecode) constant returns (bool codeChecksOut) {
        Proposal p = proposals[proposalNumber];
        return p.proposalHash == sha3(beneficiary, etherAmount, transactionBytecode);
    }

    /* */
    function vote(uint proposalNumber, bool supportsProposal) onlyShareholders returns (uint voteID){
        Proposal p = proposals[proposalNumber];
        if (p.voted[msg.sender] == true) throw;

        voteID = p.votes.length++;
        p.votes[voteID] = Vote({inSupport: supportsProposal, voter: msg.sender});
        p.voted[msg.sender] = true;
        p.numberOfVotes = voteID +1;
        Voted(proposalNumber,  supportsProposal, msg.sender);
    }

    function executeProposal(uint proposalNumber, bytes transactionBytecode) returns (int result) {
        Proposal p = proposals[proposalNumber];
        /* Check if the proposal can be executed */
        if (now < p.votingDeadline  /* has the voting deadline arrived? */
            || !p.openToVote        /* has it been already executed? */
            ||  p.proposalHash != sha3(p.recipient, p.amount, transactionBytecode)) /* Does the transaction code match the proposal? */
            throw;

        /* tally the votes */
        uint quorum = 0;
        uint yea = 0;
        uint nay = 0;

        for (uint i = 0; i <  p.votes.length; ++i) {
            Vote v = p.votes[i];
            uint voteWeight = sharesTokenAddress.balanceOf(v.voter);
            quorum += voteWeight;
            if (v.inSupport) {
                yea += voteWeight;
            } else {
                nay += voteWeight;
            }
        }
        /* execute result */
        if (quorum > minimumQuorum && yea > nay ) {
            // has quorum and was approved
            if(p.recipient.call.value(p.amount*1000000000000000000)(transactionBytecode)) {
        // do something
         p.openToVote = false;
    } else {
        // do something else
         p.proposalPassed = true;
    }
        } else if (quorum > minimumQuorum && nay > yea) {
            p.openToVote = false;
            p.proposalPassed = false;
        }
        /* Fire Events */
        ProposalTallied(proposalNumber, result, quorum, p.openToVote);
    }
}

para que el sistema lo acepte. Quiero preguntar si el código es bueno para implementar el contrato o cometo un error aquí.

ingrese la descripción de la imagen aquí

¡Gracias de antemano!

Creo que debe preguntarse: "¿El código hace lo que quiero que haga?" Para responder a esa pregunta, debe probarlo y, para probarlo correctamente, debe comprender completamente lo que está haciendo el código. El proceso de hacerlo será de gran ayuda para comprender cómo funcionan Solidity y los contratos inteligentes :-)

Respuestas (1)

Precaución re:

bueno para implementar el contrato o cometo un error aquí

Sospecho que no es realista pedir a los usuarios de este foro que certifiquen que el código no tiene defectos. Veo lo que parecen ser desviaciones de las mejores prácticas y áreas de preocupación. Entonces, todavía no .

Estoy de acuerdo con Richard, en que profundizar en los puntos planteados a continuación será de gran ayuda para su comprensión.

Elaboré mi respuesta en Valor de retorno de llamadas de bajo nivel no utilizadas . Respondió la pregunta original (más o menos, ¿por qué se queja el compilador?) y brindó un poco más de orientación sobre // do something // do something else. En resumen, tenga cuidado y observe las mejores prácticas descritas aquí: https://github.com/ConsenSys/smart-contract-best-practices

Bajo el encabezado Llamadas externas , encontrará un patrón etiquetado como "Malo" y parece coincidir con su código.

Entonces, el reingreso es una preocupación porque veo manipulación de variables de estado después de la llamada externa.

Otra preocupación es la presencia de un forbucle.

for (uint i = 0; i <  p.votes.length; ++i) {

Si bien esto posiblemente se mitiga en otra parte del código, si es así, no es obvio, al menos para mí. No veo nada que limite p.votes.length. Eso significaría que no hay límite para el número de iteraciones en el ciclo. Eso conduciría a una función que no puede hacer su trabajo sobre un cierto número de votos debido al bloque gasLimit. ¿Debemos entender que si el contrato tiene éxito y hay muchos votantes, se supone que el contrato se romperá? Obviamente, no, por lo que necesitaría entender por qué eso no sucederá antes de poder sentirme cómodo con esto.

Otra preocupación es el uso (¿inteligente?) de transactionByteCode. Parece proporcionar una gran flexibilidad; posiblemente demasiada flexibilidad. Parece aumentar el área de superficie de ataque y los casos de prueba. Con ese movimiento, las cosas pasan de una lista finita de cosas que hace el contrato a una lista posiblemente ilimitada de cosas que podría hacer ByteCode.

El problema con este tipo de cosas es anticipar cómo se puede usar y abusar en la etapa de prueba, y cómo las vulnerabilidades pueden no surgir hasta que se confíe un valor considerable al contrato y los atacantes estén motivados para encontrar una debilidad. Como abreviatura, hay un mundo de diferencia entre preguntar aquí en SE y ofrecer una recompensa de un millón de dólares por la pregunta. Pondría la carga de la prueba sobre los defensores de la estrategia. No se preocupe por probar que hay una manera de hackearlo. Alguien tiene que demostrar que no hay forma de hackearlo.

Ahora veo que estás siguiendo un tutorial. Una revisión casual sugiere que la publicación no se ha actualizado desde 2015 , mucho antes del ataque DAO de 2016. Además, no se actualizó para abordar el problema del compilador que se informó por primera vez en su otra publicación. Estas observaciones sugieren precaución al usar este ejemplo.

Teniendo en cuenta la fuente, es posible que otros se hayan tomado el tiempo de comprender realmente qué hace el contrato en cada paso del camino. Es posible que cada una de mis tres preocupaciones pueda dejarse de lado si alguien interviene con una explicación satisfactoria de cómo el contrato es defensivo.

Estoy de acuerdo con ricardo. Siempre debe saber lo que hace su contrato. No puede ser demasiado cauteloso con una pieza de software que no se puede modificar. Encontré tres inquietudes con solo una mirada casual al código, por lo que estoy lejos de sentirme cómodo expresando confianza de que todo está listo.

Sería mejor ver el ejemplo como una demostración del potencial de Ethereum, pero no como una solución lista para la batalla en el mundo real.

Espero eso ayude.