diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index ca351354d43..2aa22bfd776 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -44,7 +44,7 @@ jobs: path: ${{ steps.pip-cache.outputs.dir }} key: ${{ runner.os }}-${{ hashFiles('.github/workflows/nix.yml') }} - name: install Conan - run: pip install wheel 'conan>=1.52.0' + run: pip install wheel 'conan~=1.52' - name: check environment run: | echo ${PATH} | tr ':' '\n' diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 637eba4ea51..b50f9ab550a 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -46,7 +46,7 @@ jobs: path: ${{ steps.pip-cache.outputs.dir }} key: ${{ runner.os }}-${{ hashFiles('.github/workflows/windows.yml') }} - name: install Conan - run: pip install wheel 'conan>=1.52.0' + run: pip install wheel 'conan~=1.52' - name: check environment run: | $env:PATH -split ';' diff --git a/Builds/VisualStudio2017/README.md b/Builds/VisualStudio2017/README.md new file mode 100644 index 00000000000..fce8e824a05 --- /dev/null +++ b/Builds/VisualStudio2017/README.md @@ -0,0 +1 @@ +[Build instructions are currently located in `BUILD.md`](../../BUILD.md) diff --git a/Builds/linux/README.md b/Builds/linux/README.md index 15a84a33e43..fce8e824a05 100644 --- a/Builds/linux/README.md +++ b/Builds/linux/README.md @@ -1,269 +1 @@ -# Linux Build Instructions - -This document focuses on building rippled for development purposes under recent -Ubuntu linux distributions. To build rippled for Redhat, Fedora or Centos -builds, including docker based builds for those distributions, please consult -the [rippled-package-builder](https://github.com/ripple/rippled-package-builder) -repository. - -Note: Ubuntu 16.04 users may need to update their compiler (see the dependencies -section). For non Ubuntu distributions, the steps below should work by -installing the appropriate dependencies using that distribution's package -management tools. - - -## Dependencies - -gcc-8 or later is required. - -Use `apt-get` to install the dependencies provided by the distribution - -``` -$ apt-get update -$ apt-get install -y gcc g++ wget git cmake pkg-config libprotoc-dev protobuf-compiler libprotobuf-dev libssl-dev -``` - -To build the software in reporting mode, install these additional dependencies: -``` -$ apt-get install -y autoconf flex bison -``` - -Advanced users can choose to install newer versions of gcc, or the clang compiler. - -### Build Boost - -Boost 1.70 or later is required. We recommend downloading and compiling boost -with the following process: After changing to the directory where -you wish to download and compile boost, run -``` -$ wget https://boostorg.jfrog.io/artifactory/main/release/1.70.0/source/boost_1_70_0.tar.gz -$ tar -xzf boost_1_70_0.tar.gz -$ cd boost_1_70_0 -$ ./bootstrap.sh -$ ./b2 headers -$ ./b2 -j $(echo $(nproc)-2 | bc) -``` - -### (Optional) Dependencies for Building Source Documentation - -Source code documentation is not required for running/debugging rippled. That -said, the documentation contains some helpful information about specific -components of the application. For more information on how to install and run -the necessary components, see [this document](../../docs/README.md) - -## Build - -### Clone the rippled repository - -From a shell: - -``` -git clone git@github.com:ripple/rippled.git -cd rippled -``` - -For a stable release, choose the `master` branch or one of the tagged releases -listed on [GitHub](https://github.com/ripple/rippled/releases). - -``` -git checkout master -``` - -or to test the latest release candidate, choose the `release` branch. - -``` -git checkout release -``` - -If you are doing development work and want the latest set of untested -features, you can consider using the `develop` branch instead. - -``` -git checkout develop -``` - -### Configure Library Paths - -If you didn't persistently set the `BOOST_ROOT` environment variable to the -directory in which you compiled boost, then you should set it temporarily. - -For example, if you built Boost in your home directory `~/boost_1_70_0`, you -would run the following shell command: - -``` -export BOOST_ROOT=~/boost_1_70_0 -``` - -Alternatively, you can add `DBOOST_ROOT=~/boost_1_70_0` to the command line when -invoking `cmake`. - -### Generate Configuration - -All builds should be done in a separate directory from the source tree root -(a subdirectory is fine). For example, from the root of the ripple source tree: - -``` -mkdir build -cd build -``` - -followed by: - -``` -cmake -DCMAKE_BUILD_TYPE=Debug .. -``` - -If your operating system does not provide static libraries (Arch Linux, and -Manjaro Linux, for example), you must configure a non-static build by adding -`-Dstatic=OFF` to the above cmake line. - -`CMAKE_BUILD_TYPE` can be changed as desired for `Debug` vs. -`Release` builds (all four standard cmake build types are supported). - -To select a different compiler (most likely gcc will be found by default), pass -`-DCMAKE_C_COMPILER=` and -`-DCMAKE_CXX_COMPILER=` when configuring. If you prefer, -you can instead set `CC` and `CXX` environment variables which cmake will honor. - -#### Options During Configuration: - -The CMake file defines a number of configure-time options which can be -examined by running `cmake-gui` or `ccmake` to generated the build. In -particular, the `unity` option allows you to select between the unity and -non-unity builds. `unity` builds are faster to compile since they combine -multiple sources into a single compiliation unit - this is the default if you -don't specify. `nounity` builds can be helpful for detecting include omissions -or for finding other build-related issues, but aren't generally needed for -testing and running. - -* `-Dunity=ON` to enable/disable unity builds (defaults to ON) -* `-Dassert=ON` to enable asserts -* `-Djemalloc=ON` to enable jemalloc support for heap checking -* `-Dsan=thread` to enable the thread sanitizer with clang -* `-Dsan=address` to enable the address sanitizer with clang -* `-Dstatic=ON` to enable static linking library dependencies -* `-Dreporting=ON` to build code necessary for reporting mode (defaults to OFF) - -Several other infrequently used options are available - run `ccmake` or -`cmake-gui` for a list of all options. - -### Build - -Once you have generated the build system, you can run the build via cmake: - -``` -cmake --build . -- -j $(echo $(nproc)-2 | bc) -``` - -the `-j` parameter in this example tells the build tool to compile several -files in parallel. This value should be chosen roughly based on the number of -cores you have available and/or want to use for building. - -When the build completes successfully, you will have a `rippled` executable in -the current directory, which can be used to connect to the network (when -properly configured) or to run unit tests. - - -#### Optional Installation - -The rippled cmake build supports an installation target that will install -rippled as well as a support library that can be used to sign transactions. In -order to build and install the files, specify the `install` target when -building, e.g.: - -``` -cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/opt/local .. -cmake --build . --target install -- -j $(echo $(nproc)-2 | bc) -``` - -We recommend specifying `CMAKE_INSTALL_PREFIX` when configuring in order to -explicitly control the install location for your files. Without this setting, -cmake will typically install in `/usr/local`. It is also possible to "rehome" -the installation by specifying the `DESTDIR` env variable during the install phase, -e.g.: - -``` -DESTDIR=~/mylibs cmake --build . --target install -- -j $(echo $(nproc)-2 | bc) -``` - -in which case, the files would be installed in the `CMAKE_INSTALL_PREFIX` within -the specified `DESTDIR` path. - -#### Signing Library - -If you want to use the signing support library to create an application, there -are two simple mechanisms with cmake + git that facilitate this. - -With either option below, you will have access to a library from the -rippled project that you can link to in your own project's CMakeLists.txt, e.g.: - -``` -target_link_libraries (my-signing-app Ripple::xrpl_core) -``` - -##### Option 1: git submodules + add_subdirectory - -First, add the rippled repo as a submodule to your project repo: - -``` -git submodule add -b master https://github.com/ripple/rippled.git vendor/rippled -``` - -change the `vendor/rippled` path as desired for your repo layout. Furthermore, -change the branch name if you want to track a different rippled branch, such -as `develop`. - -Second, to bring this submodule into your project, just add the rippled subdirectory: - -``` -add_subdirectory (vendor/rippled) -``` - -##### Option 2: installed rippled + find_package - -First, follow the "Optional Installation" instructions above to -build and install the desired version of rippled. - -To make use of the installed files, add the following to your CMakeLists.txt file: - -``` -set (CMAKE_MODULE_PATH /opt/local/lib/cmake/ripple ${CMAKE_MODULE_PATH}) -find_package(Ripple REQUIRED) -``` - -change the `/opt/local` module path above to match your chosen installation prefix. - -## Unit Tests (Recommended) - -`rippled` builds a set of unit tests into the server executable. To run these unit -tests after building, pass the `--unittest` option to the compiled `rippled` -executable. The executable will exit with summary info after running the unit tests. - -## Workaround for a compile error in soci - -Compilation errors have been observed with Apple Clang 13.1.6+ and soci v4.x. soci compiles with the `-Werror` flag which causes warnings to be treated as errors. These warnings pertain to style (not correctness). However, they cause the cmake process to fail. - -Here's an example of how this looks: -``` -.../rippled/.nih_c/unix_makefiles/AppleClang_13.1.6.13160021/Debug/src/soci/src/core/session.cpp:450:66: note: in instantiation of function template specialization 'soci::use' requested here - return prepare << backEnd_->get_column_descriptions_query(), use(table_name, "t"); - ^ -1 error generated. -``` - -Please apply the below patch (courtesy of Scott Determan) to remove these errors. `.nih_c/unix_makefiles/AppleClang_13.1.6.13160021/Debug/src/soci/cmake/SociConfig.cmake` file needs to be edited. This file is an example for Mac OS and it might be slightly different for other OS/Architectures. - -``` -diff --git a/cmake/SociConfig.cmake b/cmake/SociConfig.cmake -index 97d907e4..11bcd1f3 100644 ---- a/cmake/SociConfig.cmake -+++ b/cmake/SociConfig.cmake -@@ -58,8 +58,8 @@ if (MSVC) - - else() - -- set(SOCI_GCC_CLANG_COMMON_FLAGS -- "-pedantic -Werror -Wno-error=parentheses -Wall -Wextra -Wpointer-arith -Wcast-align -Wcast-qual -Wfloat-equal -Woverloaded-virtual -Wredundant-decls -Wno-long-long") -+ set(SOCI_GCC_CLANG_COMMON_FLAGS "") -+ # "-pedantic -Werror -Wno-error=parentheses -Wall -Wextra -Wpointer-arith -Wcast-align -Wcast-qual -Wfloat-equal -Woverloaded-virtual -Wredundant-decls -Wno-long-long") -``` +[Build instructions are currently located in `BUILD.md`](../../BUILD.md) diff --git a/Builds/macos/README.md b/Builds/macos/README.md index 2a4e28deb68..fce8e824a05 100644 --- a/Builds/macos/README.md +++ b/Builds/macos/README.md @@ -1,3 +1 @@ -# macOS Build Instructions - -[Build and Run rippled on macOS](https://xrpl.org/build-run-rippled-macos.html) +[Build instructions are currently located in `BUILD.md`](../../BUILD.md) diff --git a/README.md b/README.md index 267ecfb258b..b2d0ff42a3d 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,7 @@ The server software that powers the XRP Ledger is called `rippled` and is availa ### Build from Source -* [Linux](Builds/linux/README.md) -* [Mac](Builds/macos/README.md) (Not recommended for production) -* [Windows](Builds/VisualStudio2017/README.md) (Not recommended for production) +* [Read the build instructions in `BUILD.md`](BUILD.md) ## Key Features of the XRP Ledger @@ -34,8 +32,12 @@ The server software that powers the XRP Ledger is called `rippled` and is availa ## Source Code -[![travis-ci.com: Build Status](https://travis-ci.com/ripple/rippled.svg?branch=develop)](https://travis-ci.com/ripple/rippled) -[![codecov.io: Code Coverage](https://codecov.io/gh/ripple/rippled/branch/develop/graph/badge.svg)](https://codecov.io/gh/ripple/rippled) + +Here are some good places to start learning the source code: + +- Read the markdown files in the source tree: `src/ripple/**/*.md`. +- Read [the levelization document](./Builds/levelization) to get an idea of the internal dependency graph. +- In the big picture, the `main` function constructs an `ApplicationImp` object, which implements the `Application` virtual interface. Almost every component in the application takes an `Application&` parameter in its constructor, typically named `app` and stored as a member variable `app_`. This allows most components to depend on any other component. ### Repository Contents diff --git a/src/ripple/app/consensus/RCLConsensus.cpp b/src/ripple/app/consensus/RCLConsensus.cpp index 12a150a4a54..7ba059881c0 100644 --- a/src/ripple/app/consensus/RCLConsensus.cpp +++ b/src/ripple/app/consensus/RCLConsensus.cpp @@ -337,7 +337,7 @@ RCLConsensus::Adaptor::onClose( // pseudo-transactions auto validations = app_.validators().negativeUNLFilter( app_.getValidations().getTrustedForLedger( - prevLedger->info().parentHash)); + prevLedger->info().parentHash, prevLedger->seq() - 1)); if (validations.size() >= app_.validators().quorum()) { feeVote_->doVoting(prevLedger, validations, initialSet); diff --git a/src/ripple/app/ledger/impl/LedgerMaster.cpp b/src/ripple/app/ledger/impl/LedgerMaster.cpp index ad08b18dd58..7476698ee3a 100644 --- a/src/ripple/app/ledger/impl/LedgerMaster.cpp +++ b/src/ripple/app/ledger/impl/LedgerMaster.cpp @@ -341,7 +341,8 @@ LedgerMaster::setValidLedger(std::shared_ptr const& l) if (!standalone_) { auto validations = app_.validators().negativeUNLFilter( - app_.getValidations().getTrustedForLedger(l->info().hash)); + app_.getValidations().getTrustedForLedger( + l->info().hash, l->info().seq)); times.reserve(validations.size()); for (auto const& val : validations) times.push_back(val->getSignTime()); @@ -987,7 +988,7 @@ LedgerMaster::checkAccept(uint256 const& hash, std::uint32_t seq) return; auto validations = app_.validators().negativeUNLFilter( - app_.getValidations().getTrustedForLedger(hash)); + app_.getValidations().getTrustedForLedger(hash, seq)); valCount = validations.size(); if (valCount >= app_.validators().quorum()) { @@ -1053,7 +1054,8 @@ LedgerMaster::checkAccept(std::shared_ptr const& ledger) auto const minVal = getNeededValidations(); auto validations = app_.validators().negativeUNLFilter( - app_.getValidations().getTrustedForLedger(ledger->info().hash)); + app_.getValidations().getTrustedForLedger( + ledger->info().hash, ledger->info().seq)); auto const tvc = validations.size(); if (tvc < minVal) // nothing we can do { @@ -1128,7 +1130,7 @@ LedgerMaster::checkAccept(std::shared_ptr const& ledger) { // Have not printed the warning before, check if need to print. auto const vals = app_.getValidations().getTrustedForLedger( - ledger->info().parentHash); + ledger->info().parentHash, ledger->info().seq - 1); std::size_t higherVersionCount = 0; std::size_t rippledCount = 0; for (auto const& v : vals) diff --git a/src/ripple/app/misc/NegativeUNLVote.cpp b/src/ripple/app/misc/NegativeUNLVote.cpp index fba02637e51..5c133403b46 100644 --- a/src/ripple/app/misc/NegativeUNLVote.cpp +++ b/src/ripple/app/misc/NegativeUNLVote.cpp @@ -198,7 +198,7 @@ NegativeUNLVote::buildScoreTable( for (int i = 0; i < FLAG_LEDGER_INTERVAL; ++i) { for (auto const& v : validations.getTrustedForLedger( - ledgerAncestors[numAncestors - 1 - i])) + ledgerAncestors[numAncestors - 1 - i], seq - 2 - i)) { if (scoreTable.count(v->getNodeID())) ++scoreTable[v->getNodeID()]; diff --git a/src/ripple/consensus/Validations.h b/src/ripple/consensus/Validations.h index 46bf4322a5a..a9dbd5585e2 100644 --- a/src/ripple/consensus/Validations.h +++ b/src/ripple/consensus/Validations.h @@ -1049,10 +1049,11 @@ class Validations /** Get trusted full validations for a specific ledger @param ledgerID The identifier of ledger of interest + @param seq The sequence number of ledger of interest @return Trusted validations associated with ledger */ std::vector - getTrustedForLedger(ID const& ledgerID) + getTrustedForLedger(ID const& ledgerID, Seq const& seq) { std::vector res; std::lock_guard lock{mutex_}; @@ -1061,7 +1062,7 @@ class Validations ledgerID, [&](std::size_t numValidations) { res.reserve(numValidations); }, [&](NodeID const&, Validation const& v) { - if (v.trusted() && v.full()) + if (v.trusted() && v.full() && v.seq() == seq) res.emplace_back(v.unwrap()); }); diff --git a/src/test/consensus/Validations_test.cpp b/src/test/consensus/Validations_test.cpp index 79de1fc8063..7dc2086e55c 100644 --- a/src/test/consensus/Validations_test.cpp +++ b/src/test/consensus/Validations_test.cpp @@ -613,7 +613,8 @@ class Validations_test : public beast::unit_test::suite c.setLoadFee(12); e.setLoadFee(12); - hash_map> trustedValidations; + hash_map, std::vector> + trustedValidations; //---------------------------------------------------------------------- // checkers @@ -624,14 +625,15 @@ class Validations_test : public beast::unit_test::suite auto compare = [&]() { for (auto& it : trustedValidations) { - auto const& id = it.first; + auto const& id = it.first.first; + auto const& seq = it.first.second; auto const& expectedValidations = it.second; BEAST_EXPECT( harness.vals().numTrustedForLedger(id) == expectedValidations.size()); BEAST_EXPECT( - sorted(harness.vals().getTrustedForLedger(id)) == + sorted(harness.vals().getTrustedForLedger(id, seq)) == sorted(expectedValidations)); std::uint32_t baseFee = 0; @@ -653,7 +655,7 @@ class Validations_test : public beast::unit_test::suite Ledger ledgerAC = h["ac"]; // Add a dummy ID to cover unknown ledger identifiers - trustedValidations[Ledger::ID{100}] = {}; + trustedValidations[{Ledger::ID{100}, Ledger::Seq{100}}] = {}; // first round a,b,c agree for (auto const& node : {a, b, c}) @@ -661,13 +663,14 @@ class Validations_test : public beast::unit_test::suite auto const val = node.validate(ledgerA); BEAST_EXPECT(ValStatus::current == harness.add(val)); if (val.trusted()) - trustedValidations[val.ledgerID()].emplace_back(val); + trustedValidations[{val.ledgerID(), val.seq()}].emplace_back( + val); } // d disagrees { auto const val = d.validate(ledgerB); BEAST_EXPECT(ValStatus::current == harness.add(val)); - trustedValidations[val.ledgerID()].emplace_back(val); + trustedValidations[{val.ledgerID(), val.seq()}].emplace_back(val); } // e only issues partials { @@ -681,7 +684,8 @@ class Validations_test : public beast::unit_test::suite auto const val = node.validate(ledgerAC); BEAST_EXPECT(ValStatus::current == harness.add(val)); if (val.trusted()) - trustedValidations[val.ledgerID()].emplace_back(val); + trustedValidations[{val.ledgerID(), val.seq()}].emplace_back( + val); } // d now thinks ledger 1, but cannot re-issue a previously used seq // and attempting it should generate a conflict. @@ -1035,6 +1039,9 @@ class Validations_test : public beast::unit_test::suite std::vector const& trustedVals) { Ledger::ID testID = trustedVals.empty() ? this->genesisLedger.id() : trustedVals[0].ledgerID(); + Ledger::Seq testSeq = trustedVals.empty() + ? this->genesisLedger.seq() + : trustedVals[0].seq(); BEAST_EXPECT(vals.currentTrusted() == trustedVals); BEAST_EXPECT(vals.getCurrentNodeIDs() == listed); BEAST_EXPECT( @@ -1046,7 +1053,8 @@ class Validations_test : public beast::unit_test::suite else BEAST_EXPECT( vals.getPreferred(this->genesisLedger)->second == testID); - BEAST_EXPECT(vals.getTrustedForLedger(testID) == trustedVals); + BEAST_EXPECT( + vals.getTrustedForLedger(testID, testSeq) == trustedVals); BEAST_EXPECT( vals.numTrustedForLedger(testID) == trustedVals.size()); };