¿Manejar correctamente los errores de falla de solicitud/afirmación desde una aplicación Node.JS?

Tengo una función getter en mi contrato inteligente que devuelve uno de los valores de cadena en una matriz de cadenas definida estáticamente. Al ingresar a la función, realiza una verificación de límites en el índice entrante usando require(). Si la verificación de límites falla, ¿qué sucederá en mi aplicación Node.JS que usó Web3.js para realizar la llamada? ¿Se lanzará un error de Javascript? ¿Recuperaré NULL?

Si alguien tiene un buen artículo o recurso web que muestre la forma correcta de manejar los errores de una llamada Web3.JS que resultó en una operación de afirmación o de solicitud que se activa en el lado del contrato inteligente, por favor compártalo.

Aquí está mi código de contrato inteligente:

pragma solidity ^0.4.23;

import "github.com/OpenZeppelin/zeppelin-solidity/contracts/ownership/Ownable.sol";

contract VideoDummyData is Ownable{

    // Constructor, MUST be public.
    constructor() public {
        // Unused.
    }

    // Array of sample video IDs.
    string[3] m_aryVideoIds = 
        ["ZUSPD9zOyJs", "4nqJiBRNQuw", "PLcxE4UkJt0"];


    // Return one of the sample video IDs.
    function getVideoIdAt (uint ndx) public view returns(string)
    {
        // Bounds check on the desired index.
        require(ndx < m_aryVideoIds.length);

        return m_aryVideoIds[ndx];
    }
}
Recibirá un error de web3, pero no podrá saber cuál es el error exacto.
@Andromelus: no hasta la próxima versión de Solidity, ¿cuándo te permitirán devolver un mensaje de error con afirmar/revertir? Si tengo razón en eso, ¿sabe si el cambio será inmediato o tendremos que esperar a que todos los nodos de la red Ethereum se actualicen o adopten el cambio (como una bifurcación blanda)?
Solo necesita que la transacción sea minada. Entonces, el nodo al que está conectado necesita saber el bloque en el que se encuentra el tx.
Se trata callde una viewfunción, por lo que no hay transacción para extraer.

Respuestas (2)

Dado que está llamando a una viewfunción, la primera devolución de llamada generará un error, más o menos inmediatamente.

Actualmente es posible devolver errores con

require(expression, "error msg");

El desafío es acceder a este mensaje más arriba en la pila en Web3 y Node.

Mientras tanto, puede usar tryy .catch()en código prometido, como una abstracción de contrato de trufa.

No sabrá el motivo exacto, pero podrá inferirlo dados los requisitos del contrato.

Espero eso ayude.

Una vez que los métodos de llamada/envío se revierten con cualquier motivo, obtendrá la siguiente respuesta en su código express/nodejs.

   {
    "data": {
        "0x926192b712005c4eab709b7f7e1718435b6f2117580360b73e7601a439feffcd": {
            "error": "revert",
            "program_counter": 383,
            "return": "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000165468697320496420616c72656164792065786973747300000000000000000000",
            "reason": "This Id already exists"
        },
        "stack": "RuntimeError: VM Exception while processing transaction: revert This Id already exists\n    at Function.RuntimeError.fromResults (C:\\Program Files\\WindowsApps\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\app\\resources\\static\\node\\node_modules\\ganache-core\\lib\\utils\\runtimeerror.js:94:13)\n    at BlockchainDouble.processBlock (C:\\Program Files\\WindowsApps\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\app\\resources\\static\\node\\node_modules\\ganache-core\\lib\\blockchain_double.js:627:24)\n    at processTicksAndRejections (internal/process/task_queues.js:93:5)",
        "name": "RuntimeError"
    }
}

Ahora aquí tenemos que mostrarle al usuario un mensaje apropiado para que el usuario pueda entender que podemos usar el siguiente código. Para obtener el motivo de la respuesta revertida. use el siguiente código en el código nodeJS/expressjs....

try {
    await myContract.methods.foo().send();
} catch (e) {
    const data = e.data;
    const txHash = Object.keys(data)[0]; 
    const reason = data[txHash].reason;

    console.log(reason); 
}