diff --git a/src/Qiner.cpp b/src/Qiner.cpp index 14f238a..e67ef91 100644 --- a/src/Qiner.cpp +++ b/src/Qiner.cpp @@ -7,97 +7,13 @@ #include #include #include -#ifdef _MSC_VER -#include -#include -#pragma comment (lib, "ws2_32.lib") - -#else -#include -#include -#include -#include -#include -#endif +#include "node_connection.h" #include "score_hyperidentity.h" #include "score_addition.h" #include "keyUtils.h" -struct RequestResponseHeader -{ -private: - unsigned char _size[3]; - unsigned char _type; - unsigned int _dejavu; - -public: - inline unsigned int size() - { - return (*((unsigned int*)_size)) & 0xFFFFFF; - } - - inline void setSize(unsigned int size) - { - _size[0] = (unsigned char)size; - _size[1] = (unsigned char)(size >> 8); - _size[2] = (unsigned char)(size >> 16); - } - - inline bool isDejavuZero() const - { - return !_dejavu; - } - - inline void zeroDejavu() - { - _dejavu = 0; - } - - - inline unsigned int dejavu() const - { - return _dejavu; - } - - inline void setDejavu(unsigned int dejavu) - { - _dejavu = dejavu; - } - - inline void randomizeDejavu() - { - _rdrand32_step(&_dejavu); - if (!_dejavu) - { - _dejavu = 1; - } - } - - inline unsigned char type() const - { - return _type; - } - - inline void setType(const unsigned char type) - { - _type = type; - } -}; - -#define BROADCAST_MESSAGE 1 - -typedef struct -{ - unsigned char sourcePublicKey[32]; - unsigned char destinationPublicKey[32]; - unsigned char gammingNonce[32]; -} Message; - -char* nodeIp = NULL; -int nodePort = 0; - static std::atomic state(0); static unsigned char computorPublicKey[32]; @@ -239,122 +155,6 @@ int miningThreadProc() return 0; } -struct ServerSocket -{ -#ifdef _MSC_VER - ServerSocket() - { - WSADATA wsaData; - WSAStartup(MAKEWORD(2, 2), &wsaData); - } - - ~ServerSocket() - { - WSACleanup(); - } - - void closeConnection() - { - closesocket(serverSocket); - } - - bool establishConnection(char* address) - { - serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (serverSocket == INVALID_SOCKET) - { - printf("Fail to create a socket (%d)!\n", WSAGetLastError()); - return false; - } - - sockaddr_in addr; - ZeroMemory(&addr, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(nodePort); - sscanf_s(address, "%hhu.%hhu.%hhu.%hhu", &addr.sin_addr.S_un.S_un_b.s_b1, &addr.sin_addr.S_un.S_un_b.s_b2, &addr.sin_addr.S_un.S_un_b.s_b3, &addr.sin_addr.S_un.S_un_b.s_b4); - if (connect(serverSocket, (const sockaddr*)&addr, sizeof(addr))) - { - printf("Fail to connect to %d.%d.%d.%d (%d)!\n", addr.sin_addr.S_un.S_un_b.s_b1, addr.sin_addr.S_un.S_un_b.s_b2, addr.sin_addr.S_un.S_un_b.s_b3, addr.sin_addr.S_un.S_un_b.s_b4, WSAGetLastError()); - closeConnection(); - return false; - } - - return true; - } - - SOCKET serverSocket; -#else - void closeConnection() - { - close(serverSocket); - } - bool establishConnection(char* address) - { - serverSocket = socket(AF_INET, SOCK_STREAM, 0); - if (serverSocket == -1) - { - printf("Fail to create a socket (%d)!\n", errno); - return false; - } - - sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(nodePort); - if (inet_pton(AF_INET, address, &addr.sin_addr) <= 0) - { - printf("Invalid address/ Address not supported (%s)\n", address); - return false; - } - - if (connect(serverSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) - { - printf("Fail to connect to %s (%d)\n", address, errno); - closeConnection(); - return false; - } - - return true; - } - - int serverSocket; -#endif - - bool sendData(char* buffer, unsigned int size) - { - while (size) - { - int numberOfBytes; - if ((numberOfBytes = send(serverSocket, buffer, size, 0)) <= 0) - { - return false; - } - buffer += numberOfBytes; - size -= numberOfBytes; - } - - return true; - } - bool receiveData(char* buffer, unsigned int size) - { - const auto beginningTime = std::chrono::steady_clock::now(); - unsigned long long deltaTime = 0; - while (size && deltaTime <= 2000) - { - int numberOfBytes; - if ((numberOfBytes = recv(serverSocket, buffer, size, 0)) <= 0) - { - return false; - } - buffer += numberOfBytes; - size -= numberOfBytes; - deltaTime = std::chrono::duration_cast(std::chrono::steady_clock::now() - beginningTime).count(); - } - - return true; - } -}; - static void hexToByte(const char* hex, uint8_t* byte, const int sizeInByte) { for (int i = 0; i < sizeInByte; i++){ @@ -364,10 +164,14 @@ static void hexToByte(const char* hex, uint8_t* byte, const int sizeInByte) int main(int argc, char* argv[]) { + char* nodeIp = NULL; + int nodePort = 0; std::vector miningThreads; if (argc != 7) { - printf("Usage: Qiner [Node IP] [Node Port] [MiningID] [Signing Seed] [Mining Seed] [Number of threads]\n"); + printf( + "Usage: Qiner [Node IP] [Node Port] [MiningID] [Signing Seed] [Mining Seed] [Number " + "of threads]\n"); } else { @@ -378,33 +182,21 @@ int main(int argc, char* argv[]) consoleCtrlHandler(); - { - getPublicKeyFromIdentity(miningID, computorPublicKey); - - // Data for signing the solution - char* signingSeed = argv[4]; - unsigned char signingPrivateKey[32]; - unsigned char signingSubseed[32]; - unsigned char signingPublicKey[32]; - char privateKeyQubicFormat[128] = {0}; - char publicKeyQubicFormat[128] = {0}; - char publicIdentity[128] = {0}; - getSubseedFromSeed((unsigned char*)signingSeed, signingSubseed); - getPrivateKeyFromSubSeed(signingSubseed, signingPrivateKey); - getPublicKeyFromPrivateKey(signingPrivateKey, signingPublicKey); - - //getIdentityFromPublicKey(signingPublicKey, miningID, false); + char* signingSeed = argv[4]; + hexToByte(argv[5], randomSeed, 32); + getPublicKeyFromIdentity(miningID, computorPublicKey); + + unsigned int numberOfThreads = atoi(argv[6]); + printf("%d threads are used.\n", numberOfThreads); - hexToByte(argv[5], randomSeed, 32); - unsigned int numberOfThreads = atoi(argv[6]); - printf("%d threads are used.\n", numberOfThreads); - miningThreads.reserve(numberOfThreads); - for (unsigned int i = numberOfThreads; i-- > 0; ) - { - miningThreads.emplace_back(miningThreadProc); - } - ServerSocket serverSocket; + SolutionSubmitter solutionSubmitter(nodeIp, nodePort, randomSeed, miningID, signingSeed); + miningThreads.reserve(numberOfThreads); + for (unsigned int i = numberOfThreads; i-- > 0;) + { + miningThreads.emplace_back(miningThreadProc); + } + { auto timestamp = std::chrono::steady_clock::now(); long long prevNumberOfMiningIterations = 0; while (!state) @@ -423,88 +215,39 @@ int main(int argc, char* argv[]) } if (haveNonceToSend) { - if (serverSocket.establishConnection(nodeIp)) + bool solutionSendSuccess = solutionSubmitter.submit(&sendNonce[0]); + if (solutionSendSuccess) { - struct - { - RequestResponseHeader header; - Message message; - unsigned char solutionMiningSeed[32]; - unsigned char solutionNonce[32]; - unsigned char signature[64]; - } packet; - - packet.header.setSize(sizeof(packet)); - packet.header.zeroDejavu(); - packet.header.setType(BROADCAST_MESSAGE); - - memcpy(packet.message.sourcePublicKey, signingPublicKey, sizeof(packet.message.sourcePublicKey)); - memcpy(packet.message.destinationPublicKey, computorPublicKey, sizeof(packet.message.destinationPublicKey)); - - unsigned char sharedKeyAndGammingNonce[64]; - // Default behavior when provided seed is just a signing address - // first 32 bytes of sharedKeyAndGammingNonce is set as zeros - memset(sharedKeyAndGammingNonce, 0, 32); - // If provided seed is the for computor public key, generate sharedKey into first 32 bytes to encrypt message - if (memcmp(computorPublicKey, signingPublicKey, 32) == 0) - { - getSharedKey(signingPrivateKey, computorPublicKey, sharedKeyAndGammingNonce); - } - // Last 32 bytes of sharedKeyAndGammingNonce is randomly created so that gammingKey[0] = 0 (MESSAGE_TYPE_SOLUTION) - unsigned char gammingKey[32]; - do - { - _rdrand64_step((unsigned long long*) & packet.message.gammingNonce[0]); - _rdrand64_step((unsigned long long*) & packet.message.gammingNonce[8]); - _rdrand64_step((unsigned long long*) & packet.message.gammingNonce[16]); - _rdrand64_step((unsigned long long*) & packet.message.gammingNonce[24]); - memcpy(&sharedKeyAndGammingNonce[32], packet.message.gammingNonce, 32); - KangarooTwelve(sharedKeyAndGammingNonce, 64, gammingKey, 32); - } while (gammingKey[0]); - - // Encrypt the message payload - unsigned char gamma[32 + 32]; - KangarooTwelve(gammingKey, sizeof(gammingKey), gamma, sizeof(gamma)); - for (unsigned int i = 0; i < 32; i++) - { - packet.solutionMiningSeed[i] = randomSeed[i] ^ gamma[i]; - packet.solutionNonce[i] = sendNonce[i] ^ gamma[i + 32]; - } - - // Sign the message - uint8_t digest[32] = {0}; - uint8_t signature[64] = {0}; - KangarooTwelve( - (unsigned char*)&packet + sizeof(RequestResponseHeader), - sizeof(packet) - sizeof(RequestResponseHeader) - 64, - digest, - 32); - sign(signingSubseed, signingPublicKey, digest, signature); - memcpy(packet.signature, signature, 64); - - // Send message - if (serverSocket.sendData((char*)&packet, packet.header.size())) - { - std::lock_guard guard(foundNonceLock); - // Send data successfully. Remove it from the queue - foundNonce.pop(); - itemToSend = foundNonce.size(); - } - serverSocket.closeConnection(); + std::lock_guard guard(foundNonceLock); + // Send data successfully. Remove it from the queue + foundNonce.pop(); + itemToSend = foundNonce.size(); } } - std::this_thread::sleep_for(std::chrono::duration < double, std::milli>(1000)); + std::this_thread::sleep_for(std::chrono::duration(1000)); - unsigned long long delta = std::chrono::duration_cast(std::chrono::steady_clock::now() - timestamp).count(); + unsigned long long delta = std::chrono::duration_cast( + std::chrono::steady_clock::now() - timestamp) + .count(); if (delta >= 1000) { // Get current time in UTC - std::time_t now_time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + std::time_t now_time = + std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); std::tm* utc_time = std::gmtime(&now_time); - printf("| %04d-%02d-%02d %02d:%02d:%02d | %llu it/s | %d solutions | %.10s... |\n", - utc_time->tm_year + 1900, utc_time->tm_mon, utc_time->tm_mday, utc_time->tm_hour, utc_time->tm_min, utc_time->tm_sec, - (numberOfMiningIterations - prevNumberOfMiningIterations) * 1000 / delta, numberOfFoundSolutions.load(), miningID); + printf( + "| %04d-%02d-%02d %02d:%02d:%02d | %llu it/s | %d solutions | " + " %.10s... |\n", + utc_time->tm_year + 1900, + utc_time->tm_mon, + utc_time->tm_mday, + utc_time->tm_hour, + utc_time->tm_min, + utc_time->tm_sec, + (numberOfMiningIterations - prevNumberOfMiningIterations) * 1000 / delta, + numberOfFoundSolutions.load(), + miningID); prevNumberOfMiningIterations = numberOfMiningIterations; timestamp = std::chrono::steady_clock::now(); } @@ -522,8 +265,14 @@ int main(int argc, char* argv[]) } // Print stats - printf("Hyperidentity sols / nonces: %llu / %llu \n", qinerStat.totalHyperIdentitySols.load(), qinerStat.totalHyperIdentityNonce.load()); - printf("Addition sols / nonces: %llu / %llu \n", qinerStat.totalAdditionSols.load(), qinerStat.totalAdditionNonce.load()); + printf( + "Hyperidentity sols / nonces: %llu / %llu \n", + qinerStat.totalHyperIdentitySols.load(), + qinerStat.totalHyperIdentityNonce.load()); + printf( + "Addition sols / nonces: %llu / %llu \n", + qinerStat.totalAdditionSols.load(), + qinerStat.totalAdditionNonce.load()); printf("Qiner is shut down.\n"); } diff --git a/src/node_connection.h b/src/node_connection.h new file mode 100644 index 0000000..9ce7609 --- /dev/null +++ b/src/node_connection.h @@ -0,0 +1,309 @@ +// For connection to node +#pragma once + +#include "K12AndKeyUtil.h" +#include "keyUtils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#include +#include +#pragma comment(lib, "ws2_32.lib") + +#else +#include +#include +#include +#include +#include + +#endif + +#define BROADCAST_MESSAGE 1 + +struct RequestResponseHeader +{ +private: + unsigned char _size[3]; + unsigned char _type; + unsigned int _dejavu; + +public: + inline unsigned int size() { return (*((unsigned int*)_size)) & 0xFFFFFF; } + + inline void setSize(unsigned int size) + { + _size[0] = (unsigned char)size; + _size[1] = (unsigned char)(size >> 8); + _size[2] = (unsigned char)(size >> 16); + } + + inline bool isDejavuZero() const { return !_dejavu; } + + inline void zeroDejavu() { _dejavu = 0; } + + inline unsigned int dejavu() const { return _dejavu; } + + inline void setDejavu(unsigned int dejavu) { _dejavu = dejavu; } + + inline void randomizeDejavu() + { + _rdrand32_step(&_dejavu); + if (!_dejavu) + { + _dejavu = 1; + } + } + + inline unsigned char type() const { return _type; } + + inline void setType(const unsigned char type) { _type = type; } +}; + +typedef struct +{ + unsigned char sourcePublicKey[32]; + unsigned char destinationPublicKey[32]; + unsigned char gammingNonce[32]; +} Message; + +struct ServerSocket +{ +#ifdef _MSC_VER + ServerSocket() + { + WSADATA wsaData; + WSAStartup(MAKEWORD(2, 2), &wsaData); + } + + ~ServerSocket() { WSACleanup(); } + + void closeConnection() { closesocket(serverSocket); } + + bool establishConnection(const char* address, int nodePort) + { + serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (serverSocket == INVALID_SOCKET) + { + printf("Fail to create a socket (%d)!\n", WSAGetLastError()); + return false; + } + + sockaddr_in addr; + ZeroMemory(&addr, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(nodePort); + sscanf_s( + address, + "%hhu.%hhu.%hhu.%hhu", + &addr.sin_addr.S_un.S_un_b.s_b1, + &addr.sin_addr.S_un.S_un_b.s_b2, + &addr.sin_addr.S_un.S_un_b.s_b3, + &addr.sin_addr.S_un.S_un_b.s_b4); + if (connect(serverSocket, (const sockaddr*)&addr, sizeof(addr))) + { + printf( + "Fail to connect to %d.%d.%d.%d (%d)!\n", + addr.sin_addr.S_un.S_un_b.s_b1, + addr.sin_addr.S_un.S_un_b.s_b2, + addr.sin_addr.S_un.S_un_b.s_b3, + addr.sin_addr.S_un.S_un_b.s_b4, + WSAGetLastError()); + closeConnection(); + return false; + } + + return true; + } + + SOCKET serverSocket; +#else + void closeConnection() { close(serverSocket); } + bool establishConnection(const char* address, int nodePort) + { + serverSocket = socket(AF_INET, SOCK_STREAM, 0); + if (serverSocket == -1) + { + printf("Fail to create a socket (%d)!\n", errno); + return false; + } + + sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(nodePort); + if (inet_pton(AF_INET, address, &addr.sin_addr) <= 0) + { + printf("Invalid address/ Address not supported (%s)\n", address); + return false; + } + + if (connect(serverSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { + printf("Fail to connect to %s (%d)\n", address, errno); + closeConnection(); + return false; + } + + return true; + } + + int serverSocket; +#endif + + bool sendData(char* buffer, unsigned int size) + { + while (size) + { + int numberOfBytes; + if ((numberOfBytes = send(serverSocket, buffer, size, 0)) <= 0) + { + return false; + } + buffer += numberOfBytes; + size -= numberOfBytes; + } + + return true; + } + bool receiveData(char* buffer, unsigned int size) + { + const auto beginningTime = std::chrono::steady_clock::now(); + unsigned long long deltaTime = 0; + while (size && deltaTime <= 2000) + { + int numberOfBytes; + if ((numberOfBytes = recv(serverSocket, buffer, size, 0)) <= 0) + { + return false; + } + buffer += numberOfBytes; + size -= numberOfBytes; + deltaTime = std::chrono::duration_cast( + std::chrono::steady_clock::now() - beginningTime) + .count(); + } + + return true; + } +}; + +struct SolutionSubmitter +{ + SolutionSubmitter( + char* address, + int nodePort, + const unsigned char* miningSeed, + const char* miningID, + const char* signingSeed) + { + _nodePort = nodePort; + _nodeIp = address; + memcpy(_miningSeed, miningSeed, sizeof(_miningSeed)); + + // Set data for submission + getSubseedFromSeed((unsigned char*)signingSeed, _signingSubseed); + getPrivateKeyFromSubSeed(_signingSubseed, _signingPrivateKey); + getPublicKeyFromPrivateKey(_signingPrivateKey, _signingPublicKey); + getPublicKeyFromIdentity(miningID, _computorPublicKey); + } + + bool submit(const unsigned char* sendNonce) + { + bool sendSuccess = false; + if (serverSocket.establishConnection(_nodeIp.c_str(), _nodePort)) + { + struct + { + RequestResponseHeader header; + Message message; + unsigned char solutionMiningSeed[32]; + unsigned char solutionNonce[32]; + unsigned char signature[64]; + } packet; + + packet.header.setSize(sizeof(packet)); + packet.header.zeroDejavu(); + packet.header.setType(BROADCAST_MESSAGE); + + memcpy( + packet.message.sourcePublicKey, + _signingPublicKey, + sizeof(packet.message.sourcePublicKey)); + memcpy( + packet.message.destinationPublicKey, + _computorPublicKey, + sizeof(packet.message.destinationPublicKey)); + + unsigned char sharedKeyAndGammingNonce[64]; + // Default behavior when provided seed is just a signing address + // first 32 bytes of sharedKeyAndGammingNonce is set as zeros + memset(sharedKeyAndGammingNonce, 0, 32); + // If provided seed is the for computor public key, generate sharedKey into first 32 + // bytes to encrypt message + if (memcmp(_computorPublicKey, _signingPublicKey, 32) == 0) + { + getSharedKey(_signingPrivateKey, _computorPublicKey, sharedKeyAndGammingNonce); + } + // Last 32 bytes of sharedKeyAndGammingNonce is randomly created so that gammingKey[0] = + // 0 (MESSAGE_TYPE_SOLUTION) + unsigned char gammingKey[32]; + do + { + _rdrand64_step((unsigned long long*)&packet.message.gammingNonce[0]); + _rdrand64_step((unsigned long long*)&packet.message.gammingNonce[8]); + _rdrand64_step((unsigned long long*)&packet.message.gammingNonce[16]); + _rdrand64_step((unsigned long long*)&packet.message.gammingNonce[24]); + memcpy(&sharedKeyAndGammingNonce[32], packet.message.gammingNonce, 32); + KangarooTwelve(sharedKeyAndGammingNonce, 64, gammingKey, 32); + } while (gammingKey[0]); + + // Encrypt the message payload + unsigned char gamma[32 + 32]; + KangarooTwelve(gammingKey, sizeof(gammingKey), gamma, sizeof(gamma)); + for (unsigned int i = 0; i < 32; i++) + { + packet.solutionMiningSeed[i] = _miningSeed[i] ^ gamma[i]; + packet.solutionNonce[i] = sendNonce[i] ^ gamma[i + 32]; + } + + // Sign the message + uint8_t digest[32] = {0}; + uint8_t signature[64] = {0}; + KangarooTwelve( + (unsigned char*)&packet + sizeof(RequestResponseHeader), + sizeof(packet) - sizeof(RequestResponseHeader) - 64, + digest, + 32); + sign(_signingSubseed, _signingPublicKey, digest, signature); + memcpy(packet.signature, signature, 64); + + // Send message + if (serverSocket.sendData((char*)&packet, packet.header.size())) + { + sendSuccess = true; + } + serverSocket.closeConnection(); + } + return sendSuccess; + } + + std::string _nodeIp; + int _nodePort; + ServerSocket serverSocket; + unsigned char _miningSeed[32]; + + unsigned char _computorPublicKey[32]; + unsigned char _signingPrivateKey[32]; + unsigned char _signingSubseed[32]; + unsigned char _signingPublicKey[32]; +}; diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 6edb39f..dbd710f 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -3,14 +3,24 @@ find_package(Threads REQUIRED) # Main executable add_executable(score_test_generator score_test_generator.cpp) +add_executable(broadcastMessageSolution + broadcastMessageSolution.cpp + ${CMAKE_SOURCE_DIR}/src/keyUtils.cpp) target_include_directories(score_test_generator PRIVATE ${CMAKE_SOURCE_DIR}/src) +target_include_directories(broadcastMessageSolution + PRIVATE + ${CMAKE_SOURCE_DIR}/src) + # Linking set(TOOLS_LINK_LIBS Threads::Threads) target_link_libraries(score_test_generator + PRIVATE + ${TOOLS_LINK_LIBS}) +target_link_libraries(broadcastMessageSolution PRIVATE ${TOOLS_LINK_LIBS}) \ No newline at end of file diff --git a/tools/broadcastMessageSolution.cpp b/tools/broadcastMessageSolution.cpp new file mode 100644 index 0000000..3a818ed --- /dev/null +++ b/tools/broadcastMessageSolution.cpp @@ -0,0 +1,61 @@ +#include +#include +#include + +#include "node_connection.h" + +static void hexToByte(const char* hex, uint8_t* byte, const int sizeInByte) +{ + for (int i = 0; i < sizeInByte; i++){ + sscanf(hex+i*2, "%2hhx", &byte[i]); + } +} + +int main(int argc, char* argv[]) +{ + if (argc < 7) + { + printf("Usage: broadcastMessageSolution [Node IP] [Node Port] [MiningID] [Signing Seed] [Mining Seed] [Nonces] [Algo ID (Optional)]\n"); + } + else + { + char* nodeIp = argv[1]; + int nodePort = std::atoi(argv[2]); + char* miningID = argv[3]; + + int selectedAlgoId = -1; + if (argc > 7) + { + selectedAlgoId = std::atoi(argv[7]); + } + + char* signingSeed = argv[4]; + unsigned char nonce[32]; + unsigned char randomSeed[32]; + hexToByte(argv[5], randomSeed, 32); + hexToByte(argv[6], nonce, 32); + + SolutionSubmitter solutionSubmitter(nodeIp, nodePort, randomSeed, miningID, signingSeed); + // Adjust the nonce if user request + if (selectedAlgoId >=0 ) + { + // Hyperidentity scoring + if (selectedAlgoId == 0) + { + nonce[0] &= 0xFE; + } + // Addition scoring + else if (selectedAlgoId == 1) + { + nonce[0] |= 0x1; + } + // Other just as it is + } + + if (!solutionSubmitter.submit(nonce)) + { + printf("Failed to send data.\n"); + } + } + return 0; +} \ No newline at end of file