Bitcoin-Cli

是否可以讀取我的節點中繼的每筆交易?

  • September 3, 2016

我想將我的節點收到的每個有效交易添加到我自己的數據庫中。

目前,我getrawmempool每秒鐘都在尋找新的交易,然後使用getrawtransaction.

但是,這些 bitcoin-cli 查詢可能很慢。那麼有沒有辦法“攔截”我的節點中繼的每一個有效交易而無需使用比特幣cli?最好使用PHP?

我被告知,讀取我的節點中繼的所有內容的一種簡單方法是連接到我的節點並接受它中繼的所有消息。

所以這是一個用 PHP 編寫的基本“節點”。

<?php

// --------
// SETTINGS
// --------
$version    = 60002;
$node       = array('85.119.83.25', 8333); // node you want to connect to
$local      = array('127.0.0.1', 8333); // our ip and port

list($node_ip, $node_port) = $node;
list($local_ip, $local_port) = $local;

echo "\nNode\n----\n";
echo 'version: '.$version.PHP_EOL;
echo 'node:    '.implode($node, ':').PHP_EOL;
echo 'local:   '.implode($local, ':').PHP_EOL.PHP_EOL;


// ------------------
// 1. VERSION MESSAGE
// ------------------

// General Functions
function fieldsize($field, $bytes = 1) {
   $length = $bytes * 2;
   $result = str_pad($field, $length, '0', STR_PAD_LEFT);
   return $result;
}

function swapEndian($hex) {
   return implode('', array_reverse(str_split($hex, 2)));
}

function byteSpaces($bytes) { // add spaces between bytes
   $bytes = implode(str_split(strtoupper($bytes), 2), ' ');
   return $bytes;
}

// Version Message Functions 
function timestamp($time) { // convert timestamp to network byte order
   $time = dechex($time);
   $time = fieldsize($time, 8);
   $time = swapEndian($time);
   return byteSpaces($time);
}

function networkaddress($ip, $port = '8333') { // convert ip address to network byte order
   $services = '01 00 00 00 00 00 00 00'; // 1 = NODE_NETWORK

   $ipv6_prefix = '00 00 00 00 00 00 00 00 00 00 FF FF';

   $ip = explode('.', $ip);
   $ip = array_map("dechex", $ip);
   $ip = array_map("fieldsize", $ip);
   $ip = array_map("strtoupper", $ip);
   $ip = implode($ip, ' ');

   $port = dechex($port); // for some fucking reason this is big-endian
   $port = byteSpaces($port);

   return "$services $ipv6_prefix $ip $port";
}

function checksum($string) {
   $string = hex2bin($string);
   $hash = hash('sha256', hash('sha256', $string, true));
   $checksum = substr($hash, 0, 8);
   return byteSpaces($checksum);
}


// MAKE MESSAGES

function makeMessage($payload) {

   // Header
   $magicbytes = 'F9 BE B4 D9';
   $command = '76 65 72 73 69 6F 6E 00 00 00 00 00';
   $payload_size = bytespaces(swapEndian(fieldsize(dechex(strlen($payload) / 2), 4)));
   $checksum = checksum($payload);

   $header_array = [
       'magicbytes'    => $magicbytes,
       'command'       => $command,
       'payload_size'  => $payload_size,
       'checksum'      => $checksum,
   ];

   $header = str_replace(' ', '', implode($header_array));
   echo 'Header: '; print_r($header_array);

   return $header.$payload;

}

function makeVersionPayload($version, $node_ip, $node_port, $local_ip, $local_port) {

   // settings
   $services = '01 00 00 00 00 00 00 00'; // (1 = NODE_NETORK)
   $user_agent = '00';
   $start_height = 0;

   // prepare
   $version = bytespaces(swapEndian(fieldsize(dechex($version), 4)));
   $timestamp = timestamp(time()); // 73 43 c9 57 00 00 00 00
   $recv = networkaddress($node_ip, $node_port);
   $from = networkaddress($local_ip, $local_port);
   $nonce = bytespaces(swapEndian(fieldsize(dechex(mt_rand()), 8)));
   $start_height = bytespaces(swapEndian(fieldsize(dechex($start_height), 4)));

   $version_array = [ // hexadecimal, network byte order
       'version'       => $version,        // 4 bytes (60002)
       'services'      => $services,       // 8 bytes
       'timestamp'     => $timestamp,      // 8 bytes
       'addr_recv'     => $recv,           // 26 bytes
       'addr_from'     => $from,           // 26 bytes
       'nonce'         => $nonce,          // 8 bytes
       'user_agent'    => $user_agent,     // varint
       'start_height'  => $start_height    // 4 bytes
   ];

   $version_payload = str_replace(' ', '', implode($version_array));
   echo 'Version Payload: '; print_r($version_array);

   return $version_payload;

}


// -----------------
// 2. SOCKET CONNECT
// -----------------

// Print socket error function
function error() {
   $error = socket_strerror(socket_last_error());
   return $error.PHP_EOL;
}


// i. Create Version Message (needs to be sent to node you want to connect to)
echo "Connect\n-------\n";
$payload = makeVersionPayload($version, $node_ip, $node_port, $local_ip, $local_port);
$message = makeMessage($payload);
$message_size = strlen($message) / 2; // the size of the message (in bytes) being sent


// ii. Connect to socket and send version message
$socket = socket_create(AF_INET, SOCK_STREAM, 6); // IPv4, TCP uses this type, TCP protocol
socket_connect($socket, $node_ip, $node_port);
socket_send($socket, hex2bin($message), $message_size, 0); // don't forget to send message in binary


// iii. Keep receiving data (inv messages) from the node we just connected to
echo "\nReceiving packets from $node_ip...\n\n";
while (true) {
   if (socket_recv($socket, $buffer, pow(2,10), MSG_DONTWAIT)) {
       echo bin2hex($buffer)."\n\n";
   }
}



/* Resources
   - https://en.bitcoin.it/wiki/Protocol_documentation
   - https://coinlogic.wordpress.com/2014/03/09/the-bitcoin-protocol-4-network-messages-1-version/
*/

感謝他們的建議。

如何使用:

只需更改您要連接的節點頂部的 IP,它就會開始接收它發回的每條消息。

警告:這是非常基本的,我剛剛開始使用它,所以請謹慎使用。但是,它似乎確實有效。


**獎勵:**這是 Python 中的一個:在 Python 中建立對等連接

引用自:https://bitcoin.stackexchange.com/questions/48363