¿Cómo recopilar todas las instancias de contrato y contar las redundancias de bytecode?

Quiero atravesar la cadena de bloques de Ethereum, recopilar todas las instancias de contratos y contar con qué frecuencia se ha instanciado qué bytecode.

Como resultado quiero tener un mapa conkey:hash(bytecode) -> value:instanceCount

Si desea saber por qué lo estoy haciendo, lea EIP 911: Reduzca los costos de gas para implementar código de bytes en tiempo de ejecución copiando bytecodeHash de un contrato existente

Hasta ahora, tengo las siguientes ideas de cómo podría hacerse:

Idea 1 Use web3 para recopilar todas las transacciones con 0x0 como destino, obtenga la dirección del contrato del recibo, obtenga el código de este contrato, cuéntelo en el mapa. [P] : ¿cómo recopilar las instancias que ocurren dentro de los contratos (-> new)?

Idea 2 Para cada bloque, obtenga el hash raíz del estado, cargue el trie correspondiente de la base de datos (leveldb/geth), recorra el árbol, recopile todas las cuentas, si la cuenta aún no se ha procesado, tome el código hash y aumente el conteo, muévase al bloque siguiente. [P] : atravesar el trie completo bloque por bloque es muy probablemente ineficiente. ¿Hay alguna manera de atravesar solo los caminos que cambiaron desde el último bloque?

Idea 3 Atraviese el trie de estado del último bloque únicamente y cuente las redundancias de código de bytes como se describe en 2. Esto simplifica la implementación, pero no se consideran los datos históricos.

[P] : ¿Alguna otra idea?

EDITAR : puede encontrar el contador de duplicación de código implementado en JavaScript en mi GitHub Repo -> https://github.com/ivica7/eth-chain-stats-collector

Respuestas (1)

¡Idea interesante!

[P]: ¿cómo recopilar las instanciaciones que suceden dentro de los contratos (-> nuevo)?

Una opción es inspeccionar los rastros de transacciones. Geth proporciona la API de traceTransaction https://github.com/ethereum/go-ethereum/wiki/Management-APIs#debug_tracetransaction que está disponible solo para transacciones ejecutadas mientras se ejecuta en modo de nodo de archivo completo. Deberá buscar el código de CREATEoperación, la dirección de la cuenta recién creada estará encima del stacksiguiente código de operación para la misma profundidad de llamada (o 0x0 si CREATEno tuvo éxito). Luego busque su código de bytes en la base de datos leveldb.

Otra opción es usar la callTracerintroducida en geth 1.8, que puede extraer llamadas internas, incluidas CREATE https://github.com/ethereum/go-ethereum/pull/15516 . Dan un ejemplo en el que puede crear una suscripción a través de ipc y obtener transacciones internas de múltiples bloques:

$ nc -U /work/temp/rinkeby/geth.ipc
{"id": 1, "method": "debug_subscribe", "params": ["traceChain", "0x0", 
"0xffff", {"tracer": "callTracer"}]}

{"jsonrpc":"2.0","id":1,"result":"0xe1deecc4b399e5fd2b2a8abbbc4624e2"}
{"jsonrpc":"2.0","method":"debug_subscription","params":{"subscription":"0xe1deecc4b399e5fd2b2a8abbbc4624e2","result":{"block":"0x37","hash":"0xdb16f0d4465f2fd79f10ba539b169404a3e026db1be082e7fd6071b4c5f37db7","traces":[{"from":"0x31b98d14007bdee637298086988a0bbd31184523","gas":"0x0","gasUsed":"0x0","input":"0x","output":"0x","time":"1.077µs","to":"0x2ed530faddb7349c1efdbf4410db2de835a004e4","type":"CALL","value":"0xde0b6b3a7640000"}]}}}
{"jsonrpc":"2.0","method":"debug_subscription","params":{"subscription":"0xe1deecc4b399e5fd2b2a8abbbc4624e2","result":{"block":"0xf43","hash":"0xacb74aa08838896ad60319bce6e07c92edb2f5253080eb3883549ed8f57ea679","traces":[{"from":"0x31b98d14007bdee637298086988a0bbd31184523","gas":"0x0","gasUsed":"0x0","input":"0x","output":"0x","time":"1.568µs","to":"0xbedcf417ff2752d996d2ade98b97a6f0bef4beb9","type":"CALL","value":"0xde0b6b3a7640000"}]}}}
{"jsonrpc":"2.0","method":"debug_subscription","params":{"subscription":"0xe1deecc4b399e5fd2b2a8abbbc4624e2","result":{"block":"0xf47","hash":"0xea841221179e37ca9cc23424b64201d8805df327c3296a513e9f1fe6faa5ffb3","traces":[{"from":"0xbedcf417ff2752d996d2ade98b97a6f0bef4beb9","gas":"0x4687a0","gasUsed":"0x12e0d","input":"0x6060604052341561000c57fe5b5b6101828061001c6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063230925601461003b575bfe5b341561004357fe5b61008360048080356000191690602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506100c5565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000600185858585604051806000526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000866161da5a03f1151561014257fe5b50506020604051035190505b9493505050505600a165627a7a7230582054abc8e7b2d8ea0972823aa9f0df23ecb80ca0b58be9f31b7348d411aaf585be0029","output":"0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063230925601461003b575bfe5b341561004357fe5b61008360048080356000191690602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506100c5565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000600185858585604051806000526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000866161da5a03f1151561014257fe5b50506020604051035190505b9493505050505600a165627a7a7230582054abc8e7b2d8ea0972823aa9f0df23ecb80ca0b58be9f31b7348d411aaf585be0029","time":"658.529µs","to":"0x5481c0fe170641bd2e0ff7f04161871829c1902d","type":"CREATE","value":"0x0"}]}}}
{"jsonrpc":"2.0","method":"debug_subscription","params":{"subscription":"0xe1deecc4b399e5fd2b2a8abbbc4624e2","result":{"block":"0xfff","hash":"0x254ccbc40eeeb183d8da11cf4908529f45d813ef8eefd0fbf8a024317561ac6b"}}}

[P]: recorrer el trie completo bloque a bloque es muy probablemente ineficiente. ¿Hay alguna manera de atravesar solo los caminos que cambiaron desde el último bloque?

Creo que es posible calcular eficientemente la diferencia de 2 Patricia Merkle Tries. La idea general es tomar 2 raíces, verificar sus mordiscos, bajar el trie solo para mordiscos que son diferentes en ambas raíces. Repítalo recursivamente para los nodos de nivel inferior. Habrá algunas complicaciones relacionadas con los nodos de hoja/extensión, pero creo que se pueden solucionar.

Otra opción es realizar un seguimiento de los nodos de Patricia Trie que ya atravesó en bloques anteriores y omitirlos para bloques posteriores.

¡Gracias por la respuesta! ¡Buena idea comparar los dos intentos! Eso podría funcionar. Atravesar la cadena de bloques a través de web3 es extremadamente lento en comparación con trabajar directamente en leveldb. PD. ¡No dude en comentar sobre el EIP-911 y el EIP-905 también!
Agregué más detalles a la respuesta, que pueden ser útiles, sobre el seguimiento de la cadena con callTracer. Ver después de "Otra opción es..."
¡Acabo de verlo! Genial que lo estés señalando. ¡Exactamente lo que necesito! Debe poner esto en un nuevo control de calidad.