Получить данные транзакции из полного узла

Исходная информация

Я создаю приложение, которое требует возможности запрашивать любой полный биткойн-узел (из сценария Python с использованием необработанных сокетов tcp), чтобы прочитать значение OP_Return, указанное в следующей транзакции ( https://live.blockcypher.com/btc- testnet/tx/2599dbe540a583ede3512fef9a0f26be718c039ffd4d04d85ff3b339f40e73b1/ )

Что я сделал на сегодняшний день

Мне удалось установить версию + verack, однако я столкнулся с двумя проблемами.

  1. Когда я отправляю запрос getdataна нужную транзакцию, Idit не возвращает результат. Я определил, что это связано с тем, что мои первоначальные предположения о том, что getdata возвращает необходимые данные, были неверны, и вместо этого он будет возвращать данные транзакций только для транзакций, все еще находящихся в мемпуле.
  2. Это привело меня к моей основной проблеме: я надеялся воспроизвести начальную загрузку блока в моем скрипте Python, начиная с блока, содержащего интересующую меня транзакцию. Однако, когда я делаю/независимо от того, что я, кажется, помещаю getblocksв getheadersхэш filter Я получаю дамп из 500 (или 2000) блоков/заголовков. Ниже приведен шестнадцатеричный дамп запросов, которые я делаю (только кадр протокола биткойн):

    • getblocks 0b110907676574626c6f636b00000000450000002a0af9950100000001000000000000592589e55cda6e8a093998e8356ea770d4aaeb7c0f5439b147d7000000000000017a09017d52db538d7a9ddcc48311866d7e5fdbbbec7d0faad5

    • getheaders 0b110907676574686561646572730000450000002a0af9950100000001000000000000592589e55cda6e8a093998e8356ea770d4aaeb7c0f5439b147d7000000000000017a09017d52db538d7a9ddcc48311866d7e5fdbbbec7d0faad5

Я ищу следующую помощь:

  1. Как я могу запросить данные транзакции без использования биткойн RPC, если я не могу использовать getdataсообщение?
  2. Как сделать так, чтобы ответ моего блока или заголовков содержал только 1 элемент запроса вместо 500/5000

РЕДАКТИРОВАТЬ (4/5/20) Подразумеваемое требование, которое здесь не было разъяснено, заключалось в том, что нам нужно было сделать это децентрализованным способом, используя блокчейн RPC API или аналогичный.

Вы хотите загрузить 250 ГБ блоков с удаленного узла, чтобы найти один выход?
Нет, я не хочу этого делать, но не похоже, что есть слишком много альтернатив. Я пытаюсь притвориться, будто я полный биткойн-узел, пытающийся синхронизироваться (но пытаясь синхронизировать необходимый блок, который мне нужен, таким образом, я буду синхронизировать данные только на 1 блок). Я просто не думаю, что я m правильно используя API
Если ваш лучший выбор — сделать что-то абсурдное, возможно, пересмотрите свою стратегию. Сеть p2p не предназначена для произвольного доступа к данным, как вы пытаетесь.
Я рассмотрел несколько альтернатив, но главная цель здесь — иметь возможность искать данные децентрализованным способом, устойчивым к цензуре. Поэтому я не могу полагаться на API обозревателя блокчейна. Кроме того, если я использую биткойн RPC, мне нужно будет подключиться к определенному полному узлу биткойнов, который может быть отключен.
Если вы хотите что-то устойчивое к цензуре, ваш единственный выбор — запустить свой собственный узел и самостоятельно проиндексировать блоки в его данных, а затем запросить это.
нет ли у меня возможности издеваться над тем, что делает полный узел (но только для части процесса синхронизации)? Конечно, я могу сказать: эй, я полный узел, и я хотел бы начать начальную загрузку блока из блока X, а затем проверить транзакции в нем. Разве это не обрабатывается через биткойнP2P? Извините заранее, если я сделал какие-либо ошибки здесь
@PieterWuille Возможно, я не совсем понимаю ваш декабрьский комментарий, но на самом деле мне удалось сделать то, на что я надеялся, теоретически вы можете прекрасно «сымитировать» функциональность полных узлов, если смоделируете первоначальные сообщения ver-ack. Вы можете просмотреть полный исходный код здесь: github.com/dummytree/blockchain-botnet-poc/blob/master/…

Ответы (3)

Я не вижу конечной точки для получения всей транзакции в документации API Blockcypher, поэтому я использовал 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
   }
}

Здесь вы можете видеть, что первый вывод имеет данные 3132372e302e302e313a38313831, декодирование которых в символы ASCII выглядит как локальный URL:

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

Отпечатки:127.0.0.1:8181

РЕДАКТИРОВАТЬ:

Чтобы получить интересующую вас транзакцию без использования какого-либо внешнего API, вам нужно будет запустить полный биткойн-узел с опцией txindex=1. Если эта транзакция отслеживается вашим кошельком, будет достаточно обрезанного узла. Затем вы можете получить информацию о транзакции с помощью этой команды:

>bitcoin-cli getrawtransaction 2599dbe540a583ede3512fef9a0f26be718c039ffd4d04d85ff3b339f40e73b1 true

Вы должны получить что-то очень похожее на ответ из API-интерфейса blockstream, который я вставил выше.

извините, если это было неясно, но мне нужно было сделать это децентрализованным способом, не полагаясь на сохраненные данные с сервера API (например, если они просто отвечают неверными данными). Я пытаюсь прочитать эти данные прямо из блокчейна и не могу найти способ сделать это.
Проверьте редактирование в последней части моего ответа, в нем объясняется, как это сделать без внешнего API.

Биткойн-протокол p2p напрямую не разрешает поиск транзакций таким образом. Возможно, некоторая фильтрация Блума минимизирует занимаемую площадь, но реализовать ее все еще относительно сложно.

Серверы Electrum, возможно, являются следующей лучшей вещью — они поддерживают поиск, который вы хотите, но они менее децентрализованы, и если ваше приложение делает непослушные вещи, они могут вступить в сговор и манипулировать только вашими результатами.

Как сделать так, чтобы ответ моего блока или заголовков содержал только 1 элемент запроса вместо 500/5000

Я не думаю, что вы можете ограничить результаты заголовков (для этого вам нужно знать все заголовки). Но как только у вас есть цепочка заголовков, вы можете отправить локатор блоков с start:HASH(n) end:HASH(n+ 1) и вы можете скачать один блок.

Повторная фильтрация Блума, если вы найдете узлы с битом BLOOM_SERVICE, вы можете сообщить им свой фильтр, а данные блока содержат только ваши txs и ложные срабатывания, разрешенные вашим фильтром.

Оказывается, основная проблема с приведенным выше кодом заключалась в том, что порядок следования байтов в python по умолчанию был перепутан с моей шестнадцатеричной полезной нагрузкой. Мне просто нужно было исправить порядок полезной нагрузки. Правильный код можно посмотреть здесь: https://github.com/dummytree/blockchain-botnet-poc/blob/master/MalwareManager.py#L284-L299 .