Permalink
| #include "Nonce.h" | |
| #include <iostream> | |
| enum colour { DARKBLUE = 1, DARKGREEN, DARKTEAL, DARKRED, DARKPINK, DARKYELLOW, GRAY, DARKGRAY, BLUE, GREEN, TEAL, RED, PINK, YELLOW, WHITE }; | |
| std::array <char*, HASH_CAP * sizeof(char*)> cache; | |
| std::array <char*, HASH_CAP * sizeof(char*)> cache_write; | |
| HANDLE hConsole = nullptr; | |
| HANDLE hHeap = nullptr; | |
| HANDLE ofile = nullptr; | |
| HANDLE ofile_stream = nullptr; | |
| std::vector<size_t> worker_status; | |
| unsigned long long written_scoops = 0; | |
| int firstrun = 0; | |
| unsigned long long addr = 0; | |
| unsigned long long startnonce = 0; | |
| unsigned long long nonces = 0; | |
| unsigned long long threads = 1; | |
| unsigned long long nonces_per_thread = 0; | |
| unsigned long long memory = 0; | |
| std::string out_path = ""; | |
| std::vector<std::string> argsp; | |
| BOOL SetPrivilege(void) | |
| { | |
| LUID luid; | |
| if (!LookupPrivilegeValue( | |
| NULL, // lookup privilege on local system | |
| SE_MANAGE_VOLUME_NAME, // privilege to lookup | |
| &luid)) // receives LUID of privilege | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("LookupPrivilegeValue error: %u\n", GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| return FALSE; | |
| } | |
| HANDLE hToken; | |
| if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("OpenProcessToken error: %u\n", GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| return FALSE; | |
| } | |
| TOKEN_PRIVILEGES tp; | |
| tp.PrivilegeCount = 1; | |
| tp.Privileges[0].Luid = luid; | |
| tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; | |
| // Enable the privilege or disable all privileges. | |
| if (!AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("AdjustTokenPrivileges error: %u\n", GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| return FALSE; | |
| } | |
| if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("PLOT REPEATING IS DISABLED.\nThe token does not have the specified privilege.\nFor faster writing you should restart plotter with Administrative rights.\n"); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| unsigned long long getFreeSpace(const char* path) | |
| { | |
| ULARGE_INTEGER lpFreeBytesAvailable; | |
| ULARGE_INTEGER lpTotalNumberOfBytes; | |
| ULARGE_INTEGER lpTotalNumberOfFreeBytes; | |
| GetDiskFreeSpaceExA(path, &lpFreeBytesAvailable, &lpTotalNumberOfBytes, &lpTotalNumberOfFreeBytes); | |
| return lpFreeBytesAvailable.QuadPart; | |
| } | |
| unsigned long long getTotalSystemMemory() | |
| { | |
| MEMORYSTATUSEX status; | |
| status.dwLength = sizeof(status); | |
| GlobalMemoryStatusEx(&status); | |
| return status.ullAvailPhys; | |
| } | |
| void writer_i(const unsigned long long offset, const unsigned long long nonces_to_write, const unsigned long long glob_nonces) | |
| { | |
| LARGE_INTEGER liDistanceToMove; | |
| LARGE_INTEGER start_time, end_time; | |
| DWORD dwBytesWritten; | |
| double PCFreq = 0.0; | |
| LARGE_INTEGER li; | |
| QueryPerformanceFrequency(&li); | |
| PCFreq = double(li.QuadPart); | |
| written_scoops = 0; | |
| QueryPerformanceCounter((LARGE_INTEGER*)&start_time); | |
| for (size_t scoop = 0; scoop < HASH_CAP; scoop++) | |
| { | |
| liDistanceToMove.QuadPart = (scoop*glob_nonces + offset) * SCOOP_SIZE; | |
| if (!SetFilePointerEx(ofile, liDistanceToMove, nullptr, FILE_BEGIN)) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf(" error SetFilePointerEx (code = %u)\n", GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| exit(-1); | |
| } | |
| if (!WriteFile(ofile, &cache_write[scoop][0], DWORD(SCOOP_SIZE * nonces_to_write), &dwBytesWritten, nullptr)) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf(" Failed WriteFile (code = %u)\n", GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| exit(-1); | |
| } | |
| written_scoops = scoop+1; | |
| } | |
| QueryPerformanceCounter((LARGE_INTEGER*)&end_time); | |
| write_to_stream(offset+nonces_to_write); | |
| return; | |
| } | |
| bool write_to_stream(const unsigned long long data) | |
| { | |
| LARGE_INTEGER liDistanceToMove; | |
| DWORD dwBytesWritten; | |
| liDistanceToMove.QuadPart = 0; | |
| unsigned long long buf = data; | |
| if (!SetFilePointerEx(ofile_stream, liDistanceToMove, nullptr, FILE_BEGIN)) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf(" error stream SetFilePointerEx (code = %u)\n", GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| return false; | |
| } | |
| if (!WriteFile(ofile_stream, &buf, DWORD(sizeof(buf)), &dwBytesWritten, nullptr)) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf(" Failed stream WriteFile (code = %u)\n", GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| return false; | |
| } | |
| if (SetEndOfFile(ofile_stream) == 0) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf(" Failed stream SetEndOfFile (code = %u)\n", GetLastError()); | |
| CloseHandle(ofile_stream); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| return false; | |
| exit(-1); | |
| } | |
| FlushFileBuffers(ofile_stream); | |
| return true; | |
| } | |
| unsigned long long read_from_stream() | |
| { | |
| LARGE_INTEGER liDistanceToMove; | |
| DWORD dwBytesRead; | |
| liDistanceToMove.QuadPart = 0; | |
| if (!SetFilePointerEx(ofile_stream, liDistanceToMove, nullptr, FILE_BEGIN)) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf(" error stream SetFilePointerEx (code = %u)\n", GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| return 0; | |
| } | |
| unsigned long long buf = 0; | |
| if (!ReadFile(ofile_stream, &buf, DWORD(sizeof(buf)), &dwBytesRead, nullptr)) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf(" Failed stream ReadFile (code = %u)\n", GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| return 0; | |
| } | |
| //printf(" read_from_stream = %llu\n", buf); | |
| return buf; | |
| } | |
| bool is_number(const std::string& s) | |
| { | |
| return(strspn(s.c_str(), "0123456789") == s.size()); | |
| } | |
| void get_args_start() | |
| { | |
| for (auto & it : argsp) | |
| for (auto & c : it) c = tolower(c); | |
| for (size_t i = 1; i < argsp.size() - 1; i++) | |
| { | |
| if ((argsp[i] == "-id") && is_number(argsp[++i])) | |
| addr = strtoull(argsp[i].c_str(), 0, 10); | |
| if ((argsp[i] == "-sn") && is_number(argsp[++i])) | |
| startnonce = strtoull(argsp[i].c_str(), 0, 10); | |
| if ((argsp[i] == "-n") && is_number(argsp[++i])) | |
| nonces = strtoull(argsp[i].c_str(), 0, 10); | |
| if ((argsp[i] == "-t") && is_number(argsp[++i])) | |
| threads = strtoull(argsp[i].c_str(), 0, 10); | |
| if (argsp[i] == "-path") | |
| out_path = argsp[++i]; | |
| if (argsp[i] == "-mem") | |
| { | |
| i++; | |
| memory = strtoull(argsp[i].substr(0, argsp[i].find_last_of("0123456789") + 1).c_str(), 0, 10); | |
| switch (argsp[i][argsp[i].length() - 1]) | |
| { | |
| case 't': | |
| case 'T': | |
| memory *= 1024; | |
| case 'g': | |
| case 'G': | |
| memory *= 1024; | |
| } | |
| } | |
| } | |
| } | |
| void get_args_next() | |
| { | |
| for (auto & it : argsp) | |
| for (auto & c : it) c = tolower(c); | |
| for (size_t i = 1; i < argsp.size() - 1; i++) | |
| { | |
| if ((argsp[i] == "-t") && is_number(argsp[++i])) | |
| threads = strtoull(argsp[i].c_str(), 0, 10); | |
| if (argsp[i] == "-mem") | |
| { | |
| i++; | |
| memory = strtoull(argsp[i].substr(0, argsp[i].find_last_of("0123456789") + 1).c_str(), 0, 10); | |
| switch (argsp[i][argsp[i].length() - 1]) | |
| { | |
| case 't': | |
| case 'T': | |
| memory *= 1024; | |
| case 'g': | |
| case 'G': | |
| memory *= 1024; | |
| } | |
| } | |
| } | |
| } | |
| int main(int argc, char* argv[]) | |
| { | |
| // Get arguements | |
| std::vector<std::string> args(argv, &argv[(size_t)argc]); | |
| // Lazy set global | |
| argsp = args; | |
| std::thread writer; | |
| std::vector<std::thread> workers; | |
| unsigned long long start_timer = 0; | |
| get_args_start(); | |
| hConsole = GetStdHandle(STD_OUTPUT_HANDLE); | |
| if (hConsole == NULL) { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("Failed to retrieve handle of the process (%u).\n", GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| exit(-1); | |
| } | |
| SetConsoleTextAttribute(hConsole, colour::GREEN); | |
| printf("SPlotter for BURST\n"); | |
| printf("This software allows you to make lots of small pre-optimized plots automatically\n Please consider donating: BURST-ZNEH-ZB8X-9T38-HSND9"); | |
| if (out_path.empty() || (out_path.find(":") == std::string::npos)) | |
| { | |
| char Buffer[MAX_PATH]; | |
| GetCurrentDirectoryA(MAX_PATH, Buffer); | |
| std::string _path = Buffer; | |
| out_path = _path + "\\" + out_path; | |
| } | |
| if (out_path.rfind("\\") < out_path.length() - 1) out_path += "\\"; | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| printf("\nChecking Directory Exists...\n"); | |
| if (!CreateDirectoryA(out_path.c_str(), nullptr) && ERROR_ALREADY_EXISTS != GetLastError()) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("Can't create directory %s for plots (Error %u)\n", out_path.c_str(), GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| exit(-1); | |
| } | |
| SetConsoleTextAttribute(hConsole, colour::BLUE); | |
| printf("Wallet ID: %llu\n", addr); | |
| printf("Start Nonce: %llu\n", startnonce); | |
| printf("Nonces: %llu\n", nonces); | |
| printf("End Nonce: %llu\n", startnonce + nonces); | |
| repeater: | |
| DWORD sectorsPerCluster; | |
| DWORD bytesPerSector; | |
| DWORD numberOfFreeClusters; | |
| DWORD totalNumberOfClusters; | |
| if (!GetDiskFreeSpaceA(out_path.c_str(), §orsPerCluster, &bytesPerSector, &numberOfFreeClusters, &totalNumberOfClusters)) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("\nGetDiskFreeSpace failed (Error %u)\n", GetLastError()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| exit(-1); | |
| } | |
| if (nonces == 0) nonces = getFreeSpace(out_path.c_str()) / PLOT_SIZE; | |
| nonces = (nonces / (bytesPerSector / SCOOP_SIZE)) * (bytesPerSector / SCOOP_SIZE); | |
| std::string filename = std::to_string(addr) + "_" + std::to_string(startnonce) + "_" + std::to_string(nonces) + "_" + std::to_string(nonces); | |
| BOOL granted = SetPrivilege(); | |
| ofile_stream = CreateFileA((out_path + filename + ":stream").c_str(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); | |
| if (ofile_stream == INVALID_HANDLE_VALUE) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("\nError creating stream for file %s\n", (out_path + filename).c_str()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| exit(-1); | |
| } | |
| unsigned long long nonces_done = read_from_stream(); | |
| if (nonces_done == nonces) // exit | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("\nFile is already finished. Delete the existing file to start over\n"); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| CloseHandle(ofile_stream); | |
| exit(0); | |
| } | |
| if (nonces_done > 0) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::YELLOW); | |
| printf("\nContinuing with plot from nonce: %llu\n", nonces_done); | |
| } | |
| SetConsoleTextAttribute(hConsole, colour::DARKGRAY); | |
| printf("\nCreating file: %s\n", (out_path + filename).c_str()); | |
| ofile = CreateFileA((out_path + filename).c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_ALWAYS, FILE_FLAG_NO_BUFFERING, nullptr); //FILE_ATTRIBUTE_NORMAL FILE_FLAG_WRITE_THROUGH | | |
| if (ofile == INVALID_HANDLE_VALUE) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("\nError creating file %s\n", (out_path + filename).c_str()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| CloseHandle(ofile_stream); | |
| exit(-1); | |
| } | |
| // Reserve Free Space | |
| LARGE_INTEGER liDistanceToMove; | |
| liDistanceToMove.QuadPart = nonces * PLOT_SIZE; | |
| SetFilePointerEx(ofile, liDistanceToMove, nullptr, FILE_BEGIN); | |
| if (SetEndOfFile(ofile) == 0) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("\n Not enough free space, reduce \"nonces\"... (code = %u)\n", GetLastError()); | |
| CloseHandle(ofile); | |
| CloseHandle(ofile_stream); | |
| DeleteFileA((out_path + filename).c_str()); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| exit(-1); | |
| } | |
| if (granted) | |
| { | |
| if (SetFileValidData(ofile, nonces * PLOT_SIZE) == 0) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf("\nSetFileValidData error (code = %u)\n", GetLastError()); | |
| CloseHandle(ofile); | |
| CloseHandle(ofile_stream); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| exit(-1); | |
| } | |
| } | |
| unsigned long long freeRAM = getTotalSystemMemory(); | |
| if (memory) nonces_per_thread = memory * 2 / threads; | |
| else nonces_per_thread = 1024; //(bytesPerSector / SCOOP_SIZE) * 1024 / threads; | |
| if (nonces < nonces_per_thread * threads) nonces_per_thread = nonces / threads; | |
| // Check Free RAM | |
| if (freeRAM < nonces_per_thread * threads * PLOT_SIZE * 2) nonces_per_thread = freeRAM / threads / PLOT_SIZE / 2; | |
| nonces_per_thread = (nonces_per_thread / (bytesPerSector / SCOOP_SIZE)) * (bytesPerSector / SCOOP_SIZE); | |
| SetConsoleTextAttribute(hConsole, colour::TEAL); | |
| printf("\nUsing %llu MB of %llu MB of usable RAM\n", nonces_per_thread * threads * 2 * PLOT_SIZE / 1024 / 1024, freeRAM / 1024 / 1024); | |
| cache.fill(nullptr); | |
| cache_write.fill(nullptr); | |
| for (size_t i = 0; i < HASH_CAP; i++) | |
| { | |
| cache[i] = (char *)VirtualAlloc(nullptr, threads * nonces_per_thread * SCOOP_SIZE, MEM_COMMIT, PAGE_READWRITE); | |
| cache_write[i] = (char *)VirtualAlloc(nullptr, threads * nonces_per_thread * SCOOP_SIZE, MEM_COMMIT, PAGE_READWRITE); | |
| if ((cache[i] == nullptr) || (cache_write[i] == nullptr)) | |
| { | |
| SetConsoleTextAttribute(hConsole, colour::RED); | |
| printf(" Error allocating memory... Try lowering the amount of RAM \n"); | |
| CloseHandle(ofile); | |
| CloseHandle(ofile_stream); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| exit(-1); | |
| } | |
| } | |
| unsigned long long t_timer; | |
| unsigned long long x = 0; | |
| unsigned long long leftover = 0; | |
| unsigned long long nonces_in_work = 0; | |
| start_timer = GetTickCount64(); | |
| while (nonces_done < nonces) | |
| { | |
| t_timer = GetTickCount64(); | |
| leftover = nonces - nonces_done; | |
| if (leftover / (nonces_per_thread*threads) == 0) | |
| { | |
| if (leftover >= threads*(bytesPerSector / SCOOP_SIZE)) | |
| { | |
| nonces_per_thread = leftover / threads; | |
| //ajusting | |
| nonces_per_thread = (nonces_per_thread / (bytesPerSector / SCOOP_SIZE)) * (bytesPerSector / SCOOP_SIZE); | |
| } | |
| else | |
| { | |
| threads = 1; | |
| nonces_per_thread = leftover; | |
| } | |
| } | |
| for (size_t i = 0; i < threads; i++) | |
| { | |
| #ifdef __AVX__ | |
| std::thread th(std::thread(AVX1::work_i, i, addr, startnonce + nonces_done + i*nonces_per_thread, nonces_per_thread)); | |
| #else | |
| std::thread th(std::thread(SSE4::work_i, i, addr, startnonce + nonces_done + i*nonces_per_thread, nonces_per_thread)); | |
| #endif | |
| workers.push_back(move(th)); | |
| worker_status.push_back(0); | |
| } | |
| nonces_in_work = threads*nonces_per_thread; | |
| SetConsoleTextAttribute(hConsole, colour::WHITE); | |
| printf("\r[%llu%%] Generating nonces from %llu to %llu\t\t\t\t\t\t\n", (nonces_done * 100) / nonces, startnonce + nonces_done, startnonce + nonces_done + nonces_in_work); | |
| SetConsoleTextAttribute(hConsole, colour::YELLOW); | |
| do | |
| { | |
| Sleep(100); | |
| x = 0; | |
| for (auto it = worker_status.begin(); it != worker_status.end(); ++it) x += *it; | |
| printf("\r[CPU] Nonces Done: %llu (%llu nonces/min)", nonces_done + x, x * 60000 / (GetTickCount64() - t_timer)); | |
| printf("\t\t[HDD] Writing Scoops: %.2f%%", (double)(written_scoops * 100) / (double)HASH_CAP); | |
| } while (x < nonces_in_work); | |
| SetConsoleTextAttribute(hConsole, colour::GRAY); | |
| for (auto it = workers.begin(); it != workers.end(); ++it) if (it->joinable()) it->join(); | |
| for (auto it = worker_status.begin(); it != worker_status.end(); ++it) *it = 0; | |
| while ((written_scoops != 0) && (written_scoops < HASH_CAP)) | |
| { | |
| Sleep(100); | |
| printf("\r[CPU] Nonces Done: %llu ", nonces_done + x); | |
| printf("\t\t[HDD] Writing Scoops: %.2f%% ", (double)(written_scoops * 100) / (double)HASH_CAP); | |
| } | |
| if (writer.joinable()) writer.join(); | |
| cache_write.swap(cache); | |
| writer = std::thread(writer_i, nonces_done, nonces_in_work, nonces); | |
| nonces_done += nonces_in_work; | |
| } | |
| while ((written_scoops != 0) && (written_scoops < HASH_CAP)) | |
| { | |
| Sleep(100); | |
| printf("\r[CPU] Nonces Done: %llu", nonces_done + x); | |
| printf("\t\t[HDD] Writing scoops: %.2f%%", (double)(written_scoops * 100) / (double)HASH_CAP); | |
| } | |
| printf("\nFinishing up with this plot... Please wait..\n"); | |
| if (writer.joinable()) writer.join(); | |
| FlushFileBuffers(ofile); //https://msdn.microsoft.com/en-en/library/windows/desktop/aa364218(v=vs.85).aspx | |
| CloseHandle(ofile_stream); | |
| CloseHandle(ofile); | |
| printf("\rThat plot took %llu seconds..\n", (GetTickCount64() - start_timer) / 1000); | |
| // Freeing up RAM | |
| SetConsoleTextAttribute(hConsole, colour::DARKGRAY); | |
| printf("Releasing memory...\n "); | |
| for (size_t i = 0; i < HASH_CAP; i++) | |
| {VirtualFree(cache[i], 0, MEM_RELEASE);VirtualFree(cache_write[i], 0, MEM_RELEASE);} | |
| SetConsoleTextAttribute(hConsole, colour::YELLOW); | |
| printf("\nStarting the next plot, Please wait... \n"); | |
| // Set next Start Nonce | |
| startnonce = startnonce + nonces + 1; | |
| //Set flags for the next plot | |
| get_args_next(); | |
| SetConsoleTextAttribute(hConsole, colour::BLUE); | |
| printf("\nLast Start Nonce: %llu", startnonce); | |
| printf("\nNonces Per Plot : %llu", nonces); | |
| printf("\nNext Start Nonce: %llu ", startnonce + nonces + 1); | |
| printf("\nThreads : %llu ", threads); | |
| // Poor mans Loop | |
| goto repeater; | |
| } | |