├── .github └── workflows │ └── efi-build-develop.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE.md ├── Qubic.sln ├── README.md ├── README_CLANG.md ├── SEAMLESS.md ├── cmake └── CompilerSetup.cmake ├── doc ├── acquireShares.png ├── acquireShares.svg ├── contracts.md ├── contributing.md ├── custom_mining.md ├── profiling_csv.png ├── protocol.md ├── qubic-initial-disk.zip ├── releaseShares.png └── releaseShares.svg ├── lib ├── platform_common │ ├── CMakeLists.txt │ ├── compiler_warnings.h │ ├── edk2_mdepkg │ │ ├── Include │ │ │ ├── Base.h │ │ │ ├── Library │ │ │ │ ├── BaseLib.h │ │ │ │ └── DebugLib.h │ │ │ └── X64 │ │ │ │ └── ProcessorBind.h │ │ ├── Library │ │ │ └── BaseLib │ │ │ │ ├── BaseLibInternals.h │ │ │ │ ├── LongJump.c │ │ │ │ ├── SetJump.c │ │ │ │ └── X64 │ │ │ │ ├── LongJump.S │ │ │ │ ├── LongJump.asm │ │ │ │ ├── LongJump.nasm │ │ │ │ ├── SetJump.S │ │ │ │ ├── SetJump.asm │ │ │ │ └── SetJump.nasm │ │ ├── License.txt │ │ └── README.md │ ├── long_jump.h │ ├── platform_common.vcxproj │ ├── platform_common.vcxproj.filters │ ├── platform_common.vcxproj.user │ ├── processor.h │ ├── qintrin.h │ ├── qstdint.h │ └── sleep.h ├── platform_efi │ ├── CMakeLists.txt │ ├── edk2_debug.c │ ├── platform_efi.vcxproj │ ├── platform_efi.vcxproj.user │ ├── processor.cpp │ ├── sleep.cpp │ ├── uefi.h │ ├── uefi_globals.cpp │ └── uefi_globals.h └── platform_os │ ├── CMakeLists.txt │ ├── edk2_debug.c │ ├── platform_os.vcxproj │ ├── platform_os.vcxproj.user │ ├── processor.cpp │ └── sleep.cpp ├── src ├── CMakeLists.txt ├── K12 │ ├── brg_endian.h │ └── kangaroo_twelve_xkcp.h ├── Qubic.vcxproj ├── Qubic.vcxproj.filters ├── Qubic.vcxproj.user ├── addons │ └── tx_status_request.h ├── assets │ ├── assets.h │ └── net_msg_impl.h ├── common_buffers.h ├── contract_core │ ├── contract_action_tracker.h │ ├── contract_def.h │ ├── contract_exec.h │ ├── ipo.h │ ├── qpi_asset_impl.h │ ├── qpi_collection_impl.h │ ├── qpi_hash_map_impl.h │ ├── qpi_ipo_impl.h │ ├── qpi_proposal_voting.h │ ├── qpi_spectrum_impl.h │ ├── qpi_system_impl.h │ ├── qpi_ticking_impl.h │ ├── qpi_trivial_impl.h │ └── stack_buffer.h ├── contracts │ ├── ComputorControlledFund.h │ ├── EmptyTemplate.h │ ├── GeneralQuorumProposal.h │ ├── MsVault.h │ ├── MyLastMatch.h │ ├── QUtil.h │ ├── QVAULT.h │ ├── Qbay.h │ ├── Qearn.h │ ├── Quottery.h │ ├── Qx.h │ ├── README.md │ ├── Random.h │ ├── SupplyWatcher.h │ ├── TestExampleA.h │ ├── TestExampleB.h │ ├── TestExampleC.h │ ├── TestExampleD.h │ ├── math_lib.h │ └── qpi.h ├── files │ └── files.h ├── four_q.h ├── kangaroo_twelve.h ├── logging │ ├── logging.h │ └── net_msg_impl.h ├── mining │ └── mining.h ├── network_core │ ├── peers.h │ └── tcp4.h ├── network_messages │ ├── README.md │ ├── all.h │ ├── assets.h │ ├── broadcast_message.h │ ├── common_def.h │ ├── common_response.h │ ├── computors.h │ ├── contract.h │ ├── custom_mining.h │ ├── entity.h │ ├── header.h │ ├── logging.h │ ├── public_peers.h │ ├── special_command.h │ ├── system_info.h │ ├── tick.h │ └── transactions.h ├── oracles │ ├── Price.h │ └── oracle_machines.h ├── platform │ ├── assert.h │ ├── common_types.h │ ├── concurrency.h │ ├── concurrency_impl.h │ ├── console_logging.h │ ├── custom_stack.asm │ ├── custom_stack.h │ ├── debugging.h │ ├── file_io.h │ ├── global_var.h │ ├── m256.h │ ├── memory.h │ ├── memory_util.h │ ├── profiling.h │ ├── random.h │ ├── read_write_lock.h │ ├── stack_size_tracker.h │ ├── time.h │ ├── time_stamp_counter.h │ └── virtual_memory.h ├── private_settings.h ├── public_settings.h ├── qubic.cpp ├── revenue.h ├── score.h ├── score_cache.h ├── spectrum │ ├── special_entities.h │ └── spectrum.h ├── system.h ├── text_output.h ├── ticking │ ├── tick_storage.h │ └── ticking.h └── vote_counter.h ├── test ├── CMakeLists.txt ├── README.md ├── assets.cpp ├── common_def.cpp ├── contract_core.cpp ├── contract_msvault.cpp ├── contract_qbay.cpp ├── contract_qearn.cpp ├── contract_qvault.cpp ├── contract_qx.cpp ├── contract_testex.cpp ├── contract_testing.h ├── custom_mining.cpp ├── data │ ├── custom_revenue.eoe │ ├── samples_20240815.csv │ └── scores_v4.csv ├── file_io.cpp ├── kangaroo_twelve.cpp ├── logging_test.h ├── m256.cpp ├── math_lib.cpp ├── network_messages.cpp ├── packages.config ├── platform.cpp ├── qpi.cpp ├── qpi_collection.cpp ├── qpi_hash_map.cpp ├── revenue.cpp ├── score.cpp ├── score_cache.cpp ├── score_params.h ├── score_reference.h ├── spectrum.cpp ├── stdlib_impl.cpp ├── test.vcxproj ├── test.vcxproj.filters ├── test.vcxproj.user ├── test_util.h ├── tick_storage.cpp ├── tx_status_request.cpp ├── utils.h ├── virtual_memory.cpp └── vote_counter.cpp └── tools ├── python └── custom_mining_revenue.py ├── score_test_generator ├── score_test_generator.vcxproj ├── score_test_generator.vcxproj.filters ├── score_test_generator.vcxproj.user └── test_generator.cpp └── tools.sln /.github/workflows/efi-build-develop.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | name: EFIBuild 7 | 8 | on: 9 | push: 10 | branches: [ "main", "develop" ] 11 | pull_request: 12 | branches: [ "main", "develop" ] 13 | 14 | env: 15 | # Path to the solution file relative to the root of the project. 16 | SOLUTION_FILE_PATH: . 17 | 18 | # Configuration type to build. 19 | # You can convert this to a build matrix if you need coverage of multiple configuration types. 20 | # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 21 | BUILD_CONFIGURATION: Release 22 | 23 | permissions: 24 | contents: read 25 | 26 | jobs: 27 | build: 28 | runs-on: windows-latest 29 | 30 | steps: 31 | - uses: actions/checkout@v3 32 | 33 | - name: Add MSBuild to PATH 34 | uses: microsoft/setup-msbuild@v1.0.2 35 | 36 | - name: Restore NuGet packages 37 | working-directory: ${{env.GITHUB_WORKSPACE}} 38 | run: nuget restore ${{env.SOLUTION_FILE_PATH}} -Verbosity detailed 39 | 40 | - name: Build 41 | working-directory: ${{env.GITHUB_WORKSPACE}} 42 | # Add additional options to the MSBuild command line here (like platform or verbosity level). 43 | # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference 44 | run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} ${{env.SOLUTION_FILE_PATH}} 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /packages/ 2 | /.vscode/ 3 | /old/ 4 | /notes/ 5 | .vs/ 6 | x64/ 7 | ~AutoRecover.*.vcxproj 8 | /test/spectrum.* 9 | /test/universe.* 10 | /test/contract0???.??? 11 | /test/tmp_file_* 12 | /test/*.pg 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(qubic CXX) 3 | 4 | # Set C++ standard 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | # Include the centralized compiler detection module 9 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 10 | include(CompilerSetup) 11 | 12 | # Build options 13 | option(BUILD_TESTS "Build the test suite" ON) 14 | option(BUILD_EFI "Build the EFI application" ON) 15 | option(USE_SANITIZER "Build test with sanitizer support (clang only)" ON) 16 | 17 | if(IS_WINDOWS) 18 | message(WARNING "Building on Windows using Visual Studio and CMake has undergone limited testing and is not officially supported at this time.") 19 | if(USE_SANITIZER) 20 | message(WARNING "Building tests with sanitizer support is not supported on Windows.") 21 | endif() 22 | endif() 23 | 24 | # Always include platform_common as it's needed for both application and tests 25 | add_subdirectory(lib/platform_common) 26 | 27 | if(BUILD_EFI OR BUILD_TESTS) 28 | add_subdirectory(lib/platform_efi) 29 | endif() 30 | 31 | # Build the tests first. On fail, the build will fail completely 32 | if(BUILD_TESTS) 33 | message(STATUS "Building test suite") 34 | enable_testing() 35 | add_subdirectory(lib/platform_os) 36 | 37 | # If we're not building the application, we still need src for tests 38 | # but don't make it a default target 39 | if(NOT BUILD_EFI) 40 | add_subdirectory(src EXCLUDE_FROM_ALL) 41 | endif() 42 | 43 | add_subdirectory(test) 44 | endif() 45 | 46 | # Build the application if requested 47 | if(BUILD_EFI) 48 | message(STATUS "Building EFI application") 49 | add_subdirectory(src) 50 | endif() 51 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, perpetual, worldwide, non-exclusive, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 2 | 3 | 4 | 5 | 1. The Software cannot be used in any form or in any substantial portions for development, maintenance and for any other purposes, in the military sphere and in relation to military products, including, but not limited to: 6 | 7 | a. any kind of armored force vehicles, missile weapons, warships, artillery weapons, air military vehicles (including military aircrafts, combat helicopters, military drones aircrafts), air defense systems, rifle armaments, small arms, firearms and side arms, melee weapons, chemical weapons, weapons of mass destruction; 8 | 9 | b. any special software for development technical documentation for military purposes; 10 | 11 | c. any special equipment for tests of prototypes of any subjects with military purpose of use; 12 | 13 | d. any means of protection for conduction of acts of a military nature; 14 | 15 | e. any software or hardware for determining strategies, reconnaissance, troop positioning, conducting military actions, conducting special operations; 16 | 17 | f. any dual-use products with possibility to use the product in military purposes; 18 | 19 | g. any other products, software or services connected to military activities; 20 | 21 | h. any auxiliary means related to abovementioned spheres and products. 22 | 23 | 24 | 25 | 2. The Software cannot be used as described herein in any connection to the military activities. A person, a company, or any other entity, which wants to use the Software, shall take all reasonable actions to make sure that the purpose of use of the Software cannot be possibly connected to military purposes. 26 | 27 | 28 | 29 | 3. The Software cannot be used by a person, a company, or any other entity, activities of which are connected to military sphere in any means. If a person, a company, or any other entity, during the period of time for the usage of Software, would engage in activities, connected to military purposes, such person, company, or any other entity shall immediately stop the usage of Software and any its modifications or alterations. 30 | 31 | 32 | 33 | 4. Abovementioned restrictions should apply to all modification, alteration, merge, and to other actions, related to the Software, regardless of how the Software was changed due to the abovementioned actions. 34 | 35 | 36 | 37 | The above copyright notice and this permission notice shall be included in all copies or substantial portions, modifications and alterations of the Software. 38 | 39 | 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 42 | -------------------------------------------------------------------------------- /Qubic.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33414.496 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Qubic", "src\Qubic.vcxproj", "{6A7C1322-658B-4FD8-8150-A2F88202B57F}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {61270221-BD41-438E-8F74-48AEC8C3F9A5} = {61270221-BD41-438E-8F74-48AEC8C3F9A5} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", "{30E8E249-6B00-4575-BCDF-BE2445D5E099}" 12 | EndProject 13 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "platform_common", "lib\platform_common\platform_common.vcxproj", "{61270221-BD41-438E-8F74-48AEC8C3F9A5}" 14 | EndProject 15 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "platform_efi", "lib\platform_efi\platform_efi.vcxproj", "{E8755F8F-3AD0-435A-992A-B05DCC188F6F}" 16 | EndProject 17 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "platform_os", "lib\platform_os\platform_os.vcxproj", "{88B4CDA8-8248-44D0-848E-0E938A2AAD6D}" 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|x64 = Debug|x64 22 | Release|x64 = Release|x64 23 | ReleaseAVX512|x64 = ReleaseAVX512|x64 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {6A7C1322-658B-4FD8-8150-A2F88202B57F}.Debug|x64.ActiveCfg = Debug|x64 27 | {6A7C1322-658B-4FD8-8150-A2F88202B57F}.Debug|x64.Build.0 = Debug|x64 28 | {6A7C1322-658B-4FD8-8150-A2F88202B57F}.Release|x64.ActiveCfg = Release|x64 29 | {6A7C1322-658B-4FD8-8150-A2F88202B57F}.Release|x64.Build.0 = Release|x64 30 | {6A7C1322-658B-4FD8-8150-A2F88202B57F}.ReleaseAVX512|x64.ActiveCfg = ReleaseAVX512|x64 31 | {6A7C1322-658B-4FD8-8150-A2F88202B57F}.ReleaseAVX512|x64.Build.0 = ReleaseAVX512|x64 32 | {30E8E249-6B00-4575-BCDF-BE2445D5E099}.Debug|x64.ActiveCfg = Debug|x64 33 | {30E8E249-6B00-4575-BCDF-BE2445D5E099}.Debug|x64.Build.0 = Debug|x64 34 | {30E8E249-6B00-4575-BCDF-BE2445D5E099}.Release|x64.ActiveCfg = Release|x64 35 | {30E8E249-6B00-4575-BCDF-BE2445D5E099}.Release|x64.Build.0 = Release|x64 36 | {30E8E249-6B00-4575-BCDF-BE2445D5E099}.ReleaseAVX512|x64.ActiveCfg = ReleaseAVX512|x64 37 | {30E8E249-6B00-4575-BCDF-BE2445D5E099}.ReleaseAVX512|x64.Build.0 = ReleaseAVX512|x64 38 | {61270221-BD41-438E-8F74-48AEC8C3F9A5}.Debug|x64.ActiveCfg = Debug|x64 39 | {61270221-BD41-438E-8F74-48AEC8C3F9A5}.Debug|x64.Build.0 = Debug|x64 40 | {61270221-BD41-438E-8F74-48AEC8C3F9A5}.Release|x64.ActiveCfg = Release|x64 41 | {61270221-BD41-438E-8F74-48AEC8C3F9A5}.Release|x64.Build.0 = Release|x64 42 | {61270221-BD41-438E-8F74-48AEC8C3F9A5}.ReleaseAVX512|x64.ActiveCfg = Release|x64 43 | {61270221-BD41-438E-8F74-48AEC8C3F9A5}.ReleaseAVX512|x64.Build.0 = Release|x64 44 | {E8755F8F-3AD0-435A-992A-B05DCC188F6F}.Debug|x64.ActiveCfg = Debug|x64 45 | {E8755F8F-3AD0-435A-992A-B05DCC188F6F}.Debug|x64.Build.0 = Debug|x64 46 | {E8755F8F-3AD0-435A-992A-B05DCC188F6F}.Release|x64.ActiveCfg = Release|x64 47 | {E8755F8F-3AD0-435A-992A-B05DCC188F6F}.Release|x64.Build.0 = Release|x64 48 | {E8755F8F-3AD0-435A-992A-B05DCC188F6F}.ReleaseAVX512|x64.ActiveCfg = Release|x64 49 | {E8755F8F-3AD0-435A-992A-B05DCC188F6F}.ReleaseAVX512|x64.Build.0 = Release|x64 50 | {88B4CDA8-8248-44D0-848E-0E938A2AAD6D}.Debug|x64.ActiveCfg = Debug|x64 51 | {88B4CDA8-8248-44D0-848E-0E938A2AAD6D}.Debug|x64.Build.0 = Debug|x64 52 | {88B4CDA8-8248-44D0-848E-0E938A2AAD6D}.Release|x64.ActiveCfg = Release|x64 53 | {88B4CDA8-8248-44D0-848E-0E938A2AAD6D}.Release|x64.Build.0 = Release|x64 54 | {88B4CDA8-8248-44D0-848E-0E938A2AAD6D}.ReleaseAVX512|x64.ActiveCfg = Release|x64 55 | {88B4CDA8-8248-44D0-848E-0E938A2AAD6D}.ReleaseAVX512|x64.Build.0 = Release|x64 56 | EndGlobalSection 57 | GlobalSection(SolutionProperties) = preSolution 58 | HideSolutionNode = FALSE 59 | EndGlobalSection 60 | GlobalSection(ExtensibilityGlobals) = postSolution 61 | SolutionGuid = {26B81876-BC99-44C5-8A20-158EB96600D7} 62 | EndGlobalSection 63 | EndGlobal 64 | -------------------------------------------------------------------------------- /README_CLANG.md: -------------------------------------------------------------------------------- 1 | # qubic clang port 2 | The Qubic Core is currently ported to be compiled with clang. As this requires a lot of changes the port is develop along the main development work and continuously integrated. However this also implies that the compilation of the core code with clang is not resulting in a working node at the moment. Hence it shall now be used in production! 3 | 4 | 5 | ## Prerequisites 6 | To be able to compile the core code with clang the following prerequisites have to be meet: 7 | 8 | > Clang >= 18.1.0 9 | > cmake >= 3.14 10 | > nasm >= 2.16.03 11 | 12 | Potentially it also works with lower versions but isn't tested yet. 13 | 14 | ## Compilation 15 | Currently compilation with cmake and clang is only supported on Linux systems. Window and OSX might work but is not properly tested. 16 | For a example compilation execute the following commands: 17 | 18 | 1. **Navigate to the Project Root:** 19 | Open your terminal and change the directory to the root of the project where the main `CMakeLists.txt` file is located. 20 | 21 | ```bash 22 | cd /path/to/your/project 23 | ``` 24 | 25 | 2. **Create and Enter Build Directory:** 26 | It's standard practice to perform an "out-of-source" build. Create a build directory (e.g., `build`) and navigate into it. 27 | 28 | ```bash 29 | # Create the build directory if it doesn't exist 30 | mkdir -p build 31 | 32 | # Enter the build directory 33 | cd build 34 | ``` 35 | 36 | 3. **Configure project** 37 | Instruct cmake to use `clang` and `clang++` as well configure the rest of the build. 38 | 39 | ```bash 40 | # In your build directory 41 | cmake .. -D CMAKE_C_COMPILER=clang -D CMAKE_CXX_COMPILER=clang++ -D BUILD_TESTS:BOOL=ON -D BUILD_EFI:BOOL=OFF -D CMAKE_BUILD_TYPE=Debug -D ENABLE_AVX512=ON 42 | ``` 43 | 44 | There are a few option to set during configuration: 45 | 46 | * **`-D BUILD_TESTS=`** 47 | * **Values:** `ON`, `OFF` 48 | * **Meaning:** `ON` builds the test suite, `OFF` skips building tests. 49 | 50 | * **`-D BUILD_EFI=`** 51 | * **Values:** `ON`, `OFF` 52 | * **Meaning:** `ON` builds the EFI file, `OFF` skips building EFI file. Currently this build is not working. 53 | 54 | * **`-D CMAKE_BUILD_TYPE=`** 55 | * **Values:** `Debug`, `Release`, `RelWithDebInfo`, `MinSizeRel` 56 | * **Meaning:** Sets the build mode for optimization and debug info (e.g., `Debug` for debugging, `Release` for performance). 57 | 58 | * **`-D ENABLE_AVX512=`** 59 | * **Values:** `ON`, `OFF` 60 | * **Meaning:** `ON` enables code using AVX-512 CPU instructions (requires support), `OFF` disables it. 61 | 62 | 4. **Build the Project:** 63 | Use the CMake `--build` command to invoke the underlying build tool (like `make` or `ninja`). 64 | 65 | ```bash 66 | # Build the project using the configuration generated in the previous step 67 | cmake --build . 68 | 69 | # Optional: Build in parallel (e.g., using 4 cores if using make) 70 | # cmake --build . -- -j4 71 | # Or if using Ninja (often the default if installed), it usually uses all cores by default 72 | ``` 73 | 74 | 75 | ## State 76 | At the moment the basic build scripts are setup and tests will be ported piece by piece. 77 | 78 | Current state of the working tests: 79 | | Test Module | Source File | Status | 80 | | :----------------- | :---------------------- | :---------- | 81 | | Assets | `assets.cpp` | Pending | 82 | | Common Def | `common_def.cpp` | Pending | 83 | | Contract Core | `contract_core.cpp` | Pending | 84 | | Contract qEarn | `contract_qearn.cpp` | Pending | 85 | | Contract qVault | `contract_qvault.cpp` | Pending | 86 | | Contract qX | `contract_qx.cpp` | Pending | 87 | | KangarooTwelve | `kangaroo_twelve.cpp` | Pending | 88 | | M256 | `m256.cpp` | Pending | 89 | | Math Lib | `math_lib.cpp` | **Working** | 90 | | Network Messages | `network_messages.cpp` | Pending | 91 | | Platform | `platform.cpp` | Pending | 92 | | QPI Collection | `qpi_collection.cpp` | Pending | 93 | | QPI | `qpi.cpp` | Pending | 94 | | QPI Hash Map | `qpi_hash_map.cpp` | Pending | 95 | | Score Cache | `score_cache.cpp` | Pending | 96 | | Score | `score.cpp` | Pending | 97 | | Spectrum | `spectrum.cpp` | Pending | 98 | | Stdlib Impl | `stdlib_impl.cpp` | Pending | 99 | | Tick Storage | `tick_storage.cpp` | Pending | 100 | | TX Status Request | `tx_status_request.cpp` | Pending | 101 | | Vote Counter | `vote_counter.cpp` | Pending | -------------------------------------------------------------------------------- /SEAMLESS.md: -------------------------------------------------------------------------------- 1 | Since Epoch 102, Qubic has introduced a feature known as "Seamless Epoch Transition". This feature eliminates the need for computer operators to manually halt and update their nodes each Wednesday. Consequently, this reduces network downtime every week. 2 | 3 | Previously: 4 | 5 | ![image](https://github.com/qubic/core/assets/39078779/e0f4835d-5bb1-48cc-8da8-9e1eeaca3e82) 6 | 7 | Now: 8 | 9 | ![image](https://github.com/qubic/core/assets/39078779/62c849f9-96c1-45c8-a922-2f4106167579) 10 | 11 | 12 | #### How to deal with updates: 13 | Henceforth, for any updates, operators can deploy the code at their discretion. However, to ensure timely network synchronization and implementation by the subsequent epoch, deployment of new updates is restricted to mid-epoch or earlier (until the "hyper-sync" feature is implemented). These deployed computors will synchronize with the network while operating in AUX mode. Once synchronization is complete, operators may then switch the nodes to MAIN mode. 14 | 15 | #### Introducing new features and code 16 | - `#define START_NETWORK_FROM_SCRATCH 1` in `public_settings.h`: 17 | - If this flag is 1, it indicates that the whole network (all 676 IDs) will start from scratch and agree that the very first tick timestamp will be set at (2022-04-13 Wed 12:00:00.000UTC). 18 | - If this flag is 0, the node will try to fetch the initial tick info (`prevDigests` and `timestamp`) of the new epoch from other nodes, because the timestamp of the first tick of a new epoch (when doing seamless transition) is always different from (2022-04-13 Wed 12:00:00.000UTC), and `prevDigests` in the initial tick is the digests of the last tick of the last epoch (which are hard to obtained by a fresh nodes). 19 | - `F7` function: in a rare case, slow nodes are unable to do the transition because of mismatched data and lack of votes to reach the consensus. In that case, operators can press `F7` to **FORCE** the node to switch to the new epoch and continue ticking. 20 | - Generally, the initial `TICK` value will be provided on the main branch after switching epoch. You may independently query a ticking node using the `qubic-cli` tool. The command for this purpose is `./qubic-cli -nodeip 1.2.3.4 -getcurrenttick`. This command will return both the correct initial tick and epoch values. Then you can update those numbers (tick, epoch) in `public_settings.h`, set the flag `#define START_NETWORK_FROM_SCRATCH 0` and start the node. 21 | #### Guide for developing 22 | - Since we have "Seamless Epoch Transition", a critical modification to the protocol necessitates the implementation of conditional logic within the codebase, for example: 23 | ``` 24 | // Currently it's epoch 102, this code is supposed to change the way processing data from epoch 103 25 | if (system.epoch >= 103){ 26 | // do something new 27 | } else { 28 | // Keep processing like the old way 29 | } 30 | ``` 31 | - For large changes in protocol, it's still best to restart the whole network with the flag `#define START_NETWORK_FROM_SCRATCH 1` 32 | -------------------------------------------------------------------------------- /doc/acquireShares.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qubic/core/492756941e4e22c90dfb96f9dc297b20005fba12/doc/acquireShares.png -------------------------------------------------------------------------------- /doc/custom_mining.md: -------------------------------------------------------------------------------- 1 | # General Workflow of Custom Mining 2 | 3 | - A solution's nonce must satisfy `nonce % NUMBER_OF_COMPUTORS == computorID` to be considered valid for a specific computor. 4 | - Custom mining only occurs during the **idle phase** (solution submission, verification, etc.). 5 | - **Accepted Solutions** = Total Received Solutions - Invalid Solutions ( or **Accepted Solutions** = non-verified Solutions + Valid Solutions). 6 | 7 | ## During the Idle State (Custom Mining Active) 8 | - The node receives broadcast messages and propagates them across the network. 9 | - It verifies whether each message is a **task from the DISPATCHER** or a **solution from a COMPUTOR**. 10 | - **Tasks** are stored for future querying. 11 | - **Solutions** are also stored, checked for duplication, and can be queried later. 12 | - Ownership of a solution is determined by `nonce % NUMBER_OF_COMPUTORS`. 13 | 14 | ## At the End of Idle State 15 | - The node aggregates all valid solutions it has seen. 16 | - It packs them following the **vote counter design**, embeds this into a transaction, and broadcasts it. 17 | - **Each computor is limited to 1023 solutions per phase** due to transaction size limits. 18 | If this is exceeded, the console logs a message for the DISPATCHER to adjust the difficulty. 19 | 20 | ## When a Node Receives a Custom Mining Transaction 21 | - It accumulates the received solution counts into its internal counter. 22 | 23 | ## At the End of the Epoch 24 | - The node calculates revenue scores: 25 | - Sum all counted solutions. 26 | - Multiply the sum by the current revenue score. 27 | - Apply the formula again to determine each computor’s final revenue. 28 | 29 | --- 30 | 31 | # Solution Verification 32 | 33 | - A **verifier** requests data from the node using `RequestedCustomMiningData`, authenticated with the **OPERATOR's seed** (`core/src/network_message/custom_mining.h`). 34 | - First, it requests a **range of tasks** using their `taskIndex`. 35 | - Then, using these indices, it requests **associated solutions**. 36 | - The node responds with all **unverified solutions** related to those tasks (max 1MB) using `RespondCustomMiningData`. 37 | - The verifier validates these solutions and reports results using `RequestedCustomMiningSolutionVerification`. 38 | - The node updates the solutions' **verified** status and marks them **valid** or **invalid**. 39 | 40 | **Reference Verifier**: [`oc_verifier`](https://github.com/qubic/outsourced-computing/tree/main/monero-poc/verifier) 41 | 42 | --- 43 | 44 | # Core API Overview 45 | 46 | ## `processBroadcastMessage` 47 | - If the destination public key is all-zero: 48 | - **From Dispatcher**: 49 | - Decode the gamming key to determine task type. 50 | - If it’s a `CUSTOM_MINING_MESSAGE_TYPE` and idle state is active, store the task. 51 | - **From Computor**: 52 | - Decode the gamming key. 53 | - If it's a custom mining solution: 54 | - Check for duplicates in cache. 55 | - If new, store the solution and update stats. 56 | 57 | ## `processRequestCustomMiningData` 58 | - Verify the OPERATOR signature. 59 | - Determine requested data type: **Tasks (`taskType`)** or **Solutions (`solutionType`)**. 60 | 61 | ### `taskType` 62 | - Extract task data in the requested `taskIndex` range. 63 | - Respond with packed task data or empty response if none found. 64 | 65 | ### `solutionType` 66 | - Extract solutions related to the given `taskIndex`. 67 | - Iterate through them: 68 | - Only send solutions that are **not yet verified** and match the task/nonce. 69 | - Respond with those solutions or an empty response if none are found. 70 | 71 | ## `processRequestedCustomMiningSolutionVerificationRequest` 72 | - Accept solutions if **valid** or **not yet verified**. 73 | - Only process if in the custom mining state. 74 | - Mark the solution as verified, with valid/invalid status. 75 | - If the solution exists and is invalid: 76 | - Decrement the computor’s share count. 77 | - Set response status to `invalid`. 78 | - Respond with the verification status of the solution. -------------------------------------------------------------------------------- /doc/profiling_csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qubic/core/492756941e4e22c90dfb96f9dc297b20005fba12/doc/profiling_csv.png -------------------------------------------------------------------------------- /doc/qubic-initial-disk.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qubic/core/492756941e4e22c90dfb96f9dc297b20005fba12/doc/qubic-initial-disk.zip -------------------------------------------------------------------------------- /doc/releaseShares.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qubic/core/492756941e4e22c90dfb96f9dc297b20005fba12/doc/releaseShares.png -------------------------------------------------------------------------------- /lib/platform_common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | # Project definition - Enable C always 4 | project(PlatformCommon LANGUAGES C) 5 | 6 | # Use the centralized compiler detection 7 | # Note: IS_WINDOWS, IS_LINUX, IS_MSVC, IS_CLANG, IS_GCC, and ASM_LANG are already set 8 | # by the CompilerDetection.cmake module included from the root CMakeLists.txt 9 | 10 | # For backward compatibility with existing code 11 | if(IS_LINUX AND (IS_CLANG OR IS_GCC)) 12 | set(IS_LINUX_CLANG TRUE) 13 | else() 14 | set(IS_LINUX_CLANG FALSE) 15 | endif() 16 | 17 | # --- Source File Definitions --- 18 | set(C_SOURCES 19 | edk2_mdepkg/Library/BaseLib/LongJump.c 20 | edk2_mdepkg/Library/BaseLib/SetJump.c 21 | ) 22 | 23 | # --- Conditional Assembly Sources & Build Steps --- 24 | set(ASM_OBJECT_LIBS "") # Store object libraries generated from assembly 25 | 26 | if(IS_WINDOWS AND ASM_LANG STREQUAL ASM_MASM) 27 | # Add MASM files directly if using MSVC 28 | add_library(platform_common_asm OBJECT 29 | edk2_mdepkg/Library/BaseLib/X64/LongJump.asm 30 | edk2_mdepkg/Library/BaseLib/X64/SetJump.asm 31 | ) 32 | list(APPEND ASM_OBJECT_LIBS platform_common_asm) 33 | 34 | elseif(IS_LINUX_CLANG AND ASM_LANG STREQUAL ASM_NASM) 35 | # Use custom commands for NASM files requiring preprocessing (.nasm extension assumed) 36 | # --- NASM File 1: LongJump --- 37 | set(NASM_SRC_LJ ${CMAKE_CURRENT_SOURCE_DIR}/edk2_mdepkg/Library/BaseLib/X64/LongJump.nasm) 38 | set(NASM_PREPROC_LJ ${CMAKE_CURRENT_BINARY_DIR}/LongJump.nasm.preprocessed) 39 | set(NASM_OBJ_LJ ${CMAKE_CURRENT_BINARY_DIR}/LongJump.nasm.o) 40 | set(ASM_PFX_DEFINE "ASM_PFX(x)=x") # Define for NASM preprocessing 41 | 42 | add_custom_command( 43 | OUTPUT ${NASM_OBJ_LJ} 44 | COMMAND ${CMAKE_C_COMPILER} -E -P -x assembler-with-cpp "-D${ASM_PFX_DEFINE}" ${NASM_SRC_LJ} -o ${NASM_PREPROC_LJ} 45 | COMMAND ${NASM_EXECUTABLE} -f elf64 ${NASM_PREPROC_LJ} -o ${NASM_OBJ_LJ} 46 | DEPENDS ${NASM_SRC_LJ} 47 | COMMENT "Preprocessing/Assembling (NASM) ${NASM_SRC_LJ}" 48 | VERBATIM 49 | ) 50 | add_library(LongJumpNasmObject OBJECT ${NASM_OBJ_LJ}) 51 | set_target_properties(LongJumpNasmObject PROPERTIES LINKER_LANGUAGE C) 52 | list(APPEND ASM_OBJECT_LIBS LongJumpNasmObject) 53 | 54 | # --- NASM File 2: SetJump --- 55 | set(NASM_SRC_SJ ${CMAKE_CURRENT_SOURCE_DIR}/edk2_mdepkg/Library/BaseLib/X64/SetJump.nasm) 56 | set(NASM_PREPROC_SJ ${CMAKE_CURRENT_BINARY_DIR}/SetJump.nasm.preprocessed) 57 | set(NASM_OBJ_SJ ${CMAKE_CURRENT_BINARY_DIR}/SetJump.nasm.o) 58 | 59 | add_custom_command( 60 | OUTPUT ${NASM_OBJ_SJ} 61 | COMMAND ${CMAKE_C_COMPILER} -E -P -x assembler-with-cpp "-D${ASM_PFX_DEFINE}" ${NASM_SRC_SJ} -o ${NASM_PREPROC_SJ} 62 | COMMAND ${NASM_EXECUTABLE} -f elf64 ${NASM_PREPROC_SJ} -o ${NASM_OBJ_SJ} 63 | DEPENDS ${NASM_SRC_SJ} 64 | COMMENT "Preprocessing/Assembling (NASM) ${NASM_SRC_SJ}" 65 | VERBATIM 66 | ) 67 | add_library(SetJumpNasmObject OBJECT ${NASM_OBJ_SJ}) 68 | set_target_properties(SetJumpNasmObject PROPERTIES LINKER_LANGUAGE C) 69 | list(APPEND ASM_OBJECT_LIBS SetJumpNasmObject) 70 | 71 | endif() 72 | 73 | # --- Target Definition --- 74 | add_library(platform_common STATIC ${C_SOURCES}) 75 | 76 | # Link the assembly object libraries (if any) into the main static library 77 | if(ASM_OBJECT_LIBS) 78 | target_link_libraries(platform_common PRIVATE ${ASM_OBJECT_LIBS}) 79 | endif() 80 | 81 | 82 | # --- Include Directories (Common) --- 83 | # Get the project root directory by going up two levels from the current directory 84 | get_filename_component(PROJECT_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../.." ABSOLUTE) 85 | message(STATUS "Project root directory: ${PROJECT_ROOT_DIR}") 86 | 87 | target_include_directories(platform_common PUBLIC 88 | "${CMAKE_CURRENT_SOURCE_DIR}/edk2_mdepkg/Include" 89 | "${CMAKE_CURRENT_SOURCE_DIR}" 90 | "${PROJECT_ROOT_DIR}" # Add project root directory to match vcxproj configuration 91 | ) 92 | 93 | # --- Common Preprocessor Definitions --- 94 | # Apply common compiler flags from the centralized detection module 95 | apply_common_compiler_flags(platform_common) -------------------------------------------------------------------------------- /lib/platform_common/compiler_warnings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Macros to suppress specific compiler warnings for specific sections of code. 4 | // Useful to hide warnings about unknown pragmas while using other compilers. 5 | 6 | // Example usage: 7 | // #include "lib/platform_common/compiler_warnings.h" 8 | // 9 | // int foo() { 10 | // SUPPRESS_WARNINGS_BEGIN 11 | // IGNORE_CAST_ALIGN_WARNING 12 | // // Code that generates warnings 13 | // SUPPRESS_WARNINGS_END 14 | // return 0; 15 | // } 16 | 17 | 18 | #if defined(__clang__) 19 | #define PRAGMA(x) _Pragma(#x) 20 | #define WARNING_PUSH PRAGMA(clang diagnostic push) 21 | #define WARNING_POP PRAGMA(clang diagnostic pop) 22 | #define WARNING_IGNORE_CAST_ALIGN PRAGMA(clang diagnostic ignored "-Wcast-align") 23 | #define WARNING_IGNORE_UNUSED PRAGMA(clang diagnostic ignored "-Wunused-parameter") 24 | #define WARNING_IGNORE_SELFASSIGNMENT PRAGMA(clang diagnostic ignored "-Wself-assign-overloaded") 25 | 26 | #else 27 | #define WARNING_PUSH 28 | #define WARNING_POP 29 | #define WARNING_IGNORE_CAST_ALIGN 30 | #define WARNING_IGNORE_UNUSED 31 | #define WARNING_IGNORE_SELFASSIGNMENT 32 | #endif 33 | 34 | // Shortcuts 35 | #define SUPPRESS_WARNINGS_BEGIN WARNING_PUSH 36 | #define SUPPRESS_WARNINGS_END WARNING_POP 37 | #define IGNORE_CAST_ALIGN_WARNING WARNING_IGNORE_CAST_ALIGN 38 | #define IGNORE_UNUSED_WARNING WARNING_IGNORE_UNUSED 39 | #define IGNORE_SELFASSIGNMENT_WARNING WARNING_IGNORE_SELFASSIGNMENT 40 | 41 | -------------------------------------------------------------------------------- /lib/platform_common/edk2_mdepkg/Library/BaseLib/LongJump.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | Long Jump functions. 3 | 4 | Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
5 | This program and the accompanying materials 6 | are licensed and made available under the terms and conditions of the BSD License 7 | which accompanies this distribution. The full text of the license may be found at 8 | http://opensource.org/licenses/bsd-license.php. 9 | 10 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 | 13 | **/ 14 | 15 | 16 | 17 | 18 | #include "BaseLibInternals.h" 19 | 20 | /** 21 | Restores the CPU context that was saved with SetJump(). 22 | 23 | Restores the CPU context from the buffer specified by JumpBuffer. This 24 | function never returns to the caller. Instead is resumes execution based on 25 | the state of JumpBuffer. 26 | 27 | If JumpBuffer is NULL, then ASSERT(). 28 | For IPF CPUs, if JumpBuffer is not aligned on a 16-byte boundary, then ASSERT(). 29 | If Value is 0, then ASSERT(). 30 | 31 | @param JumpBuffer A pointer to CPU context buffer. 32 | @param Value The value to return when the SetJump() context is 33 | restored and must be non-zero. 34 | 35 | **/ 36 | VOID 37 | EFIAPI 38 | LongJump( 39 | IN BASE_LIBRARY_JUMP_BUFFER* JumpBuffer, 40 | IN UINTN Value 41 | ) 42 | { 43 | InternalAssertJumpBuffer(JumpBuffer); 44 | ASSERT(Value != 0); 45 | 46 | InternalLongJump(JumpBuffer, Value); 47 | } 48 | -------------------------------------------------------------------------------- /lib/platform_common/edk2_mdepkg/Library/BaseLib/SetJump.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | Internal ASSERT () functions for SetJump. 3 | 4 | Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
5 | This program and the accompanying materials 6 | are licensed and made available under the terms and conditions of the BSD License 7 | which accompanies this distribution. The full text of the license may be found at 8 | http://opensource.org/licenses/bsd-license.php. 9 | 10 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 | 13 | **/ 14 | 15 | 16 | 17 | 18 | #include "BaseLibInternals.h" 19 | 20 | /** 21 | Worker function that checks ASSERT condition for JumpBuffer 22 | 23 | Checks ASSERT condition for JumpBuffer. 24 | 25 | If JumpBuffer is NULL, then ASSERT(). 26 | For IPF CPUs, if JumpBuffer is not aligned on a 16-byte boundary, then ASSERT(). 27 | 28 | @param JumpBuffer A pointer to CPU context buffer. 29 | 30 | **/ 31 | VOID 32 | EFIAPI 33 | InternalAssertJumpBuffer( 34 | IN BASE_LIBRARY_JUMP_BUFFER* JumpBuffer 35 | ) 36 | { 37 | ASSERT(JumpBuffer != NULL); 38 | 39 | ASSERT(((UINTN)JumpBuffer & (BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT - 1)) == 0); 40 | } 41 | -------------------------------------------------------------------------------- /lib/platform_common/edk2_mdepkg/Library/BaseLib/X64/LongJump.S: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------ 2 | # 3 | # Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
4 | # This program and the accompanying materials 5 | # are licensed and made available under the terms and conditions of the BSD License 6 | # which accompanies this distribution. The full text of the license may be found at 7 | # http://opensource.org/licenses/bsd-license.php. 8 | # 9 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 | # 12 | # Module Name: 13 | # 14 | # LongJump.S 15 | # 16 | # Abstract: 17 | # 18 | # Implementation of _LongJump() on x64. 19 | # 20 | #------------------------------------------------------------------------------ 21 | 22 | #------------------------------------------------------------------------------ 23 | # VOID 24 | # EFIAPI 25 | # InternalLongJump ( 26 | # IN BASE_LIBRARY_JUMP_BUFFER *JumpBuffer, 27 | # IN UINTN Value 28 | # ); 29 | #------------------------------------------------------------------------------ 30 | ASM_GLOBAL ASM_PFX(InternalLongJump) 31 | ASM_PFX(InternalLongJump): 32 | mov (%rcx), %rbx 33 | mov 0x8(%rcx), %rsp 34 | mov 0x10(%rcx), %rbp 35 | mov 0x18(%rcx), %rdi 36 | mov 0x20(%rcx), %rsi 37 | mov 0x28(%rcx), %r12 38 | mov 0x30(%rcx), %r13 39 | mov 0x38(%rcx), %r14 40 | mov 0x40(%rcx), %r15 41 | # load non-volatile fp registers 42 | ldmxcsr 0x50(%rcx) 43 | movdqu 0x58(%rcx), %xmm6 44 | movdqu 0x68(%rcx), %xmm7 45 | movdqu 0x78(%rcx), %xmm8 46 | movdqu 0x88(%rcx), %xmm9 47 | movdqu 0x98(%rcx), %xmm10 48 | movdqu 0xA8(%rcx), %xmm11 49 | movdqu 0xB8(%rcx), %xmm12 50 | movdqu 0xC8(%rcx), %xmm13 51 | movdqu 0xD8(%rcx), %xmm14 52 | movdqu 0xE8(%rcx), %xmm15 53 | mov %rdx, %rax # set return value 54 | jmp *0x48(%rcx) 55 | -------------------------------------------------------------------------------- /lib/platform_common/edk2_mdepkg/Library/BaseLib/X64/LongJump.asm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; 3 | ; Copyright (c) 2006, Intel Corporation. All rights reserved.BR 4 | ; This program and the accompanying materials 5 | ; are licensed and made available under the terms and conditions of the BSD License 6 | ; which accompanies this distribution. The full text of the license may be found at 7 | ; httpopensource.orglicensesbsd-license.php. 8 | ; 9 | ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN AS IS BASIS, 10 | ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 | ; 12 | ; Module Name 13 | ; 14 | ; LongJump.Asm 15 | ; 16 | ; Abstract 17 | ; 18 | ; Implementation of _LongJump() on x64. 19 | ; 20 | ;------------------------------------------------------------------------------ 21 | 22 | .code 23 | 24 | ;------------------------------------------------------------------------------ 25 | ; VOID 26 | ; EFIAPI 27 | ; InternalLongJump ( 28 | ; IN BASE_LIBRARY_JUMP_BUFFER JumpBuffer, 29 | ; IN UINTN Value 30 | ; ); 31 | ;------------------------------------------------------------------------------ 32 | InternalLongJump PROC 33 | mov rbx, [rcx] 34 | mov rsp, [rcx + 8] 35 | mov rbp, [rcx + 10h] 36 | mov rdi, [rcx + 18h] 37 | mov rsi, [rcx + 20h] 38 | mov r12, [rcx + 28h] 39 | mov r13, [rcx + 30h] 40 | mov r14, [rcx + 38h] 41 | mov r15, [rcx + 40h] 42 | ; load non-volatile fp registers 43 | ldmxcsr [rcx + 50h] 44 | movdqu xmm6, [rcx + 58h] 45 | movdqu xmm7, [rcx + 68h] 46 | movdqu xmm8, [rcx + 78h] 47 | movdqu xmm9, [rcx + 88h] 48 | movdqu xmm10, [rcx + 98h] 49 | movdqu xmm11, [rcx + 0A8h] 50 | movdqu xmm12, [rcx + 0B8h] 51 | movdqu xmm13, [rcx + 0C8h] 52 | movdqu xmm14, [rcx + 0D8h] 53 | movdqu xmm15, [rcx + 0E8h] 54 | mov rax, rdx ; set return value 55 | jmp qword ptr [rcx + 48h] 56 | InternalLongJump ENDP 57 | 58 | END 59 | 60 | -------------------------------------------------------------------------------- /lib/platform_common/edk2_mdepkg/Library/BaseLib/X64/LongJump.nasm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; 3 | ; Copyright (c) 2006, Intel Corporation. All rights reserved.
4 | ; This program and the accompanying materials 5 | ; are licensed and made available under the terms and conditions of the BSD License 6 | ; which accompanies this distribution. The full text of the license may be found at 7 | ; http://opensource.org/licenses/bsd-license.php. 8 | ; 9 | ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 | ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 | ; 12 | ; Module Name: 13 | ; 14 | ; LongJump.Asm 15 | ; 16 | ; Abstract: 17 | ; 18 | ; Implementation of _LongJump() on x64. 19 | ; 20 | ;------------------------------------------------------------------------------ 21 | 22 | DEFAULT REL 23 | SECTION .text 24 | 25 | ;------------------------------------------------------------------------------ 26 | ; VOID 27 | ; EFIAPI 28 | ; InternalLongJump ( 29 | ; IN BASE_LIBRARY_JUMP_BUFFER *JumpBuffer, 30 | ; IN UINTN Value 31 | ; ); 32 | ;------------------------------------------------------------------------------ 33 | global ASM_PFX(InternalLongJump) 34 | ASM_PFX(InternalLongJump): 35 | mov rbx, [rcx] 36 | mov rsp, [rcx + 8] 37 | mov rbp, [rcx + 0x10] 38 | mov rdi, [rcx + 0x18] 39 | mov rsi, [rcx + 0x20] 40 | mov r12, [rcx + 0x28] 41 | mov r13, [rcx + 0x30] 42 | mov r14, [rcx + 0x38] 43 | mov r15, [rcx + 0x40] 44 | ; load non-volatile fp registers 45 | ldmxcsr [rcx + 0x50] 46 | movdqu xmm6, [rcx + 0x58] 47 | movdqu xmm7, [rcx + 0x68] 48 | movdqu xmm8, [rcx + 0x78] 49 | movdqu xmm9, [rcx + 0x88] 50 | movdqu xmm10, [rcx + 0x98] 51 | movdqu xmm11, [rcx + 0xA8] 52 | movdqu xmm12, [rcx + 0xB8] 53 | movdqu xmm13, [rcx + 0xC8] 54 | movdqu xmm14, [rcx + 0xD8] 55 | movdqu xmm15, [rcx + 0xE8] 56 | mov rax, rdx ; set return value 57 | jmp qword [rcx + 0x48] 58 | -------------------------------------------------------------------------------- /lib/platform_common/edk2_mdepkg/Library/BaseLib/X64/SetJump.S: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------ 2 | # 3 | # Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
4 | # This program and the accompanying materials 5 | # are licensed and made available under the terms and conditions of the BSD License 6 | # which accompanies this distribution. The full text of the license may be found at 7 | # http://opensource.org/licenses/bsd-license.php. 8 | # 9 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 | # 12 | # Module Name: 13 | # 14 | # SetJump.S 15 | # 16 | # Abstract: 17 | # 18 | # Implementation of SetJump() on x86_64 19 | # 20 | #------------------------------------------------------------------------------ 21 | 22 | ASM_GLOBAL ASM_PFX(SetJump) 23 | ASM_PFX(SetJump): 24 | push %rcx 25 | add $0xffffffffffffffe0,%rsp 26 | call ASM_PFX(InternalAssertJumpBuffer) 27 | add $0x20,%rsp 28 | pop %rcx 29 | pop %rdx 30 | mov %rbx,(%rcx) 31 | mov %rsp,0x8(%rcx) 32 | mov %rbp,0x10(%rcx) 33 | mov %rdi,0x18(%rcx) 34 | mov %rsi,0x20(%rcx) 35 | mov %r12,0x28(%rcx) 36 | mov %r13,0x30(%rcx) 37 | mov %r14,0x38(%rcx) 38 | mov %r15,0x40(%rcx) 39 | mov %rdx,0x48(%rcx) 40 | # save non-volatile fp registers 41 | stmxcsr 0x50(%rcx) 42 | movdqu %xmm6, 0x58(%rcx) 43 | movdqu %xmm7, 0x68(%rcx) 44 | movdqu %xmm8, 0x78(%rcx) 45 | movdqu %xmm9, 0x88(%rcx) 46 | movdqu %xmm10, 0x98(%rcx) 47 | movdqu %xmm11, 0xA8(%rcx) 48 | movdqu %xmm12, 0xB8(%rcx) 49 | movdqu %xmm13, 0xC8(%rcx) 50 | movdqu %xmm14, 0xD8(%rcx) 51 | movdqu %xmm15, 0xE8(%rcx) 52 | xor %rax,%rax 53 | jmpq *%rdx 54 | -------------------------------------------------------------------------------- /lib/platform_common/edk2_mdepkg/Library/BaseLib/X64/SetJump.asm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; 3 | ; Copyright (c) 2006, Intel Corporation. All rights reserved.
4 | ; This program and the accompanying materials 5 | ; are licensed and made available under the terms and conditions of the BSD License 6 | ; which accompanies this distribution. The full text of the license may be found at 7 | ; http://opensource.org/licenses/bsd-license.php. 8 | ; 9 | ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 | ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 | ; 12 | ; Module Name: 13 | ; 14 | ; SetJump.Asm 15 | ; 16 | ; Abstract: 17 | ; 18 | ; Implementation of SetJump() on x64. 19 | ; 20 | ;------------------------------------------------------------------------------ 21 | 22 | .code 23 | 24 | EXTERN InternalAssertJumpBuffer:PROC 25 | 26 | ;------------------------------------------------------------------------------ 27 | ; UINTN 28 | ; EFIAPI 29 | ; SetJump ( 30 | ; OUT BASE_LIBRARY_JUMP_BUFFER *JumpBuffer 31 | ; ); 32 | ;------------------------------------------------------------------------------ 33 | SetJump PROC 34 | push rcx 35 | add rsp, -20h 36 | call InternalAssertJumpBuffer 37 | add rsp, 20h 38 | pop rcx 39 | pop rdx 40 | mov [rcx], rbx 41 | mov [rcx + 8], rsp 42 | mov [rcx + 10h], rbp 43 | mov [rcx + 18h], rdi 44 | mov [rcx + 20h], rsi 45 | mov [rcx + 28h], r12 46 | mov [rcx + 30h], r13 47 | mov [rcx + 38h], r14 48 | mov [rcx + 40h], r15 49 | mov [rcx + 48h], rdx 50 | ; save non-volatile fp registers 51 | stmxcsr [rcx + 50h] 52 | movdqu [rcx + 58h], xmm6 53 | movdqu [rcx + 68h], xmm7 54 | movdqu [rcx + 78h], xmm8 55 | movdqu [rcx + 88h], xmm9 56 | movdqu [rcx + 98h], xmm10 57 | movdqu [rcx + 0A8h], xmm11 58 | movdqu [rcx + 0B8h], xmm12 59 | movdqu [rcx + 0C8h], xmm13 60 | movdqu [rcx + 0D8h], xmm14 61 | movdqu [rcx + 0E8h], xmm15 62 | xor rax, rax 63 | jmp rdx 64 | SetJump ENDP 65 | 66 | END 67 | -------------------------------------------------------------------------------- /lib/platform_common/edk2_mdepkg/Library/BaseLib/X64/SetJump.nasm: -------------------------------------------------------------------------------- 1 | ;------------------------------------------------------------------------------ 2 | ; 3 | ; Copyright (c) 2006, Intel Corporation. All rights reserved.
4 | ; This program and the accompanying materials 5 | ; are licensed and made available under the terms and conditions of the BSD License 6 | ; which accompanies this distribution. The full text of the license may be found at 7 | ; http://opensource.org/licenses/bsd-license.php. 8 | ; 9 | ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 | ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 | ; 12 | ; Module Name: 13 | ; 14 | ; SetJump.Asm 15 | ; 16 | ; Abstract: 17 | ; 18 | ; Implementation of SetJump() on x64. 19 | ; 20 | ;------------------------------------------------------------------------------ 21 | 22 | DEFAULT REL 23 | SECTION .text 24 | 25 | extern ASM_PFX(InternalAssertJumpBuffer) 26 | 27 | ;------------------------------------------------------------------------------ 28 | ; UINTN 29 | ; EFIAPI 30 | ; SetJump ( 31 | ; OUT BASE_LIBRARY_JUMP_BUFFER *JumpBuffer 32 | ; ); 33 | ;------------------------------------------------------------------------------ 34 | global ASM_PFX(SetJump) 35 | ASM_PFX(SetJump): 36 | push rcx 37 | add rsp, -0x20 38 | call ASM_PFX(InternalAssertJumpBuffer) 39 | add rsp, 0x20 40 | pop rcx 41 | pop rdx 42 | mov [rcx], rbx 43 | mov [rcx + 8], rsp 44 | mov [rcx + 0x10], rbp 45 | mov [rcx + 0x18], rdi 46 | mov [rcx + 0x20], rsi 47 | mov [rcx + 0x28], r12 48 | mov [rcx + 0x30], r13 49 | mov [rcx + 0x38], r14 50 | mov [rcx + 0x40], r15 51 | mov [rcx + 0x48], rdx 52 | ; save non-volatile fp registers 53 | stmxcsr [rcx + 0x50] 54 | movdqu [rcx + 0x58], xmm6 55 | movdqu [rcx + 0x68], xmm7 56 | movdqu [rcx + 0x78], xmm8 57 | movdqu [rcx + 0x88], xmm9 58 | movdqu [rcx + 0x98], xmm10 59 | movdqu [rcx + 0xA8], xmm11 60 | movdqu [rcx + 0xB8], xmm12 61 | movdqu [rcx + 0xC8], xmm13 62 | movdqu [rcx + 0xD8], xmm14 63 | movdqu [rcx + 0xE8], xmm15 64 | xor rax, rax 65 | jmp rdx 66 | -------------------------------------------------------------------------------- /lib/platform_common/edk2_mdepkg/License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Intel Corporation. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in 11 | the documentation and/or other materials provided with the 12 | distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 17 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 18 | COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /lib/platform_common/edk2_mdepkg/README.md: -------------------------------------------------------------------------------- 1 | Source: https://android.googlesource.com/device/linaro/bootloader/edk2/+/refs/heads/android10-c2f2-release/MdePkg/ 2 | -------------------------------------------------------------------------------- /lib/platform_common/long_jump.h: -------------------------------------------------------------------------------- 1 | // Minimal interface definitions for using SetJump() and LongJump() of edk2_mdepkg 2 | 3 | // Based on code of BaseLib.h in edk2_mdepkg with the following license: 4 | /* 5 | Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
6 | Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
7 | This program and the accompanying materials 8 | are licensed and made available under the terms and conditions of the BSD License 9 | which accompanies this distribution. The full text of the license may be found at 10 | http://opensource.org/licenses/bsd-license.php. 11 | 12 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 | */ 15 | 16 | #pragma once 17 | 18 | // Jump buffer used by SetJump() and LongJump(). Must be 8-byte aligned. 19 | struct LongJumpBuffer 20 | { 21 | unsigned char registerStorage[248]; 22 | }; 23 | 24 | static_assert(sizeof(LongJumpBuffer) == 248, "Unexpected struct size. Check with X64 version of BASE_LIBRARY_JUMP_BUFFER in BaseLib.h"); 25 | 26 | 27 | extern "C" 28 | { 29 | 30 | /** 31 | Saves the current CPU context that can be restored with a call to LongJump() 32 | and returns 0. 33 | 34 | Saves the current CPU context in the buffer specified by JumpBuffer and 35 | returns 0. The initial call to SetJump() must always return 0. Subsequent 36 | calls to LongJump() cause a non-zero value to be returned by SetJump(). 37 | 38 | If JumpBuffer is NULL, then ASSERT(). 39 | For Itanium processors, if JumpBuffer is not aligned on a 16-byte boundary, then ASSERT(). 40 | 41 | NOTE: The structure BASE_LIBRARY_JUMP_BUFFER is CPU architecture specific. 42 | The same structure must never be used for more than one CPU architecture context. 43 | For example, a BASE_LIBRARY_JUMP_BUFFER allocated by an IA-32 module must never be used from an x64 module. 44 | SetJump()/LongJump() is not currently supported for the EBC processor type. 45 | 46 | @param JumpBuffer A pointer to CPU context buffer. 47 | 48 | @retval 0 Indicates a return from SetJump(). 49 | 50 | **/ 51 | unsigned long long _cdecl SetJump(LongJumpBuffer* JumpBuffer); 52 | 53 | 54 | /** 55 | Restores the CPU context that was saved with SetJump(). 56 | 57 | Restores the CPU context from the buffer specified by JumpBuffer. This 58 | function never returns to the caller. Instead is resumes execution based on 59 | the state of JumpBuffer. 60 | 61 | If JumpBuffer is NULL, then ASSERT(). 62 | For Itanium processors, if JumpBuffer is not aligned on a 16-byte boundary, then ASSERT(). 63 | If Value is 0, then ASSERT(). 64 | 65 | @param JumpBuffer A pointer to CPU context buffer. 66 | @param Value The value to return when the SetJump() context is 67 | restored and must be non-zero. 68 | 69 | **/ 70 | void _cdecl LongJump(LongJumpBuffer* JumpBuffer, unsigned long long Value); 71 | 72 | } 73 | -------------------------------------------------------------------------------- /lib/platform_common/platform_common.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | edk2_mdepkg 7 | 8 | 9 | edk2_mdepkg 10 | 11 | 12 | edk2_mdepkg 13 | 14 | 15 | edk2_mdepkg 16 | 17 | 18 | edk2_mdepkg 19 | 20 | 21 | 22 | 23 | 24 | 25 | edk2_mdepkg 26 | 27 | 28 | edk2_mdepkg 29 | 30 | 31 | 32 | 33 | edk2_mdepkg 34 | 35 | 36 | edk2_mdepkg 37 | 38 | 39 | 40 | 41 | {ed3dfa66-046c-4345-88e0-a234e7737a2c} 42 | 43 | 44 | -------------------------------------------------------------------------------- /lib/platform_common/platform_common.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /lib/platform_common/processor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Return processor number of processor running this function 4 | unsigned long long getRunningProcessorID(); 5 | 6 | // Check if running processor is main processor (bootstrap processor in EFI) 7 | bool isMainProcessor(); 8 | 9 | // TODO: hide this? 10 | extern unsigned long long mainThreadProcessorID; 11 | -------------------------------------------------------------------------------- /lib/platform_common/qintrin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Header file for the inclusion of plartform specific x86/x64 intrinsics header files. 4 | 5 | #if defined(_MSC_VER) && !defined(__clang__) 6 | #include 7 | #else 8 | #include 9 | #endif 10 | -------------------------------------------------------------------------------- /lib/platform_common/qstdint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Header file for the definition of standard integer types for different platforms. 4 | 5 | // Try to detect if standard headers have already been included e.g., from gtest. If already included, ignore qstdint.h. 6 | #if defined(__has_include) 7 | #if __has_include() 8 | #include 9 | #define STDINT_USING_STD 1 10 | #elif __has_include() 11 | #include 12 | #define STDINT_USING_STD 1 13 | #endif 14 | #endif 15 | 16 | #ifndef STDINT_USING_STD 17 | 18 | #if defined(_MSC_VER) && !defined(__clang__) 19 | // MSVC definitions 20 | typedef signed __int8 int8_t; 21 | typedef unsigned __int8 uint8_t; 22 | typedef signed __int16 int16_t; 23 | typedef unsigned __int16 uint16_t; 24 | typedef signed __int32 int32_t; 25 | typedef unsigned __int32 uint32_t; 26 | typedef signed __int64 int64_t; 27 | typedef unsigned __int64 uint64_t; 28 | #else 29 | // Clang/Linux definitions 30 | typedef signed char int8_t; 31 | typedef unsigned char uint8_t; 32 | typedef short int16_t; 33 | typedef unsigned short uint16_t; 34 | typedef int int32_t; 35 | typedef unsigned int uint32_t; 36 | typedef long long int64_t; 37 | typedef unsigned long long uint64_t; 38 | #endif 39 | 40 | // static asserts to validate sizes 41 | static_assert(sizeof(int8_t) == 1, "int8_t must be 1 byte"); 42 | static_assert(sizeof(uint8_t) == 1, "uint8_t must be 1 byte"); 43 | static_assert(sizeof(int16_t) == 2, "int16_t must be 2 bytes"); 44 | static_assert(sizeof(uint16_t) == 2, "uint16_t must be 2 bytes"); 45 | static_assert(sizeof(int32_t) == 4, "int32_t must be 4 bytes"); 46 | static_assert(sizeof(uint32_t) == 4, "uint32_t must be 4 bytes"); 47 | static_assert(sizeof(int64_t) == 8, "int64_t must be 8 bytes"); 48 | static_assert(sizeof(uint64_t) == 8, "uint64_t must be 8 bytes"); 49 | 50 | #endif -------------------------------------------------------------------------------- /lib/platform_common/sleep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void sleepMicroseconds(unsigned int microseconds); 4 | void sleepMilliseconds(unsigned int milliseconds); 5 | -------------------------------------------------------------------------------- /lib/platform_efi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(platform_efi CXX C) 3 | 4 | # Set C++ standard 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | # Set C standard 9 | set(CMAKE_C_STANDARD 11) 10 | set(CMAKE_C_STANDARD_REQUIRED ON) 11 | 12 | 13 | # --- Include Directories (Common) --- 14 | # Get the project root directory by going up two levels from the current directory 15 | get_filename_component(PROJECT_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../.." ABSOLUTE) 16 | 17 | # Include directories 18 | include_directories( 19 | ${CMAKE_CURRENT_SOURCE_DIR} 20 | ${CMAKE_SOURCE_DIR} 21 | ${PROJECT_ROOT_DIR} 22 | ) 23 | 24 | # Source files 25 | set(SOURCES 26 | edk2_debug.c 27 | sleep.cpp 28 | uefi_globals.cpp 29 | ) 30 | 31 | # Create static library 32 | add_library(platform_efi STATIC ${SOURCES}) 33 | 34 | # Apply EFI-specific compiler flags from the centralized detection module 35 | apply_efi_compiler_flags(platform_efi) 36 | 37 | # Set library properties 38 | set_target_properties(platform_efi PROPERTIES 39 | LINKER_LANGUAGE CXX 40 | ) 41 | 42 | # Install 43 | install(TARGETS platform_efi 44 | ARCHIVE DESTINATION lib 45 | LIBRARY DESTINATION lib 46 | ) 47 | 48 | # Install headers 49 | install(FILES 50 | uefi.h 51 | uefi_globals.h 52 | DESTINATION include/platform_efi 53 | ) -------------------------------------------------------------------------------- /lib/platform_efi/edk2_debug.c: -------------------------------------------------------------------------------- 1 | // implements DebugLib of edk2 in platform_common 2 | 3 | #include 4 | #include 5 | 6 | VOID 7 | EFIAPI 8 | DebugAssert( 9 | IN CONST CHAR8* FileName, 10 | IN UINTN LineNumber, 11 | IN CONST CHAR8* Description 12 | ) 13 | { 14 | // TODO: add output!!! 15 | } 16 | 17 | BOOLEAN 18 | EFIAPI 19 | DebugAssertEnabled( 20 | VOID 21 | ) 22 | { 23 | return TRUE; 24 | } 25 | -------------------------------------------------------------------------------- /lib/platform_efi/platform_efi.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /lib/platform_efi/processor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | unsigned long long mainThreadProcessorID = -1; 5 | 6 | EFI_MP_SERVICES_PROTOCOL* mpServicesProtocol = nullptr; 7 | 8 | 9 | // Return processor number of processor running this function 10 | unsigned long long getRunningProcessorID() 11 | { 12 | // if mpServicesProtocol isn't set, we can be sure that this is still the main processor thread, because 13 | // mpServicesProtocol is needed to startup other processors 14 | unsigned long long processorNumber = mainThreadProcessorID; 15 | if (mpServicesProtocol) 16 | mpServicesProtocol->WhoAmI(mpServicesProtocol, &processorNumber); 17 | return processorNumber; 18 | } 19 | 20 | // Check if running processor is main processor (bootstrap processor in EFI) 21 | bool isMainProcessor() 22 | { 23 | return getRunningProcessorID() == mainThreadProcessorID; 24 | } 25 | -------------------------------------------------------------------------------- /lib/platform_efi/sleep.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "uefi_globals.h" 4 | 5 | void sleepMicroseconds(unsigned int microseconds) 6 | { 7 | bs->Stall(microseconds); 8 | } 9 | 10 | void sleepMilliseconds(unsigned int milliseconds) 11 | { 12 | bs->Stall(milliseconds * 1000); 13 | } 14 | -------------------------------------------------------------------------------- /lib/platform_efi/uefi_globals.cpp: -------------------------------------------------------------------------------- 1 | #include "uefi_globals.h" 2 | 3 | EFI_HANDLE ih = nullptr; 4 | EFI_SYSTEM_TABLE* st = nullptr; 5 | EFI_RUNTIME_SERVICES* rs = nullptr; 6 | EFI_BOOT_SERVICES* bs = nullptr; 7 | -------------------------------------------------------------------------------- /lib/platform_efi/uefi_globals.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "uefi.h" 4 | 5 | extern EFI_HANDLE ih; 6 | extern EFI_SYSTEM_TABLE* st; 7 | extern EFI_RUNTIME_SERVICES* rs; 8 | extern EFI_BOOT_SERVICES* bs; 9 | 10 | // TODO: later hide this in processor.cpp 11 | extern EFI_MP_SERVICES_PROTOCOL* mpServicesProtocol; 12 | -------------------------------------------------------------------------------- /lib/platform_os/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(platform_os CXX C) 3 | 4 | # Set C++ standard 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | # Set C standard 9 | set(CMAKE_C_STANDARD 11) 10 | set(CMAKE_C_STANDARD_REQUIRED ON) 11 | 12 | # --- Include Directories (Common) --- 13 | # Get the project root directory by going up two levels from the current directory 14 | get_filename_component(PROJECT_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../.." ABSOLUTE) 15 | 16 | # Include directories 17 | include_directories( 18 | ${CMAKE_CURRENT_SOURCE_DIR} 19 | ${CMAKE_SOURCE_DIR} 20 | ${PROJECT_ROOT_DIR} 21 | ) 22 | 23 | # Source files 24 | set(SOURCES 25 | edk2_debug.c 26 | sleep.cpp 27 | ) 28 | 29 | # Create static library 30 | add_library(platform_os STATIC ${SOURCES}) 31 | 32 | # Apply OS-specific compiler flags from the centralized detection module 33 | apply_os_compiler_flags(platform_os) 34 | 35 | # Set library properties 36 | set_target_properties(platform_os PROPERTIES 37 | LINKER_LANGUAGE CXX 38 | ) 39 | 40 | # Install 41 | install(TARGETS platform_os 42 | ARCHIVE DESTINATION lib 43 | LIBRARY DESTINATION lib 44 | ) -------------------------------------------------------------------------------- /lib/platform_os/edk2_debug.c: -------------------------------------------------------------------------------- 1 | // implements DebugLib of edk2 in platform_common 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | VOID 9 | EFIAPI 10 | DebugAssert( 11 | IN CONST CHAR8* FileName, 12 | IN UINTN LineNumber, 13 | IN CONST CHAR8* Description 14 | ) 15 | { 16 | printf("ASSERT failed in file %s line %llu: %s\n", FileName, LineNumber, Description); 17 | } 18 | 19 | BOOLEAN 20 | EFIAPI 21 | DebugAssertEnabled( 22 | VOID 23 | ) 24 | { 25 | return TRUE; 26 | } 27 | -------------------------------------------------------------------------------- /lib/platform_os/platform_os.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /lib/platform_os/processor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | unsigned long long mainProcessorID = -1; 5 | 6 | 7 | // Return processor number of processor running this function 8 | unsigned long long getRunningProcessorID() 9 | { 10 | // TODO: implement this 11 | return mainProcessorID; 12 | } 13 | 14 | // Check if running processor is main processor (bootstrap processor in EFI) 15 | bool isMainProcessor() 16 | { 17 | return getRunningProcessorID() == mainProcessorID; 18 | } 19 | -------------------------------------------------------------------------------- /lib/platform_os/sleep.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | void sleepMicroseconds(unsigned int microseconds) 7 | { 8 | std::this_thread::sleep_for(std::chrono::microseconds(microseconds)); 9 | } 10 | 11 | void sleepMilliseconds(unsigned int milliseconds) 12 | { 13 | std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); 14 | } 15 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(qubic_core CXX) 3 | 4 | # GoogleTest requires at least C++20 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | # Include directories 9 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 10 | include_directories(${CMAKE_SOURCE_DIR}/lib) 11 | 12 | # Define the executable 13 | add_executable( 14 | Qubic 15 | qubic.cpp 16 | ) 17 | 18 | # Apply EFI-specific compiler flags from the centralized detection module 19 | apply_efi_compiler_flags(Qubic) 20 | 21 | # Add additional compiler-specific flags for the main application 22 | if(IS_CLANG) 23 | # Clang-specific flags 24 | target_compile_options(Qubic PRIVATE 25 | -mrdrnd 26 | -target x86_64-unknown-windows 27 | $<$:--sysroot="${CLANG_SYSROOT}"> 28 | -Werror 29 | -Wno-unused-parameter 30 | ) 31 | elseif(IS_MSVC) 32 | # MSVC-specific flags 33 | target_compile_options(Qubic PRIVATE 34 | /Gs1638400 # Control stack checking 35 | /W3 # Warning level 36 | ) 37 | endif() 38 | 39 | # Link with platform libraries 40 | if(BUILD_TESTS) 41 | # When building for tests, link only with platform_common and platform_os 42 | target_link_libraries(Qubic 43 | platform_common 44 | platform_os 45 | ) 46 | else() 47 | # When building the application, link with platform_common and platform_efi 48 | target_link_libraries(Qubic 49 | platform_common 50 | platform_efi 51 | ) 52 | endif() 53 | 54 | # Configure linker settings based on compiler 55 | if(IS_MSVC) 56 | # MSVC-specific linker settings 57 | set_target_properties(Qubic PROPERTIES 58 | LINK_FLAGS "/SUBSYSTEM:EFI_APPLICATION /ENTRY:efi_main /IGNORE:4086 /IGNORE:4108 /NODEFAULTLIB" 59 | SUFFIX ".efi" 60 | ) 61 | 62 | # Set stack size for MSVC 63 | set_property(TARGET Qubic APPEND_STRING PROPERTY LINK_FLAGS " /STACK:131072") 64 | elseif(IS_CLANG) 65 | # Clang-specific linker settings 66 | set(CMAKE_LINKER "lld") 67 | set(CMAKE_CXX_LINK_EXECUTABLE 68 | "${CMAKE_LINKER} -flavor link \ 69 | -subsystem:efi_application \ 70 | -entry:efi_main \ 71 | \ 72 | -out:" 73 | ) 74 | 75 | # Set output suffix to .efi 76 | set_target_properties(Qubic PROPERTIES 77 | SUFFIX ".efi" 78 | ) 79 | endif() 80 | 81 | -------------------------------------------------------------------------------- /src/Qubic.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/common_buffers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "platform/global_var.h" 4 | #include "platform/memory_util.h" 5 | 6 | #include "network_messages/entity.h" 7 | #include "network_messages/assets.h" 8 | 9 | 10 | constexpr unsigned long long spectrumSizeInBytes = SPECTRUM_CAPACITY * sizeof(::Entity); 11 | constexpr unsigned long long universeSizeInBytes = ASSETS_CAPACITY * sizeof(AssetRecord); 12 | // TODO: check that max contract state size does not exceed size of spectrum or universe 13 | constexpr unsigned long long reorgBufferSize = (spectrumSizeInBytes >= universeSizeInBytes) ? spectrumSizeInBytes : universeSizeInBytes; 14 | 15 | // Buffer used for reorganizing spectrum and universe hash maps, currently also used as scratchpad buffer for contracts 16 | // Must be large enough to fit any contract, full spectrum, and full universe! 17 | GLOBAL_VAR_DECL void* reorgBuffer GLOBAL_VAR_INIT(nullptr); 18 | 19 | static bool initCommonBuffers() 20 | { 21 | if (!allocPoolWithErrorLog(L"reorgBuffer", reorgBufferSize, (void**)&reorgBuffer, __LINE__)) 22 | { 23 | return false; 24 | } 25 | 26 | return true; 27 | } 28 | 29 | static void deinitCommonBuffers() 30 | { 31 | if (reorgBuffer) 32 | { 33 | freePool(reorgBuffer); 34 | reorgBuffer = nullptr; 35 | } 36 | } 37 | 38 | static void* __scratchpad() 39 | { 40 | return reorgBuffer; 41 | } 42 | -------------------------------------------------------------------------------- /src/contract_core/contract_action_tracker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../platform/m256.h" 4 | #include "platform/memory_util.h" 5 | 6 | struct ContractAction 7 | { 8 | enum Type { 9 | none = 0, 10 | quTransferType, 11 | }; 12 | 13 | unsigned char type; 14 | 15 | union 16 | { 17 | struct QuTransfer 18 | { 19 | m256i sourcePublicKey; 20 | m256i destinationPublicKey; 21 | long long amount; 22 | } quTransfer; 23 | }; 24 | }; 25 | 26 | 27 | // Class for tracking changes in spectrum and universe during a contract procedure invocation 28 | template 29 | class ContractActionTracker 30 | { 31 | public: 32 | bool allocBuffer() 33 | { 34 | actions = nullptr; 35 | return allocPoolWithErrorLog(L"ContractActionTracker", maxActions * sizeof(ContractAction), (void**)&actions, __LINE__); 36 | } 37 | 38 | void freeBuffer() 39 | { 40 | if (actions) 41 | freePool(actions); 42 | } 43 | 44 | // Called before every use, allocBuffer() needs to be called before. 45 | void init() 46 | { 47 | ASSERT(actions != nullptr); 48 | numActions = 0; 49 | } 50 | 51 | bool addQuTransfer(const m256i& sourcePublicKey, const m256i& destinationPublicKey, long long amount) 52 | { 53 | ASSERT(actions != nullptr); 54 | ASSERT(numActions <= maxActions); 55 | 56 | if (numActions == maxActions) 57 | return false; 58 | 59 | ContractAction& qa = actions[numActions++]; 60 | qa.type = ContractAction::quTransferType; 61 | qa.quTransfer.sourcePublicKey = sourcePublicKey; 62 | qa.quTransfer.destinationPublicKey = destinationPublicKey; 63 | qa.quTransfer.amount = amount; 64 | 65 | return true; 66 | } 67 | 68 | long long getOverallQuTransferBalance(const m256i& publicKey) 69 | { 70 | long long amount = 0; 71 | for (unsigned int i = 0; i < numActions; ++i) 72 | { 73 | ContractAction& qa = actions[i]; 74 | if (qa.type == ContractAction::quTransferType) 75 | { 76 | if (qa.quTransfer.sourcePublicKey == publicKey) 77 | amount = amount - qa.quTransfer.amount; 78 | if (qa.quTransfer.destinationPublicKey == publicKey) 79 | amount = amount + qa.quTransfer.amount; 80 | } 81 | } 82 | return amount; 83 | } 84 | 85 | private: 86 | ContractAction* actions; 87 | unsigned int numActions; 88 | }; 89 | -------------------------------------------------------------------------------- /src/contract_core/qpi_ipo_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "contract_core/ipo.h" 4 | 5 | QPI::sint64 QPI::QpiContextProcedureCall::bidInIPO(unsigned int IPOContractIndex, long long price, unsigned int quantity) const 6 | { 7 | if (contractCallbacksRunning != NoContractCallback) 8 | return -1; 9 | 10 | if (_currentContractIndex >= contractCount || IPOContractIndex >= contractCount || _currentContractIndex >= IPOContractIndex) 11 | { 12 | return -1; 13 | } 14 | 15 | if (system.epoch >= contractDescriptions[IPOContractIndex].constructionEpoch) // IPO is finished. 16 | { 17 | return -1; 18 | } 19 | 20 | const int spectrumIndex = ::spectrumIndex(_currentContractId); 21 | 22 | if (spectrumIndex < 0) 23 | { 24 | return -1; 25 | } 26 | 27 | return bidInContractIPO(price, quantity, _currentContractId, spectrumIndex, IPOContractIndex, this); 28 | } 29 | 30 | // Returns the ID of the entity who has made this IPO bid or NULL_ID if the ipoContractIndex or ipoBidIndex are invalid. 31 | QPI::id QPI::QpiContextFunctionCall::ipoBidId(QPI::uint32 ipoContractIndex, QPI::uint32 ipoBidIndex) const 32 | { 33 | if (ipoContractIndex >= contractCount || system.epoch >= contractDescriptions[ipoContractIndex].constructionEpoch || ipoBidIndex >= NUMBER_OF_COMPUTORS) 34 | { 35 | return NULL_ID; 36 | } 37 | 38 | contractStateLock[ipoContractIndex].acquireRead(); 39 | IPO* ipo = (IPO*)contractStates[ipoContractIndex]; 40 | QPI::id publicKey = ipo->publicKeys[ipoBidIndex]; 41 | contractStateLock[ipoContractIndex].releaseRead(); 42 | 43 | return publicKey; 44 | } 45 | 46 | // Returns the price of an IPO bid, -1 if contract index is invalid, -2 if contract is not in IPO, -3 if bid index is invalid. 47 | QPI::sint64 QPI::QpiContextFunctionCall::ipoBidPrice(QPI::uint32 ipoContractIndex, QPI::uint32 ipoBidIndex) const 48 | { 49 | if (ipoContractIndex >= contractCount) 50 | { 51 | return -1; 52 | } 53 | 54 | if (system.epoch >= contractDescriptions[ipoContractIndex].constructionEpoch) 55 | { 56 | return -2; 57 | } 58 | 59 | if (ipoBidIndex >= NUMBER_OF_COMPUTORS) 60 | { 61 | return -3; 62 | } 63 | 64 | contractStateLock[ipoContractIndex].acquireRead(); 65 | IPO* ipo = (IPO*)contractStates[ipoContractIndex]; 66 | QPI::sint64 price = ipo->prices[ipoBidIndex]; 67 | contractStateLock[ipoContractIndex].releaseRead(); 68 | 69 | return price; 70 | } 71 | -------------------------------------------------------------------------------- /src/contract_core/qpi_spectrum_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "contract_core/contract_exec.h" 4 | #include "spectrum/spectrum.h" 5 | 6 | 7 | bool QPI::QpiContextFunctionCall::getEntity(const m256i& id, QPI::Entity& entity) const 8 | { 9 | int index = spectrumIndex(id); 10 | if (index < 0) 11 | { 12 | entity.publicKey = id; 13 | entity.incomingAmount = 0; 14 | entity.outgoingAmount = 0; 15 | entity.numberOfIncomingTransfers = 0; 16 | entity.numberOfOutgoingTransfers = 0; 17 | entity.latestIncomingTransferTick = 0; 18 | entity.latestOutgoingTransferTick = 0; 19 | 20 | return false; 21 | } 22 | else 23 | { 24 | entity.publicKey = spectrum[index].publicKey; 25 | entity.incomingAmount = spectrum[index].incomingAmount; 26 | entity.outgoingAmount = spectrum[index].outgoingAmount; 27 | entity.numberOfIncomingTransfers = spectrum[index].numberOfIncomingTransfers; 28 | entity.numberOfOutgoingTransfers = spectrum[index].numberOfOutgoingTransfers; 29 | entity.latestIncomingTransferTick = spectrum[index].latestIncomingTransferTick; 30 | entity.latestOutgoingTransferTick = spectrum[index].latestOutgoingTransferTick; 31 | 32 | return true; 33 | } 34 | } 35 | 36 | // Return reference to fee reserve of contract for changing its value (data stored in state of contract 0) 37 | static long long& contractFeeReserve(unsigned int contractIndex) 38 | { 39 | contractStateChangeFlags[0] |= 1ULL; 40 | return ((Contract0State*)contractStates[0])->contractFeeReserves[contractIndex]; 41 | } 42 | 43 | long long QPI::QpiContextProcedureCall::burn(long long amount) const 44 | { 45 | if (amount < 0 || amount > MAX_AMOUNT) 46 | { 47 | return -((long long)(MAX_AMOUNT + 1)); 48 | } 49 | 50 | const int index = spectrumIndex(_currentContractId); 51 | 52 | if (index < 0) 53 | { 54 | return -amount; 55 | } 56 | 57 | const long long remainingAmount = energy(index) - amount; 58 | 59 | if (remainingAmount < 0) 60 | { 61 | return remainingAmount; 62 | } 63 | 64 | if (decreaseEnergy(index, amount)) 65 | { 66 | contractStateLock[0].acquireWrite(); 67 | contractFeeReserve(_currentContractIndex) += amount; 68 | contractStateLock[0].releaseWrite(); 69 | 70 | const Burning burning = { _currentContractId , amount }; 71 | logger.logBurning(burning); 72 | } 73 | 74 | return remainingAmount; 75 | } 76 | 77 | long long QPI::QpiContextProcedureCall::transfer(const m256i& destination, long long amount) const 78 | { 79 | if (contractCallbacksRunning & ContractCallbackPostIncomingTransfer) 80 | { 81 | return INVALID_AMOUNT; 82 | } 83 | 84 | if (amount < 0 || amount > MAX_AMOUNT) 85 | { 86 | return -((long long)(MAX_AMOUNT + 1)); 87 | } 88 | 89 | const int index = spectrumIndex(_currentContractId); 90 | 91 | if (index < 0) 92 | { 93 | return -amount; 94 | } 95 | 96 | const long long remainingAmount = energy(index) - amount; 97 | 98 | if (remainingAmount < 0) 99 | { 100 | return remainingAmount; 101 | } 102 | 103 | if (decreaseEnergy(index, amount)) 104 | { 105 | increaseEnergy(destination, amount); 106 | 107 | if (!contractActionTracker.addQuTransfer(_currentContractId, destination, amount)) 108 | __qpiAbort(ContractErrorTooManyActions); 109 | 110 | __qpiNotifyPostIncomingTransfer(_currentContractId, destination, amount, TransferType::qpiTransfer); 111 | 112 | const QuTransfer quTransfer = { _currentContractId , destination , amount }; 113 | logger.logQuTransfer(quTransfer); 114 | } 115 | 116 | return remainingAmount; 117 | } 118 | 119 | m256i QPI::QpiContextFunctionCall::nextId(const m256i& currentId) const 120 | { 121 | int index = spectrumIndex(currentId); 122 | while (++index < SPECTRUM_CAPACITY) 123 | { 124 | const m256i& nextId = spectrum[index].publicKey; 125 | if (!isZero(nextId)) 126 | { 127 | return nextId; 128 | } 129 | } 130 | 131 | return m256i::zero(); 132 | } 133 | 134 | m256i QPI::QpiContextFunctionCall::prevId(const m256i& currentId) const 135 | { 136 | int index = spectrumIndex(currentId); 137 | while (--index >= 0) 138 | { 139 | const m256i& prevId = spectrum[index].publicKey; 140 | if (!isZero(prevId)) 141 | { 142 | return prevId; 143 | } 144 | } 145 | 146 | return m256i::zero(); 147 | } 148 | -------------------------------------------------------------------------------- /src/contract_core/qpi_system_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "contracts/qpi.h" 4 | #include "system.h" 5 | 6 | unsigned short QPI::QpiContextFunctionCall::epoch() const 7 | { 8 | return system.epoch; 9 | } 10 | 11 | unsigned int QPI::QpiContextFunctionCall::tick() const 12 | { 13 | return system.tick; 14 | } 15 | -------------------------------------------------------------------------------- /src/contract_core/qpi_ticking_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "contracts/qpi.h" 4 | 5 | #include "ticking/ticking.h" 6 | 7 | 8 | unsigned char QPI::QpiContextFunctionCall::day() const 9 | { 10 | return etalonTick.day; 11 | } 12 | 13 | unsigned char QPI::QpiContextFunctionCall::year() const 14 | { 15 | return etalonTick.year; 16 | } 17 | 18 | unsigned char QPI::QpiContextFunctionCall::hour() const 19 | { 20 | return etalonTick.hour; 21 | } 22 | 23 | unsigned short QPI::QpiContextFunctionCall::millisecond() const 24 | { 25 | return etalonTick.millisecond; 26 | } 27 | 28 | unsigned char QPI::QpiContextFunctionCall::minute() const 29 | { 30 | return etalonTick.minute; 31 | } 32 | 33 | unsigned char QPI::QpiContextFunctionCall::month() const 34 | { 35 | return etalonTick.month; 36 | } 37 | 38 | int QPI::QpiContextFunctionCall::numberOfTickTransactions() const 39 | { 40 | return numberTickTransactions; 41 | } 42 | 43 | unsigned char QPI::QpiContextFunctionCall::second() const 44 | { 45 | return etalonTick.second; 46 | } 47 | -------------------------------------------------------------------------------- /src/contract_core/qpi_trivial_impl.h: -------------------------------------------------------------------------------- 1 | // Implements several trivial util functions of QPI 2 | // CAUTION: Include this AFTER the contract implementations! 3 | 4 | #pragma once 5 | 6 | #include "../contracts/qpi.h" 7 | #include "../platform/memory.h" 8 | #include "../platform/time.h" 9 | 10 | #include "../four_q.h" 11 | #include "../kangaroo_twelve.h" 12 | #include "../spectrum/special_entities.h" 13 | 14 | namespace QPI 15 | { 16 | template 17 | inline void copyMemory(T1& dst, const T2& src) 18 | { 19 | static_assert(sizeof(dst) == sizeof(src), "Size of source and destination must match to run copyMemory()."); 20 | copyMem(&dst, &src, sizeof(dst)); 21 | } 22 | 23 | template 24 | inline void setMemory(T& dst, uint8 value) 25 | { 26 | setMem(&dst, sizeof(dst), value); 27 | } 28 | 29 | // Check if array is sorted in given range (duplicates allowed). Returns false if range is invalid. 30 | template 31 | bool isArraySorted(const Array& Array, uint64 beginIdx, uint64 endIdx) 32 | { 33 | if (endIdx > L || beginIdx > endIdx) 34 | return false; 35 | 36 | for (uint64 i = beginIdx + 1; i < endIdx; ++i) 37 | { 38 | if (Array.get(i - 1) > Array.get(i)) 39 | return false; 40 | } 41 | 42 | return true; 43 | } 44 | 45 | // Check if array is sorted without duplicates in given range. Returns false if range is invalid. 46 | template 47 | bool isArraySortedWithoutDuplicates(const Array& Array, uint64 beginIdx, uint64 endIdx) 48 | { 49 | if (endIdx > L || beginIdx > endIdx) 50 | return false; 51 | 52 | for (uint64 i = beginIdx + 1; i < endIdx; ++i) 53 | { 54 | if (Array.get(i - 1) >= Array.get(i)) 55 | return false; 56 | } 57 | 58 | return true; 59 | } 60 | } 61 | 62 | QPI::id QPI::QpiContextFunctionCall::arbitrator() const 63 | { 64 | return arbitratorPublicKey; 65 | } 66 | 67 | QPI::id QPI::QpiContextFunctionCall::computor(unsigned short computorIndex) const 68 | { 69 | return broadcastedComputors.computors.publicKeys[computorIndex % NUMBER_OF_COMPUTORS]; 70 | } 71 | 72 | unsigned char QPI::QpiContextFunctionCall::dayOfWeek(unsigned char year, unsigned char month, unsigned char day) const 73 | { 74 | return dayIndex(year, month, day) % 7; 75 | } 76 | 77 | bool QPI::QpiContextFunctionCall::signatureValidity(const m256i& entity, const m256i& digest, const Array& signature) const 78 | { 79 | return verify(entity.m256i_u8, digest.m256i_u8, reinterpret_cast(&signature)); 80 | } 81 | 82 | template 83 | m256i QPI::QpiContextFunctionCall::K12(const T& data) const 84 | { 85 | m256i digest; 86 | 87 | KangarooTwelve(&data, sizeof(data), &digest, sizeof(digest)); 88 | 89 | return digest; 90 | } 91 | -------------------------------------------------------------------------------- /src/contracts/EmptyTemplate.h: -------------------------------------------------------------------------------- 1 | using namespace QPI; 2 | 3 | struct CNAME2 4 | { 5 | }; 6 | 7 | struct CNAME : public ContractBase 8 | { 9 | REGISTER_USER_FUNCTIONS_AND_PROCEDURES() 10 | { 11 | } 12 | 13 | INITIALIZE() 14 | { 15 | } 16 | 17 | BEGIN_EPOCH() 18 | { 19 | } 20 | 21 | END_EPOCH() 22 | { 23 | } 24 | 25 | BEGIN_TICK() 26 | { 27 | } 28 | 29 | END_TICK() 30 | { 31 | } 32 | 33 | PRE_ACQUIRE_SHARES() 34 | { 35 | } 36 | 37 | POST_ACQUIRE_SHARES() 38 | { 39 | } 40 | 41 | PRE_RELEASE_SHARES() 42 | { 43 | } 44 | 45 | POST_RELEASE_SHARES() 46 | { 47 | } 48 | 49 | POST_INCOMING_TRANSFER() 50 | { 51 | } 52 | 53 | EXPAND() 54 | { 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /src/contracts/MyLastMatch.h: -------------------------------------------------------------------------------- 1 | using namespace QPI; 2 | 3 | struct MLM2 4 | { 5 | }; 6 | 7 | struct MLM : public ContractBase 8 | { 9 | REGISTER_USER_FUNCTIONS_AND_PROCEDURES() 10 | { 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /src/contracts/README.md: -------------------------------------------------------------------------------- 1 | # Qubic Contract Development Guidelines 2 | 3 | This directory contains the smart contract implementations in header files starting with a capital letter. 4 | 5 | Further, it contains `qpi.h`, the Qubic Programming Interface for implementing the smart contracts. 6 | It is available automatically in the smart contract implementation header files. 7 | 8 | Other header files starting with a lowercase letter, such as `math_lib.h`, provide examples of useful functions that can be used in contract code. 9 | 10 | This document outlines the guidelines for developing secure and efficient Qubic contracts. Adherence to these guidelines is crucial for ensuring the proper functionality and security of your contracts within the Qubic environment. 11 | 12 | ### Concepts: 13 | 14 | The state is the persistent memory of the contract that is kept aligned in all nodes. 15 | 16 | A contract can have member functions and procedures. 17 | 18 | Functions cannot change the state of the contract. They can be called via a `RequestContractFunction` network message. 19 | 20 | Procedures can change the state of the contract. They are invoked by a transaction and run when the tick containing the transaction is processed. 21 | 22 | There are some special procedures that are called by the system at the beginning of the tick etc. 23 | 24 | A call of a user procedure usually goes along with a transfer of an invocation reward from the invoking user to the contract. 25 | 26 | Procedures can call procedures and functions of the same contract and of contracts with lower contract index. 27 | 28 | Functions can call functions of the same contract and of contracts with lower contract ID. 29 | 30 | Private functions and procedures cannot be called from other contracts. 31 | 32 | In order to be available for invocation by transaction and network message, procedures and functions need to be registered in the special member function `REGISTER_USER_FUNCTIONS_AND_PROCEDURES`. 33 | 34 | 35 | 36 | ### Syntax and Formatting: 37 | - Qubic contracts generally inherit the syntax and format of C/C++. 38 | - However, due to security reasons, certain things are prohibited: 39 | - Declaring and accessing arrays using the C/C++ notation (`[` `]`). Utilize pre-defined array structures within qpi.h such as `collection`, `uint32_64`, `uint32_128`, ... 40 | - Any pointer-related techniques such as casting, accessing, ... 41 | - Native data types like `int`, `long`, `char`, ... Use their corresponding predefined data types in `qpi.h` (`uint8`, `sint8`, `uint16`, `sint32`, `uint64`, ...) 42 | - Inclusion of other files via `#include`. All functions must reside within a single file. 43 | - Math operators `%` and `/`. Use `mod` and `div` from `qpi.h` instead. `+`, `-`, `*`(multiplication), and bit-wise operators are accepted. 44 | - Local variable declaration, even for for-loop. You need to define all necessary variables in either in the contract state or in a "locals" struct similar to the input and output struct of a function or procedure. 45 | - The `typedef`, `union` keyword. 46 | - Floating point data types (half, float, double) 47 | 48 | Currently, the maximum contract state size is capped at 1 GiB (03/02/2024). This value is subject to change based on hardware upgrades of computors. 49 | -------------------------------------------------------------------------------- /src/contracts/Random.h: -------------------------------------------------------------------------------- 1 | using namespace QPI; 2 | 3 | struct RANDOM2 4 | { 5 | }; 6 | 7 | struct RANDOM : public ContractBase 8 | { 9 | public: 10 | struct RevealAndCommit_input 11 | { 12 | bit_4096 revealedBits; 13 | id committedDigest; 14 | }; 15 | struct RevealAndCommit_output 16 | { 17 | }; 18 | 19 | private: 20 | uint64 _earnedAmount; 21 | uint64 _distributedAmount; 22 | uint64 _burnedAmount; 23 | 24 | uint32 _bitFee; // Amount of qus 25 | 26 | PUBLIC_PROCEDURE(RevealAndCommit) 27 | { 28 | qpi.transfer(qpi.invocator(), qpi.invocationReward()); 29 | } 30 | 31 | REGISTER_USER_FUNCTIONS_AND_PROCEDURES() 32 | { 33 | REGISTER_USER_PROCEDURE(RevealAndCommit, 1); 34 | } 35 | 36 | INITIALIZE() 37 | { 38 | state._bitFee = 1000; 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /src/contracts/SupplyWatcher.h: -------------------------------------------------------------------------------- 1 | using namespace QPI; 2 | 3 | struct SWATCH2 4 | { 5 | }; 6 | 7 | struct SWATCH : public ContractBase 8 | { 9 | REGISTER_USER_FUNCTIONS_AND_PROCEDURES() 10 | { 11 | } 12 | 13 | struct BEGIN_EPOCH_locals 14 | { 15 | Entity ownEntity; 16 | sint64 ownBalance; 17 | }; 18 | 19 | BEGIN_EPOCH_WITH_LOCALS() 20 | { 21 | // Burn all coins of this contract. According to agreement of the quorum, a part of the 22 | // computor revenue is donated to this contract for burning. 23 | if (qpi.getEntity(SELF, locals.ownEntity)) 24 | { 25 | locals.ownBalance = locals.ownEntity.incomingAmount - locals.ownEntity.outgoingAmount; 26 | if (locals.ownBalance > 0) 27 | qpi.burn(locals.ownBalance); 28 | } 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/contracts/TestExampleD.h: -------------------------------------------------------------------------------- 1 | using namespace QPI; 2 | 3 | struct TESTEXD2 4 | { 5 | }; 6 | 7 | struct TESTEXD : public ContractBase 8 | { 9 | struct END_TICK_locals 10 | { 11 | Entity entity; 12 | sint64 balance; 13 | }; 14 | 15 | END_TICK_WITH_LOCALS() 16 | { 17 | // Distribute balance to sharesholders at the end of each tick 18 | qpi.getEntity(SELF, locals.entity); 19 | locals.balance = locals.entity.incomingAmount - locals.entity.outgoingAmount; 20 | if (locals.balance > NUMBER_OF_COMPUTORS) 21 | { 22 | qpi.distributeDividends(locals.balance / NUMBER_OF_COMPUTORS); 23 | } 24 | } 25 | 26 | REGISTER_USER_FUNCTIONS_AND_PROCEDURES() 27 | { 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /src/contracts/math_lib.h: -------------------------------------------------------------------------------- 1 | // Basic math functions (not optimized but with minimal dependencies) 2 | 3 | #pragma once 4 | 5 | namespace math_lib 6 | { 7 | 8 | template 9 | inline constexpr const T& max(const T& left, const T& right) 10 | { 11 | return (left < right) ? right : left; 12 | } 13 | 14 | template 15 | inline constexpr const T& min(const T& left, const T& right) 16 | { 17 | return (left < right) ? left : right; 18 | } 19 | 20 | template 21 | inline constexpr T abs(const T& a) 22 | { 23 | return (a < 0) ? -a : a; 24 | } 25 | 26 | // div() and mod() are defined in qpi.h 27 | 28 | // Divides a by b rounding up, but return 0 if b is 0 (only supports unsigned integers) 29 | inline static unsigned long long divUp(unsigned long long a, unsigned long long b) 30 | { 31 | return b ? ((a + b - 1) / b) : 0; 32 | } 33 | 34 | // Divides a by b rounding up, but return 0 if b is 0 (only supports unsigned integers) 35 | inline static unsigned int divUp(unsigned int a, unsigned int b) 36 | { 37 | return b ? ((a + b - 1) / b) : 0; 38 | } 39 | 40 | // Divides a by b rounding up, but return 0 if b is 0 (only supports unsigned integers) 41 | inline static unsigned short divUp(unsigned short a, unsigned short b) 42 | { 43 | return b ? ((a + b - 1) / b) : 0; 44 | } 45 | 46 | // Divides a by b rounding up, but return 0 if b is 0 (only supports unsigned integers) 47 | inline static unsigned char divUp(unsigned char a, unsigned char b) 48 | { 49 | return b ? ((a + b - 1) / b) : 0; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/files/files.h: -------------------------------------------------------------------------------- 1 | struct FileHeaderTransaction : public Transaction 2 | { 3 | static constexpr unsigned char transactionType() 4 | { 5 | return 3; // TODO: Set actual value 6 | } 7 | 8 | static constexpr long long minAmount() 9 | { 10 | return 0; 11 | } 12 | 13 | static constexpr unsigned short minInputSize() 14 | { 15 | return sizeof(fileSize) 16 | + sizeof(numberOfFragments) 17 | + sizeof(fileFormat); 18 | } 19 | 20 | unsigned long long fileSize; 21 | unsigned long long numberOfFragments; 22 | unsigned char fileFormat[8]; 23 | unsigned char signature[SIGNATURE_SIZE]; 24 | }; 25 | 26 | struct FileFragmentTransactionPrefix : public Transaction 27 | { 28 | static constexpr unsigned char transactionType() 29 | { 30 | return 4; // TODO: Set actual value 31 | } 32 | 33 | static constexpr long long minAmount() 34 | { 35 | return 0; 36 | } 37 | 38 | static constexpr unsigned short minInputSize() 39 | { 40 | return sizeof(fragmentIndex) 41 | + sizeof(prevFileFragmentTransactionDigest); 42 | } 43 | 44 | unsigned long long fragmentIndex; 45 | m256i prevFileFragmentTransactionDigest; 46 | }; 47 | 48 | struct FileFragmentTransactionPostfix 49 | { 50 | unsigned char signature[SIGNATURE_SIZE]; 51 | }; 52 | 53 | struct FileTrailerTransaction : public Transaction 54 | { 55 | static constexpr unsigned char transactionType() 56 | { 57 | return 5; // TODO: Set actual value 58 | } 59 | 60 | static constexpr long long minAmount() 61 | { 62 | return 0; 63 | } 64 | 65 | static constexpr unsigned short minInputSize() 66 | { 67 | return sizeof(fileSize) 68 | + sizeof(numberOfFragments) 69 | + sizeof(fileFormat) 70 | + sizeof(lastFileFragmentTransactionDigest); 71 | } 72 | 73 | unsigned long long fileSize; 74 | unsigned long long numberOfFragments; 75 | unsigned char fileFormat[8]; 76 | m256i lastFileFragmentTransactionDigest; 77 | unsigned char signature[SIGNATURE_SIZE]; 78 | }; -------------------------------------------------------------------------------- /src/network_messages/README.md: -------------------------------------------------------------------------------- 1 | # network_messages 2 | 3 | This directory contains all definitions of the network messages used in the Qubic communication protocol. 4 | This includes all constants and data types used in the network message definition. 5 | 6 | You may use the code of this directory in your software project for communicating with the Qubic Core. 7 | In order to disable dependencies to other code, `#define NETWORK_MESSAGES_WITHOUT_CORE_DEPENDENCIES` 8 | before including any header of this directory or edit the `#if ...` line in `common_def.h`. 9 | -------------------------------------------------------------------------------- /src/network_messages/all.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common_def.h" 4 | #include "header.h" 5 | 6 | #include "assets.h" 7 | #include "broadcast_message.h" 8 | #include "common_response.h" 9 | #include "computors.h" 10 | #include "contract.h" 11 | #include "custom_mining.h" 12 | #include "entity.h" 13 | #include "logging.h" 14 | #include "public_peers.h" 15 | #include "special_command.h" 16 | #include "tick.h" 17 | #include "transactions.h" 18 | #include "system_info.h" 19 | -------------------------------------------------------------------------------- /src/network_messages/broadcast_message.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common_def.h" 4 | 5 | #define MESSAGE_TYPE_SOLUTION 0 6 | #define MESSAGE_TYPE_CUSTOM_MINING_TASK 1 7 | #define MESSAGE_TYPE_CUSTOM_MINING_SOLUTION 2 8 | 9 | // TODO: documentation needed: 10 | // "A General Message type used to send/receive messages from/to peers." -> right? 11 | // What the the gammingNonce about exactly? 12 | // Which other message types are planned next to MESSAGE_TYPE_SOLUTION? 13 | // 14 | // MESSAGE_TYPE_SOLUTION 15 | // sourcePublicKey Must not be NULL_ID. It can be a signing public key or a computor/candidate public key. 16 | // destinationPublicKey Public key of a computor/candidate controlled by a node. 17 | // gammingNonce There are two cases: 18 | // - If sourcePublicKey is just a signing pubkey: the first 32 bytes are zeros, and the last 32 bytes are taken from the message. 19 | // - If sourcePublicKey is a public key of a computor: the message is encrypted. 20 | struct BroadcastMessage 21 | { 22 | m256i sourcePublicKey; 23 | m256i destinationPublicKey; 24 | m256i gammingNonce; 25 | 26 | enum { 27 | type = 1, 28 | }; 29 | }; 30 | 31 | static_assert(sizeof(BroadcastMessage) == 32 + 32 + 32, "Something is wrong with the struct size."); 32 | 33 | struct CustomMiningTaskMessage 34 | { 35 | m256i sourcePublicKey; 36 | m256i zero; 37 | m256i gammingNonce; 38 | 39 | m256i codeFileTrailerDigest; 40 | m256i dataFileTrailerDigest; 41 | 42 | // Task payload 43 | }; 44 | 45 | struct CustomMiningSolutionMessage 46 | { 47 | m256i sourcePublicKey; 48 | m256i zero; 49 | m256i gammingNonce; 50 | 51 | // Solution payload 52 | }; -------------------------------------------------------------------------------- /src/network_messages/common_def.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SIGNATURE_SIZE 64 4 | #define NUMBER_OF_TRANSACTIONS_PER_TICK 1024 // Must be 2^N 5 | #define MAX_NUMBER_OF_PENDING_TRANSACTIONS_PER_COMPUTOR 128 6 | #define MAX_NUMBER_OF_CONTRACTS 1024 // Must be 1024 7 | #define NUMBER_OF_COMPUTORS 676 8 | #define QUORUM (NUMBER_OF_COMPUTORS * 2 / 3 + 1) 9 | #define NUMBER_OF_EXCHANGED_PEERS 4 10 | 11 | #define SPECTRUM_DEPTH 24 // Defines SPECTRUM_CAPACITY (1 << SPECTRUM_DEPTH) 12 | #define SPECTRUM_CAPACITY (1ULL << SPECTRUM_DEPTH) // Must be 2^N 13 | 14 | #define ASSETS_CAPACITY 0x1000000ULL // Must be 2^N 15 | #define ASSETS_DEPTH 24 // Is derived from ASSETS_CAPACITY (=N) 16 | 17 | #define MAX_INPUT_SIZE 1024ULL 18 | #define ISSUANCE_RATE 1000000000000LL 19 | #define MAX_AMOUNT (ISSUANCE_RATE * 1000ULL) 20 | #define MAX_SUPPLY (ISSUANCE_RATE * 200ULL) 21 | 22 | 23 | // If you want to use the network_meassges directory in your project without dependencies to other code, 24 | // you may define NETWORK_MESSAGES_WITHOUT_CORE_DEPENDENCIES before including any header or change the 25 | // following line to "#if 1". 26 | #if defined(NETWORK_MESSAGES_WITHOUT_CORE_DEPENDENCIES) 27 | 28 | #include 29 | 30 | typedef union m256i 31 | { 32 | __int8 m256i_i8[32]; 33 | __int16 m256i_i16[16]; 34 | __int32 m256i_i32[8]; 35 | __int64 m256i_i64[4]; 36 | unsigned __int8 m256i_u8[32]; 37 | unsigned __int16 m256i_u16[16]; 38 | unsigned __int32 m256i_u32[8]; 39 | unsigned __int64 m256i_u64[4]; 40 | } m256i; 41 | 42 | #else 43 | 44 | #include "../platform/m256.h" 45 | 46 | #endif 47 | 48 | typedef union IPv4Address 49 | { 50 | unsigned __int8 u8[4]; 51 | unsigned __int32 u32; 52 | } IPv4Address; 53 | 54 | static_assert(sizeof(IPv4Address) == 4, "Unexpected size!"); 55 | 56 | static inline bool operator==(const IPv4Address& a, const IPv4Address& b) 57 | { 58 | return a.u32 == b.u32; 59 | } 60 | 61 | static inline bool operator!=(const IPv4Address& a, const IPv4Address& b) 62 | { 63 | return a.u32 != b.u32; 64 | } 65 | 66 | // Compute the siblings array of each level of tree. This function is not thread safe 67 | // make sure resource protection is handled outside 68 | template 69 | static void getSiblings(int digestIndex, const m256i* digests, m256i siblings[depth]) 70 | { 71 | const unsigned int capacity = (1ULL << depth); 72 | int siblingIndex = digestIndex; 73 | unsigned int digestOffset = 0; 74 | for (unsigned int j = 0; j < depth; j++) 75 | { 76 | siblings[j] = digests[digestOffset + (siblingIndex ^ 1)]; 77 | digestOffset += (capacity >> j); 78 | siblingIndex >>= 1; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/network_messages/common_response.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct EndResponse 4 | { 5 | enum { 6 | type = 35, 7 | }; 8 | }; 9 | 10 | struct TryAgain // Must be returned if _dejavu is not 0, and the incoming packet cannot be processed (usually when incoming packets queue is full) 11 | { 12 | enum { 13 | type = 54, 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /src/network_messages/computors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common_def.h" 4 | 5 | // Use "#pragma pack" keep the binary struct compatibility after changing from unsigned char [32] to m256i 6 | #pragma pack(push,1) 7 | struct Computors 8 | { 9 | // TODO: Padding 10 | unsigned short epoch; 11 | m256i publicKeys[NUMBER_OF_COMPUTORS]; 12 | unsigned char signature[SIGNATURE_SIZE]; 13 | }; 14 | #pragma pack(pop) 15 | 16 | static_assert(sizeof(Computors) == 2 + 32 * NUMBER_OF_COMPUTORS + SIGNATURE_SIZE, "Something is wrong with the struct size."); 17 | 18 | struct BroadcastComputors 19 | { 20 | Computors computors; 21 | 22 | enum { 23 | type = 2, 24 | }; 25 | }; 26 | 27 | 28 | struct RequestComputors 29 | { 30 | enum { 31 | type = 11, 32 | }; 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /src/network_messages/contract.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common_def.h" 4 | 5 | 6 | 7 | struct RequestContractIPO 8 | { 9 | unsigned int contractIndex; 10 | 11 | enum { 12 | type = 33, 13 | }; 14 | }; 15 | 16 | 17 | struct RespondContractIPO 18 | { 19 | unsigned int contractIndex; 20 | unsigned int tick; 21 | m256i publicKeys[NUMBER_OF_COMPUTORS]; 22 | long long prices[NUMBER_OF_COMPUTORS]; 23 | 24 | enum { 25 | type = 34, 26 | }; 27 | }; 28 | 29 | static_assert(sizeof(RespondContractIPO) == 4 + 4 + 32 * NUMBER_OF_COMPUTORS + 8 * NUMBER_OF_COMPUTORS, "Something is wrong with the struct size."); 30 | 31 | 32 | struct RequestContractFunction // Invokes contract function 33 | { 34 | unsigned int contractIndex; 35 | unsigned short inputType; 36 | unsigned short inputSize; 37 | // Variable-size input 38 | 39 | enum { 40 | type = 42, 41 | }; 42 | }; 43 | 44 | 45 | struct RespondContractFunction // Returns result of contract function invocation 46 | { 47 | // Variable-size output; the size must be 0 if the invocation has failed for whatever reason (e.g. no a function registered for [inputType], or the function has timed out) 48 | 49 | enum { 50 | type = 43, 51 | }; 52 | }; 53 | -------------------------------------------------------------------------------- /src/network_messages/custom_mining.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Message struture for request custom mining data 4 | struct RequestedCustomMiningData 5 | { 6 | enum 7 | { 8 | type = 60, 9 | }; 10 | enum 11 | { 12 | taskType = 0, 13 | solutionType = 1, 14 | }; 15 | // Task index information: 16 | // - For taskType: 'fromTaskIndex' is the lower bound and 'toTaskIndex' is the upper bound of the task range [fromTaskIndex, toTaskIndex]. 17 | // - For solutionType: only 'fromTaskIndex' is used, since the solution response is tied to a single task. 18 | unsigned long long fromTaskIndex; 19 | unsigned long long toTaskIndex; 20 | 21 | // Determine which task partition 22 | unsigned short firstComputorIdx; 23 | unsigned short lastComputorIdx; 24 | unsigned int padding; 25 | 26 | // Type of the request: either task (taskType) or solution (solutionType). 27 | long long dataType; 28 | }; 29 | 30 | // Message struture for respond custom mining data 31 | struct RespondCustomMiningData 32 | { 33 | enum 34 | { 35 | type = 61, 36 | }; 37 | enum 38 | { 39 | taskType = 0, 40 | solutionType = 1, 41 | }; 42 | // The 'payload' variable is defined externally and usually contains a byte array. 43 | // Ussualy: [CustomMiningRespondDataHeader ... NumberOfItems * ItemSize]; 44 | }; 45 | 46 | struct RequestedCustomMiningSolutionVerification 47 | { 48 | enum 49 | { 50 | type = 62, 51 | }; 52 | unsigned long long taskIndex; 53 | unsigned short firstComputorIdx; 54 | unsigned short lastComputorIdx; 55 | unsigned int nonce; 56 | unsigned long long isValid; // validity of the solution. 0: invalid, >0: valid 57 | }; 58 | struct RespondCustomMiningSolutionVerification 59 | { 60 | enum 61 | { 62 | type = 63, 63 | }; 64 | enum 65 | { 66 | notExisted = 0, // solution not existed in cache 67 | valid = 1, // solution are set as valid 68 | invalid = 2, // solution are set as invalid 69 | customMiningStateEnded = 3, // not in custom mining state 70 | }; 71 | unsigned long long taskIndex; 72 | unsigned short firstComputorIdx; 73 | unsigned short lastComputorIdx; 74 | unsigned int nonce; 75 | long long status; // Flag indicate the status of solution 76 | }; 77 | 78 | -------------------------------------------------------------------------------- /src/network_messages/entity.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common_def.h" 4 | 5 | struct Entity 6 | { 7 | m256i publicKey; 8 | long long incomingAmount, outgoingAmount; 9 | 10 | // Numbers of transfers. These may overflow for entities with high traffic, such as Qx. 11 | unsigned int numberOfIncomingTransfers, numberOfOutgoingTransfers; 12 | 13 | unsigned int latestIncomingTransferTick, latestOutgoingTransferTick; 14 | }; 15 | 16 | static_assert(sizeof(::Entity) == 32 + 2 * 8 + 2 * 4 + 2 * 4, "Something is wrong with the struct size."); 17 | 18 | 19 | #define REQUEST_ENTITY 31 20 | 21 | struct RequestedEntity 22 | { 23 | m256i publicKey; 24 | }; 25 | 26 | static_assert(sizeof(RequestedEntity) == 32, "Something is wrong with the struct size."); 27 | 28 | 29 | #define RESPOND_ENTITY 32 30 | 31 | struct RespondedEntity 32 | { 33 | ::Entity entity; 34 | unsigned int tick; 35 | int spectrumIndex; 36 | m256i siblings[SPECTRUM_DEPTH]; 37 | }; 38 | 39 | static_assert(sizeof(RespondedEntity) == sizeof(::Entity) + 4 + 4 + 32 * SPECTRUM_DEPTH, "Something is wrong with the struct size."); 40 | -------------------------------------------------------------------------------- /src/network_messages/header.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct RequestResponseHeader 6 | { 7 | private: 8 | unsigned char _size[3]; 9 | unsigned char _type; 10 | unsigned int _dejavu; 11 | 12 | public: 13 | // The maximum size that a message may have (encoded in 3 bytes) 14 | static constexpr unsigned int max_size = 0xFFFFFF; 15 | 16 | // Return the size of the message 17 | inline unsigned int size() const 18 | { 19 | return (*((unsigned int*)_size)) & 0xFFFFFF; 20 | } 21 | 22 | // Set message size with compile-time check 23 | template 24 | constexpr inline void setSize() 25 | { 26 | static_assert(size <= max_size); 27 | _size[0] = (unsigned char)size; 28 | _size[1] = (unsigned char)(size >> 8); 29 | _size[2] = (unsigned char)(size >> 16); 30 | } 31 | 32 | // Set message size with run-time check of size (returns false if message is too big) 33 | inline bool checkAndSetSize(unsigned int size) 34 | { 35 | if (size > max_size) 36 | return false; 37 | 38 | _size[0] = (unsigned char)size; 39 | _size[1] = (unsigned char)(size >> 8); 40 | _size[2] = (unsigned char)(size >> 16); 41 | return true; 42 | } 43 | 44 | // Check if dejavue is 0. A zero dejavu is used to signal that a message should be distributed to other peers. 45 | inline bool isDejavuZero() const 46 | { 47 | return !_dejavu; 48 | } 49 | 50 | inline unsigned int dejavu() const 51 | { 52 | return _dejavu; 53 | } 54 | 55 | inline void setDejavu(unsigned int dejavu) 56 | { 57 | _dejavu = dejavu; 58 | } 59 | 60 | inline void randomizeDejavu() 61 | { 62 | _rdrand32_step(&_dejavu); 63 | if (!_dejavu) 64 | { 65 | _dejavu = 1; 66 | } 67 | } 68 | 69 | inline unsigned char type() const 70 | { 71 | return _type; 72 | } 73 | 74 | inline void setType(const unsigned char type) 75 | { 76 | _type = type; 77 | } 78 | 79 | // Return pointer to payload, which is stored behind the header. 80 | // The type() is not checked against the PayloadType! 81 | template 82 | inline PayloadType* getPayload() 83 | { 84 | return reinterpret_cast(this + 1); 85 | } 86 | 87 | // Check if the payload size is as expected. 88 | inline bool checkPayloadSize(unsigned int expected_payload_size) const 89 | { 90 | return size() == expected_payload_size + sizeof(RequestResponseHeader); 91 | } 92 | 93 | // Check if the payload size is in the expected range. 94 | inline bool checkPayloadSizeMinMax(unsigned int min_payload_size, unsigned int max_payload_size) const 95 | { 96 | return min_payload_size + sizeof(RequestResponseHeader) <= size() && size() <= max_payload_size + sizeof(RequestResponseHeader); 97 | } 98 | 99 | // Get size of the payload (without checking validity of overall size). 100 | inline unsigned int getPayloadSize() const 101 | { 102 | return this->size() - sizeof(RequestResponseHeader); 103 | } 104 | }; 105 | -------------------------------------------------------------------------------- /src/network_messages/logging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common_def.h" 4 | 5 | #define LOG_TX_NUMBER_OF_SPECIAL_EVENT 5 6 | #define LOG_TX_PER_TICK (NUMBER_OF_TRANSACTIONS_PER_TICK + LOG_TX_NUMBER_OF_SPECIAL_EVENT)// +5 special events 7 | 8 | // Fetches log 9 | struct RequestLog 10 | { 11 | unsigned long long passcode[4]; 12 | unsigned long long fromID; 13 | unsigned long long toID; // inclusive 14 | 15 | enum { 16 | type = 44, 17 | }; 18 | }; 19 | 20 | 21 | struct RespondLog 22 | { 23 | // Variable-size log; 24 | 25 | enum { 26 | type = 45, 27 | }; 28 | }; 29 | 30 | 31 | // Request logid ranges from tx hash 32 | struct RequestLogIdRangeFromTx 33 | { 34 | unsigned long long passcode[4]; 35 | unsigned int tick; 36 | unsigned int txId; 37 | 38 | enum { 39 | type = 48, 40 | }; 41 | }; 42 | 43 | 44 | // Response logid ranges from tx hash 45 | struct ResponseLogIdRangeFromTx 46 | { 47 | long long fromLogId; 48 | long long length; 49 | 50 | enum { 51 | type = 49, 52 | }; 53 | }; 54 | 55 | // Request logId ranges (fromLogId, length) of all txs from a tick 56 | struct RequestAllLogIdRangesFromTick 57 | { 58 | unsigned long long passcode[4]; 59 | unsigned int tick; 60 | 61 | enum { 62 | type = 50, 63 | }; 64 | }; 65 | 66 | 67 | // Response logId ranges (fromLogId, length) of all txs from a tick 68 | struct ResponseAllLogIdRangesFromTick 69 | { 70 | long long fromLogId[LOG_TX_PER_TICK]; 71 | long long length[LOG_TX_PER_TICK]; 72 | 73 | enum { 74 | type = 51, 75 | }; 76 | }; 77 | 78 | // Request the node to prune logs (to save disk) 79 | struct RequestPruningLog 80 | { 81 | unsigned long long passcode[4]; 82 | unsigned long long fromLogId; 83 | unsigned long long toLogId; 84 | 85 | enum { 86 | type = 56, 87 | }; 88 | }; 89 | 90 | // Response to above request, 0 if success, otherwise error code will be returned 91 | struct ResponsePruningLog 92 | { 93 | long long success; 94 | enum { 95 | type = 57, 96 | }; 97 | }; 98 | 99 | // Request the digest of log event state, given requestedTick 100 | struct RequestLogStateDigest 101 | { 102 | unsigned long long passcode[4]; 103 | unsigned int requestedTick; 104 | 105 | enum { 106 | type = 58, 107 | }; 108 | }; 109 | 110 | // Response above request, a 32 bytes digest 111 | struct ResponseLogStateDigest 112 | { 113 | m256i digest; 114 | enum { 115 | type = 59, 116 | }; 117 | }; -------------------------------------------------------------------------------- /src/network_messages/public_peers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common_def.h" 4 | 5 | struct ExchangePublicPeers 6 | { 7 | IPv4Address peers[NUMBER_OF_EXCHANGED_PEERS]; 8 | 9 | enum { 10 | type = 0, 11 | }; 12 | }; 13 | 14 | static_assert(sizeof(ExchangePublicPeers) == 4 * NUMBER_OF_EXCHANGED_PEERS, "Unexpected size!"); 15 | -------------------------------------------------------------------------------- /src/network_messages/special_command.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common_def.h" 4 | 5 | 6 | struct SpecialCommand 7 | { 8 | unsigned long long everIncreasingNonceAndCommandType; 9 | 10 | enum { 11 | type = 255, 12 | }; 13 | }; 14 | 15 | #define SPECIAL_COMMAND_SHUT_DOWN 0ULL 16 | 17 | 18 | #define SPECIAL_COMMAND_SET_SOLUTION_THRESHOLD_REQUEST 5ULL 19 | #define SPECIAL_COMMAND_SET_SOLUTION_THRESHOLD_RESPONSE 6ULL 20 | struct SpecialCommandSetSolutionThresholdRequestAndResponse 21 | { 22 | unsigned long long everIncreasingNonceAndCommandType; 23 | unsigned int epoch; 24 | int threshold; 25 | }; 26 | 27 | 28 | #define SPECIAL_COMMAND_TOGGLE_MAIN_MODE_REQUEST 7ULL // F12 29 | #define SPECIAL_COMMAND_TOGGLE_MAIN_MODE_RESPONSE 8ULL // F12 30 | struct SpecialCommandToggleMainModeRequestAndResponse 31 | { 32 | unsigned long long everIncreasingNonceAndCommandType; 33 | unsigned char mainModeFlag; // 0 Aux - 1 Main 34 | unsigned char padding[7]; 35 | }; 36 | #define SPECIAL_COMMAND_REFRESH_PEER_LIST 9ULL // F4 37 | #define SPECIAL_COMMAND_FORCE_NEXT_TICK 10ULL // F5 38 | #define SPECIAL_COMMAND_REISSUE_VOTE 11ULL // F9 39 | 40 | 41 | struct UtcTime 42 | { 43 | unsigned short year; // 1900 - 9999 44 | unsigned char month; // 1 - 12 45 | unsigned char day; // 1 - 31 46 | unsigned char hour; // 0 - 23 47 | unsigned char minute; // 0 - 59 48 | unsigned char second; // 0 - 59 49 | unsigned char pad1; 50 | unsigned int nanosecond; // 0 - 999,999,999 51 | }; 52 | 53 | #define SPECIAL_COMMAND_QUERY_TIME 12ULL // send this to node to query time, responds with time read from clock 54 | #define SPECIAL_COMMAND_SEND_TIME 13ULL // send this to node to set time, responds with time read from clock after setting 55 | 56 | struct SpecialCommandSendTime 57 | { 58 | unsigned long long everIncreasingNonceAndCommandType; 59 | UtcTime utcTime; 60 | }; 61 | 62 | #define SPECIAL_COMMAND_GET_MINING_SCORE_RANKING 14ULL 63 | #pragma pack( push, 1) 64 | template 65 | struct SpecialCommandGetMiningScoreRanking 66 | { 67 | struct ScoreRankingEntry { 68 | m256i minerPublicKey; 69 | unsigned int minerScore; 70 | }; 71 | 72 | unsigned long long everIncreasingNonceAndCommandType; 73 | unsigned int numberOfRankings; 74 | ScoreRankingEntry rankings[maxNumberOfMiners]; 75 | }; 76 | 77 | #define SPECIAL_COMMAND_FORCE_SWITCH_EPOCH 15ULL // F7 78 | #define SPECIAL_COMMAND_CONTINUE_SWITCH_EPOCH 16ULL // F10 (only log-enabled nodes need this) 79 | 80 | #define SPECIAL_COMMAND_SET_CONSOLE_LOGGING_MODE 17ULL // PAUSE key 81 | struct SpecialCommandSetConsoleLoggingModeRequestAndResponse 82 | { 83 | unsigned long long everIncreasingNonceAndCommandType; 84 | unsigned char loggingMode; // 0 disabled, 1 low computational cost, 2 full logging 85 | unsigned char padding[7]; 86 | }; 87 | 88 | #pragma pack(pop) 89 | -------------------------------------------------------------------------------- /src/network_messages/system_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common_def.h" 4 | 5 | #define REQUEST_SYSTEM_INFO 46 6 | 7 | 8 | #define RESPOND_SYSTEM_INFO 47 9 | 10 | #pragma pack(push, 1) 11 | struct RespondSystemInfo 12 | { 13 | short version; 14 | unsigned short epoch; 15 | unsigned int tick; 16 | unsigned int initialTick; 17 | unsigned int latestCreatedTick; 18 | 19 | unsigned short initialMillisecond; 20 | unsigned char initialSecond; 21 | unsigned char initialMinute; 22 | unsigned char initialHour; 23 | unsigned char initialDay; 24 | unsigned char initialMonth; 25 | unsigned char initialYear; 26 | 27 | unsigned int numberOfEntities; 28 | unsigned int numberOfTransactions; 29 | 30 | m256i randomMiningSeed; 31 | int solutionThreshold; 32 | 33 | unsigned long long totalSpectrumAmount; 34 | 35 | // Entity balances less or euqal this value will be burned if number of entites rises to 75% of spectrum capacity. 36 | // Starts to be meaningful if >50% of spectrum is filled but may still change after that. 37 | unsigned long long currentEntityBalanceDustThreshold; 38 | 39 | unsigned int targetTickVoteSignature; 40 | unsigned long long _reserve0; 41 | unsigned long long _reserve1; 42 | unsigned long long _reserve2; 43 | unsigned long long _reserve3; 44 | unsigned long long _reserve4; 45 | }; 46 | #pragma pack(pop) 47 | 48 | static_assert(sizeof(RespondSystemInfo) == 128, "Something is wrong with the struct size of RespondSystemInfo."); 49 | -------------------------------------------------------------------------------- /src/network_messages/tick.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common_def.h" 4 | 5 | 6 | struct Tick 7 | { 8 | unsigned short computorIndex; 9 | unsigned short epoch; 10 | unsigned int tick; 11 | 12 | unsigned short millisecond; 13 | unsigned char second; 14 | unsigned char minute; 15 | unsigned char hour; 16 | unsigned char day; 17 | unsigned char month; 18 | unsigned char year; 19 | 20 | unsigned int prevResourceTestingDigest; 21 | unsigned int saltedResourceTestingDigest; 22 | 23 | unsigned int prevTransactionBodyDigest; 24 | unsigned int saltedTransactionBodyDigest; 25 | 26 | m256i prevSpectrumDigest; 27 | m256i prevUniverseDigest; 28 | m256i prevComputerDigest; 29 | m256i saltedSpectrumDigest; 30 | m256i saltedUniverseDigest; 31 | m256i saltedComputerDigest; 32 | 33 | m256i transactionDigest; 34 | m256i expectedNextTickTransactionDigest; 35 | 36 | unsigned char signature[SIGNATURE_SIZE]; 37 | }; 38 | 39 | static_assert(sizeof(Tick) == 8 + 8 + 2 * 4 + 2 * 4 + 6 * 32 + 2 * 32 + SIGNATURE_SIZE, "Something is wrong with the struct size."); 40 | 41 | 42 | struct BroadcastTick 43 | { 44 | Tick tick; 45 | 46 | enum { 47 | type = 3, 48 | }; 49 | }; 50 | 51 | 52 | 53 | struct TickData 54 | { 55 | unsigned short computorIndex; 56 | unsigned short epoch; 57 | unsigned int tick; 58 | 59 | unsigned short millisecond; 60 | unsigned char second; 61 | unsigned char minute; 62 | unsigned char hour; 63 | unsigned char day; 64 | unsigned char month; 65 | unsigned char year; 66 | 67 | m256i timelock; 68 | m256i transactionDigests[NUMBER_OF_TRANSACTIONS_PER_TICK]; 69 | long long contractFees[MAX_NUMBER_OF_CONTRACTS]; 70 | 71 | unsigned char signature[SIGNATURE_SIZE]; 72 | }; 73 | 74 | static_assert(sizeof(TickData) == 8 + 8 + 32 + NUMBER_OF_TRANSACTIONS_PER_TICK * 32 + 8 * MAX_NUMBER_OF_CONTRACTS + SIGNATURE_SIZE, "Something is wrong with the struct size."); 75 | 76 | 77 | struct BroadcastFutureTickData 78 | { 79 | TickData tickData; 80 | 81 | enum { 82 | type = 8, 83 | }; 84 | }; 85 | 86 | 87 | struct RequestedQuorumTick 88 | { 89 | unsigned int tick; 90 | unsigned char voteFlags[(NUMBER_OF_COMPUTORS + 7) / 8]; 91 | }; 92 | 93 | 94 | struct RequestQuorumTick 95 | { 96 | RequestedQuorumTick quorumTick; 97 | 98 | enum { 99 | type = 14, 100 | }; 101 | }; 102 | 103 | 104 | struct RequestedTickData 105 | { 106 | unsigned int tick; 107 | }; 108 | 109 | 110 | struct RequestTickData 111 | { 112 | RequestedTickData requestedTickData; 113 | 114 | enum { 115 | type = 16, 116 | }; 117 | }; 118 | 119 | 120 | #define REQUEST_CURRENT_TICK_INFO 27 121 | 122 | #define RESPOND_CURRENT_TICK_INFO 28 123 | 124 | struct CurrentTickInfo 125 | { 126 | unsigned short tickDuration; 127 | unsigned short epoch; 128 | unsigned int tick; 129 | unsigned short numberOfAlignedVotes; 130 | unsigned short numberOfMisalignedVotes; 131 | unsigned int initialTick; 132 | }; 133 | 134 | -------------------------------------------------------------------------------- /src/network_messages/transactions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common_def.h" 4 | 5 | // used with Transaction 6 | struct ContractIPOBid 7 | { 8 | long long price; 9 | unsigned short quantity; 10 | }; 11 | 12 | #define BROADCAST_TRANSACTION 24 13 | 14 | 15 | // A transaction is made of this struct, followed by inputSize Bytes payload data and SIGNATURE_SIZE Bytes signature 16 | struct Transaction 17 | { 18 | m256i sourcePublicKey; 19 | m256i destinationPublicKey; 20 | long long amount; 21 | unsigned int tick; 22 | unsigned short inputType; 23 | unsigned short inputSize; 24 | 25 | // Return total transaction data size with payload data and signature 26 | unsigned int totalSize() const 27 | { 28 | return sizeof(Transaction) + inputSize + SIGNATURE_SIZE; 29 | } 30 | 31 | // Check if transaction is valid 32 | bool checkValidity() const 33 | { 34 | return amount >= 0 && amount <= MAX_AMOUNT && inputSize <= MAX_INPUT_SIZE; 35 | } 36 | 37 | // Return pointer to transaction's payload (CAUTION: This is behind the memory reserved for this struct!) 38 | unsigned char* inputPtr() 39 | { 40 | return (((unsigned char*)this) + sizeof(Transaction)); 41 | } 42 | 43 | // Return pointer to transaction's payload (CAUTION: This is behind the memory reserved for this struct!) 44 | const unsigned char* inputPtr() const 45 | { 46 | return (((const unsigned char*)this) + sizeof(Transaction)); 47 | } 48 | 49 | // Return pointer to signature (CAUTION: This is behind the memory reserved for this struct!) 50 | unsigned char* signaturePtr() 51 | { 52 | return ((unsigned char*)this) + sizeof(Transaction) + inputSize; 53 | } 54 | }; 55 | 56 | static_assert(sizeof(Transaction) == 32 + 32 + 8 + 4 + 2 + 2, "Something is wrong with the struct size."); 57 | 58 | #define REQUEST_TICK_TRANSACTIONS 29 59 | 60 | struct RequestedTickTransactions 61 | { 62 | unsigned int tick; 63 | unsigned char transactionFlags[NUMBER_OF_TRANSACTIONS_PER_TICK / 8]; 64 | }; 65 | 66 | #define REQUEST_TRANSACTION_INFO 26 67 | struct RequestedTransactionInfo 68 | { 69 | m256i txDigest; 70 | }; 71 | 72 | -------------------------------------------------------------------------------- /src/oracles/Price.h: -------------------------------------------------------------------------------- 1 | struct Price : public OracleBase 2 | { 3 | // TODO 4 | }; -------------------------------------------------------------------------------- /src/oracles/oracle_machines.h: -------------------------------------------------------------------------------- 1 | struct OracleReplyCommitTransaction : public Transaction 2 | { 3 | static constexpr unsigned char transactionType() 4 | { 5 | return 6; // TODO: Set actual value 6 | } 7 | 8 | unsigned long long queryIndex; 9 | m256i replyDigest; 10 | m256i replyKnowledgeProof; 11 | unsigned char signature[SIGNATURE_SIZE]; 12 | }; 13 | 14 | struct OracleReplyRevealTransactionPrefix : public Transaction 15 | { 16 | static constexpr unsigned char transactionType() 17 | { 18 | return 7; // TODO: Set actual value 19 | } 20 | 21 | unsigned long long queryIndex; 22 | }; 23 | 24 | struct OracleReplyRevealTransactionPostfix 25 | { 26 | unsigned char signature[SIGNATURE_SIZE]; 27 | }; -------------------------------------------------------------------------------- /src/platform/assert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(EXPECT_TRUE) 4 | 5 | // in gtest context, use EXPECT_TRUE as ASSERT 6 | #define ASSERT EXPECT_TRUE 7 | #elif defined(NDEBUG) 8 | 9 | // with NDEBUG, make ASSERT disappear 10 | #define ASSERT(expression) ((void)0) 11 | 12 | #else 13 | 14 | // otherwise, use addDebugMessageAssert() defined in debugging.h 15 | #define ASSERT(expression) (void)( \ 16 | (!!(expression)) || \ 17 | (addDebugMessageAssert(#expression, __FILE__, (unsigned int)(__LINE__)), 0) \ 18 | ) 19 | 20 | static void addDebugMessageAssert(const char* message, const char* file, const unsigned int lineNumber); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/platform/common_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef unsigned short CHAR16; 4 | -------------------------------------------------------------------------------- /src/platform/concurrency.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // Acquire lock, may block 6 | #define ACQUIRE_WITHOUT_DEBUG_LOGGING(lock) while (_InterlockedCompareExchange8(&lock, 1, 0)) _mm_pause() 7 | 8 | #ifdef NDEBUG 9 | 10 | // Acquire lock, may block 11 | #define ACQUIRE(lock) ACQUIRE_WITHOUT_DEBUG_LOGGING(lock) 12 | 13 | #else 14 | 15 | // Emit output if waiting long 16 | class BusyWaitingTracker 17 | { 18 | unsigned long long mStartTsc; 19 | unsigned long long mNextReportTscDelta; 20 | const char* mExpr; 21 | const char* mFile; 22 | unsigned int mLine; 23 | bool mTotalWaitTimeReport; 24 | public: 25 | BusyWaitingTracker(const char* expr, const char* file, unsigned int line); 26 | ~BusyWaitingTracker(); 27 | void pause(); 28 | }; 29 | 30 | // Acquire lock, may block and may log if it is blocked for a long time 31 | #define ACQUIRE(lock) \ 32 | if (_InterlockedCompareExchange8(&lock, 1, 0)) { \ 33 | BusyWaitingTracker bwt(#lock, __FILE__, __LINE__); \ 34 | while (_InterlockedCompareExchange8(&lock, 1, 0)) \ 35 | bwt.pause(); \ 36 | } 37 | 38 | #endif 39 | 40 | // Try to acquire lock and return if successful (without blocking) 41 | #define TRY_ACQUIRE(lock) (_InterlockedCompareExchange8(&lock, 1, 0) == 0) 42 | 43 | // Release lock 44 | #define RELEASE(lock) lock = 0 45 | 46 | 47 | #ifdef NDEBUG 48 | 49 | // Begin waiting loop (with short expected waiting time). Outputs to debug.log if waiting long and NDEBUG isn't defined. 50 | #define BEGIN_WAIT_WHILE(condition) \ 51 | while (condition) { 52 | 53 | // End waiting loop, corresponding to BEGIN_WAIT_WHILE(). 54 | #define END_WAIT_WHILE() _mm_pause(); } 55 | 56 | #else 57 | 58 | // Begin waiting loop (with short expected waiting time). Outputs to debug.log if waiting long and NDEBUG isn't defined. 59 | #define BEGIN_WAIT_WHILE(condition) \ 60 | if (condition) { \ 61 | BusyWaitingTracker bwt(#condition, __FILE__, __LINE__); \ 62 | while (condition) { 63 | 64 | // End waiting loop, corresponding to BEGIN_WAIT_WHILE(). 65 | #define END_WAIT_WHILE() bwt.pause(); } } 66 | 67 | #endif 68 | 69 | 70 | // Waiting loop with short expected waiting time. Outputs to debug.log if waiting long and NDEBUG isn't defined. 71 | #define WAIT_WHILE(condition) \ 72 | BEGIN_WAIT_WHILE(condition) \ 73 | END_WAIT_WHILE() 74 | 75 | #define ATOMIC_STORE8(target, val) _InterlockedExchange8(&target, val) 76 | #define ATOMIC_INC64(target) _InterlockedIncrement64(&target) 77 | #define ATOMIC_AND64(target, val) _InterlockedAnd64(&target, val) 78 | #define ATOMIC_STORE64(target, val) _InterlockedExchange64(&target, val) 79 | #define ATOMIC_LOAD64(target) _InterlockedCompareExchange64(&target, 0, 0) 80 | #define ATOMIC_ADD64(target, val) _InterlockedExchangeAdd64(&target, val) 81 | #define ATOMIC_MAX64(target, val) atomicMax64(&target, val) 82 | -------------------------------------------------------------------------------- /src/platform/concurrency_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // TODO: move dependencies to platform_* libs 4 | // TODO: move to cpp file in platform_common lib (independent of NDEBUG) 5 | 6 | #include 7 | #include "concurrency.h" 8 | #include "time_stamp_counter.h" 9 | #include "debugging.h" 10 | #include "system.h" 11 | 12 | #ifndef NDEBUG 13 | 14 | BusyWaitingTracker::BusyWaitingTracker(const char* expr, const char* file, unsigned int line) 15 | { 16 | #ifdef NO_UEFI 17 | if (!frequency) 18 | initTimeStampCounter(); 19 | #else 20 | ASSERT(frequency != 0); 21 | #endif 22 | mStartTsc = __rdtsc(); 23 | mNextReportTscDelta = frequency / 2; // first report after 0.5 seconds 24 | mExpr = expr; 25 | mFile = file; 26 | mLine = line; 27 | mTotalWaitTimeReport = false; 28 | } 29 | 30 | BusyWaitingTracker::~BusyWaitingTracker() 31 | { 32 | ASSERT(frequency != 0); 33 | if (mTotalWaitTimeReport) 34 | { 35 | CHAR16 msgBuffer[300]; 36 | const unsigned long long curTsc = __rdtsc(); 37 | setText(msgBuffer, L"Finished waiting for "); 38 | appendTextShortenBack(msgBuffer, mExpr, 50); 39 | appendText(msgBuffer, " for "); 40 | appendNumber(msgBuffer, (curTsc - mStartTsc) * 1000 / frequency, false); 41 | appendText(msgBuffer, " milliseconds in "); 42 | appendTextShortenFront(msgBuffer, mFile, 50); 43 | appendText(msgBuffer, " line "); 44 | appendNumber(msgBuffer, mLine, false); 45 | appendText(msgBuffer, ", processor #"); 46 | appendNumber(msgBuffer, getRunningProcessorID(), false); 47 | appendText(msgBuffer, ", tick "); 48 | appendNumber(msgBuffer, system.tick, false); 49 | addDebugMessage(msgBuffer); 50 | if (isMainProcessor()) 51 | printDebugMessages(); 52 | } 53 | } 54 | 55 | void BusyWaitingTracker::pause() 56 | { 57 | ASSERT(frequency != 0); 58 | const unsigned long long curTsc = __rdtsc(); 59 | if (curTsc > mStartTsc + mNextReportTscDelta) 60 | { 61 | CHAR16 msgBuffer[300]; 62 | setText(msgBuffer, L"Waiting for "); 63 | appendTextShortenBack(msgBuffer, mExpr, 50); 64 | appendText(msgBuffer, " for "); 65 | appendNumber(msgBuffer, mNextReportTscDelta * 1000 / frequency, false); 66 | appendText(msgBuffer, " milliseconds in "); 67 | appendTextShortenFront(msgBuffer, mFile, 50); 68 | appendText(msgBuffer, " line "); 69 | appendNumber(msgBuffer, mLine, false); 70 | appendText(msgBuffer, ", processor #"); 71 | appendNumber(msgBuffer, getRunningProcessorID(), false); 72 | addDebugMessage(msgBuffer); 73 | if (isMainProcessor()) 74 | printDebugMessages(); 75 | mNextReportTscDelta *= 2; 76 | mTotalWaitTimeReport = true; 77 | } 78 | _mm_pause(); 79 | } 80 | 81 | #endif 82 | // Atomic max 83 | void atomicMax64(long long* dest, long long value) 84 | { 85 | long long old = *dest; 86 | while (value > old) 87 | { 88 | long long prev = _InterlockedCompareExchange64(dest, value, old); 89 | if (prev == old) 90 | { 91 | break; 92 | } 93 | old = prev; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/platform/custom_stack.asm: -------------------------------------------------------------------------------- 1 | PUBLIC __customStackSetupAndRunFunc 2 | 3 | .code 4 | 5 | __customStackSetupAndRunFunc PROC 6 | ; arguments are passed in registers: 7 | ; - RCX newStackTop 8 | ; - RDX funcToCall 9 | ; - R8 dataToPass 10 | ; (x64 UEFI/Windows calling convention https://uefi.org/specs/UEFI/2.9_A/02_Overview.html?highlight=stack#detailed-calling-conventions) 11 | 12 | ; store rbp of caller 13 | push rbp 14 | 15 | ; replace stack and store old rsp on stack 16 | mov rbp, rsp ; save rsp in rbp for later pushing it onto new stack 17 | mov rsp, rcx ; use newStackTop as function call stack stack 18 | push rbp ; push rbp (old stack pointer) to stack 19 | 20 | ; prepare stack for call 21 | mov rbp, rsp ; save rsp from before function call in rbp 22 | sub rsp, 32 ; add shadow space required for function call 23 | and spl, -16 ; align stack at 16 24 | 25 | ; set parameter and call function 26 | mov rcx, r8 ; move r8 (data to pass) to rcx (first param of call) 27 | call rdx ; call funcToCall function pointer 28 | 29 | ; restore rbp and rsp of caller and return 30 | mov rsp, rbp ; restore rsp from before function call 31 | pop rsp ; get old stack pointer from stack (switching back to original stack) 32 | pop rbp ; restore rbp of caller 33 | ret 34 | __customStackSetupAndRunFunc ENDP 35 | 36 | END 37 | -------------------------------------------------------------------------------- /src/platform/custom_stack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "memory_util.h" 4 | #include "debugging.h" 5 | 6 | typedef unsigned int CustomStackSizeType; 7 | typedef EFI_AP_PROCEDURE CustomStackProcessorFunc; 8 | 9 | // Function call stack with custom size that can be used for running a function on it. Memory is allocated with allocPoolWithErrorLog(). 10 | class CustomStack 11 | { 12 | public: 13 | // Constructor (disabled because not called without MS CRT, you need to call init() to init) 14 | //CustomStack() 15 | //{ 16 | // init(); 17 | //} 18 | 19 | // Init (set all to 0). 20 | void init() 21 | { 22 | stackTop = nullptr; 23 | stackBottom = nullptr; 24 | setupFuncToCall = nullptr; 25 | setupDataToPass = nullptr; 26 | } 27 | 28 | // Allocate memory, return if successful 29 | bool alloc(CustomStackSizeType size) 30 | { 31 | free(); 32 | 33 | if (!allocPoolWithErrorLog(L"stackBottom", size, (void**)&stackBottom, __LINE__)) 34 | return false; 35 | 36 | stackTop = stackBottom + size; 37 | 38 | setMem(stackBottom, size, 0x55); 39 | 40 | return true; 41 | } 42 | 43 | // Free memory 44 | void free() 45 | { 46 | if (stackBottom) 47 | { 48 | freePool(stackBottom); 49 | stackBottom = nullptr; 50 | } 51 | stackTop = nullptr; 52 | } 53 | 54 | // Get maximum stack size used so far 55 | CustomStackSizeType maxStackUsed() const 56 | { 57 | ASSERT(stackTop >= stackBottom); 58 | for (char* p = stackBottom; p < stackTop; ++p) 59 | { 60 | if (*p != 0x55) 61 | return CustomStackSizeType(stackTop - p); 62 | } 63 | return 0; 64 | } 65 | 66 | // Prepare function call with run() 67 | void setupFunction(CustomStackProcessorFunc functionToCall, void* dataToPassToFunction) 68 | { 69 | setupFuncToCall = functionToCall; 70 | setupDataToPass = dataToPassToFunction; 71 | } 72 | 73 | // Run function using custom stack allocated with alloc(), function is set with setup() 74 | static void runFunction(void* data); 75 | 76 | private: 77 | char* stackTop; 78 | char* stackBottom; 79 | CustomStackProcessorFunc setupFuncToCall; 80 | void* setupDataToPass; 81 | }; 82 | 83 | extern "C" void __customStackSetupAndRunFunc(void* newStackTop, CustomStackProcessorFunc funcToCall, void* dataToPass); 84 | 85 | void CustomStack::runFunction(void* data) 86 | { 87 | ASSERT(data != nullptr); 88 | CustomStack* me = reinterpret_cast(data); 89 | 90 | ASSERT(me->stackTop != nullptr); 91 | ASSERT(me->stackBottom != nullptr); 92 | ASSERT(me->setupFuncToCall != nullptr); 93 | ASSERT(me->stackTop > me->stackBottom); 94 | 95 | __customStackSetupAndRunFunc(me->stackTop, me->setupFuncToCall, me->setupDataToPass); 96 | } 97 | 98 | -------------------------------------------------------------------------------- /src/platform/debugging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "assert.h" 4 | #include "concurrency.h" 5 | #include "file_io.h" 6 | 7 | 8 | #if defined(EXPECT_TRUE) 9 | 10 | // In gtest context, print with standard library 11 | static void addDebugMessage(const CHAR16* msg) 12 | { 13 | wprintf(L"%ls\n", msg); 14 | } 15 | 16 | // In gtest context, this is noop 17 | static void printDebugMessages() 18 | { 19 | } 20 | 21 | #elif defined(NDEBUG) 22 | 23 | // static void addDebugMessage(const CHAR16* msg){} // empty impl 24 | #else 25 | 26 | static CHAR16 debugMessage[128][16384]; 27 | static int debugMessageCount = 0; 28 | static char volatile debugLogLock = 0; 29 | static bool volatile debugLogOnlyMainProcessorRunning = true; 30 | static bool forceLogToConsoleAsAddDebugMessage = false; 31 | 32 | #define WRITE_DEBUG_MESSAGES_TO_FILE 1 33 | 34 | // Print debug messages added with addDebugMessage(). 35 | // CAUTION: Can only be called from main processor thread. Otherwise there is a high risk of crashing. 36 | static void printDebugMessages() 37 | { 38 | if (!debugMessageCount) 39 | return; 40 | ACQUIRE_WITHOUT_DEBUG_LOGGING(debugLogLock); 41 | 42 | // Write to console first 43 | for (int i = 0; i < debugMessageCount; i++) 44 | { 45 | // Make sure there is a newline at the end 46 | unsigned int strLen = stringLength(debugMessage[i]); 47 | if (debugMessage[i][strLen - 1] != L'\n') 48 | { 49 | appendText(debugMessage[i], L"\r\n"); 50 | strLen += 2; 51 | } 52 | 53 | // Write to console 54 | outputStringToConsole(debugMessage[i]); 55 | } 56 | 57 | #if WRITE_DEBUG_MESSAGES_TO_FILE 58 | // Open debug log file and seek to the end of file for appending 59 | EFI_STATUS status; 60 | EFI_FILE_PROTOCOL* file = nullptr; 61 | if (!root) 62 | { 63 | } 64 | else if (status = root->Open(root, (void**)&file, (CHAR16*)L"debug.log", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0)) 65 | { 66 | setText(::message, L"EFI_FILE_PROTOCOL.Open() failed in printDebugMessages() with status "); 67 | appendErrorStatus(::message, status); 68 | appendText(::message, L"\r\n"); 69 | outputStringToConsole(::message); 70 | file = nullptr; 71 | } 72 | else 73 | { 74 | if (status = root->SetPosition(file, 0xFFFFFFFFFFFFFFFF)) 75 | { 76 | setText(::message, L"EFI_FILE_PROTOCOL.SetPosition() failed in printDebugMessages() with status "); 77 | appendErrorStatus(::message, status); 78 | appendText(::message, L"\r\n"); 79 | outputStringToConsole(::message); 80 | file->Close(file); 81 | file = nullptr; 82 | } 83 | } 84 | 85 | if (file) 86 | { 87 | // Write to log file 88 | for (int i = 0; i < debugMessageCount; i++) 89 | { 90 | unsigned int strLen = stringLength(debugMessage[i]); 91 | char* buffer = (char*)debugMessage[i]; 92 | unsigned long long totalSize = strLen * sizeof(CHAR16); 93 | unsigned long long writtenSize = 0; 94 | while (writtenSize < totalSize) 95 | { 96 | unsigned long long size = (WRITING_CHUNK_SIZE <= (totalSize - writtenSize) ? WRITING_CHUNK_SIZE : (totalSize - writtenSize)); 97 | status = file->Write(file, &size, &buffer[writtenSize]); 98 | if (status 99 | || size != (WRITING_CHUNK_SIZE <= (totalSize - writtenSize) ? WRITING_CHUNK_SIZE : (totalSize - writtenSize))) 100 | { 101 | setText(::message, L"EFI_FILE_PROTOCOL.Write() failed in printDebugMessages() with status "); 102 | appendErrorStatus(::message, status); 103 | appendText(::message, L"\r\n"); 104 | outputStringToConsole(::message); 105 | 106 | goto closeFile; 107 | } 108 | writtenSize += size; 109 | } 110 | } 111 | 112 | closeFile: 113 | file->Close(file); 114 | } 115 | #endif 116 | 117 | debugMessageCount = 0; 118 | RELEASE(debugLogLock); 119 | } 120 | 121 | // Add a message for logging from arbitrary thread 122 | static void addDebugMessage(const CHAR16* msg) 123 | { 124 | ACQUIRE_WITHOUT_DEBUG_LOGGING(debugLogLock); 125 | if (debugMessageCount < 128) 126 | { 127 | setText(debugMessage[debugMessageCount], msg); 128 | ++debugMessageCount; 129 | } 130 | RELEASE(debugLogLock); 131 | if (debugLogOnlyMainProcessorRunning) 132 | { 133 | debugLogOnlyMainProcessorRunning = false; 134 | printDebugMessages(); 135 | debugLogOnlyMainProcessorRunning = true; 136 | } 137 | } 138 | 139 | // Add a assert message for logging from arbitrary thread 140 | static void addDebugMessageAssert(const char* message, const char* file, const unsigned int lineNumber) 141 | { 142 | ACQUIRE_WITHOUT_DEBUG_LOGGING(debugLogLock); 143 | if (debugMessageCount < 128) 144 | { 145 | setText(debugMessage[debugMessageCount], L"Assertion failed: "); 146 | appendText(debugMessage[debugMessageCount], message); 147 | appendText(debugMessage[debugMessageCount], " at line "); 148 | appendNumber(debugMessage[debugMessageCount], lineNumber, FALSE); 149 | appendText(debugMessage[debugMessageCount], " in "); 150 | appendText(debugMessage[debugMessageCount], file); 151 | ++debugMessageCount; 152 | } 153 | RELEASE(debugLogLock); 154 | if (debugLogOnlyMainProcessorRunning) 155 | { 156 | debugLogOnlyMainProcessorRunning = false; 157 | printDebugMessages(); 158 | debugLogOnlyMainProcessorRunning = true; 159 | } 160 | } 161 | 162 | #endif 163 | -------------------------------------------------------------------------------- /src/platform/global_var.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // If multiple compile units are used, having all globals declared as static causes 4 | // trouble if code is shared between compile units. Thus, globals need to be declared 5 | // extern and defined in only one compile unit. 6 | 7 | #if defined(SINGLE_COMPILE_UNIT) 8 | 9 | // single compile unit -> make static 10 | #define GLOBAL_VAR_DECL static 11 | #define GLOBAL_VAR_INIT(val) =val 12 | 13 | #else 14 | 15 | // multiple compile units -> only define in one file (declare as extern in the others) 16 | #if defined(DEFINE_VARIABLES_SHARED_BETWEEN_COMPILE_UNITS) 17 | #define GLOBAL_VAR_DECL 18 | #define GLOBAL_VAR_INIT(val) =val 19 | #else 20 | #define GLOBAL_VAR_DECL extern 21 | #define GLOBAL_VAR_INIT(val) 22 | #endif 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/platform/memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef NO_UEFI 4 | 5 | // Defined in test/stdlib_impl.cpp 6 | 7 | void setMem(void* buffer, unsigned long long size, unsigned char value); 8 | 9 | void copyMem(void* destination, const void* source, unsigned long long length); 10 | 11 | bool allocatePool(unsigned long long size, void** buffer); 12 | 13 | void freePool(void* buffer); 14 | 15 | #else 16 | 17 | #include 18 | 19 | static inline void setMem(void* buffer, unsigned long long size, unsigned char value) 20 | { 21 | bs->SetMem(buffer, size, value); 22 | } 23 | 24 | static inline void copyMem(void* destination, const void* source, unsigned long long length) 25 | { 26 | bs->CopyMem(destination, (void*)source, length); 27 | } 28 | 29 | static inline bool allocatePool(unsigned long long size, void** buffer) 30 | { 31 | return bs->AllocatePool(EfiRuntimeServicesData, size, buffer) == EFI_SUCCESS; 32 | } 33 | 34 | static inline void freePool(void* buffer) 35 | { 36 | bs->FreePool(buffer); 37 | } 38 | 39 | static inline void closeEvent(EFI_EVENT Event) 40 | { 41 | bs->CloseEvent(Event); 42 | } 43 | 44 | static inline EFI_STATUS createEvent(unsigned int Type, EFI_TPL NotifyTpl, void* NotifyFunction, void* NotifyContext, EFI_EVENT* Event) 45 | { 46 | return bs->CreateEvent(Type, NotifyTpl, NotifyFunction, NotifyContext, Event); 47 | } 48 | 49 | 50 | // Function to get the current free RAM size 51 | unsigned long long GetFreeRAMSize() 52 | { 53 | unsigned long long MemoryMapSize = 0; 54 | EFI_MEMORY_DESCRIPTOR* MemoryMap = nullptr; 55 | unsigned long long MapKey = 0; 56 | unsigned long long DescriptorSize = 0; 57 | unsigned int DescriptorVersion = 0; 58 | 59 | // First call to get the size of the memory map 60 | EFI_STATUS status = bs->GetMemoryMap(&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion); 61 | if (status == EFI_BUFFER_TOO_SMALL) 62 | { 63 | if (!allocatePool(MemoryMapSize, (void**)&MemoryMap)) 64 | { 65 | return 0; 66 | } 67 | 68 | status = bs->GetMemoryMap(&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion); 69 | } 70 | 71 | if (status != EFI_SUCCESS) 72 | { 73 | if (NULL != MemoryMap) 74 | { 75 | freePool(MemoryMap); 76 | } 77 | return 0; 78 | } 79 | 80 | unsigned long long freeRAM = 0; 81 | 82 | unsigned long long count = MemoryMapSize / DescriptorSize; 83 | for (unsigned int i = 0; i < count; ++i) 84 | { 85 | EFI_MEMORY_DESCRIPTOR* desc = (EFI_MEMORY_DESCRIPTOR*)((char*)MemoryMap + (i * DescriptorSize)); 86 | 87 | if (desc->Type == EfiConventionalMemory) 88 | { 89 | freeRAM += desc->NumberOfPages * 4096; // Each page is 4KB 90 | } 91 | } 92 | 93 | freePool(MemoryMap); 94 | return freeRAM; 95 | } 96 | 97 | 98 | // Function to get the largest free consecutive memory block size 99 | unsigned long long GetLargestFreeConsecutiveMemory() 100 | { 101 | unsigned long long MemoryMapSize = 0; 102 | EFI_MEMORY_DESCRIPTOR* MemoryMap = nullptr; 103 | unsigned long long MapKey = 0; 104 | unsigned long long DescriptorSize = 0; 105 | unsigned int DescriptorVersion = 0; 106 | 107 | // First call to get the size of the memory map 108 | EFI_STATUS status = bs->GetMemoryMap(&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion); 109 | if (status == EFI_BUFFER_TOO_SMALL) 110 | { 111 | // Allocate memory for the memory map 112 | if (!allocatePool(MemoryMapSize, (void**)&MemoryMap)) 113 | { 114 | return 0; 115 | } 116 | 117 | // Second call to get the actual memory map 118 | status = bs->GetMemoryMap(&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion); 119 | } 120 | 121 | if (status != EFI_SUCCESS) 122 | { 123 | if (MemoryMap) 124 | { 125 | freePool(MemoryMap); 126 | } 127 | return 0; 128 | } 129 | 130 | unsigned long long largestFreeBlock = 0; 131 | 132 | // Calculate the largest free consecutive memory block size 133 | unsigned long long count = MemoryMapSize / DescriptorSize; 134 | for (unsigned int i = 0; i < count; ++i) 135 | { 136 | EFI_MEMORY_DESCRIPTOR* desc = (EFI_MEMORY_DESCRIPTOR*)((char*)MemoryMap + (i * DescriptorSize)); 137 | 138 | if (desc->Type == EfiConventionalMemory) 139 | { 140 | unsigned long long blockSize = desc->NumberOfPages * 4096; // Each page is 4KB 141 | if (blockSize > largestFreeBlock) 142 | { 143 | largestFreeBlock = blockSize; 144 | } 145 | } 146 | } 147 | 148 | freePool(MemoryMap); 149 | return largestFreeBlock; 150 | } 151 | #endif 152 | 153 | // This should to be optimized if used in non-debugging context (using unsigned long long comparison as much as possible) 154 | static inline bool isZero(const void* ptr, unsigned long long size) 155 | { 156 | const char* cPtr = (const char*)ptr; 157 | for (unsigned long long i = 0; i < size; ++i) 158 | { 159 | if (cPtr[i] != 0) 160 | return false; 161 | } 162 | return true; 163 | } -------------------------------------------------------------------------------- /src/platform/memory_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "console_logging.h" 4 | #include 5 | #include "memory.h" 6 | 7 | #ifdef NO_UEFI 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | static bool allocPoolWithErrorLog(const wchar_t* name, const unsigned long long size, void** buffer, const int LINE) 14 | { 15 | *buffer = malloc(size); 16 | if (*buffer == nullptr) 17 | { 18 | printf("Memory allocation failed for %ls on line %u\n", name, LINE); 19 | return false; 20 | } 21 | 22 | // Zero out allocated memory 23 | setMem(*buffer, size, 0); 24 | 25 | return true; 26 | } 27 | 28 | #else 29 | 30 | static bool allocPoolWithErrorLog(const CHAR16* name, const unsigned long long size, void** buffer, const int LINE) 31 | { 32 | EFI_STATUS status; 33 | CHAR16 message[512]; 34 | constexpr EFI_MEMORY_TYPE poolType = EfiRuntimeServicesData; 35 | 36 | // Check for invalid input 37 | if (buffer == nullptr || size == 0) { 38 | logStatusAndMemInfoToConsole(L"Invalid buffer pointer or size", EFI_INVALID_PARAMETER, __LINE__, size); 39 | return false; 40 | } 41 | 42 | status = bs->AllocatePool(poolType, size, buffer); 43 | if (status != EFI_SUCCESS) 44 | { 45 | setText(message, L"EFI_BOOT_SERVICES.AllocatePool() fails for "); 46 | appendText(message, name); 47 | appendText(message, L" with size "); 48 | appendNumber(message, size, TRUE); 49 | logStatusAndMemInfoToConsole(message, status, LINE, size); 50 | return false; 51 | } 52 | #ifndef NDEBUG 53 | else { 54 | setText(message, L"EFI_BOOT_SERVICES.AllocatePool() completed for "); 55 | appendText(message, name); 56 | appendText(message, L" with size "); 57 | appendNumber(message, size, TRUE); 58 | logStatusAndMemInfoToConsole(message, status, LINE, size); 59 | } 60 | #endif 61 | // Zero out allocated memory 62 | if (*buffer != nullptr) { 63 | setMem(*buffer, size, 0); 64 | } 65 | return true; 66 | } 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/platform/random.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | inline static unsigned int random(const unsigned int range) 6 | { 7 | unsigned int value; 8 | _rdrand32_step(&value); 9 | 10 | return value % range; 11 | } 12 | 13 | inline static void random64(unsigned long long* dst) 14 | { 15 | ASSERT(dst != NULL); 16 | _rdrand64_step(dst); 17 | } 18 | 19 | inline static void random256(m256i* dst) 20 | { 21 | ASSERT(dst != NULL); 22 | dst->setRandomValue(); 23 | } -------------------------------------------------------------------------------- /src/platform/read_write_lock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "debugging.h" 5 | #include "concurrency.h" 6 | 7 | // Lock that allows multiple readers but only one writer. 8 | // Priorizes writers, that is, additional readers can only gain access if no writer is waiting. 9 | class ReadWriteLock 10 | { 11 | public: 12 | // Constructor (disabled because not called without MS CRT, you need to call reset() to init) 13 | //ReadWriteLock() 14 | //{ 15 | // reset(); 16 | //} 17 | 18 | // Set lock fully unlocked state. 19 | void reset() 20 | { 21 | readers = 0; 22 | writersWaiting = 0; 23 | } 24 | 25 | // Aquire lock for reading (wait if needed). 26 | void acquireRead() 27 | { 28 | ASSERT(readers >= -1); 29 | ASSERT(writersWaiting >= 0); 30 | 31 | // Wait until getting read access 32 | WAIT_WHILE(!tryAcquireRead()); 33 | } 34 | 35 | // Try to aquire lock for reading without waiting. Return true if lock has been acquired. 36 | bool tryAcquireRead() 37 | { 38 | ASSERT(readers >= -1); 39 | ASSERT(writersWaiting >= 0); 40 | 41 | // Prioritize writers over readers (do not grant access for new reader if writer is waiting) 42 | if (writersWaiting) 43 | return false; 44 | 45 | // It may happen that writersWaiting changes before the read lock is acquired below. But this should 46 | // be rare and does not justify the overhead of additional locking. 47 | 48 | // If not acquired by writer (would be -1 readers), acquire read access by incrementing number of readers. 49 | // Below is the atomic version of the following: 50 | // 51 | // if (readers >= 0) { 52 | // ++readers; 53 | // return true; 54 | // } else { 55 | // return false; 56 | // } 57 | long currentReaders, newReaders; 58 | while (1) 59 | { 60 | // Get number of current readers and return false if locked by writer 61 | currentReaders = readers; 62 | if (currentReaders < 0) 63 | return false; 64 | 65 | // Increment readers counter. 66 | // If readers is changed after setting currentReaders, the _InterlockedCompareExchange will fail 67 | // and we retry in the next iteration of the while loop. 68 | newReaders = currentReaders + 1; 69 | if (_InterlockedCompareExchange(&readers, newReaders, currentReaders) == currentReaders) 70 | return true; 71 | } 72 | } 73 | 74 | // Release read lock. Needs to follow corresponding acquireRead() or successful tryAcquireRead(). 75 | void releaseRead() 76 | { 77 | ASSERT(readers > 0); 78 | ASSERT(writersWaiting >= 0); 79 | 80 | _InterlockedDecrement(&readers); 81 | } 82 | 83 | // Aquire lock for writing (wait if needed). 84 | void acquireWrite() 85 | { 86 | ASSERT(readers >= -1); 87 | ASSERT(writersWaiting >= 0); 88 | 89 | // Indicate that one more writer is waiting for access 90 | // -> don't grant access to additional readers in tryAcquireRead() in concurrent threads 91 | _InterlockedIncrement(&writersWaiting); 92 | 93 | // Wait until getting write access 94 | WAIT_WHILE(!tryAcquireWrite()); 95 | 96 | // Writer got access -> decrement counter of writers waiting for access 97 | _InterlockedDecrement(&writersWaiting); 98 | } 99 | 100 | // Try to aquire lock for writing without waiting. Return true if lock has been acquired. 101 | bool tryAcquireWrite() 102 | { 103 | ASSERT(readers >= -1); 104 | ASSERT(writersWaiting >= 0); 105 | 106 | // If no readers or writers, lock for writing. 107 | // Below is the atomic version of the following: 108 | // 109 | // if (readers == 0) 110 | // { 111 | // readers = -1; 112 | // return true; 113 | // } 114 | if (_InterlockedCompareExchange(&readers, -1, 0) == 0) 115 | return true; 116 | 117 | return false; 118 | } 119 | 120 | // Release write lock. Needs to follow corresponding acquireWrite() or successful tryAcquireWrite(). 121 | void releaseWrite() 122 | { 123 | ASSERT(readers == -1); 124 | ASSERT(writersWaiting >= 0); 125 | readers = 0; 126 | } 127 | 128 | // Return if currently locked for writing. Note that the status may change any time. 129 | bool isLockedForWriting() const 130 | { 131 | ASSERT(readers >= -1); 132 | ASSERT(writersWaiting >= 0); 133 | return readers == -1; 134 | } 135 | 136 | // Return number of reader who have currently locked the resource or -1 if locked for writing. Note that the status may change any time. 137 | long getCurrentReaderLockCount() const 138 | { 139 | ASSERT(readers >= -1); 140 | ASSERT(writersWaiting >= 0); 141 | return readers; 142 | } 143 | 144 | private: 145 | // Positive values means number of readers using having acquired a read lock; -1 means writer has acquired lock; 0 mean no lock is active 146 | volatile long readers; 147 | 148 | // Number of writers waiting for lock (>= 0) 149 | volatile long writersWaiting; 150 | }; 151 | -------------------------------------------------------------------------------- /src/platform/stack_size_tracker.h: -------------------------------------------------------------------------------- 1 | // Not used anymore because custom_stack.h is easier to use provides same/more features -> may be removed 2 | #pragma once 3 | 4 | #include "debugging.h" 5 | 6 | 7 | // Define StackSizeTracker, recommended to use in global scope 8 | #define DEFINE_STACK_SIZE_TRACKER(name) static StackSizeTracker name 9 | 10 | // Init stack size tracker, use this as in thread entry point function 11 | #define INIT_STACK_SIZE_TRACKER(name) name.initStackTop(_AddressOfReturnAddress()) 12 | 13 | // Update tracker, call this in functions called by thread 14 | #define UPDATE_STACK_SIZE_TRACKER(name) name.update() 15 | 16 | 17 | // Track size of function call stack used (x86 stack grows downwards) 18 | // This is not byte-accurate, but approximate. 19 | class StackSizeTracker 20 | { 21 | public: 22 | static constexpr unsigned long long uninitialized = -1; 23 | 24 | StackSizeTracker() 25 | { 26 | reset(); 27 | } 28 | 29 | void reset() 30 | { 31 | pTop = uninitialized; 32 | pBottom = uninitialized; 33 | } 34 | 35 | // Call this once passing the top of the stack (first variable at entry point) 36 | void initStackTop(void* stackTop) 37 | { 38 | unsigned long long pTopNew = (unsigned long long)stackTop; 39 | if (pTop != uninitialized && pBottom != uninitialized && pTop != pTopNew) 40 | { 41 | // Keep max size value if the stack tracker is reused with other tack top 42 | ASSERT(pTop >= pBottom); 43 | unsigned long long maxSize = pTop - pBottom; 44 | pBottom = pTopNew - maxSize; 45 | } 46 | pTop = pTopNew; 47 | } 48 | 49 | // Update the maximum used stack size. Call this in deep functions 50 | void update() 51 | { 52 | unsigned long long pCurBottom = (unsigned long long) & pCurBottom; 53 | if (pCurBottom < pBottom) 54 | pBottom = pCurBottom; 55 | } 56 | 57 | // Maximum of stack size used based on calls of update() and initStackTop(), 58 | // or unitialized if one of the two functions has not been called. 59 | unsigned long long maxStackSize() const 60 | { 61 | if (pTop == uninitialized || pBottom == uninitialized) 62 | return uninitialized; 63 | ASSERT(pTop >= pBottom); 64 | return pTop - pBottom; 65 | } 66 | 67 | private: 68 | unsigned long long pTop, pBottom; 69 | }; 70 | -------------------------------------------------------------------------------- /src/platform/time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "global_var.h" 4 | #include 5 | #include "memory.h" 6 | #include 7 | 8 | 9 | GLOBAL_VAR_DECL EFI_TIME utcTime; 10 | 11 | 12 | #ifdef NO_UEFI 13 | 14 | // Defined in test/stdlib_impl.cpp 15 | void updateTime(); 16 | 17 | #else 18 | 19 | #include 20 | #include 21 | 22 | static void updateTime() 23 | { 24 | ASSERT(isMainProcessor()); 25 | EFI_TIME newTime; 26 | if (!rs->GetTime(&newTime, NULL)) 27 | { 28 | copyMem(&utcTime, &newTime, sizeof(utcTime)); 29 | } 30 | } 31 | 32 | #endif 33 | 34 | static void initTime() 35 | { 36 | setMem(&utcTime, sizeof(utcTime), 0); 37 | utcTime.Year = 2022; 38 | utcTime.Month = 4; 39 | utcTime.Day = 13; 40 | utcTime.Hour = 12; 41 | 42 | updateTime(); 43 | } 44 | 45 | inline int dayIndex(unsigned int year, unsigned int month, unsigned int day) // 0 = Wednesday 46 | { 47 | return (year += (2000 - (month = (month + 9) % 12) / 10)) * 365 + year / 4 - year / 100 + year / 400 + (month * 306 + 5) / 10 + day - 1; 48 | } 49 | 50 | inline long long ms(unsigned char year, unsigned char month, unsigned char day, unsigned char hour, unsigned char minute, unsigned char second, unsigned short millisecond) 51 | { 52 | return (((((long long)dayIndex(year, month, day)) * 24 + hour) * 60 + minute) * 60 + second) * 1000 + millisecond; 53 | } 54 | 55 | #ifndef NO_UEFI 56 | inline unsigned long long now_ms() 57 | { 58 | // utcTime is updated on main thread - because only main thread can do it 59 | return ms(unsigned char(utcTime.Year % 100), utcTime.Month, utcTime.Day, utcTime.Hour, utcTime.Minute, utcTime.Second, utcTime.Nanosecond / 1000000); 60 | } 61 | #else 62 | unsigned long long now_ms(); 63 | #endif -------------------------------------------------------------------------------- /src/platform/time_stamp_counter.h: -------------------------------------------------------------------------------- 1 | // The TSC (time stamp counter) is a x86 register counting CPU clock cycles. 2 | // Given several assumptions such as no CPU seed change and no hibernating, it 3 | // can be used to measure run-time with low overhead. 4 | // See https://en.wikipedia.org/wiki/Time_Stamp_Counter 5 | // TSC of different processors may be out of sync. 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "global_var.h" 12 | #include "console_logging.h" 13 | 14 | #include 15 | 16 | // frequency of CPU clock 17 | GLOBAL_VAR_DECL unsigned long long frequency GLOBAL_VAR_INIT(0); 18 | 19 | 20 | static void initTimeStampCounter() 21 | { 22 | int cpuInfo[4]; 23 | __cpuid(cpuInfo, 0x15); 24 | if (cpuInfo[2] == 0 || cpuInfo[1] == 0 || cpuInfo[0] == 0) 25 | { 26 | logToConsole(L"Theoretical TSC frequency = n/a."); 27 | } 28 | else 29 | { 30 | setText(message, L"Theoretical TSC frequency = "); 31 | appendNumber(message, ((unsigned long long)cpuInfo[1]) * cpuInfo[2] / cpuInfo[0], TRUE); 32 | appendText(message, L" Hz."); 33 | logToConsole(message); 34 | } 35 | 36 | frequency = __rdtsc(); 37 | sleepMilliseconds(1000); 38 | frequency = __rdtsc() - frequency; 39 | setText(message, L"Practical TSC frequency = "); 40 | appendNumber(message, frequency, TRUE); 41 | appendText(message, L" Hz."); 42 | logToConsole(message); 43 | } 44 | -------------------------------------------------------------------------------- /src/private_settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | ////////// Private Settings \\\\\\\\\\ 4 | 5 | // Do NOT share the data of "Private Settings" section with anybody!!! 6 | 7 | #define OPERATOR "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" 8 | 9 | static unsigned char computorSeeds[][55 + 1] = { 10 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 11 | }; 12 | 13 | // Enter static IPs of peers (ideally at least 4 including your own IP) to disseminate them to other peers. 14 | // You can find current peer IPs at https://app.qubic.li/network/live 15 | static const unsigned char knownPublicPeers[][4] = { 16 | {127, 0, 0, 1}, // REMOVE THIS ENTRY AND REPLACE IT WITH YOUR OWN IP ADDRESSES 17 | }; 18 | 19 | /* Whitelisting has been disabled, as requesting the IP of the incoming connection freezes the node occasionally 20 | // Enter static IPs that shall be prioritized in incoming connection 21 | // There are connection slots reserved for those whitelist IPs 22 | static const unsigned char whiteListPeers[][4] = { 23 | {127, 0, 0, 1}, // REMOVE THIS ENTRY AND REPLACE IT WITH YOUR OWN IP ADDRESSES 24 | }; 25 | */ 26 | 27 | #define ENABLE_STANDARD_LOGGING 0 // logging universe + spectrum 28 | #define ENABLE_SMART_CONTRACT_LOGGING 0// logging smart contract 29 | 30 | #if !ENABLE_STANDARD_LOGGING && ENABLE_SMART_CONTRACT_LOGGING 31 | #error ENABLE_SMART_CONTRACT_LOGGING 1 also requires ENABLE_STANDARD_LOGGING 1 32 | #endif 33 | 34 | #if ENABLE_STANDARD_LOGGING 35 | #define LOG_UNIVERSE 1 // all universe activities/events (incl: issue, ownership/possession changes) 36 | #define LOG_SPECTRUM 1 // all spectrum activities/events (incl: transfers, burn, dust cleaning) 37 | #else 38 | #define LOG_UNIVERSE 0 39 | #define LOG_SPECTRUM 0 40 | #endif 41 | #if ENABLE_SMART_CONTRACT_LOGGING 42 | #define LOG_CONTRACT_ERROR_MESSAGES 1 43 | #define LOG_CONTRACT_WARNING_MESSAGES 1 44 | #define LOG_CONTRACT_INFO_MESSAGES 1 45 | #define LOG_CONTRACT_DEBUG_MESSAGES 1 46 | #define LOG_CUSTOM_MESSAGES 1 47 | #else 48 | #define LOG_CONTRACT_ERROR_MESSAGES 0 49 | #define LOG_CONTRACT_WARNING_MESSAGES 0 50 | #define LOG_CONTRACT_INFO_MESSAGES 0 51 | #define LOG_CONTRACT_DEBUG_MESSAGES 0 52 | #define LOG_CUSTOM_MESSAGES 0 53 | #endif 54 | static unsigned long long logReaderPasscodes[4] = { 55 | 0, 0, 0, 0 // REMOVE THIS ENTRY AND REPLACE IT WITH YOUR OWN RANDOM NUMBERS IN [0..18446744073709551615] RANGE IF LOGGING IS ENABLED 56 | }; 57 | 58 | // Mode for auto save ticks: 59 | // 0: disable 60 | // 1: save tick storage every TICK_STORAGE_AUTOSAVE_TICK_PERIOD ticks, only AUX mode 61 | // 2: save tick storage only when pressing the `F8` key or it is requested remotely 62 | #define TICK_STORAGE_AUTOSAVE_MODE 0 63 | // NOTE: Strategy to pick TICK_STORAGE_AUTOSAVE_TICK_PERIOD: 64 | // Although the default value is 1000, there is a chance that your node can be misaligned at tick XXXX2000,XXXX3000,XXXX4000,... 65 | // Perform state persisting when your node is misaligned will also make your node misaligned after resuming. 66 | // Thus, picking various TICK_STORAGE_AUTOSAVE_TICK_PERIOD numbers across AUX nodes is recommended. 67 | // some suggested prime numbers you can try: 971 977 983 991 997 68 | #define TICK_STORAGE_AUTOSAVE_TICK_PERIOD 1000 -------------------------------------------------------------------------------- /src/public_settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | ////////// Public Settings \\\\\\\\\\ 4 | 5 | ////////////////////////////////////////////////////////////////////////// 6 | // Config options for operators 7 | 8 | // no need to define AVX512 here anymore, just change the project settings to use the AVX512 version 9 | // random seed is now obtained from spectrumDigests 10 | 11 | #define MAX_NUMBER_OF_PROCESSORS 32 12 | #define NUMBER_OF_SOLUTION_PROCESSORS 12 13 | 14 | // Number of buffers available for executing contract functions in parallel; having more means reserving a bit more RAM (+1 = +32 MB) 15 | // and less waiting in request processors if there are more parallel contract function requests. The maximum value that may make sense 16 | // is MAX_NUMBER_OF_PROCESSORS - 1. 17 | #define NUMBER_OF_CONTRACT_EXECUTION_BUFFERS 10 18 | 19 | #define USE_SCORE_CACHE 1 20 | #define SCORE_CACHE_SIZE 2000000 // the larger the better 21 | #define SCORE_CACHE_COLLISION_RETRIES 20 // number of retries to find entry in cache in case of hash collision 22 | 23 | // Number of ticks from prior epoch that are kept after seamless epoch transition. These can be requested after transition. 24 | #define TICKS_TO_KEEP_FROM_PRIOR_EPOCH 100 25 | 26 | #define TARGET_TICK_DURATION 1500 27 | #define TRANSACTION_SPARSENESS 1 28 | 29 | // Below are 2 variables that are used for auto-F5 feature: 30 | #define AUTO_FORCE_NEXT_TICK_THRESHOLD 0ULL // Multiplier of TARGET_TICK_DURATION for the system to detect "F5 case" | set to 0 to disable 31 | // to prevent bad actor causing misalignment. 32 | // depends on actual tick time of the network, operators should set this number randomly in this range [12, 26] 33 | // eg: If AUTO_FORCE_NEXT_TICK_THRESHOLD is 8 and TARGET_TICK_DURATION is 2, then the system will start "auto F5 procedure" after 16 seconds after receveing 451+ votes 34 | 35 | #define PROBABILITY_TO_FORCE_EMPTY_TICK 800 // after (AUTO_FORCE_NEXT_TICK_THRESHOLD x TARGET_TICK_DURATION) seconds, the node will start casting F5 randomly every second with this probability 36 | // to prevent bad actor causing misalignment, operators should set this number in this range [700, 900] (aka [7%, 9%]) 37 | 38 | #define NEXT_TICK_TIMEOUT_THRESHOLD 5ULL // Multiplier of TARGET_TICK_DURATION for the system to discard next tick in tickData. 39 | // This will lead to zero `expectedNextTickTransactionDigest` in consensus 40 | 41 | #define PEER_REFRESHING_PERIOD 120000ULL 42 | #if AUTO_FORCE_NEXT_TICK_THRESHOLD != 0 43 | static_assert(NEXT_TICK_TIMEOUT_THRESHOLD < AUTO_FORCE_NEXT_TICK_THRESHOLD, "Timeout threshold must be smaller than auto F5 threshold"); 44 | static_assert(AUTO_FORCE_NEXT_TICK_THRESHOLD* TARGET_TICK_DURATION >= PEER_REFRESHING_PERIOD, "AutoF5 threshold must be greater than PEER_REFRESHING_PERIOD"); 45 | #endif 46 | // Set START_NETWORK_FROM_SCRATCH to 0 if you start the node for syncing with the already ticking network. 47 | // If this flag is 1, it indicates that the whole network (all 676 IDs) will start from scratch and agree that the very first tick time will be set at (2022-04-13 Wed 12:00:00.000UTC). 48 | // If this flag is 0, the node will try to fetch data of the initial tick of the epoch from other nodes, because the tick's timestamp may differ from (2022-04-13 Wed 12:00:00.000UTC). 49 | // If you restart your node after seamless epoch transition, make sure EPOCH and TICK are set correctly for the currently running epoch. 50 | #define START_NETWORK_FROM_SCRATCH 0 51 | 52 | // Addons: If you don't know it, leave it 0. 53 | #define ADDON_TX_STATUS_REQUEST 0 54 | 55 | ////////////////////////////////////////////////////////////////////////// 56 | // Config options that should NOT be changed by operators 57 | 58 | #define VERSION_A 1 59 | #define VERSION_B 246 60 | #define VERSION_C 3 61 | 62 | // Epoch and initial tick for node startup 63 | #define EPOCH 164 64 | #define TICK 26851119 65 | 66 | #define ARBITRATOR "AFZPUAIYVPNUYGJRQVLUKOPPVLHAZQTGLYAAUUNBXFTVTAMSBKQBLEIEPCVJ" 67 | #define DISPATCHER "XPXYKFLGSWRHRGAUKWFWVXCDVEYAPCPCNUTMUDWFGDYQCWZNJMWFZEEGCFFO" 68 | 69 | static unsigned short SYSTEM_FILE_NAME[] = L"system"; 70 | static unsigned short SYSTEM_END_OF_EPOCH_FILE_NAME[] = L"system.eoe"; 71 | static unsigned short SPECTRUM_FILE_NAME[] = L"spectrum.???"; 72 | static unsigned short UNIVERSE_FILE_NAME[] = L"universe.???"; 73 | static unsigned short SCORE_CACHE_FILE_NAME[] = L"score.???"; 74 | static unsigned short CONTRACT_FILE_NAME[] = L"contract????.???"; 75 | static unsigned short CUSTOM_MINING_REVENUE_END_OF_EPOCH_FILE_NAME[] = L"custom_revenue.eoe"; 76 | static unsigned short CUSTOM_MINING_CACHE_FILE_NAME[] = L"custom_mining_cache???.???"; 77 | 78 | #define DATA_LENGTH 256 79 | #define NUMBER_OF_HIDDEN_NEURONS 3000 80 | #define NUMBER_OF_NEIGHBOR_NEURONS 3000 81 | #define MAX_DURATION 9000000 82 | #define NUMBER_OF_OPTIMIZATION_STEPS 60 83 | #define NEURON_VALUE_LIMIT 1LL 84 | #define SOLUTION_THRESHOLD_DEFAULT 137 85 | 86 | #define SOLUTION_SECURITY_DEPOSIT 1000000 87 | 88 | // Signing difficulty 89 | #define TARGET_TICK_VOTE_SIGNATURE 0x000CFFFFU // around 5000 signing operations per ID 90 | 91 | // include commonly needed definitions 92 | #include "network_messages/common_def.h" 93 | 94 | #define MAX_NUMBER_OF_TICKS_PER_EPOCH (((((60 * 60 * 24 * 7) / (TARGET_TICK_DURATION / 1000)) + NUMBER_OF_COMPUTORS - 1) / NUMBER_OF_COMPUTORS) * NUMBER_OF_COMPUTORS) 95 | #define FIRST_TICK_TRANSACTION_OFFSET sizeof(unsigned long long) 96 | #define MAX_TRANSACTION_SIZE (MAX_INPUT_SIZE + sizeof(Transaction) + SIGNATURE_SIZE) 97 | 98 | #define INTERNAL_COMPUTATIONS_INTERVAL 676 99 | #define EXTERNAL_COMPUTATIONS_INTERVAL (676 + 1) 100 | 101 | #define STACK_SIZE 4194304 102 | #define TRACK_MAX_STACK_BUFFER_SIZE 103 | -------------------------------------------------------------------------------- /src/spectrum/special_entities.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "platform/global_var.h" 4 | #include "platform/m256.h" 5 | 6 | #include "network_messages/computors.h" 7 | 8 | #include "four_q.h" 9 | #include "private_settings.h" 10 | #include "public_settings.h" 11 | 12 | GLOBAL_VAR_DECL m256i operatorPublicKey; 13 | GLOBAL_VAR_DECL m256i computorSubseeds[sizeof(computorSeeds) / sizeof(computorSeeds[0])]; 14 | GLOBAL_VAR_DECL m256i computorPrivateKeys[sizeof(computorSeeds) / sizeof(computorSeeds[0])]; 15 | GLOBAL_VAR_DECL m256i computorPublicKeys[sizeof(computorSeeds) / sizeof(computorSeeds[0])]; 16 | GLOBAL_VAR_DECL m256i arbitratorPublicKey; 17 | GLOBAL_VAR_DECL m256i dispatcherPublicKey; 18 | 19 | GLOBAL_VAR_DECL BroadcastComputors broadcastedComputors; 20 | 21 | 22 | static bool initSpecialEntities() 23 | { 24 | getPublicKeyFromIdentity((const unsigned char*)OPERATOR, operatorPublicKey.m256i_u8); 25 | if (isZero(operatorPublicKey)) 26 | { 27 | operatorPublicKey.setRandomValue(); 28 | } 29 | 30 | for (unsigned int i = 0; i < sizeof(computorSeeds) / sizeof(computorSeeds[0]); i++) 31 | { 32 | if (!getSubseed(computorSeeds[i], computorSubseeds[i].m256i_u8)) 33 | { 34 | return false; 35 | } 36 | getPrivateKey(computorSubseeds[i].m256i_u8, computorPrivateKeys[i].m256i_u8); 37 | getPublicKey(computorPrivateKeys[i].m256i_u8, computorPublicKeys[i].m256i_u8); 38 | } 39 | 40 | getPublicKeyFromIdentity((const unsigned char*)ARBITRATOR, (unsigned char*)&arbitratorPublicKey); 41 | getPublicKeyFromIdentity((const unsigned char*)DISPATCHER, dispatcherPublicKey.m256i_u8); 42 | 43 | setMem(&broadcastedComputors, sizeof(broadcastedComputors), 0); 44 | 45 | return true; 46 | } 47 | 48 | static void deinitSpecialEntities() 49 | { 50 | setMem(computorSeeds, sizeof(computorSeeds), 0); 51 | setMem(computorSubseeds, sizeof(computorSubseeds), 0); 52 | setMem(computorPrivateKeys, sizeof(computorPrivateKeys), 0); 53 | setMem(computorPublicKeys, sizeof(computorPublicKeys), 0); 54 | } 55 | -------------------------------------------------------------------------------- /src/system.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "platform/global_var.h" 4 | #include "platform/m256.h" 5 | 6 | #include "network_messages/special_command.h" 7 | 8 | #define MAX_NUMBER_OF_SOLUTIONS 65536 // Must be 2^N 9 | 10 | 11 | 12 | struct System 13 | { 14 | short version; 15 | unsigned short epoch; 16 | unsigned int tick; 17 | unsigned int initialTick; 18 | unsigned int latestCreatedTick, latestLedTick; 19 | 20 | unsigned short initialMillisecond; 21 | unsigned char initialSecond; 22 | unsigned char initialMinute; 23 | unsigned char initialHour; 24 | unsigned char initialDay; 25 | unsigned char initialMonth; 26 | unsigned char initialYear; 27 | 28 | unsigned long long latestOperatorNonce; 29 | 30 | unsigned int numberOfSolutions; 31 | struct Solution 32 | { 33 | m256i computorPublicKey; 34 | m256i miningSeed; 35 | m256i nonce; 36 | } solutions[MAX_NUMBER_OF_SOLUTIONS]; 37 | 38 | m256i futureComputors[NUMBER_OF_COMPUTORS]; 39 | }; 40 | static_assert(sizeof(System) == 20 + 8 + 8 + 8 + 4 + 96 * MAX_NUMBER_OF_SOLUTIONS + 32 * NUMBER_OF_COMPUTORS, "Unexpected size"); 41 | 42 | GLOBAL_VAR_DECL System system; 43 | -------------------------------------------------------------------------------- /src/text_output.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "public_settings.h" 4 | #include "platform/console_logging.h" 5 | 6 | #include "network_messages/common_def.h" 7 | 8 | 9 | static void appendQubicVersion(CHAR16* dst) 10 | { 11 | appendNumber(dst, VERSION_A, FALSE); 12 | appendText(dst, L"."); 13 | appendNumber(dst, VERSION_B, FALSE); 14 | appendText(dst, L"."); 15 | appendNumber(dst, VERSION_C, FALSE); 16 | } 17 | 18 | static void appendIPv4Address(CHAR16* dst, const IPv4Address& address) 19 | { 20 | appendNumber(message, address.u8[0], FALSE); 21 | appendText(message, L"."); 22 | appendNumber(message, address.u8[1], FALSE); 23 | appendText(message, L"."); 24 | appendNumber(message, address.u8[2], FALSE); 25 | appendText(message, L"."); 26 | appendNumber(message, address.u8[3], FALSE); 27 | } 28 | -------------------------------------------------------------------------------- /src/ticking/ticking.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "platform/global_var.h" 4 | #include "platform/m256.h" 5 | 6 | #include "network_messages/tick.h" 7 | 8 | #include "ticking/tick_storage.h" 9 | 10 | #include "private_settings.h" 11 | 12 | GLOBAL_VAR_DECL Tick etalonTick; 13 | GLOBAL_VAR_DECL int numberTickTransactions GLOBAL_VAR_INIT(-1); 14 | -------------------------------------------------------------------------------- /src/vote_counter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/memory.h" 3 | #include "network_messages/transactions.h" 4 | #define VOTE_COUNTER_INPUT_TYPE 1 5 | #define VOTE_COUNTER_DATA_SIZE_IN_BYTES 848 6 | #define VOTE_COUNTER_NUM_BIT_PER_COMP 10 7 | static_assert((1<< VOTE_COUNTER_NUM_BIT_PER_COMP) >= NUMBER_OF_COMPUTORS, "Invalid number of bit per datum"); 8 | static_assert(VOTE_COUNTER_DATA_SIZE_IN_BYTES * 8 >= NUMBER_OF_COMPUTORS * VOTE_COUNTER_NUM_BIT_PER_COMP, "Invalid data size"); 9 | 10 | class VoteCounter 11 | { 12 | private: 13 | unsigned int votes[NUMBER_OF_COMPUTORS*2][NUMBER_OF_COMPUTORS]; 14 | unsigned long long accumulatedVoteCount[NUMBER_OF_COMPUTORS]; 15 | unsigned int buffer[NUMBER_OF_COMPUTORS]; 16 | protected: 17 | unsigned int extract10Bit(const unsigned char* data, unsigned int idx) 18 | { 19 | //TODO: simplify this 20 | unsigned int byte0 = data[idx + (idx >> 2)]; 21 | unsigned int byte1 = data[idx + (idx >> 2) + 1]; 22 | unsigned int last_bit0 = 8 - (idx & 3) * 2; 23 | unsigned int first_bit1 = 10 - last_bit0; 24 | unsigned int res = (byte0 & ((1 << last_bit0) - 1)) << first_bit1; 25 | res |= (byte1 >> (8 - first_bit1)); 26 | return res; 27 | } 28 | void update10Bit(unsigned char* data, unsigned int idx, unsigned int value) 29 | { 30 | //TODO: simplify this 31 | unsigned char& byte0 = data[idx + (idx >> 2)]; 32 | unsigned char& byte1 = data[idx + (idx >> 2) + 1]; 33 | unsigned int last_bit0 = 8 - (idx & 3) * 2; 34 | unsigned int first_bit1 = 10 - last_bit0; 35 | unsigned char mask0 = ~((1 << last_bit0) - 1); 36 | unsigned char mask1 = ((1 << (8-first_bit1)) - 1); 37 | byte0 &= mask0; 38 | byte1 &= mask1; 39 | unsigned char ubyte0 = (value >> first_bit1); 40 | unsigned char ubyte1 = (value & ((1 << first_bit1) - 1)) << (8-first_bit1); 41 | byte0 |= ubyte0; 42 | byte1 |= ubyte1; 43 | } 44 | 45 | void accumulateVoteCount(unsigned int computorIdx, unsigned int value) 46 | { 47 | accumulatedVoteCount[computorIdx] += value; 48 | } 49 | 50 | public: 51 | static constexpr unsigned int VoteCounterDataSize = sizeof(votes) + sizeof(accumulatedVoteCount); 52 | void init() 53 | { 54 | setMem(votes, sizeof(votes), 0); 55 | setMem(accumulatedVoteCount, sizeof(accumulatedVoteCount), 0); 56 | } 57 | 58 | void registerNewVote(unsigned int tick, unsigned int computorIdx) 59 | { 60 | unsigned int slotId = tick % (NUMBER_OF_COMPUTORS * 2); 61 | votes[slotId][computorIdx] = tick; 62 | } 63 | 64 | // get and compress number of votes of 676 computors to 676x10 bit numbers between [fromTick, toTick) 65 | void compressNewVotesPacket(unsigned int fromTick, unsigned int toTick, unsigned int computorIdx, unsigned char votePacket[VOTE_COUNTER_DATA_SIZE_IN_BYTES]) 66 | { 67 | setMem(votePacket, sizeof(votePacket), 0); 68 | setMem(buffer, sizeof(buffer), 0); 69 | for (unsigned int i = fromTick; i < toTick; i++) 70 | { 71 | unsigned int slotId = i % (NUMBER_OF_COMPUTORS * 2); 72 | for (int j = 0; j < NUMBER_OF_COMPUTORS; j++) 73 | { 74 | if (votes[slotId][j] == i) 75 | { 76 | buffer[j]++; 77 | } 78 | } 79 | } 80 | buffer[computorIdx] = 0; // remove self-report 81 | for (unsigned int i = 0; i < NUMBER_OF_COMPUTORS; i++) 82 | { 83 | update10Bit(votePacket, i, buffer[i]); 84 | } 85 | } 86 | 87 | bool validateNewVotesPacket(const unsigned char* votePacket, unsigned int computorIdx) 88 | { 89 | unsigned long long sum = 0; 90 | for (int i = 0; i < NUMBER_OF_COMPUTORS; i++) 91 | { 92 | buffer[i] = extract10Bit(votePacket, i); 93 | if (buffer[i] > NUMBER_OF_COMPUTORS) 94 | { 95 | return false; 96 | } 97 | sum += buffer[i]; 98 | } 99 | // check #0: sum of all vote must be >= 675*451 (vote of the tick leader is removed) 100 | if (sum < (NUMBER_OF_COMPUTORS - 1) * QUORUM) 101 | { 102 | return false; 103 | } 104 | // check #1: own number of vote must be zero 105 | if (buffer[computorIdx] != 0) 106 | { 107 | return false; 108 | } 109 | return true; 110 | } 111 | 112 | void addVotes(const unsigned char* newVotePacket, unsigned int computorIdx) 113 | { 114 | if (validateNewVotesPacket(newVotePacket, computorIdx)) 115 | { 116 | for (int i = 0; i < NUMBER_OF_COMPUTORS; i++) 117 | { 118 | unsigned int vote_count = extract10Bit(newVotePacket, i); 119 | accumulateVoteCount(i, vote_count); 120 | } 121 | } 122 | } 123 | 124 | unsigned long long getVoteCount(unsigned int computorIdx) 125 | { 126 | return accumulatedVoteCount[computorIdx]; 127 | } 128 | 129 | void saveAllDataToArray(unsigned char* dst) 130 | { 131 | copyMem(dst, &votes[0][0], sizeof(votes)); 132 | copyMem(dst + sizeof(votes), &accumulatedVoteCount[0], sizeof(accumulatedVoteCount)); 133 | } 134 | 135 | void loadAllDataFromArray(const unsigned char* src) 136 | { 137 | copyMem(&votes[0][0], src, sizeof(votes)); 138 | copyMem(&accumulatedVoteCount[0], src + sizeof(votes), sizeof(accumulatedVoteCount)); 139 | } 140 | }; -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(qubic_core_tests CXX C) 3 | 4 | # GoogleTest requires at least C++20 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | include(FetchContent) 9 | FetchContent_Declare( 10 | googletest 11 | GIT_REPOSITORY https://github.com/google/googletest.git 12 | GIT_TAG v1.16.0 13 | ) 14 | # For Windows: Prevent overriding the parent project's compiler/linker settings 15 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 16 | FetchContent_MakeAvailable(googletest) 17 | 18 | 19 | get_filename_component(PROJECT_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.." ABSOLUTE) 20 | 21 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../lib/platform_common) 22 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../lib/platform_os) 23 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../lib/platform_efi) # Currently still needed due to various imports 24 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src) 25 | include_directories(${PROJECT_ROOT_DIR}) 26 | 27 | 28 | add_executable( 29 | qubic_core_tests 30 | # assets.cpp 31 | # common_def.cpp 32 | # contract_core.cpp 33 | # contract_qearn.cpp 34 | # contract_qvault.cpp 35 | # contract_qx.cpp 36 | # kangaroo_twelve.cpp 37 | # m256.cpp 38 | math_lib.cpp 39 | # network_messages.cpp 40 | # platform.cpp 41 | # qpi_collection.cpp 42 | # qpi.cpp 43 | # qpi_hash_map.cpp 44 | # score_cache.cpp 45 | # score.cpp 46 | # spectrum.cpp 47 | # stdlib_impl.cpp 48 | # tick_storage.cpp 49 | # tx_status_request.cpp 50 | # vote_counter.cpp 51 | ) 52 | 53 | # Apply test-specific compiler flags from the centralized detection module 54 | apply_test_compiler_flags(qubic_core_tests) 55 | 56 | # Add additional test-specific flags if needed 57 | if(IS_CLANG OR IS_GCC) 58 | target_compile_options(qubic_core_tests PRIVATE -mrdrnd) 59 | endif() 60 | 61 | 62 | target_link_libraries( 63 | qubic_core_tests PRIVATE 64 | GTest::gtest_main 65 | platform_common 66 | platform_os 67 | platform_efi #Currently still needed due to various imports 68 | ) 69 | 70 | include(GoogleTest) 71 | gtest_discover_tests(qubic_core_tests) -------------------------------------------------------------------------------- /test/common_def.cpp: -------------------------------------------------------------------------------- 1 | #define NO_UEFI 2 | #define DEFINE_VARIABLES_SHARED_BETWEEN_COMPILE_UNITS 3 | 4 | #include "contract_testing.h" 5 | #include "logging_test.h" 6 | #include "platform/concurrency_impl.h" 7 | #include "platform/profiling.h" 8 | 9 | // Implement non-QPI version of notification trigger function that is defined in qubic.cpp, where it hands over the 10 | // notification to the contract processor for running the incomming transfer callback. 11 | // We don't have separate tick and contract processors in testing, so we run the callback directly. 12 | void notifyContractOfIncomingTransfer(const m256i& source, const m256i& dest, long long amount, unsigned char type) 13 | { 14 | // Only notify if amount > 0 and dest is contract 15 | if (amount <= 0 || dest.u64._0 >= contractCount || dest.u64._1 || dest.u64._2 || dest.u64._3) 16 | return; 17 | 18 | unsigned int contractIndex = (unsigned int)dest.m256i_u64[0]; 19 | ASSERT(system.epoch >= contractDescriptions[contractIndex].constructionEpoch); 20 | ASSERT(system.epoch < contractDescriptions[contractIndex].destructionEpoch); 21 | 22 | // Run callback system procedure POST_INCOMING_TRANSFER 23 | QpiContextSystemProcedureCall qpiContext(contractIndex, POST_INCOMING_TRANSFER); 24 | QPI::PostIncomingTransfer_input input{ source, amount, type }; 25 | qpiContext.call(input); 26 | } 27 | -------------------------------------------------------------------------------- /test/data/custom_revenue.eoe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qubic/core/492756941e4e22c90dfb96f9dc297b20005fba12/test/data/custom_revenue.eoe -------------------------------------------------------------------------------- /test/kangaroo_twelve.cpp: -------------------------------------------------------------------------------- 1 | #define NO_UEFI 2 | 3 | #include "../src/K12/kangaroo_twelve_xkcp.h" 4 | #include "../src/kangaroo_twelve.h" 5 | #include "../src/platform/memory.h" 6 | #include 7 | #include "gtest/gtest.h" 8 | 9 | #include 10 | #include 11 | 12 | 13 | TEST(TestCoreK12, PerformanceDigest32Of1GB) 14 | { 15 | constexpr size_t bytesPerGigaByte = 1024 * 1024 * 1024; 16 | constexpr size_t repN = 1; 17 | constexpr size_t inputN = bytesPerGigaByte; 18 | constexpr size_t outputN = 32; 19 | 20 | char* inputPtr = new char[inputN]; 21 | for (size_t i = 0; i < 100; ++i) 22 | { 23 | unsigned int pos, val; 24 | _rdrand32_step(&pos); 25 | _rdrand32_step(&val); 26 | inputPtr[pos % inputN] = val & 0xff; 27 | } 28 | char outputArray[outputN]; 29 | 30 | auto startTime = std::chrono::high_resolution_clock::now(); 31 | for (size_t i = 0; i < repN; ++i) 32 | XKCP::KangarooTwelve((unsigned char *) inputPtr, inputN, (unsigned char*) outputArray, outputN); 33 | auto durationMilliSec = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime); 34 | 35 | double bytePerMilliSec = double(repN * inputN) / double(durationMilliSec.count()); 36 | double gigaBytePerSec = bytePerMilliSec * (1000.0 / bytesPerGigaByte); 37 | std::cout << "K12 of 1 GB to 32 Byte digest: " << gigaBytePerSec << " GB/sec = " << 1.0 / gigaBytePerSec << " sec/GB" << std::endl; 38 | 39 | delete [] inputPtr; 40 | } 41 | 42 | TEST(TestCoreK12, CompareK12Implementations) 43 | { 44 | constexpr size_t bytesPerGigaByte = 1024 * 1024 * 1024; 45 | constexpr size_t repN = 1; 46 | constexpr size_t inputN = bytesPerGigaByte; 47 | constexpr size_t outputN = 32; 48 | 49 | char* inputPtr = new char[inputN]; 50 | for (size_t i = 0; i < 100; ++i) 51 | { 52 | unsigned int pos, val; 53 | _rdrand32_step(&pos); 54 | _rdrand32_step(&val); 55 | inputPtr[pos % inputN] = val & 0xff; 56 | } 57 | char outputArrayXKCP[outputN]; 58 | 59 | auto startTime = std::chrono::high_resolution_clock::now(); 60 | for (size_t i = 0; i < repN; ++i) 61 | XKCP::KangarooTwelve((unsigned char *) inputPtr, inputN, (unsigned char*) outputArrayXKCP, outputN); 62 | auto durationMilliSec = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime); 63 | 64 | double bytePerMilliSec = double(repN * inputN) / double(durationMilliSec.count()); 65 | double gigaBytePerSec = bytePerMilliSec * (1000.0 / bytesPerGigaByte); 66 | std::cout << "K12 of 1 GB to 32 Byte digest: " << gigaBytePerSec << " GB/sec = " << 1.0 / gigaBytePerSec << " sec/GB" << std::endl; 67 | std::cout << "Digest of xkcp implementation: "; 68 | for (int i = 0; i < sizeof(outputArrayXKCP); i++){ 69 | std::cout << std::hex << std::setfill('0') << std::setw(2) 70 | << (static_cast(outputArrayXKCP[i]) & 0xff); 71 | } 72 | std::cout << std::endl; 73 | 74 | char outputArray[outputN]; 75 | startTime = std::chrono::high_resolution_clock::now(); 76 | for (size_t i = 0; i < repN; ++i) 77 | KangarooTwelve((unsigned char *) inputPtr, inputN, (unsigned char*) outputArray, outputN); 78 | durationMilliSec = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime); 79 | 80 | bytePerMilliSec = double(repN * inputN) / double(durationMilliSec.count()); 81 | gigaBytePerSec = bytePerMilliSec * (1000.0 / bytesPerGigaByte); 82 | std::cout << "K12 of 1 GB to 32 Byte digest: " << gigaBytePerSec << " GB/sec = " << 1.0 / gigaBytePerSec << " sec/GB" << std::endl; 83 | std::cout << "Digest of native implementation: "; 84 | 85 | for (int i = 0; i < sizeof(outputArray); i++){ 86 | std::cout << std::hex << std::setfill('0') << std::setw(2) 87 | << (static_cast(outputArray[i]) & 0xff); 88 | } 89 | std::cout << std::endl; 90 | ASSERT_EQ(memcmp(outputArrayXKCP, outputArray, outputN), 0); 91 | delete [] inputPtr; 92 | } 93 | -------------------------------------------------------------------------------- /test/logging_test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gtest/gtest.h" 4 | 5 | // workaround for name clash with stdlib 6 | #define system qubicSystemStruct 7 | 8 | // enable all logging that is used in tests 9 | #include "private_settings.h" 10 | #undef LOG_SPECTRUM 11 | #define LOG_SPECTRUM 1 12 | 13 | // also reduce size of logging tx index by reducing maximum number of ticks per epoch 14 | #include "public_settings.h" 15 | #undef MAX_NUMBER_OF_TICKS_PER_EPOCH 16 | #define MAX_NUMBER_OF_TICKS_PER_EPOCH 3000 17 | 18 | #include "logging/logging.h" 19 | 20 | class LoggingTest 21 | { 22 | public: 23 | LoggingTest() 24 | { 25 | EXPECT_TRUE(qLogger::initLogging()); 26 | } 27 | 28 | ~LoggingTest() 29 | { 30 | qLogger::deinitLogging(); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /test/math_lib.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | #include 4 | #include "../src/contracts/math_lib.h" 5 | 6 | TEST(TestCoreMathLib, Max) { 7 | EXPECT_EQ(math_lib::max(0, 0), 0); 8 | EXPECT_EQ(math_lib::max(10, 0), 10); 9 | EXPECT_EQ(math_lib::max(0, 20), 20); 10 | EXPECT_EQ(math_lib::max(-10, 0), 0); 11 | EXPECT_EQ(math_lib::max(0, -20), 0); 12 | 13 | EXPECT_EQ(math_lib::max(0.0, 0.0), 0.0); 14 | EXPECT_EQ(math_lib::max(10.0, 0.0), 10.0); 15 | EXPECT_EQ(math_lib::max(0.0, 20.0), 20.0); 16 | EXPECT_EQ(math_lib::max(-10.0, 0.0), 0.0); 17 | EXPECT_EQ(math_lib::max(0.0, -20.0), 0.0); 18 | } 19 | 20 | TEST(TestCoreMathLib, Min) { 21 | EXPECT_EQ(math_lib::min(0, 0), 0); 22 | EXPECT_EQ(math_lib::min(10, 0), 0); 23 | EXPECT_EQ(math_lib::min(0, 20), 0); 24 | EXPECT_EQ(math_lib::min(-10, 0), -10); 25 | EXPECT_EQ(math_lib::min(0, -20), -20); 26 | 27 | EXPECT_EQ(math_lib::min(0.0, 0.0), 0.0); 28 | EXPECT_EQ(math_lib::min(10.0, 0.0), 0.0); 29 | EXPECT_EQ(math_lib::min(0.0, 20.0), 0.0); 30 | EXPECT_EQ(math_lib::min(-10.0, 0.0), -10.0); 31 | EXPECT_EQ(math_lib::min(0.0, -20.0), -20.0); 32 | } 33 | 34 | TEST(TestCoreMathLib, Abs) { 35 | EXPECT_EQ(math_lib::abs(0), 0); 36 | EXPECT_EQ(math_lib::abs(10), 10); 37 | EXPECT_EQ(math_lib::abs(-1110), 1110); 38 | EXPECT_EQ(math_lib::abs(-987654ll), 987654llu); 39 | 40 | EXPECT_EQ(math_lib::abs(0.0), 0.0); 41 | EXPECT_EQ(math_lib::abs(-0.0), 0.0); 42 | EXPECT_EQ(math_lib::abs(-1230.0f), 1230.0f); 43 | EXPECT_EQ(math_lib::abs(INFINITY), INFINITY); 44 | EXPECT_EQ(math_lib::abs(-INFINITY), INFINITY); 45 | EXPECT_EQ(math_lib::abs(FP_NAN), FP_NAN); 46 | } 47 | 48 | // div() and mod() are defined in qpi.h 49 | 50 | template 51 | void testDivUp() 52 | { 53 | EXPECT_EQ(int(math_lib::divUp(T(0), T(0))), 0); 54 | EXPECT_EQ(int(math_lib::divUp(T(1), T(0))), 0); 55 | EXPECT_EQ(int(math_lib::divUp(T(0), T(1))), 0); 56 | EXPECT_EQ(int(math_lib::divUp(T(1), T(1))), 1); 57 | EXPECT_EQ(int(math_lib::divUp(T(2), T(1))), 2); 58 | EXPECT_EQ(int(math_lib::divUp(T(3), T(1))), 3); 59 | EXPECT_EQ(int(math_lib::divUp(T(0), T(2))), 0); 60 | EXPECT_EQ(int(math_lib::divUp(T(1), T(2))), 1); 61 | EXPECT_EQ(int(math_lib::divUp(T(2), T(2))), 1); 62 | EXPECT_EQ(int(math_lib::divUp(T(3), T(2))), 2); 63 | EXPECT_EQ(int(math_lib::divUp(T(4), T(2))), 2); 64 | EXPECT_EQ(int(math_lib::divUp(T(5), T(2))), 3); 65 | EXPECT_EQ(int(math_lib::divUp(T(0), T(3))), 0); 66 | EXPECT_EQ(int(math_lib::divUp(T(1), T(3))), 1); 67 | EXPECT_EQ(int(math_lib::divUp(T(2), T(3))), 1); 68 | EXPECT_EQ(int(math_lib::divUp(T(3), T(3))), 1); 69 | EXPECT_EQ(int(math_lib::divUp(T(4), T(3))), 2); 70 | EXPECT_EQ(int(math_lib::divUp(T(5), T(3))), 2); 71 | EXPECT_EQ(int(math_lib::divUp(T(6), T(3))), 2); 72 | EXPECT_EQ(int(math_lib::divUp(T(7), T(3))), 3); 73 | EXPECT_EQ(int(math_lib::divUp(T(20), T(19))), 2); 74 | EXPECT_EQ(int(math_lib::divUp(T(20), T(20))), 1); 75 | EXPECT_EQ(int(math_lib::divUp(T(20), T(21))), 1); 76 | EXPECT_EQ(int(math_lib::divUp(T(20), T(22))), 1); 77 | EXPECT_EQ(int(math_lib::divUp(T(50), T(24))), 3); 78 | EXPECT_EQ(int(math_lib::divUp(T(50), T(25))), 2); 79 | EXPECT_EQ(int(math_lib::divUp(T(50), T(26))), 2); 80 | EXPECT_EQ(int(math_lib::divUp(T(50), T(27))), 2); 81 | } 82 | 83 | TEST(TestCoreMathLib, DivUp) { 84 | testDivUp(); 85 | testDivUp(); 86 | testDivUp(); 87 | testDivUp(); 88 | } 89 | -------------------------------------------------------------------------------- /test/network_messages.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | #define NETWORK_MESSAGES_WITHOUT_CORE_DEPENDENCIES 4 | #include "../src/network_messages/all.h" 5 | 6 | 7 | TEST(TestCoreRequestResponseHeader, TestSize) { 8 | RequestResponseHeader hdr; 9 | memset(& hdr, 0, sizeof(hdr)); 10 | EXPECT_EQ(0, hdr.size()); 11 | EXPECT_EQ(0, hdr.type()); 12 | EXPECT_EQ(0, hdr.dejavu()); 13 | 14 | EXPECT_TRUE(hdr.checkAndSetSize(1)); 15 | EXPECT_EQ(1, hdr.size()); 16 | 17 | hdr.setSize<10>(); 18 | EXPECT_EQ(10, hdr.size()); 19 | 20 | EXPECT_TRUE(hdr.checkAndSetSize(13579864)); 21 | EXPECT_EQ(13579864, hdr.size()); 22 | 23 | hdr.setSize<9876543>(); 24 | EXPECT_EQ(9876543, hdr.size()); 25 | 26 | EXPECT_TRUE(hdr.checkAndSetSize(0xffffff)); 27 | EXPECT_EQ(0xffffff, hdr.size()); 28 | 29 | // maximum size is 0xffffff = 16777215 30 | EXPECT_FALSE(hdr.checkAndSetSize(RequestResponseHeader::max_size + 1)); 31 | EXPECT_FALSE(hdr.checkAndSetSize(RequestResponseHeader::max_size * 2)); 32 | } 33 | 34 | TEST(TestCoreRequestResponseHeader, TestPayload) { 35 | RequestResponseHeader hdr; 36 | memset(&hdr, 0, sizeof(hdr)); 37 | EXPECT_EQ(hdr.getPayload(), ((char*)&hdr) + sizeof(RequestResponseHeader)); 38 | 39 | EXPECT_TRUE(hdr.checkAndSetSize(1234 + sizeof(RequestResponseHeader))); 40 | EXPECT_TRUE(hdr.checkPayloadSize(1234)); 41 | EXPECT_FALSE(hdr.checkPayloadSize(1235)); 42 | EXPECT_TRUE(hdr.checkPayloadSizeMinMax(1234, 1234)); 43 | EXPECT_TRUE(hdr.checkPayloadSizeMinMax(123, 1234)); 44 | EXPECT_TRUE(hdr.checkPayloadSizeMinMax(1234, 12346)); 45 | EXPECT_TRUE(hdr.checkPayloadSizeMinMax(123, 12346)); 46 | EXPECT_FALSE(hdr.checkPayloadSizeMinMax(1235, 1235)); 47 | EXPECT_FALSE(hdr.checkPayloadSizeMinMax(12, 13)); 48 | EXPECT_FALSE(hdr.checkPayloadSizeMinMax(13, 12)); 49 | EXPECT_EQ(hdr.getPayloadSize(), 1234); 50 | } 51 | 52 | TEST(TestCoreCommonDef, IPv4Address) { 53 | const unsigned char ip_char_array[4] = { 1, 2, 3, 4 }; 54 | const IPv4Address& ip_ref = *reinterpret_cast(ip_char_array); 55 | EXPECT_EQ(ip_ref.u8[0], 1); 56 | EXPECT_EQ(ip_ref.u8[1], 2); 57 | EXPECT_EQ(ip_ref.u8[2], 3); 58 | EXPECT_EQ(ip_ref.u8[3], 4); 59 | EXPECT_EQ(ip_ref.u32, 0x04030201); 60 | 61 | IPv4Address ip2 {100, 200, 32, 4}; 62 | EXPECT_TRUE(ip_ref != ip2); 63 | EXPECT_FALSE(ip_ref == ip2); 64 | 65 | ip2 = ip_ref; 66 | EXPECT_TRUE(ip_ref == ip2); 67 | EXPECT_FALSE(ip_ref != ip2); 68 | } 69 | -------------------------------------------------------------------------------- /test/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /test/score_params.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace score_params 4 | { 5 | enum ParamType 6 | { 7 | NR_NEURONS = 0, 8 | NR_NEIGHBOR_NEURONS, 9 | DURATIONS, 10 | NR_OPTIMIZATION_STEPS, 11 | MAX_PARAM_TYPE 12 | }; 13 | 14 | static constexpr unsigned long long kDataLength = 256; 15 | 16 | // Comment out when we want to reduce the number of running test 17 | static constexpr unsigned long long kSettings[][MAX_PARAM_TYPE] = { 18 | {512, 256, 100000, 10}, 19 | {856, 520, 120000, 20}, 20 | {1000, 1000, 1000000, 30}, 21 | {2844, 2160, 9000000ULL, 89}, 22 | {3000, 3000, 9000000ULL, 30}, 23 | {3000, 3000, 9000000ULL, 100}, 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /test/stdlib_impl.cpp: -------------------------------------------------------------------------------- 1 | // Implements NO_UEFI versions of several functions that require cstdlib functions. 2 | // Having them in a separate cpp file avoids the name clash between cstdlib's system and Qubic's system. 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define NO_UEFI 9 | 10 | #include "platform/time.h" 11 | 12 | 13 | void setMem(void* buffer, unsigned long long size, unsigned char value) 14 | { 15 | memset(buffer, value, size); 16 | } 17 | 18 | void copyMem(void* destination, const void* source, unsigned long long length) 19 | { 20 | memcpy(destination, source, length); 21 | } 22 | 23 | bool allocatePool(unsigned long long size, void** buffer) 24 | { 25 | void* ptr = malloc(size); 26 | if (ptr) 27 | { 28 | *buffer = ptr; 29 | return true; 30 | } 31 | return false; 32 | } 33 | 34 | void freePool(void* buffer) 35 | { 36 | free(buffer); 37 | } 38 | 39 | void updateTime() 40 | { 41 | std::time_t t = std::time(nullptr); 42 | std::tm* tm = std::gmtime(&t); 43 | utcTime.Year = tm->tm_year + 1900; 44 | utcTime.Month = tm->tm_mon + 1; 45 | utcTime.Day = tm->tm_mday; 46 | utcTime.Hour = tm->tm_hour; 47 | utcTime.Minute = tm->tm_min; 48 | utcTime.Second = tm->tm_sec; 49 | utcTime.Nanosecond = 0; 50 | utcTime.TimeZone = 0; 51 | utcTime.Daylight = 0; 52 | } 53 | 54 | unsigned long long now_ms() 55 | { 56 | std::time_t t = std::time(nullptr); 57 | std::tm* tm = std::gmtime(&t); 58 | return ms(unsigned char(tm->tm_year % 100), tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, 0); 59 | } -------------------------------------------------------------------------------- /test/test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | {b544a744-99a4-4a9d-b445-211aabef63f2} 46 | 47 | 48 | 49 | 50 | core 51 | 52 | 53 | -------------------------------------------------------------------------------- /test/test.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --gtest_break_on_failure 5 | WindowsLocalDebugger 6 | 7 | 8 | 9 | 10 | WindowsLocalDebugger 11 | 12 | -------------------------------------------------------------------------------- /test/test_util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "gtest/gtest.h" 4 | 5 | #include "four_q.h" 6 | 7 | 8 | static std::ostream& operator<<(std::ostream& s, const m256i& v) 9 | { 10 | CHAR16 identityWchar[61]; 11 | char identityChar[61]; 12 | getIdentity(v.m256i_u8, identityWchar, false); 13 | size_t size; 14 | wcstombs_s(&size, identityChar, identityWchar, 61); 15 | s << identityChar; 16 | return s; 17 | } 18 | 19 | static unsigned long long assetNameFromString(const char* assetName) 20 | { 21 | size_t n = strlen(assetName); 22 | EXPECT_LE(n, 7); 23 | unsigned long long integer = 0; 24 | copyMem(&integer, assetName, n); 25 | return integer; 26 | } 27 | 28 | static std::string assetNameFromInt64(unsigned long long assetName) 29 | { 30 | char buffer[8]; 31 | copyMem(&buffer, &assetName, sizeof(assetName)); 32 | buffer[7] = 0; 33 | return buffer; 34 | } -------------------------------------------------------------------------------- /test/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace test_utils 10 | { 11 | 12 | std::string byteToHex(const unsigned char* byteArray, size_t sizeInByte) 13 | { 14 | std::ostringstream oss; 15 | for (size_t i = 0; i < sizeInByte; ++i) 16 | { 17 | oss << std::hex << std::setw(2) << std::setfill('0') << static_cast(byteArray[i]); 18 | } 19 | return oss.str(); 20 | 21 | } 22 | m256i hexToByte(const std::string& hex, const int sizeInByte) 23 | { 24 | if (hex.length() != sizeInByte * 2) { 25 | throw std::invalid_argument("Hex string length does not match the expected size"); 26 | } 27 | 28 | m256i byteArray; 29 | for (size_t i = 0; i < sizeInByte; ++i) 30 | { 31 | byteArray.m256i_u8[i] = std::stoi(hex.substr(i * 2, 2), nullptr, 16); 32 | } 33 | 34 | return byteArray; 35 | } 36 | 37 | // Function to read and parse the CSV file 38 | std::vector> readCSV(const std::string& filename) 39 | { 40 | std::vector> data; 41 | std::ifstream file(filename); 42 | std::string line; 43 | 44 | // Read each line from the file 45 | while (std::getline(file, line)) 46 | { 47 | std::stringstream ss(line); 48 | std::string item; 49 | std::vector parsedLine; 50 | 51 | // Parse each item separated by commas 52 | while (std::getline(ss, item, ',')) 53 | { 54 | // Remove any spaces in the string 55 | item.erase(remove_if(item.begin(), item.end(), isspace), item.end()); 56 | 57 | parsedLine.push_back(item); 58 | } 59 | data.push_back(parsedLine); 60 | } 61 | return data; 62 | } 63 | 64 | m256i convertFromString(std::string& rStr) 65 | { 66 | m256i value; 67 | std::stringstream ss(rStr); 68 | std::string item; 69 | int i = 0; 70 | while (std::getline(ss, item, '-')) 71 | { 72 | value.m256i_u64[i++] = std::stoull(item); 73 | } 74 | return value; 75 | } 76 | 77 | std::vector convertULLFromString(std::string& rStr) 78 | { 79 | std::vector values; 80 | std::stringstream ss(rStr); 81 | std::string item; 82 | int i = 0; 83 | while (std::getline(ss, item, '-')) 84 | { 85 | values.push_back(std::stoull(item)); 86 | } 87 | return values; 88 | } 89 | 90 | } // test_utils 91 | -------------------------------------------------------------------------------- /test/vote_counter.cpp: -------------------------------------------------------------------------------- 1 | #define NO_UEFI 2 | 3 | #include "gtest/gtest.h" 4 | 5 | #include "../src/public_settings.h" 6 | #include "../src/vote_counter.h" 7 | 8 | #include 9 | 10 | 11 | class TestVoteCounter : public VoteCounter 12 | { 13 | public: 14 | unsigned int testExtract10Bit(unsigned char* data, unsigned int idx) 15 | { 16 | return extract10Bit(data, idx); 17 | } 18 | void testUpdate10Bit(unsigned char* data, unsigned int idx, unsigned int value) 19 | { 20 | update10Bit(data, idx, value); 21 | } 22 | }; 23 | 24 | TestVoteCounter tvc; 25 | 26 | 27 | TEST(TestCoreVoteCounter, TenBitsEncodeDecode) { 28 | unsigned char data_u10[848]; 29 | unsigned int data_u32[676]; 30 | for (int i = 0; i < 32; i++) 31 | { 32 | srand(i); 33 | for (int i = 0; i < 676; i++) 34 | { 35 | unsigned int rd = rand() % 676; 36 | data_u32[i] = rd; 37 | tvc.testUpdate10Bit(data_u10, i, rd); 38 | } 39 | bool isMatched = true; 40 | for (int i = 0; i < 676; i++) 41 | { 42 | unsigned int extracted = tvc.testExtract10Bit(data_u10, i); 43 | if (extracted != data_u32[i]) 44 | { 45 | isMatched = false; 46 | break; 47 | } 48 | } 49 | EXPECT_TRUE(isMatched); 50 | } 51 | } 52 | 53 | TEST(TestCoreVoteCounter, NewVotePacketValidation) { 54 | unsigned char data_u10[848]; 55 | srand(0); 56 | setMem(data_u10, sizeof(data_u10), 0); 57 | for (int i = 0; i < 451; i++) 58 | { 59 | unsigned int rd = rand() % 676; 60 | tvc.testUpdate10Bit(data_u10, i, rd); 61 | } 62 | tvc.testUpdate10Bit(data_u10, 0, 0); 63 | bool isValid = tvc.validateNewVotesPacket(data_u10, 0); // total votes is lower than 451 * 676 64 | EXPECT_TRUE(!isValid); 65 | 66 | setMem(data_u10, sizeof(data_u10), 0); 67 | for (int i = 0; i < 676; i++) 68 | { 69 | unsigned int rd = 451 + rand() % (676-451); 70 | tvc.testUpdate10Bit(data_u10, i, rd); 71 | } 72 | tvc.testUpdate10Bit(data_u10, 0, 300); 73 | isValid = tvc.validateNewVotesPacket(data_u10, 0); // self-report is not zero 74 | EXPECT_TRUE(!isValid); 75 | 76 | setMem(data_u10, sizeof(data_u10), 0); 77 | for (int i = 0; i < 676; i++) 78 | { 79 | unsigned int rd = 451 + rand() % (676 - 451); 80 | tvc.testUpdate10Bit(data_u10, i, rd); 81 | } 82 | tvc.testUpdate10Bit(data_u10, 0, 0); 83 | isValid = tvc.validateNewVotesPacket(data_u10, 0); // valid 84 | EXPECT_TRUE(isValid); 85 | } 86 | 87 | TEST(TestCoreVoteCounter, AddGetVotes) { 88 | unsigned char data_u10[848] = { 0 }; 89 | unsigned int data_u32[676] = { 0 }; 90 | srand(0); 91 | tvc.init(); 92 | for (int comp = 0; comp < 676; comp++) 93 | { 94 | for (int i = 0; i < 676; i++) 95 | { 96 | unsigned int rd = 451 + (rand() % (676-451)); 97 | tvc.testUpdate10Bit(data_u10, i, rd); 98 | } 99 | tvc.testUpdate10Bit(data_u10, comp, 0); 100 | 101 | tvc.addVotes(data_u10, comp); 102 | for (int i = 0; i < 676; i++) 103 | { 104 | data_u32[i] += tvc.testExtract10Bit(data_u10, i); 105 | } 106 | } 107 | bool isMatched = true; 108 | for (int i = 0; i < 676; i++) 109 | { 110 | if (tvc.getVoteCount(i) != data_u32[i]) 111 | { 112 | isMatched = false; 113 | printf("[FAILED] comp %d: %llu vs %lu\n", i, tvc.getVoteCount(i), data_u32[i]); 114 | break; 115 | } 116 | } 117 | EXPECT_TRUE(isMatched); 118 | } 119 | 120 | bool tick_data[676 * 4][676]; 121 | TEST(TestCoreVoteCounter, RegisterNewCompressVotes) { 122 | unsigned char data_u10[848] = { 0 }; 123 | unsigned int data_u32[676] = { 0 }; 124 | setMem(tick_data, sizeof(tick_data), 0); 125 | srand(0); 126 | tvc.init(); 127 | bool isMatched = true; 128 | unsigned int startTick = 676 + rand() % 676; 129 | for (unsigned int tick = startTick; tick < 676 * 4; tick++) 130 | { 131 | bool flag[676]; 132 | setMem(flag, sizeof(flag), true); 133 | int n_non_vote = rand() % (676 - 451); 134 | for (int i = 0; i < n_non_vote; i++) 135 | { 136 | flag[rand() % 676] = false; 137 | } 138 | for (int i = 0; i < 676; i++) 139 | { 140 | if (flag[i]) 141 | { 142 | tvc.registerNewVote(tick, i); 143 | tick_data[tick][i] = true; 144 | } 145 | } 146 | for (int k = 0; k < 2; k++) // randomly select 2 comp to test 147 | { 148 | int comp = rand() % 676; 149 | tvc.compressNewVotesPacket(tick - 675, tick + 1, comp, data_u10); 150 | setMem(data_u32, sizeof(data_u32), 0); 151 | for (unsigned int t = tick - 675; t <= tick; t++) 152 | { 153 | for (int i = 0; i < 676; i++) 154 | { 155 | if (tick_data[t][i]) data_u32[i]++; 156 | } 157 | } 158 | data_u32[comp] = 0; 159 | for (int i = 0; i < 676; i++) 160 | { 161 | unsigned int vote = tvc.testExtract10Bit(data_u10, i); 162 | if (vote != data_u32[i]) 163 | { 164 | isMatched = false; 165 | break; 166 | } 167 | } 168 | } 169 | EXPECT_TRUE(isMatched); 170 | //printf("[PASSED] tick %u\n", tick); 171 | } 172 | } -------------------------------------------------------------------------------- /tools/python/custom_mining_revenue.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import sys 3 | 4 | NUMBER_OF_COMPUTORS = 676 5 | UINT64_SIZE = 8 6 | 7 | def computeNewScore(oldScore, customScore): 8 | new_score = oldScore * customScore 9 | return new_score 10 | 11 | class RevenueScore: 12 | def __init__(self): 13 | self.old_final_score = [0] * NUMBER_OF_COMPUTORS 14 | self.custom_mining_score = [0] * NUMBER_OF_COMPUTORS 15 | 16 | def bytes_to_uint64(byte_data): 17 | """Convert 8 bytes (little-endian) to an unsigned 64-bit integer.""" 18 | value = 0 19 | for i in range(UINT64_SIZE): 20 | value |= byte_data[i] << (i * 8) 21 | return value 22 | 23 | def dump_custom_mining_share_to_csv(input_file, output_file): 24 | custom_mining_rev = RevenueScore() 25 | 26 | try: 27 | with open(input_file, "rb") as file: 28 | # Read old final scores 29 | for i in range(NUMBER_OF_COMPUTORS): 30 | byte_data = file.read(UINT64_SIZE) 31 | if len(byte_data) != UINT64_SIZE: 32 | raise ValueError("Unexpected end of file.") 33 | custom_mining_rev.old_final_score[i] = bytes_to_uint64(byte_data) 34 | 35 | # Read custom mining scores 36 | for i in range(NUMBER_OF_COMPUTORS): 37 | byte_data = file.read(UINT64_SIZE) 38 | if len(byte_data) != UINT64_SIZE: 39 | raise ValueError("Unexpected end of file.") 40 | custom_mining_rev.custom_mining_score[i] = bytes_to_uint64(byte_data) 41 | 42 | except FileNotFoundError: 43 | print(f"Error: Cannot open file '{input_file}'") 44 | exit(1) 45 | 46 | try: 47 | with open(output_file, "w", newline="") as file: 48 | writer = csv.writer(file) 49 | 50 | # Write header 51 | writer.writerow(["Index", "OldFinalScore", "CustomMiningScore", "NewScore"]) 52 | 53 | # Write data 54 | for i in range(NUMBER_OF_COMPUTORS): 55 | old_score = custom_mining_rev.old_final_score[i] 56 | custom_score = custom_mining_rev.custom_mining_score[i] 57 | new_score = computeNewScore(old_score, custom_score) 58 | writer.writerow([i, old_score, custom_score, new_score]) 59 | 60 | print(f"CSV file '{output_file}' written successfully.") 61 | 62 | except Exception as e: 63 | print(f"Error writing file '{output_file}': {e}") 64 | exit(1) 65 | 66 | 67 | if __name__ == "__main__": 68 | if len(sys.argv) != 3: 69 | print("Usage: python/python3 custom_mining_revenue.py ") 70 | sys.exit(1) 71 | 72 | input_file = sys.argv[1] 73 | output_file = sys.argv[2] 74 | 75 | dump_custom_mining_share_to_csv(input_file, output_file) -------------------------------------------------------------------------------- /tools/score_test_generator/score_test_generator.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | 17.0 15 | Win32Proj 16 | {e2e05292-4d27-41a7-b6bf-a7e4fe869374} 17 | testgenerator 18 | 10.0 19 | 20 | 21 | 22 | Application 23 | true 24 | v143 25 | Unicode 26 | 27 | 28 | Application 29 | false 30 | v143 31 | true 32 | Unicode 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Level3 49 | true 50 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 51 | true 52 | false 53 | stdcpp20 54 | 55 | 56 | Console 57 | true 58 | 59 | 60 | 61 | 62 | Level3 63 | true 64 | true 65 | true 66 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 67 | true 68 | false 69 | stdcpp20 70 | Speed 71 | false 72 | true 73 | 74 | 75 | Console 76 | true 77 | true 78 | true 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /tools/score_test_generator/score_test_generator.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tools/score_test_generator/score_test_generator.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | WindowsLocalDebugger 7 | 8 | 9 | 10 | 11 | WindowsLocalDebugger 12 | 13 | -------------------------------------------------------------------------------- /tools/tools.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34009.444 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "score_test_generator", "score_test_generator\score_test_generator.vcxproj", "{E2E05292-4D27-41A7-B6BF-A7E4FE869374}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E2E05292-4D27-41A7-B6BF-A7E4FE869374}.Debug|x64.ActiveCfg = Debug|x64 15 | {E2E05292-4D27-41A7-B6BF-A7E4FE869374}.Debug|x64.Build.0 = Debug|x64 16 | {E2E05292-4D27-41A7-B6BF-A7E4FE869374}.Release|x64.ActiveCfg = Release|x64 17 | {E2E05292-4D27-41A7-B6BF-A7E4FE869374}.Release|x64.Build.0 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {B438A610-AE7C-4B16-9E2B-F95D81C6262D} 24 | EndGlobalSection 25 | EndGlobal 26 | --------------------------------------------------------------------------------