No se pueden capturar todos los eventos (registros) del contrato; en su lugar, capture un par de eventos aleatorios

Mi contrato tiene una transacción que desencadena un evento. Pude capturar todos los eventos cuando enviaba transacciones manualmente.

Pero ahora estoy enviando 100 transacciones en ciclo y obtengo solo 2.5 eventos. Sí, al azar, lo que más me desconcierta. Obtengo una cantidad aleatoria de eventos y un último evento aleatorio capturado cada vez que ejecuto mi código. Por favor, vea la salida de la consola a continuación.

Intenté agregar una pausa entre transacciones. Cuanto más larga sea la pausa, más eventos se capturan. Esto también me desconcierta: no entiendo por qué esto es importante para los eventos.

Mi contrato .sol

contract Example {

    uint32 public value;

    event ValueSet(uint);

    function setValue(uint32 val) {
        value = val;
        ValueSet(val);
    }

}

Mi código python (perdón por el código largo, tenía miedo de estropearlo y acortarlo)

class MyContract:

    address = ""
    filter = ""

    def __init__(self):
        self.c = EthJsonRpc('127.0.0.1', 8545)

    def deploy(self):

        # get contract address
        compiled = '6060604052610.....' # shortening it here.
        contract_tx = self.c.create_contract(self.c.eth_coinbase(), compiled, gas=3000000)
        self.address = self.c.get_contract_address(contract_tx)

        # set new filter
        params = {
            "fromBlock": "0x01",
            "address": self.address
        }
        self.filter = str(self.new_filter(params))


    def send_transaction(self, foo, value):
        tx = self.c.call_with_transaction(self.c.eth_coinbase(), self.address, foo, value)
        return tx

    def new_filter(self, params):
        return self.c.eth_newFilter(params)

    def listen(self):
        return self.c.eth_getFilterLogs(self.filter)



def main():
    my_contract = MyContract()
    my_contract.deploy()

    #sending transactions which trigger events 
    for i in range(100):
        my_contract.send_transaction('setValue(uint32)', [i])
        time.sleep(1) # the more time the more events are caught 

    # retrieve all logs from the filter
    logs = my_contract.listen()

    print repr(logs)
    print "Quantity of events: " + str(len(logs))
    if logs:
        print "Data: " + str(int(logs[-1]['data'], 16))

Salida de consola

[
   {
      u'type':u'mined',
      u'blockHash':u'0xac739ae0feac68eae0cddb5216ef64c7931821cf26db327c85bd3da16f947f44',
      u'transactionHash':u'0x4d2465e9b978a275cca63fb9129a5da8f7a9dcc9b2c6e8b717ecf734be7ab950',
      u'data':u'0x0000000000000000000000000000000000000000000000000000000000000026',
      u'topics':[
         u'0x012c78e2b84325878b1bd9d250d772cfe5bda7722d795f45036fa5e1e6e303fc'
      ],
      u'blockNumber':u'0x0223',
      u'address':u'0x9062a6b9299af4bdb535a5ecdbfeb8a28e6cf4c1',
      u'logIndex':u'0x00',
      u'transactionIndex':u'0x0'
   },
   {
      u'type':u'mined',
      u'blockHash':u'0x1014603151080201cc26990c6b4f1dd01a5b65545b19a570a01c9ad11532c7f2',
      u'transactionHash':u'0xe79af54c765368e73e3c9ca996de667e43363e92856ca234459633fda86c77ca',
      u'data':u'0x000000000000000000000000000000000000000000000000000000000000005f',
      u'topics':[
         u'0x012c78e2b84325878b1bd9d250d772cfe5bda7722d795f45036fa5e1e6e303fc'
      ],
      u'blockNumber':u'0x025c',
      u'address':u'0x9062a6b9299af4bdb535a5ecdbfeb8a28e6cf4c1',
      u'logIndex':u'0x00',
      u'transactionIndex':u'0x0'
   }
]
Quantity of events: 2
Data: 95

Relacionado

¿Cómo listar transacciones desde la dirección de la cuenta?

¿Cómo puedo crear un oyente para una nueva transacción con llamadas RPC de Ethereum?

Creación de oyentes de temas eth_newFilter con Python

Por qué preguntas

Estoy tratando de escribir un código que guardará el evento del contrato en una base de datos en modo "en vivo" (capturar nuevos eventos) y en modo "retrospectivo" (recuperar todos los eventos del contrato). Y solo quiero entender cómo funcionan los eventos.

Estoy usando ethjsonrpc con testrpc (Ethereumjs).

¡Muchos gracias!

testrpc se inició sin parámetros.
¿Qué versión de testrpc estás usando? Los eventos no son compatibles hasta la versión v0.2.0 . Mientras tanto, use un cliente clásico como geth.
Consulte ethereum.stackexchange.com/questions/4452/… para ver un ejemplo práctico de extracción de eventos.
Consulte github.com/pipermerriam/populus : estoy usando eventos allí y están funcionando
@GiuseppeBertone Estoy usando EthereumJS TestRPC v2.1.0. Necesito probar 10 000 transacciones, así que necesito algo más rápido que geth (¿o puedo ejecutar una cadena de bloques virtual con geth?)
@MikkoOhtamaa gracias! Y gracias por tu hermoso código de detector de eventos .

Respuestas (1)

Solo necesitaba agregar el recibo = self.c.eth_getTransactionReceipt(tx) . Supongo que asegura que la transacción sea minada.

Ahora captura los 100 eventos.

También intenté agregar un temporizador después de cada transacción. 5 segundos después de cada transacción fueron suficientes para detectar todos los eventos. Pero eth_getTransactionReceipt funciona mucho más rápido (un par de segundos para las 100 transacciones).

¿Alguien puede explicar esto? ¿Cómo sería el código para la cadena de bloques de producción?

    def send_transaction(self, foo, value):
        tx = self.c.call_with_transaction(self.c.eth_coinbase(), self.address, foo, value)
        receipt = self.c.eth_getTransactionReceipt(tx)
        return tx