network – Version message C++

0
19


I learn bitcoin and I am trying to send a version message and get response, respectevily, by using C++. I can not find any examples or articles how to do it in C++. I’m forming request and send it by boost asio to remote bitcoin nodes, but I get no response. My request is a hex string that i convert to the binary std::vectorstd::bitset<8> container. Wireshark doesn’t see my request for some reasons.

void hex2bin(string hex, vector<bitset<8>>& binary_vector)
{
    for (std::size_t size = 0; size < hex.size(); ++size)
        binary_vector.push_back(bitset<8>(hex[size]));
}

void checksum(vector <bitset<8>> payload_bytes, string& checksum)
{
    string payload_str;
    for (bitset<8> byte : payload_bytes) payload_str += byte.to_string();

    SHA256 sha256;
    sha256.update(payload_str);
    uint8_t* digest = sha256.digest();
    sha256.update(sha256.toString(digest));
    digest = sha256.digest();
    payload_str = sha256.toString(digest);

    checksum = payload_str.substr(0, 8);
    delete[] digest;
}

vector<bitset<8>> message::get_version_message_payload(int _start_height, bool is_debug)
{
    vector<std::bitset<8>> payload_bytes;

    for (int i = 0; i < _seeds_ips.size(); ++i)
    {
        // Payload fields definition

        stringstream sstream;

        // Version - 4 bytes
        int32_t version = 70015;
        sstream << hex << _byteswap_ulong(version);

        // Service - 8 bytes
        string service = " 01 00 00 00 00 00 00 00 ";
        sstream << service;

        // Timestamp - 8 bytes
        int64_t timestamp = _byteswap_uint64(duration_cast<seconds>(system_clock::now().time_since_epoch()).count());
        sstream << hex << timestamp;

        // Addr_recv - 26 bytes
        string addr_service = service;

        string ip_prefix = " 00 00 00 00 00 00 00 00 00 00 FF FF ";
        // replace ip
        string ip = _seeds_ips[i];
        vector<string> ip_res;
        ip2hex(ip, ip_res);
        sstream << ip_prefix;
        for (string s : ip_res) sstream << hex << stoi(s);
        int32_t port = 8333;
        sstream << hex << port;

        // Addr_from
        ip = "127.0.0.1";
        vector<string> from_ip_res;
        ip2hex(ip, from_ip_res);
        sstream << ip_prefix;
        for (string s : from_ip_res) sstream << hex << stoi(s);
        sstream << hex << port << " ";

        // Service
        std::random_device rd;
        std::mt19937_64 n64(rd());

        uint64_t nonce = n64();
        sstream << hex << _byteswap_uint64(nonce) << " ";

        // User-agent
        string user_agent = " 0F 2F 53 61 74 6F 73 68 69 3A 30 2E 37 2E 32 2F ";

        // Block height
        int32_t start_height = _start_height;
        sstream << hex << _byteswap_ulong(start_height) << " ";

        string request_string = sstream.str();
        hex2bin(request_string, payload_bytes);

        if (is_debug)
        {
            cout << "Payload in hex: " << sstream.str() << endl;
        }

        if (payload_bytes.size() > 0) return payload_bytes;
    }

    return payload_bytes;
}

void message::version_message(int start_height, vector<bitset<8>>& message)
{
    stringstream sstream;

    vector<bitset<8>> payload_bytes = get_version_message_payload(start_height, true);

    // Magic
    string magic = "F9 BE B4 D9";
    sstream << magic;

    // Version command
    string command = "76 65 72 73 69 6F 6E 00 00 00 00 00 ";
    sstream << command;

    // Length of payload
    uint32_t length = payload_bytes.size();
    sstream << hex << _byteswap_ulong(length) << " ";

    // Checksum
    string _checksum;
    checksum(payload_bytes, _checksum);
    // Maybe it will occure error. It should be little endian.
    for (char ch : _checksum) sstream << hex << ch;

    // Payload
    hex2bin(sstream.str(), message);

    for (bitset<8> byte : payload_bytes) message.push_back(byte);
    cout << "Version message in hex: " << sstream.str();
}

TCP sending

int tcp_client::send_version_message()
{
    std::vector<std::string> ips;
    get_ips(ips);

    io_context ioc;
    ip::tcp::resolver resolver(ioc);
    ip::tcp::socket socket(ioc);
    error_code erc;

    for (int i = 0; i < ips.size(); ++i)
    {
        std::cout << "Trying establish connection with " << ips[i] << std::endl;
        connect(socket, resolver.resolve(ips[i], "8333"), erc);
        std::cout << "Connection status: " << erc.message() << std::endl;
        std::cout << "----------------------------------------------------" << std::endl;
        std::cout << std::endl;
        if (erc) ++i;
        else
        {
            vector<bitset<8>> version_message;
            // Feeding version_message by bytes;
            vector<string> ips;
            get_ips(ips);
            message msg(ips);
            msg.version_message(500000, version_message);

            cout << "nBytes to send: " << version_message.size() << " bytes" << endl;
            if (version_message.size() > 1)
            {
                socket.write_some(buffer(version_message.data(), version_message.size()), erc);
                cout << "Status after writing request: " << erc.message() << endl;
                socket.wait(socket.wait_read);
                //std::cout << "Sending version message status: " << erc.message() << std::endl;
                if (erc) ++i;
                else
                {
                    vector<char> response;
                    socket.read_some(buffer(response.data(), response.size()), erc);
                    cout << "Bytes reading status: " << erc.message() << endl;
                    std::cout << "Response bytes number: " << response.size() << endl;
                    for (char ch : response)
                        std::cout << ch << " ";
                }
            }
            std::cout << "----------------------------------------------------" << std::endl;
            std::cout << std::endl;
        }
    }
    
    return 0;
}

Result

> Trying establish connection with 34.89.32.154 
> Connection status: The operation completed successfully

> Payload in hex: 7f110100 01 00 00 00 00 00 00 00 de4b336100000000 00
> 00 00 00 00 00 00 00 00 00 FF FF2259209a208d 00 00 00 00 00 00 00 00
> 00 00 FF FF7f001208d50683bf919ca88bd 20a10700

> Version message in hex: F9 BE B4 D976 65 72 73 69 6F 6E 00 00 00 00 00 a7000000 7898e2b9 
> Bytes to send: 231 bytes 
> Status after writing request: The operation completed successfully 
> Received bytes number: 0



Source link

Leave a reply