Acceder a valores pasados ​​de variables de Smart Contract

Me gustaría saber si es posible consultar valores de variables utilizando bloques más antiguos.

por ejemplo tengo

contract Simple {
    string32 message public;

    function Simple() {
        message = msg.sender;
    }
}

¿Es posible recuperar el valor del mensaje hace 1 mes? ¿Existe algún método que me permita inspeccionar dicha variable en una altura de bloque particular?

¿Existe algún método que recupere todos los valores diferentes que se encuentran en la cadena de bloques?

Muchísimas gracias.

Respuestas (3)

No hay forma de que un contrato acceda a una variable que ya no se encuentra en el almacenamiento. Sin embargo, puede acceder a estas variables desde web3.

Recomendaría usar Events , que podría indexar por marca de tiempo para facilitar la búsqueda.

Con web3, hay una posible solución (probablemente no la más rápida ni la más elegante, pero es para mostrar cómo se puede hacer). Recuperamos la primera variable del contrato (índice 0), que es de tipo uint:

contract = "0x6d363cd2eb21ebd39e50c9a2f94a9724bf907d13";
maxBlocks = 1000;

startBlock = eth.blockNumber;
for (var i = 1; i < maxBlocks; i++) { /* Be careful: we go *back* in time */
    current = web3.eth.getStorageAt(contract, 0, startBlock-i);
    if (current != previous) {
        /* TODO Where to find msg.sender? We probably have to loop
         * over the transactions in the block can call
         * web3.eth.getTransaction */
        blockDate = new Date(web3.eth.getBlock(startBlock-i+1).timestamp*1000);
        console.log("Block #" + (startBlock-i+1) +  " (" + web3.eth.getBlock(startBlock-i+1).timestamp + " " + blockDate.toString()
            +  ") : " + web3.toDecimal(previous));
        /* What if there are two changes in a single block? The
         * documentation of getStorageAt seems silent about that */
        previous = current;
    }
}
blockDate = new Date(web3.eth.getBlock(startBlock-maxBlocks).timestamp*1000);
console.log("Somewhere before block #" +(startBlock-maxBlocks) +  " (block of " + blockDate.toString()
        +  ") : " + web3.toDecimal(previous));

Puede probarlo en Testnet, donde se ha implementado el contrato con esta dirección.

No estoy seguro, pero aprobé la edición; deshágalo si lo desea y @bortzmeyer debería publicar una respuesta diferente.

En teoría, podría generar una prueba de Merkle increíblemente larga y compleja para demostrar a un contrato que una cuenta determinada tenía un valor particular en un número de bloque en particular, y podría aumentar bastante la eficiencia si tiene un contrato que almacena tantas cuentas anteriores bloquear hashes como sea posible; sin embargo, esto sería bastante difícil de implementar. Aparte de eso, la solución más simple a corto plazo puede ser averiguar exactamente a qué valores desea poder acceder de forma permanente desde el interior del contrato y mantenerlos almacenados de forma permanente en una matriz. Si solo desea acceder a valores pasados ​​​​desde la interfaz, le recomiendo eventos como los mencionados en el póster anterior.

Tal vez una opción de baja tecnología sea instalar una nueva instancia de geth y descargar la cadena de bloques de la instancia principal de geth, examinando los datos en cada bloque nuevo. Sin embargo, no sé si uno puede controlar / detener la sincronización después de cada bloque. Pensándolo bien, podría haber ELI5ado lo que decía el cartel anterior.
Hola Vitalik y otros, gracias. Vi Eventos y ya tenía en mente almacenar reescrituras de la variable en otra matriz, pero creo que crecería mucho el almacenamiento necesario. Dado que para este caso de uso, los valores anteriores no son una información que deba usar en el contrato en sí, ¿cree que usando un software externo como un explorador de bloques podría recuperar fácilmente el historial de valores de las variables? Si uso ether.camp, puedo ver las modificaciones de almacenamiento para cada transacción. ¿Crees que sería mejor que almacenar valores anteriores en una matriz diferente dentro del contrato?

Depende de sus necesidades, pero supongo que algo como, digamos: debug.setHead(800000)puede ayudar.

"Rebobina" el último bloque de su cadena de bloques para bloquear 800 000 (solo un ejemplo).

No sé si funciona para consultar contratos inteligentes anteriores, pero supongo que funcionará: a menudo lo he usado (en la consola geth JS) para consultar saldos anteriores para direcciones particulares.

El problema es que luego debe volver a sincronizar hasta el último bloque: es por eso que digo que depende de su caso de uso. La técnica no se escala, pero si sus requisitos son simples, puede ser suficiente.

Por ejemplo, si quiero consultar el saldo de una dirección (dirección que puede ser un contrato inteligente, por lo que es más avanzado que simplemente verificar la cantidad de ETH en una dirección "normal"), aproximadamente semanalmente, empiezo desde el bloque actual (el último one) luego debug.setHead(...) una semana antes de la fecha actual, luego una semana antes de eso, enjuague y repita. Eso es muy rápido. Pero al final necesitas volver a sincronizar desde donde hayas terminado.