Obtener datos de transacciones del nodo completo

Información de contexto

Estoy creando una aplicación que requiere la capacidad de consultar cualquier nodo completo de bitcoin (desde un script de python usando sockets tcp sin procesar) para leer el valor OP_Return que figura en la siguiente transacción ( https://live.blockcypher.com/btc- testnet/tx/2599dbe540a583ede3512fef9a0f26be718c039ffd4d04d85ff3b339f40e73b1/ )

Lo que he hecho hasta la fecha

Logré establecer con éxito la versión + verack, sin embargo, me enfrenté a dos problemas.

  1. Cuando envío un mensaje getdatapara la transacción necesaria, Idit no devuelve el resultado. Identifiqué que esto se debe a que mis suposiciones iniciales de que getdata devuelve los datos necesarios eran incorrectas y, en cambio, solo devolverá datos de transacciones para las transacciones que aún están en mempool.
  2. Esto me llevó a mi problema principal, esperaba replicar la descarga del bloque inicial en mi secuencia de comandos de python, comenzando desde el bloque que contiene la transacción que me interesa. Sin embargo, cuando lo hago / no importa lo que parezca poner en getblocksel getheadershash filter obtengo un volcado de 500 (o 2000) bloques/encabezados. A continuación se muestra un volcado hexadecimal de las solicitudes que estoy realizando (solo el marco del protocolo bitcoin):

    • getblocks 0b110907676574626c6f636b00000000450000002a0af9950100000001000000000000592589e55cda6e8a093998e8356ea770d4aaeb7c0f5439b147d7000000000000017a09017d52db538d7a9ddcc48311866d7e5fdbbbec7d0faad5

    • getheaders 0b110907676574686561646572730000450000002a0af9950100000001000000000000592589e55cda6e8a093998e8356ea770d4aaeb7c0f5439b147d7000000000000017a09017d52db538d7a9ddcc48311866d7e5fdbbbec7d0faad5

Busco la siguiente ayuda:

  1. ¿Cómo puedo consultar datos de transacciones sin usar bitcoin RPC si no puedo usar el getdatamensaje?
  2. ¿Cómo obtengo mi respuesta de bloque o encabezados para que solo contenga 1 elemento inv en lugar de 500/5000?

EDITAR (5/4/20) El requisito implícito que no quedó claro aquí fue que necesitábamos hacerlo de manera descentralizada utilizando la API RPC de blockchain o equivalente.

¿Desea descargar 250 GB de bloques de un par remoto para encontrar una sola salida?
No, no quiero hacer eso, pero no parece que haya demasiadas alternativas. Estoy tratando de fingir que soy un nodo completo de bitcoin que intenta sincronizar (pero intento sincronizar desde el bloque necesario que necesito, de esta manera solo estaría sincronizando 1 bloque de datos) Simplemente no lo creo estoy usando la API correctamente
Si tu mejor opción es hacer algo absurdo, quizás reconsideres tu estrategia. La red p2p no está diseñada para el acceso arbitrario a datos como el que está intentando.
He pasado por algunas alternativas, pero el objetivo principal aquí es poder buscar los datos de una manera descentralizada y resistente a la censura. Por lo tanto, no puedo confiar en mirar las API de blockchain explorer. Además, si uso bitcoin RPC, necesitaría conectarme a un nodo completo de bitcoin específico que podría ser eliminado.
Si desea algo resistente a la censura, su única opción es ejecutar su propio nodo e indexar los bloques en sus datos usted mismo y luego consultarlo.
¿No hay forma de que me burle de lo que hace un nodo completo (pero solo para una parte del proceso de sincronización)? Como seguramente puedo decir, hey, soy un nodo completo y me gustaría comenzar la descarga del bloque inicial desde el bloque X y luego validar las transacciones allí. ¿Esto no se maneja a través de bitcoinP2P? Lo siento de antemano si he cometido algún error aquí.
@PieterWuille Es posible que no entienda completamente su comentario de diciembre, pero de hecho logré hacer lo que esperaba, en teoría, puede 'simular' una funcionalidad de nodos completos perfectamente bien si simula los mensajes iniciales de ver-ack. Puede ver el código fuente completo aquí: github.com/dummytree/blockchain-botnet-poc/blob/master/…

Respuestas (3)

No veo ningún punto final para obtener la transacción completa en la documentación de la API Blockcypher, así que utilicé la API blockstream.info:

>https://blockstream.info/testnet/api/tx/2599dbe540a583ede3512fef9a0f26be718c039ffd4d04d85ff3b339f40e73b1
{ 
   "txid":"2599dbe540a583ede3512fef9a0f26be718c039ffd4d04d85ff3b339f40e73b1",
   "version":2,
   "locktime":0,
   "vin":[ 
      { 
         "txid":"382bda6ee2bac22afd051104af16146436895ecca382a76c2d66535a837254bc",
         "vout":1,
         "prevout":{ 
            "scriptpubkey":"00144ecdb2867150ff16c7d6e3258adca9ed8bac3ac1",
            "scriptpubkey_asm":"OP_0 OP_PUSHBYTES_20 4ecdb2867150ff16c7d6e3258adca9ed8bac3ac1",
            "scriptpubkey_type":"v0_p2wpkh",
            "scriptpubkey_address":"tb1qfmxm9pn32rl3d37kuvjc4h9fak96cwkpjyyjmk",
            "value":2948920
         },
         "scriptsig":"",
         "scriptsig_asm":"",
         "witness":[ 
            "304402205e9b17758d1daf2a501a1fabe06bdbf15adaadfcf6ff80c4cfb34176bd988c0c02207450185bde5c20e06270b3b7e681e0042072c6af25fc10c62430df0f04ec5bf201",
            "023532fa6b866f37729719a3615ef3a776407048989736ac2b7fafa5678a519df3"
         ],
         "is_coinbase":false,
         "sequence":4294967295
      }
   ],
   "vout":[ 
      { 
         "scriptpubkey":"6a0e3132372e302e302e313a38313831",
         "scriptpubkey_asm":"OP_RETURN OP_PUSHBYTES_14 3132372e302e302e313a38313831",
         "scriptpubkey_type":"op_return",
         "value":0
      },
      { 
         "scriptpubkey":"a914171f697fe358f7d7238b6128930bb1fa7363b44d87",
         "scriptpubkey_asm":"OP_HASH160 OP_PUSHBYTES_20 171f697fe358f7d7238b6128930bb1fa7363b44d OP_EQUAL",
         "scriptpubkey_type":"p2sh",
         "scriptpubkey_address":"2MuMVAFK2gbTDNVBhLtpZfA4Xi62mWh6bU5",
         "value":948920
      },
      { 
         "scriptpubkey":"0014af8abd63a00c40ad75e47870b1b0a1ddb2ba7e66",
         "scriptpubkey_asm":"OP_0 OP_PUSHBYTES_20 af8abd63a00c40ad75e47870b1b0a1ddb2ba7e66",
         "scriptpubkey_type":"v0_p2wpkh",
         "scriptpubkey_address":"tb1q479t6caqp3q26a0y0pctrv9pmket5lnx24twcx",
         "value":1500000
      }
   ],
   "size":248,
   "weight":665,
   "fee":500000,
   "status":{ 
      "confirmed":true,
      "block_height":1612110,
      "block_hash":"000000000000592589e55cda6e8a093998e8356ea770d4aaeb7c0f5439b147d7",
      "block_time":1576024567
   }
}

Puede ver aquí que la primera salida tiene los datos 3132372e302e302e313a38313831, cuya decodificación a caracteres ASCII parece una URL local:

hex = '3132372e302e302e313a38313831'
decoded = binascii.unhexlify(hex).decode('ascii')
print(decoded)

Huellas dactilares:127.0.0.1:8181

EDITAR:

Para obtener la transacción que le interesa sin usar ninguna API externa, deberá ejecutar un nodo de bitcoin completo con la txindex=1opción. Si su billetera rastrea esta transacción, un nodo podado sería suficiente. Luego puede obtener la información sobre la transacción con este comando:

>bitcoin-cli getrawtransaction 2599dbe540a583ede3512fef9a0f26be718c039ffd4d04d85ff3b339f40e73b1 true

Debería obtener algo muy similar a la respuesta de la API de Blockstream que pegué arriba

lo siento si no estaba claro, pero necesitaba hacer esto de forma descentralizada sin depender de los datos almacenados de un servidor API (por ejemplo, si solo responden con los datos incorrectos). Estoy tratando de leer estos datos directamente de la cadena de bloques y no puedo encontrar ninguna forma de hacerlo.
Verifique la edición en la parte final de mi respuesta, explica cómo hacerlo sin una API externa

El protocolo p2p de bitcoin no permite realizar búsquedas de transacciones directamente de esta manera. Tal vez un poco de filtrado de floración minimizaría la huella, pero aún es relativamente complejo de implementar.

Los servidores Electrum son quizás la siguiente mejor opción: admiten las búsquedas que desea, pero están menos descentralizados, y si su aplicación está haciendo cosas malas, podrían confabularse y manipular solo sus resultados.

¿Cómo obtengo mi respuesta de bloque o encabezados para que solo contenga 1 elemento inv en lugar de 500/5000?

No creo que pueda limitar los resultados de los encabezados (debe conocer todos los encabezados para hacerlo) Pero una vez que tenga la cadena de encabezados, puede enviar un localizador de bloques con inicio: HASH (n) fin: HASH (n + 1) y puedes descargar un solo bloque.

Vuelva a filtrar, si encuentra nodos con el bit BLOOM_SERVICE, puede decirles su filtro, y los datos del bloque solo contienen sus txs y los falsos positivos permitidos por su filtro.

Resultó que el problema principal con el código anterior era que el endianness en python estaba por defecto en mi carga útil hexadecimal mezclada. Simplemente necesitaba corregir el orden de la carga útil. El código correcto se puede ver aquí: https://github.com/dummytree/blockchain-botnet-poc/blob/master/MalwareManager.py#L284-L299