Add dev docs generation to Jenkins:

Fixes: RIPD-1521

Switch to pure doxygen HTML for developer docs. Remove docca/boostbook
system. Convert consensus document to markdown. Add existing markdown
files to doxygen input set. Fix some image paths and scale images for
use with MD links. Rename/cleanup some files for consistency.
Add pipeline logic for windows slaves. Add ninja and parallel test run
option. Add make doc target build in build-and-test.sh. Cleanup README
files. Add nounity windows build. Add link to jenkins summary table.
Add rippled_classic build (win). Improve formatting of summary table.
This commit is contained in:
Mike Ellery
2018-01-10 11:20:13 -08:00
parent 605ace7645
commit 755849115e
51 changed files with 676 additions and 3531 deletions

6
.codecov.yml Normal file
View File

@@ -0,0 +1,6 @@
codecov:
ci:
- ci.ops.ripple.com # add custom jenkins server
- !appveyor
- !travis

1
.gitignore vendored
View File

@@ -50,6 +50,7 @@ validators.txt
# Doxygen generated documentation output
HtmlDocumentation
docs/html_doc
# Xcode user-specific project settings
# Xcode

3
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "docs/docca"]
path = docs/docca
url = https://github.com/vinniefalco/docca.git
[submodule "src/nudb/extras/beast"]
path = src/nudb/extras/beast
url = https://github.com/vinniefalco/Beast.git

View File

@@ -32,7 +32,6 @@ addons:
matrix:
include:
# Default BUILD is "scons".
- compiler: gcc
env: GCC_VER=5 BUILD=cmake TARGET=debug

View File

@@ -32,7 +32,7 @@ package() {
cd "$srcdir/$pkgname"
install -D -m644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
install -D build/rippled "$pkgdir/usr/bin/rippled"
install -D -m644 doc/rippled-example.cfg "$pkgdir/etc/$pkgname/rippled.cfg"
install -D -m644 cfg/rippled-example.cfg "$pkgdir/etc/$pkgname/rippled.cfg"
mkdir -p "$pkgdir/var/lib/$pkgname/db"
mkdir -p "$pkgdir/var/log/$pkgname"
}

View File

@@ -21,7 +21,7 @@ RUN cd src/; scons build/rippled
RUN cp src/build/rippled rippled; strip rippled
# copy default config
RUN cp src/doc/rippled-example.cfg rippled.cfg
RUN cp src/cfg/rippled-example.cfg rippled.cfg
# clean source
RUN rm -r src

View File

@@ -1,7 +1,7 @@
set -e
mkdir -p build/docker/
cp doc/rippled-example.cfg build/clang.debug/rippled build/docker/
cp cfg/rippled-example.cfg build/clang.debug/rippled build/docker/
cp Builds/Docker/Dockerfile-testnet build/docker/Dockerfile
mv build/docker/rippled-example.cfg build/docker/rippled.cfg
strip build/docker/rippled

View File

@@ -200,7 +200,7 @@ the rippled server where that file is.
1. Create a directory to hold the configuration file. In this example, the
ripple config directory was created in `C:\Users\joe\ripple\config`.
2. Copy the example config file located in `doc\rippled-example.cfg` to the
2. Copy the example config file located in `cfg\rippled-example.cfg` to the
new directory and rename it "rippled.cfg".
3. Read the rippled.cfg file and edit as appropriate.

View File

@@ -374,15 +374,10 @@ if (WIN32 OR is_xcode)
# Documentation sources. Only needed for IDEs.
prepend(doc_srcs
docs/
Jamfile.v2
boostbook.dtd
consensus.qbk
index.xml
main.qbk
quickref.xml
reference.xsl
source.dox)
file(GLOB_RECURSE other_docs docs/*.md)
list(APPEND doc_srcs "${other_docs}")
set_property(
SOURCE ${doc_srcs}
APPEND
@@ -484,52 +479,32 @@ list(APPEND targets ${other_target})
# other_target when the user builds the solution (default when pressing <F7>)
set_property(TARGET ${other_target} PROPERTY EXCLUDE_FROM_DEFAULT_BUILD true)
find_program(
B2_EXE
NAMES b2
HINTS ${BOOST_ROOT}
PATHS ${BOOST_ROOT}
DOC "Location of the b2 build executable from Boost")
if(${B2_EXE} STREQUAL "B2_EXE-NOTFOUND")
find_package(Doxygen)
if(TARGET Doxygen::doxygen)
if (NOT DEFINED ENV{PLANTUML_JAR})
message(WARNING
"Boost b2 executable not found. docs target will not be buildable")
elseif(NOT BOOST_ROOT)
if(Boost_INCLUDE_DIRS)
set(BOOST_ROOT ${Boost_INCLUDE_DIRS})
else()
get_filename_component(BOOST_ROOT ${B2_EXE} DIRECTORY)
"PLANTUML_JAR not set - @startuml diagrams will not generate")
endif()
endif()
# The value for BOOST_ROOT will be determined based on
# 1) The environment BOOST_ROOT
# 2) The Boost_INCLUDE_DIRS found by `get_boost`
# 3) The folder the `b2` executable is found in.
# If those checks don't yield the correct path, BOOST_ROOT
# can be defined on the cmake command line:
# cmake <path> -DBOOST_ROOT=<boost_path>
if(BOOST_ROOT)
set(B2_PARAMS "-sBOOST_ROOT=${BOOST_ROOT}")
endif()
# Find bash to help Windows avoid file association problems
find_program(
BASH_EXE
NAMES bash sh
DOC "Location of the bash shell executable"
)
if(${BASH_EXE} STREQUAL "BASH_EXE-NOTFOUND")
message(WARNING
"Unable to find bash executable. docs target may not be buildable")
set(BASH_EXE "")
endif()
add_custom_target(docs
COMMAND ${CMAKE_COMMAND} -E env "PATH=$ENV{PATH} " ${BASH_EXE} ./makeqbk.sh
COMMAND ${B2_EXE} ${B2_PARAMS}
BYPRODUCTS "${CMAKE_SOURCE_DIR}/docs/html/index.html"
# read the source config and make a modified one
# that points the output files to our build directory
FILE(READ "${CMAKE_SOURCE_DIR}/docs/source.dox" dox_content)
string(REGEX REPLACE "[\t ]*OUTPUT_DIRECTORY[\t ]*=(.*)"
"OUTPUT_DIRECTORY=${CMAKE_BINARY_DIR}\n\\1"
new_config "${dox_content}")
FILE(WRITE "${CMAKE_BINARY_DIR}/source.dox" "${new_config}")
add_custom_target(docs
COMMAND "${DOXYGEN_EXECUTABLE}" "${CMAKE_BINARY_DIR}/source.dox"
BYPRODUCTS "${CMAKE_BINARY_DIR}/html_doc/index.html"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/docs"
SOURCES "${doc_srcs}"
)
else()
message(WARNING
"doxygen executable not found. docs target will not be buildable")
if(${CMAKE_VERSION} VERSION_LESS "3.9.0")
message("...consider updating to CMake 3.9.0 or greater for better doxygen support")
endif()
endif()
set_startup_project(rippled)

11
Jamroot
View File

@@ -1,11 +0,0 @@
#
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
import boost ;
boost.use-project ;

367
Jenkinsfile vendored
View File

@@ -74,11 +74,11 @@ try {
if (! collab_found) {
manager.addShortText(
"Author of this change is not a collaborator!",
"Crimson",
"white",
"0px",
"white")
'Author of this change is not a collaborator!',
'Crimson',
'white',
'0px',
'white')
all_status['startup'] =
[false, 'Author Check', "$CHANGE_AUTHOR is not a collaborator!"]
error "$CHANGE_AUTHOR does not appear to be a collaborator...bailing on this build"
@@ -88,93 +88,262 @@ try {
}
stage ('Parallel Build') {
def variants = [
'coverage',
'clang.debug.unity',
'clang.debug.nounity',
'gcc.debug.unity',
'gcc.debug.nounity',
'clang.release.unity',
'gcc.release.unity'] as String[]
String[][] variants = [
['coverage'],
['docs'],
['msvc.debug'],
// This one does not currently build (TBD):
//['msvc.debug.nounity'],
['msvc.debug', '', 'PROJECT_NAME=rippled_classic'],
['msvc.release'],
['clang.debug.unity'],
['clang.debug.unity', '', 'PARALLEL_TESTS=false'],
['clang.debug.nounity'],
['gcc.debug.unity'],
['gcc.debug.nounity'],
['clang.release.unity'],
['gcc.release.unity'],
// add a static build just to make sure it works
['gcc.debug.unity', '-Dstatic=true'],
// TODO - sanitizer runs currently fail
//['gcc.debug.nounity' , '-Dsan=address', 'PARALLEL_TESTS=false'],
//['gcc.debug.nounity' , '-Dsan=thread', 'PARALLEL_TESTS=false'],
]
// create a map of all builds
// that we want to run. The map
// is string keys and node{} object values
def builds = [:]
for (int index = 0; index < variants.size(); index++) {
def bldtype = variants[index]
builds[bldtype] = {
node('rippled-dev') {
def bldtype = variants[index][0]
def cmake_extra = variants[index].size() > 1 ? variants[index][1] : ''
def bldlabel = bldtype + cmake_extra
def extra_env = variants[index].size() > 2 ? variants[index][2..-1] : []
for (int j = 0; j < extra_env.size(); j++) {
bldlabel += "_" + extra_env[j]
}
bldlabel = bldlabel.replace('-', '_')
bldlabel = bldlabel.replace(' ', '')
bldlabel = bldlabel.replace('=', '_')
def compiler = getFirstPart(bldtype)
def target = getSecondPart(bldtype)
def config = getFirstPart(target)
if (compiler == 'coverage' || compiler == 'docs') {
compiler = 'gcc'
}
def cc =
(compiler == 'clang') ? '/opt/llvm-5.0.1/bin/clang' : 'gcc'
def cxx =
(compiler == 'clang') ? '/opt/llvm-5.0.1/bin/clang++' : 'g++'
def ucc = isNoUnity(target) ? 'true' : 'false'
def node_type =
(compiler == 'msvc') ? 'rippled-win' : 'rippled-dev'
// the default disposition for parallel test..disabled
// for coverage, enabled otherwise. Can still be overridden
// by explicitly setting with extra env settings above.
def pt = (compiler == 'coverage') ? 'false' : 'true'
def env_vars = [
"TARGET=${target}",
"CONFIG_TYPE=${config}",
"COMPILER=${compiler}",
"PARALLEL_TESTS=${pt}",
'BUILD=cmake',
"BUILD_DIR=${bldlabel}",
"CMAKE_EXTRA_ARGS=${cmake_extra}",
'VERBOSE_BUILD=true']
builds[bldlabel] = {
node(node_type) {
checkout scm
dir ('build') {
deleteDir()
}
def cdir = upDir(pwd())
echo "BASEDIR: ${cdir}"
def compiler = getCompiler(bldtype)
def target = getTarget(bldtype)
if (compiler == "coverage") {
compiler = 'gcc'
}
echo "COMPILER: ${compiler}"
echo "TARGET: ${target}"
def clang_cc =
(compiler == "clang") ? "${LLVM_ROOT}/bin/clang" : ''
def clang_cxx =
(compiler == "clang") ? "${LLVM_ROOT}/bin/clang++" : ''
def ucc = isNoUnity(target) ? 'true' : 'false'
echo "CONFIG: ${config}"
echo "USE_CC: ${ucc}"
withEnv(["CCACHE_BASEDIR=${cdir}",
"CCACHE_NOHASHDIR=true",
if (compiler == 'msvc') {
env_vars.addAll([
'BOOST_ROOT=c:\\lib\\boost_1_66',
'PROJECT_NAME=rippled',
'MSBUILDDISABLENODEREUSE=1', // this ENV setting is probably redundant since we also pass /nr:false to msbuild
'OPENSSL_ROOT=c:\\OpenSSL-Win64'])
}
else {
env_vars.addAll([
'NINJA_BUILD=false',
"CCACHE_BASEDIR=${cdir}",
'PLANTUML_JAR=/opt/plantuml/plantuml.jar',
'CCACHE_NOHASHDIR=true',
"CC=${cc}",
"CXX=${cxx}",
'LCOV_ROOT=""',
"TARGET=${target}",
"CC=${compiler}",
'BUILD=cmake',
'VERBOSE_BUILD=true',
"CLANG_CC=${clang_cc}",
"CLANG_CXX=${clang_cxx}",
'PATH+CMAKE_BIN=/opt/local/cmake',
'GDB_ROOT=/opt/local/gdb',
'BOOST_ROOT=/opt/local/boost_1_66_0',
"USE_CCACHE=${ucc}"])
}
if (extra_env.size() > 0) {
env_vars.addAll(extra_env)
}
withCredentials(
[string(
credentialsId: 'RIPPLED_CODECOV_TOKEN',
variable: 'CODECOV_TOKEN')])
{
myStage(bldtype)
withEnv(env_vars) {
myStage(bldlabel)
try {
sh "ccache -s > ${bldtype}.txt"
// the devtoolset from SCL gives us a recent gcc. It's
// not strictly needed when we are building with clang,
// but it doesn't seem to interfere either
sh "source /opt/rh/devtoolset-6/enable && " +
"(/usr/bin/time -p ./bin/ci/ubuntu/build-and-test.sh 2>&1) 2>&1 " +
">> ${bldtype}.txt"
sh "ccache -s >> ${bldtype}.txt"
if (compiler == 'msvc') {
powershell "Remove-Item -Path \"${bldlabel}.txt\" -Force -ErrorAction Ignore"
// we capture stdout to variable because I could
// not figure out how to make powershell redirect internally
output = powershell (
returnStdout: true,
script: '''
# Enable streams 3-6
$WarningPreference = 'Continue'
$VerbosePreference = 'Continue'
$DebugPreference = 'Continue'
$InformationPreference = 'Continue'
Invoke-BatchFile "${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\2017\\Community\\VC\\Auxiliary\\Build\\vcvarsall.bat" x86_amd64
Get-ChildItem env:* | Sort-Object name
cl
cmake --version
New-Item -ItemType Directory -Force -Path "build/$env:BUILD_DIR" -ErrorAction Stop
$sw = [Diagnostics.Stopwatch]::StartNew()
try {
Push-Location "build/$env:BUILD_DIR"
if ($env:NINJA_BUILD -eq "true") {
cmake -G"Ninja" -Dtarget="$env:COMPILER.$env:TARGET" -DCMAKE_VERBOSE_MAKEFILE=ON ../..
}
else {
cmake -G"Visual Studio 15 2017 Win64" -Dtarget="$env:COMPILER.$env:TARGET" -DCMAKE_VERBOSE_MAKEFILE=ON ../..
}
if ($LastExitCode -ne 0) { throw "CMake failed" }
## as of 01/2018, DO NOT USE cmake to run the actual build step. for some
## reason, cmake spawning the build under jenkins causes MSBUILD/ninja to
## get stuck at the end of the build. Perhaps cmake is spawning
## incorrectly or failing to pass certain params
if ($env:NINJA_BUILD -eq "true") {
ninja -j $env:NUMBER_OF_PROCESSORS -v
}
else {
msbuild /fl /m /nr:false /p:Configuration="$env:CONFIG_TYPE" /p:Platform=x64 /p:GenerateFullPaths=True /v:normal /nologo /clp:"ShowCommandLine;DisableConsoleColor" "$env:PROJECT_NAME.vcxproj"
}
if ($LastExitCode -ne 0) { throw "CMake build failed" }
$exe = "./$env:CONFIG_TYPE/$env:PROJECT_NAME"
if ($env:NINJA_BUILD -eq "true") {
$exe = "./$env:PROJECT_NAME"
}
"Exe is at $exe"
$params = '--unittest', '--quiet', '--unittest-log'
if ($env:PARALLEL_TESTS -eq "true") {
$params = $params += "--unittest-jobs=$env:NUMBER_OF_PROCESSORS"
}
& $exe $params
if ($LastExitCode -ne 0) { throw "Unit tests failed" }
}
catch {
throw
}
finally {
$sw.Stop()
$sw.Elapsed
Pop-Location
}
''')
// if the powershell command fails (has nonzero exit)
// then the command above throws, we don't get our output,
// and we never create this output file.
// SEE https://issues.jenkins-ci.org/browse/JENKINS-44930
// Alternatively, figure out how to reliably redirect
// all output above to a file (Start/Stop transcript does not work)
writeFile(
file: "${bldlabel}.txt",
text: output)
}
else {
sh "rm -fv ${bldlabel}.txt"
// execute the bld command in a redirecting shell
// to capture output
sh '''\
#!/bin/bash
set -ex
log_file=''' + "${bldlabel}.txt" + '''
exec 3>&1 1>>${log_file} 2>&1
ccache -s
source /opt/rh/devtoolset-6/enable
/usr/bin/time -p ./bin/ci/ubuntu/build-and-test.sh 2>&1
ccache -s
'''
}
}
finally {
def outstr = readFile("${bldtype}.txt")
def st = getResults(outstr)
def time = getTime(outstr)
def fail_count = getFailures(outstr)
def outstr = ''
def loglink = '[console](' + env.BUILD_URL + '/console)'
def logfile = "${bldlabel}.txt"
if (fileExists(logfile)) {
outstr = readFile(logfile)
loglink = "[logfile](" + env.BUILD_URL + "/artifact/${logfile})"
}
def st = getResults(outstr, bldlabel)
def time = getTime(outstr, bldlabel)
def fail_count = getFailures(outstr, bldlabel)
outstr = null
def txtcolor =
fail_count == 0 ? "DarkGreen" : "Crimson"
def shortbld = bldtype
fail_count == 0 ? 'DarkGreen' : 'Crimson'
def shortbld = bldlabel
shortbld = shortbld.replace('debug', 'dbg')
shortbld = shortbld.replace('release', 'rel')
shortbld = shortbld.replace('unity', 'un')
manager.addShortText(
"${shortbld}: ${st}, t: ${time}",
txtcolor,
"white",
"0px",
"white")
archive("${bldtype}.txt")
'white',
'0px',
'white')
archive("${bldlabel}.txt")
if (bldtype == 'docs') {
publishHTML(
allowMissing: true,
alwaysLinkToLastBuild: false,
keepAll: true,
reportName: 'Doxygen',
reportDir: 'build/docs/html_doc',
reportFiles: 'index.html')
}
def envs = ''
for (int j = 0; j < extra_env.size(); j++) {
envs += ", <br/>" + extra_env[j]
}
def cmake_txt = cmake_extra
if (cmake_txt != '') {
cmake_txt = " <br/>" + cmake_txt
}
lock('rippled_dev_status') {
all_status[bldtype] =
[fail_count == 0, bldtype, "${st}, t: ${time}"]
}
}
}
}
}
all_status[bldlabel] =
[fail_count == 0, bldtype + cmake_txt + envs, "${st}, t: ${time}", loglink]
}
} //try-catch-finally
} //withEnv
} //withCredentials
} //node
} //builds item
} //for variants
// this actually executes all the builds we just defined
// above, in parallel as slaves are available
parallel builds
}
}
@@ -183,7 +352,7 @@ finally {
stage ('Final Status') {
node {
def start_time = new Date()
def sdf = new SimpleDateFormat("yyyyMMdd - HH:mm:ss")
def sdf = new SimpleDateFormat('yyyyMMdd - HH:mm:ss')
def datestamp = sdf.format(start_time)
def results = """
@@ -195,19 +364,19 @@ Built at __${datestamp}__
### Test Results
Build Type | Result | Status
---------- | ------ | ------
Build Type | Log | Result | Status
---------- | --- | ------ | ------
"""
for ( e in all_status) {
results += e.value[1] + " | " + e.value[2] + " | " +
(e.value[0] ? "PASS :white_check_mark: " : "FAIL :red_circle: ") + "\n"
results += e.value[1] + ' | ' + e.value[3] + ' | ' + e.value[2] + ' | ' +
(e.value[0] ? 'PASS :white_check_mark: ' : 'FAIL :red_circle: ') + '\n'
}
results += "\n"
echo "FINAL BUILD RESULTS"
results += '\n'
echo 'FINAL BUILD RESULTS'
echo results
try {
def url_comment = ""
def url_comment = ''
if (env.CHANGE_ID && env.CHANGE_ID ==~ /\d+/) {
//
// CHANGE_ID indicates we are building a PR
@@ -251,7 +420,7 @@ Build Type | Result | Status
}
if (comment_id == 0) {
echo "no existing status comment found"
echo 'no existing status comment found'
}
def body = JsonOutput.toJson([
@@ -266,8 +435,8 @@ Build Type | Result | Status
httpMode: mode,
requestBody: body)
}
catch (any) {
echo "had a problem interacting with github...status is probably not updated"
catch (e) {
echo 'had a problem interacting with github...status is probably not updated'
}
}
}
@@ -295,24 +464,54 @@ ${log}
}
@NonCPS
def getResults(text) {
def getResults(text, label) {
// example:
/// 194.5s, 154 suites, 948 cases, 360485 tests total, 0 failures
def matcher = text =~ /(\d+) cases, (\d+) tests total, (\d+) (failure(s?))/
matcher ? matcher[0][1] + " cases, " + matcher[0][3] + " failed" : "no test results"
// or build log format:
// [msvc.release] 71.3s, 162 suites, 995 cases, 318901 tests total, 1 failure
def matcher =
text == '' ?
manager.getLogMatcher(/\[${label}\].+?(\d+) case[s]?, (\d+) test[s]? total, (\d+) (failure(s?))/) :
text =~ /(\d+) case[s]?, (\d+) test[s]? total, (\d+) (failure(s?))/
matcher ? matcher[0][1] + ' cases, ' + matcher[0][3] + ' failed' : 'no test results'
}
def getFailures(text) {
// example:
/// 194.5s, 154 suites, 948 cases, 360485 tests total, 0 failures
def matcher = text =~ /(\d+) tests total, (\d+) (failure(s?))/
def getFailures(text, label) {
// [see above for format]
def matcher =
text == '' ?
manager.getLogMatcher(/\[${label}\].+?(\d+) test[s]? total, (\d+) (failure(s?))/) :
text =~ /(\d+) test[s]? total, (\d+) (failure(s?))/
// if we didn't match, then return 1 since something is
// probably wrong, e.g. maybe the build failed...
matcher ? matcher[0][2] as Integer : 1i
}
@NonCPS
def getCompiler(bld) {
def getTime(text, label) {
// look for text following a label 'real' for
// wallclock time. Some `time`s report fractional
// seconds and we can omit those in what we report
def matcher =
text == '' ?
manager.getLogMatcher(/(?m)^\[${label}\]\s+real\s+(.+)\.(\d+?)[s]?/) :
text =~ /(?m)^real\s+(.+)\.(\d+?)[s]?/
if (matcher) {
return matcher[0][1] + 's'
}
// alternatively, look for powershell elapsed time
// format, e.g. :
// TotalSeconds : 523.2140529
def matcher2 =
text == '' ?
manager.getLogMatcher(/(?m)^\[${label}\]\s+TotalSeconds\s+:\s+(\d+)\.(\d+?)?/) :
text =~ /(?m)^TotalSeconds\s+:\s+(\d+)\.(\d+?)?/
matcher2 ? matcher2[0][1] + 's' : 'n/a'
}
@NonCPS
def getFirstPart(bld) {
def matcher = bld =~ /^(.+?)\.(.+)$/
matcher ? matcher[0][1] : bld
}
@@ -324,7 +523,7 @@ def isNoUnity(bld) {
}
@NonCPS
def getTarget(bld) {
def getSecondPart(bld) {
def matcher = bld =~ /^(.+?)\.(.+)$/
matcher ? matcher[0][2] : bld
}
@@ -337,12 +536,4 @@ def upDir(path) {
matcher ? matcher[0][1] : path
}
@NonCPS
def getTime(text) {
// look for text following a label 'real' for
// wallclock time. Some `time`s report fractional
// seconds and we can omit those in what we report
def matcher = text =~ /(?m)^real\s+(.+)\.(\d+?)[s]?/
matcher ? matcher[0][1] + "s" : "n/a"
}

View File

@@ -1,10 +1,11 @@
![Ripple](/images/ripple.png)
**Do you work at a digital asset exchange or wallet provider?**
Please [contact us](mailto:support@ripple.com). We can help guide your integration.
# What is Ripple?
![Ripple](docs/images/ripple.png)
> **Do you work at a digital asset exchange or wallet provider?**
>
> Please [contact us](mailto:support@ripple.com). We can help guide your integration.
Ripple is a network of computers which use the [Ripple consensus algorithm](https://www.youtube.com/watch?v=pj1QVb1vlC0) to atomically settle and record
transactions on a secure distributed database, the Ripple Consensus Ledger
(RCL). Because of its distributed nature, the RCL offers transaction immutability
@@ -36,7 +37,7 @@ multiple trading parties, who each layer costs to the transaction. Thin
liquidity and many intermediary trading parties make competitive pricing
challenging.
![Flow - Direct](images/flow1.png)
![Flow - Direct](docs/images/flow1.png)
### XRP as a Bridge Currency
Ripple can bridge even exotic currency pairs directly through XRP. Similar to
@@ -47,7 +48,7 @@ counterparty risk, or additional operational costs. By using XRP, liquidity
providers can specialize in certain currency corridors, reduce operational
costs, and ultimately, offer more competitive FX pricing.
![Flow - Bridged over XRP](images/flow2.png)
![Flow - Bridged over XRP](docs/images/flow2.png)
# rippled - Ripple server
`rippled` is the reference server implementation of the Ripple
@@ -68,7 +69,8 @@ ISC license. See the LICENSE file for more details.
| ./bin | Scripts and data files for Ripple integrators. |
| ./build | Intermediate and final build outputs. |
| ./Builds| Platform or IDE-specific project files. |
| ./doc | Documentation and example configuration files. |
| ./docs | Source documentation files and doxygen config. |
| ./cfg | Example configuration files. |
| ./src | Source code. |
Some of the directories under `src` are external repositories inlined via

View File

@@ -1,12 +1,15 @@
![Ripple](/images/ripple.png)
# Release Notes
![Ripple](docs/images/ripple.png)
This document contains the release notes for `rippled`, the reference server implementation of the Ripple protocol. To learn more about how to build and run a `rippled` server, visit https://ripple.com/build/rippled-setup/
**Do you work at a digital asset exchange or wallet provider?**
Please [contact us](mailto:support@ripple.com). We can help guide your integration.
> **Do you work at a digital asset exchange or wallet provider?**
>
> Please [contact us](mailto:support@ripple.com). We can help guide your integration.
## Updating `rippled`
If you are using Red Hat Enterprise Linux 7 or CentOS 7, you can [update using `yum`](https://ripple.com/build/rippled-setup/#updating-rippled). For other platforms, please [compile from source](https://wiki.ripple.com/Rippled_build_instructions).
# Releases

View File

@@ -6,6 +6,12 @@
set -ex
__dirname=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
echo "using CC: $CC"
"${CC}" --version
COMPNAME=$(basename $CC)
echo "using CXX: ${CXX:-notset}"
if [[ $CXX ]]; then
"${CXX}" --version
fi
echo "using TARGET: $TARGET"
# Ensure APP defaults to rippled if it's not set.
@@ -25,42 +31,69 @@ else
time=
fi
if [[ ${BUILD:-scons} == "cmake" ]]; then
if [[ ${BUILD:-cmake} == "cmake" ]]; then
echo "cmake building ${APP}"
CMAKE_EXTRA_ARGS=" -DCMAKE_VERBOSE_MAKEFILE=ON"
CMAKE_TARGET=$CC.$TARGET
BUILDARGS=" -j${JOBS}"
if [[ ${VERBOSE_BUILD:-} == true ]]; then
# TODO: if we use a different generator, this
# option to build verbose would need to change:
BUILDARGS+=" verbose=1"
: ${CMAKE_EXTRA_ARGS:=""}
if [[ ${NINJA_BUILD:-} == true ]]; then
CMAKE_EXTRA_ARGS+=" -G Ninja"
fi
CMAKE_TARGET=${COMPNAME}.${TARGET}
if [[ ${CI:-} == true ]]; then
CMAKE_TARGET=$CMAKE_TARGET.ci
fi
#
# allow explicit setting of the name of the build
# dir, otherwise default to the CMAKE_TARGET value
#
: "${BUILD_DIR:=$CMAKE_TARGET}"
BUILDARGS=" -j${JOBS}"
if [[ ${VERBOSE_BUILD:-} == true ]]; then
CMAKE_EXTRA_ARGS+=" -DCMAKE_VERBOSE_MAKEFILE=ON"
# TODO: if we use a different generator, this
# option to build verbose would need to change:
if [[ ${NINJA_BUILD:-} == true ]]; then
BUILDARGS+=" -v"
else
BUILDARGS+=" verbose=1"
fi
fi
if [[ ${USE_CCACHE:-} == true ]]; then
echo "using ccache with basedir [${CCACHE_BASEDIR:-}]"
CMAKE_EXTRA_ARGS+=" -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
CMAKE_EXTRA_ARGS+=" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
fi
if [ -d "build/${CMAKE_TARGET}" ]; then
rm -rf "build/${CMAKE_TARGET}"
if [ -d "build/${BUILD_DIR}" ]; then
rm -rf "build/${BUILD_DIR}"
fi
mkdir -p "build/${CMAKE_TARGET}"
pushd "build/${CMAKE_TARGET}"
mkdir -p "build/${BUILD_DIR}"
pushd "build/${BUILD_DIR}"
$time cmake ../.. -Dtarget=$CMAKE_TARGET ${CMAKE_EXTRA_ARGS}
if [[ ${TARGET} == "docs" ]]; then
$time cmake --build . --target docs -- $BUILDARGS
## mimic the standard test output for docs build
## to make controlling processes like jenkins happy
if [ -f html_doc/index.html ]; then
echo "1 case, 1 test total, 0 failures"
else
echo "1 case, 1 test total, 1 failures"
fi
exit
else
$time cmake --build . -- $BUILDARGS
if [[ ${BUILD_BOTH:-} == true ]]; then
if [[ ${TARGET} == *.unity ]]; then
$time cmake --build . --target rippled_classic -- $BUILDARGS
cmake --build . --target rippled_classic -- $BUILDARGS
else
$time cmake --build . --target rippled_unity -- $BUILDARGS
cmake --build . --target rippled_unity -- $BUILDARGS
fi
fi
fi
popd
export APP_PATH="$PWD/build/${CMAKE_TARGET}/${APP}"
export APP_PATH="$PWD/build/${BUILD_DIR}/${APP}"
echo "using APP_PATH: $APP_PATH"
else
export APP_PATH="$PWD/build/$CC.$TARGET/${APP}"
export APP_PATH="$PWD/build/${COMPNAME}.${TARGET}/${APP}"
echo "using APP_PATH: $APP_PATH"
# Make sure vcxproj is up to date
$time scons vcxproj
@@ -68,21 +101,21 @@ else
# $CC will be either `clang` or `gcc`
# http://docs.travis-ci.com/user/migrating-from-legacy/?utm_source=legacy-notice&utm_medium=banner&utm_campaign=legacy-upgrade
# indicates that 2 cores are available to containers.
$time scons -j${JOBS} $CC.$TARGET
$time scons -j${JOBS} ${COMPNAME}.$TARGET
fi
# We can be sure we're using the build/$CC.$TARGET variant
# (-f so never err)
rm -f build/${APP}
# See what we've actually built
ldd $APP_PATH
if [[ ${APP} == "rippled" ]]; then
export APP_ARGS+=" --unittest --quiet --unittest-log"
APP_ARGS+="--unittest --quiet --unittest-log"
# Only report on src/ripple files
export LCOV_FILES="*/src/ripple/*"
# Nothing to explicitly exclude
export LCOV_EXCLUDE_FILES="LCOV_NO_EXCLUDE"
if [[ $TARGET != "coverage" && ${PARALLEL_TESTS:-} == true ]]; then
APP_ARGS+=" --unittest-jobs ${JOBS}"
fi
else
: ${APP_ARGS:=}
: ${LCOV_FILES:="*/src/*"}
@@ -106,6 +139,7 @@ if [[ $TARGET == debug* && -v GDB_ROOT && -x $GDB_ROOT/bin/gdb ]]; then
$GDB_ROOT/bin/gdb -v
# Execute unit tests under gdb, printing a call stack
# if we get a crash.
export APP_ARGS
$GDB_ROOT/bin/gdb -return-child-result -quiet -batch \
-ex "set env MALLOC_CHECK_=3" \
-ex "set print thread-events off" \

View File

@@ -1,29 +0,0 @@
A list of rippled version numbers, and the Github pull requests they contain.
0.28.0-b12: Includes pulls 836, 887, 902, 903 and 904.
0.28.0-b13: Includes pulls 906, 912, 913, 914 and 915.
0.28.0-b14: Includes pulls 907, 910, 922 and 923.
0.28.0-b15: Includes pulls 832, 870, 879, 883, 911, 916, 919, 920, 924, 925 and 928. FAILED pulls 909 and 926.
0.28.0-b16: Includes pulls 909, 926, 929, 931, 932, 935 and 934.
0.28.0-b17: Includes pulls 927, 939, 940, 943, 944, 945 and 949.
0.28.0-b18: Includes pulls 930, 946, 947, 948, 951, 952, 953, 954, 955, 956, 959, 960 and 962.
0.29.0-b19: Includes pulls 967, 969 and 971.
0.29.0-b20: Includes pulls 935, 942, 957, 958, 963, 964, 965, 966, 968, 972, 973, 974 and 975.
0.29.0-b21: Includes pulls 970 and 976.
0.28.1-b4: Includes pulls 968, 998, 1005, 1008, 1010, 1011 and 1012.
0.28.1-b6: Includes pulls 983, 984, 1013, 1023 and 1024.
0.28.1-b8: Includes pulls 988, 1009, 1014, 1019, 1029, 1031, 1033, 1034 and 1035.
0.28.1-b9: Includes pulls 1026, 1030, 1036, 1037, 1038, 1040, and 1041.
0.28.1-rc2: Includes pulls 1044
0.28.1-rc3: Includes pulls 1052 and 1055.
0.28.1: Includes pulls 1056, 1059 and 1062, 1063.
0.28.2-b1: Includes pulls 866, 1045, 1046, 1047, 1050, 1051, 1057
0.28.2-b2: Includes pulls 1058, 1061, 1064 and 1065
0.28.2-b3: Includes pulls 1066, 1067, 1068
0.28.2-b4: Includes pulls 1060, 1069, 1071, 1072, 1075 and 1076.
0.28.2-b5: Includes pulls 1073, 1074, 1081, 1083, 1084, 1087, 1089, 1090, 1091
0.28.2-b6: Includes pulls 1085, 1093, 1094, 1096, 1101, 1102, 1105
0.28.2-b7: Includes pulls 1077, 1080, 1086, 1095, 1098, 1106 and 1112.
0.28.2-b8: Includes pulls 1078, 1100, 1108, 1114, 1118, 1119 and 1121.
0.28.2-b9: Includes pulls 1053, 1109, 1111, 1117, 1122 and 1123.
0.29.1-b11: Includes pulls 1279, 1271, 1289, 1291, 1290, 1267, 1294, 1276, 1231, and 1286.

File diff suppressed because it is too large Load Diff

View File

@@ -1,126 +0,0 @@
#
# Sample ripple.txt
#
# More information: https://ripple.com/wiki/Ripple.txt
#
# Publishing this file allows a site to declare in a trustworthy manor ripple
# associated information.
#
# This file is stored on the web server for a domain. This file is searched
# for in the following order:
# - https://ripple.DOMAIN/ripple.txt
# - https://www.DOMAIN/ripple.txt
# - https://DOMAIN/ripple.txt
#
# The server MUST set the following HTTP header when serving this file:
# Access-Control-Allow-Origin: *
#
# This file is UTF-8 with Dos, UNIX, or Mac style end of lines.
# Blank lines and lines beginning with '#' are ignored.
# Undefined sections are reserved.
# No escapes are currently defined.
#
# IMPORTANT: Please remove these comments before publishing this file. Doing so
# makes the file much more readable to humans trying to find info on your site.
#
# [expires]
# Number of days after which this file should be considered expire. Clients
# are expected to check this file when they have cause to believe it has
# changed or expired. For example, if a client discovers an account declares
# that it is associated with the domain, it should check to see if this file
# has been updated. If an expiration date is not declared, the default
# expiration for this file is 30 days.
#
# Example: 30
#
# [accounts]
# Only valid in "ripple.txt". A list of accounts that are declared to be
# controlled by this domain. A client wishing to indicate that an account is
# verified as belonging to a domain will be show the account with a green
# background. A client can verify that an account belongs to a domain by
# checking if the account's root entry mentions the domain containing this
# file and this file found at the domain mentions the account in this
# section.
#
# Example: rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn
#
# [hotwallets]
# Only valid in "ripple.txt". A list of accounts that are declared to be
# controlled by this domain and used as hotwallets.
#
# Example: rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn
#
# [validation_public_key]:
# Only valid in "ripple.txt". A validation public key that is declared
# to be used by this domain for validating ledgers and that it is the
# authorized signature for the domain. This does not imply that a node
# serving the Ripple protocol is avilable at the web host providing the
# file.
#
# Example: n9MZTnHe5D5Q2cgE8oV2usFwRqhUvEA8MwP5Mu1XVD6TxmssPRev
#
# [domain]:
# Mandatory in "ripple.txt".
# Only valid in "ripple.txt".
# Must match location of file.
#
# Example: google.com
#
# [ips]:
# Only valid in "rippled.cfg", "ripple.txt", and the referered [ips_url].
# List of ips where the Newcoin protocol is avialable.
# One ipv4 or ipv6 address per line.
# A port may optionally be specified after adding a space to the address.
# By convention, if known, IPs are listed in from most to least trusted.
#
# Examples:
# 192.168.0.1
# 192.168.0.1 3939
# 2001:0db8:0100:f101:0210:a4ff:fee3:9566
#
# [validators]:
# Only valid in "rippled.cfg", "ripple.txt", and the referered [validators_url].
# List of Ripple validators this node recommends.
#
# For domains, rippled will probe for https web servers at the specied
# domain in the following order: ripple.DOMAIN, www.DOMAIN, DOMAIN
#
# These are encoded 257-bit secp256k1 public keys.
#
# Examples:
# redstem.com
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
#
# [ips_url]:
# Only valid in "ripple.txt".
# https URL to a similarily formatted file containing [ips].
#
# Example: https://google.com/ripple_ips.txt
#
# [validators_url]:
# Only valid in "ripple.txt".
# https URL to a similarily formatted file containing [validators].
#
# Example: https://google.com/ripple_validators.txt
#
# [currencies]:
# This section allows a site to declare currencies it currently issues.
#
# Examples: (multiple allowed one per line)
# USD
# BTC
# LTC
#
[validation_public_key]
n9MZTnHe5D5Q2cgE8oV2usFwRqhUvEA8MwP5Mu1XVD6TxmssPRev
[domain]
loss
[ips]
192.168.0.5
[validators]
redstem.com

View File

@@ -1,4 +1,6 @@
# Form
# Code Style Cheat Sheet
## Form
- One class per header file.
- Place each data member on its own line.
@@ -11,7 +13,7 @@
- Order class declarations as types, public, protected, private, then data.
- Prefer 'private' over 'protected'
# Function
## Function
- Minimize external dependencies
* Pass options in the ctor instead of using theConfig

View File

@@ -1,5 +1,3 @@
--------------------------------------------------------------------------------
# Coding Standards
Coding standards used here gradually evolve and propagate through

View File

@@ -1,22 +1,31 @@
FROM ubuntu:16.04
RUN apt-get update
RUN apt-get -y install build-essential g++ git libbz2-dev wget python-dev
RUN apt -y update
RUN apt -y upgrade
RUN apt -y install build-essential g++ git libbz2-dev wget python-dev
RUN apt -y install cmake flex bison graphviz graphviz-dev libicu-dev
RUN apt -y install jarwrapper java-common
# Install Boost
ENV BOOST_SHA 440a59f8bc4023dbe6285c9998b0f7fa288468b889746b1ef00e8b36c559dce1
RUN wget https://sourceforge.net/projects/boost/files/boost/1.62.0/boost_1_62_0.tar.gz
RUN echo "$BOOST_SHA boost_1_62_0.tar.gz" | sha256sum -c
RUN tar xzf boost_1_62_0.tar.gz
RUN cd boost_1_62_0 && ./bootstrap.sh --prefix=/usr/local
RUN cd boost_1_62_0 && ./b2 install
ENV BOOST_ROOT=/boost_1_62_0
RUN cd /tmp
ENV CM_INSTALLER=cmake-3.10.0-rc3-Linux-x86_64.sh
ENV CM_VER_DIR=/opt/local/cmake-3.10.0
RUN cd /tmp && wget https://cmake.org/files/v3.10/$CM_INSTALLER && chmod a+x $CM_INSTALLER
RUN mkdir -p $CM_VER_DIR
RUN ln -s $CM_VER_DIR /opt/local/cmake
RUN /tmp/$CM_INSTALLER --prefix=$CM_VER_DIR --exclude-subdir
RUN rm -f /tmp/$CM_INSTALLER
# Install dependencies
RUN apt-get -y install doxygen
RUN apt-get -y install xsltproc
RUN cd /tmp && wget https://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.14.src.tar.gz
RUN cd /tmp && tar xvf doxygen-1.8.14.src.tar.gz
RUN mkdir -p /tmp/doxygen-1.8.14/build
RUN cd /tmp/doxygen-1.8.14/build && /opt/local/cmake/bin/cmake -G "Unix Makefiles" ..
RUN cd /tmp/doxygen-1.8.14/build && make -j2
RUN cd /tmp/doxygen-1.8.14/build && make install
RUN rm -f /tmp/doxygen-1.8.14.src.tar.gz
RUN rm -rf /tmp/doxygen-1.8.14
CMD cd /opt/rippled/docs && \
chmod +x makeqbk.sh && \
./makeqbk.sh && \
$BOOST_ROOT/b2
RUN mkdir -p /opt/plantuml
RUN wget -O /opt/plantuml/plantuml.jar http://sourceforge.net/projects/plantuml/files/plantuml.jar/download
ENV PLANTUML_JAR=/opt/plantuml/plantuml.jar
CMD cd /opt/rippled/docs && doxygen source.dox

View File

@@ -1,81 +0,0 @@
#
# Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
import os ;
local broot = [ os.environ BOOST_ROOT ] ;
project rippled/doc ;
using boostbook ;
using quickbook ;
using doxygen ;
path-constant out : . ;
install stylesheets
:
$(broot)/doc/src/boostbook.css
:
<location>$(out)/html
;
explicit stylesheets ;
install images
:
[ glob $(broot)/doc/src/images/*.png ]
:
<location>$(out)/html/images
;
explicit images ;
install callouts
:
[ glob $(broot)/doc/src/images/callouts/*.png ]
:
<location>$(out)/html/images/callouts
;
explicit callout ;
install consensus_images
:
[ glob images/consensus/*.png ]
:
<location>$(out)/html/images/consensus
;
explicit consensus_images ;
xml doc
:
main.qbk
:
<location>temp
<include>$(broot)/tools/boostbook/dtd
;
boostbook boostdoc
:
doc
:
<xsl:param>chapter.autolabel=0
<xsl:param>boost.root=$(broot)
<xsl:param>chunk.first.sections=1 # Chunk the first top-level section?
<xsl:param>chunk.section.depth=8 # Depth to which sections should be chunked
<xsl:param>generate.section.toc.level=2 # Control depth of TOC generation in sections
<xsl:param>toc.max.depth=2 # How many levels should be created for each TOC?
<xsl:param>toc.section.depth=2 # How deep should recursive sections appear in the TOC?
<xsl:param>generate.toc="chapter toc section toc"
:
<location>temp
<dependency>stylesheets
<dependency>images
<dependency>consensus_images
;

View File

@@ -13,21 +13,6 @@ relative to the `docs/` directory.
Install these dependencies:
1. Install [Doxygen](http://www.stack.nl/~dimitri/doxygen/download.html)
2. Download the following zip files from [xsltproc](https://www.zlatkovic.com/pub/libxml/)
(Alternate download: ftp://ftp.zlatkovic.com/libxml/),
and extract the `bin\` folder contents into any folder in your path.
* iconv
* libxml2
* libxslt
* zlib
3. Download [Boost](http://www.boost.org/users/download/)
1. Extract the compressed file contents to your (new) `$BOOST_ROOT` location.
2. Open a command prompt or shell in the `$BOOST_ROOT`.
3. `./bootstrap.bat`
4. (Optional, if you also plan to build rippled) `./bjam.exe --toolset=msvc-14.0
--build-type=complete variant=debug,release link=static runtime-link=static
address-model=64 stage`
5. If it is not already there, add your `$BOOST_ROOT` to your environment `$PATH`.
### MacOS
@@ -38,47 +23,54 @@ Install these dependencies:
You'll then need to make doxygen available to your command line. You can
do this by adding a symbolic link from `/usr/local/bin` to the doxygen
executable. For example, `$ ln -s /Applications/Doxygen.app/Contents/Resources/doxygen /usr/local/bin/doxygen`
2. Install [Boost](http://www.boost.org/users/download/)
1. Extract the compressed file contents to your (new) `$BOOST_ROOT` location.
2. Open a command prompt or shell in the `$BOOST_ROOT`.
3. `$ ./bootstrap.bat`
4. (Optional, if you also plan to build rippled)
`$ ./b2 toolset=clang threading=multi runtime-link=static link=static
cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" adress-model=64`
5. If it is not already there, add your `$BOOST_ROOT` to your environment
`$PATH`. This makes the `b2` command available to the command line.
3. That should be all that's required. In OS X 10.11, at least, libxml2 and
libxslt come pre-installed.
### Linux
1. Install [Docker](https://docs.docker.com/engine/installation/)
2. Build Docker image. From the rippled root folder:
```
sudo docker build -t rippled-docs docs/
```
1. Install doxygen using your package manager OR from source using the links above.
## Setup project submodules
### [Optional] Install Plantuml (all platforms)
1. Open a shell in your rippled root folder.
2. `git submodule init`
3. `git submodule update docs/docca`
Doxygen supports the optional use of [plantuml](http://plantuml.com) to
generate diagrams from `@startuml` sections. We don't currently rely on this
functionality for docs, so it's largely optional. Requirements:
1. Download/install a functioning java runtime, if you don't already have one.
2. Download [plantuml](http://plantuml.com) from
[here](http://sourceforge.net/projects/plantuml/files/plantuml.jar/download).
Set a system environment variable named `PLANTUML_JAR` with a value of the fullpath
to the file system location of the `plantuml.jar` file you downloaded.
## Do it
### Windows & MacOS
### all platforms
From the rippled root folder:
```
cd docs
./makeqbk.sh && b2
mkdir -p html_doc
doxygen source.dox
```
The output will be in `docs/html`.
The output will be in `docs/html_doc`.
### Linux
## Docker
(applicable to all platforms)
Instead of installing the doxygen tools locally, you can use the provided `Dockerfile` to create
an ubuntu based image for running the tools:
1. Install [Docker](https://docs.docker.com/engine/installation/)
2. Build Docker image. From the rippled root folder:
```
sudo docker build -t rippled-docs docs/
```
Then to run the image, from the rippled root folder:
From the rippled root folder:
```
sudo docker run -v $PWD:/opt/rippled --rm rippled-docs
```
The output will be in `docs/html`.
The output will be in `docs/html_doc`.

View File

@@ -1,439 +0,0 @@
<!--
BoostBook DTD - development version
For further information, see: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Boost_Documentation_Format
Copyright (c) 2002 by Peter Simons <simons@cryp.to>
Copyright (c) 2003-2004 by Douglas Gregor <doug.gregor -at- gmail.com>
Copyright (c) 2007 by Frank Mori Hess <fmhess@users.sourceforge.net>
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
The latest stable DTD module is identified by the PUBLIC and SYSTEM identifiers:
PUBLIC "-//Boost//DTD BoostBook XML V1.1//EN"
SYSTEM "http://www.boost.org/tools/boostbook/dtd/1.1/boostbook.dtd"
$Revision$
$Date$
-->
<!--========== Define XInclude features. ==========-->
<!-- This is not really integrated into the DTD yet. Needs more
research. -->
<!--
<!ELEMENT xi:include (xi:fallback)?>
<!ATTLIST xi:include
xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude"
href CDATA #REQUIRED
parse (xml|text) "xml"
encoding CDATA #IMPLIED>
<!ELEMENT xi:fallback ANY>
<!ATTLIST xi:fallback
xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude">
-->
<!ENTITY % local.common.attrib "last-revision CDATA #IMPLIED">
<!--========== Define the BoostBook extensions ==========-->
<!ENTITY % boost.common.attrib "%local.common.attrib;
id CDATA #IMPLIED">
<!ENTITY % boost.namespace.mix
"class|class-specialization|struct|struct-specialization|
union|union-specialization|typedef|enum|
free-function-group|function|overloaded-function|
namespace">
<!ENTITY % boost.template.mix
"template-type-parameter|template-nontype-parameter|template-varargs">
<!ENTITY % boost.class.members
"static-constant|typedef|enum|
copy-assignment|constructor|destructor|method-group|
method|overloaded-method|data-member|class|class-specialization|struct|
struct-specialization|union|union-specialization">
<!ENTITY % boost.class.mix
"%boost.class.members;|free-function-group|function|overloaded-function">
<!ENTITY % boost.class.content
"template?, inherit*, purpose?, description?,
(%boost.class.mix;|access)*">
<!ENTITY % boost.class-specialization.content
"template?, specialization?, inherit?, purpose?, description?,
(%boost.class.mix;|access)*">
<!ENTITY % boost.function.semantics
"purpose?, description?, requires?, effects?, postconditions?,
returns?, throws?, complexity?, notes?, rationale?">
<!ENTITY % library.content
"libraryinfo, (title, ((section|library-reference|testsuite))+)?">
<!ELEMENT library (%library.content;)>
<!ATTLIST library
name CDATA #REQUIRED
dirname CDATA #REQUIRED
html-only CDATA #IMPLIED
url CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT boostbook (title, (chapter|library)*)>
<!ATTLIST boostbook %boost.common.attrib;>
<!ELEMENT libraryinfo (author+, copyright*, legalnotice*, librarypurpose, librarycategory*)>
<!ATTLIST libraryinfo %boost.common.attrib;>
<!ELEMENT librarypurpose (#PCDATA|code|ulink|functionname|methodname|classname|macroname|headername|enumname|globalname)*>
<!ATTLIST librarypurpose %boost.common.attrib;>
<!ELEMENT librarycategory (#PCDATA)>
<!ATTLIST librarycategory
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT libraryname (#PCDATA)>
<!ATTLIST libraryname %boost.common.attrib;>
<!ELEMENT library-reference ANY>
<!ATTLIST library-reference
%boost.common.attrib;>
<!ELEMENT librarylist EMPTY>
<!ATTLIST librarylist %boost.common.attrib;>
<!ELEMENT librarycategorylist (librarycategorydef)*>
<!ATTLIST librarycategorylist %boost.common.attrib;>
<!ELEMENT librarycategorydef (#PCDATA)>
<!ATTLIST librarycategorydef
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT header ANY>
<!ATTLIST header
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT namespace (%boost.namespace.mix;)*>
<!ATTLIST namespace
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT class (%boost.class.content;)>
<!ATTLIST class
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT struct (%boost.class.content;)>
<!ATTLIST struct
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT union (%boost.class.content;)>
<!ATTLIST union
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT class-specialization (%boost.class-specialization.content;)>
<!ATTLIST class-specialization
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT struct-specialization (%boost.class-specialization.content;)>
<!ATTLIST struct-specialization
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT union-specialization (%boost.class-specialization.content;)>
<!ATTLIST union-specialization
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT access (%boost.class.members;)+>
<!ATTLIST access
name CDATA #REQUIRED
%boost.common.attrib;>
<!--========= C++ Templates =========-->
<!ELEMENT template (%boost.template.mix;)*>
<!ATTLIST template %boost.common.attrib;>
<!ELEMENT template-type-parameter (default?, purpose?)>
<!ATTLIST template-type-parameter
name CDATA #REQUIRED
pack CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT template-nontype-parameter (type, default?, purpose?)>
<!ATTLIST template-nontype-parameter
name CDATA #REQUIRED
pack CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT template-varargs EMPTY>
<!ATTLIST template-varargs %boost.common.attrib;>
<!ELEMENT specialization (template-arg)*>
<!ATTLIST specialization %boost.common.attrib;>
<!ELEMENT template-arg ANY>
<!ATTLIST template-arg
pack CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT default ANY>
<!ATTLIST default %boost.common.attrib;>
<!ELEMENT inherit (type, purpose?)>
<!ATTLIST inherit
access CDATA #IMPLIED
pack CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT purpose ANY>
<!ATTLIST purpose %boost.common.attrib;>
<!ELEMENT description ANY>
<!ATTLIST description %boost.common.attrib;>
<!ELEMENT type ANY>
<!ATTLIST type %boost.common.attrib;>
<!ELEMENT typedef (type, purpose?, description?)>
<!ATTLIST typedef
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT enum (enumvalue*, purpose?, description?)>
<!ATTLIST enum
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT enumvalue (default?, purpose?, description?)>
<!ATTLIST enumvalue
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT static-constant (type, default, purpose?, description?)>
<!ATTLIST static-constant
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT data-member (type, purpose?, description?)>
<!ATTLIST data-member
name CDATA #REQUIRED
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT paramtype ANY>
<!ATTLIST paramtype %boost.common.attrib;>
<!ELEMENT effects ANY>
<!ATTLIST effects %boost.common.attrib;>
<!ELEMENT postconditions ANY>
<!ATTLIST postconditions %boost.common.attrib;>
<!ELEMENT method-group (method|overloaded-method)*>
<!ATTLIST method-group
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT constructor (template?, parameter*, %boost.function.semantics;)>
<!ATTLIST constructor
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT destructor (%boost.function.semantics;)>
<!ATTLIST destructor
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT method (template?, type, parameter*, %boost.function.semantics;)>
<!ATTLIST method
name CDATA #REQUIRED
cv CDATA #IMPLIED
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT function (template?, type, parameter*, %boost.function.semantics;)>
<!ATTLIST function
name CDATA #REQUIRED
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT overloaded-method (signature*, %boost.function.semantics;)>
<!ATTLIST overloaded-method
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT overloaded-function (signature*, %boost.function.semantics;)>
<!ATTLIST overloaded-function
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT signature (template?, type, parameter*)>
<!ATTLIST signature
cv CDATA #IMPLIED
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT requires ANY>
<!ATTLIST requires %boost.common.attrib;>
<!ELEMENT returns ANY>
<!ATTLIST returns %boost.common.attrib;>
<!ELEMENT throws ANY>
<!ATTLIST throws %boost.common.attrib;>
<!ELEMENT complexity ANY>
<!ATTLIST complexity %boost.common.attrib;>
<!ELEMENT notes ANY>
<!ATTLIST notes %boost.common.attrib;>
<!ELEMENT rationale ANY>
<!ATTLIST rationale %boost.common.attrib;>
<!ELEMENT functionname (#PCDATA)>
<!ATTLIST functionname
alt CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT enumname (#PCDATA)>
<!ATTLIST enumname
alt CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT macroname (#PCDATA)>
<!ATTLIST macroname
alt CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT headername (#PCDATA)>
<!ATTLIST headername
alt CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT globalname (#PCDATA)>
<!ATTLIST globalname
alt CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT copy-assignment
(template?, type?, parameter*, %boost.function.semantics;)>
<!ATTLIST copy-assignment
cv CDATA #IMPLIED
specifiers CDATA #IMPLIED
%boost.common.attrib;>
<!ELEMENT free-function-group (function|overloaded-function)*>
<!ATTLIST free-function-group
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT precondition ANY>
<!ATTLIST precondition %boost.common.attrib;>
<!ELEMENT code ANY>
<!ATTLIST code %boost.common.attrib;>
<!ELEMENT using-namespace EMPTY>
<!ATTLIST using-namespace
name CDATA #REQUIRED
%boost.common.attrib;>
<!ELEMENT using-class EMPTY>
<!ATTLIST using-class
name CDATA #REQUIRED
%boost.common.attrib;>
<!--========== Boost Testsuite Extensions ==========-->
<!ENTITY % boost.testsuite.tests
"compile-test|link-test|run-test|
compile-fail-test|link-fail-test|run-fail-test">
<!ENTITY % boost.testsuite.test.content
"source*, lib*, requirement*, purpose, if-fails?">
<!ELEMENT testsuite ((%boost.testsuite.tests;)+)>
<!ATTLIST testsuite %boost.common.attrib;>
<!ELEMENT compile-test (%boost.testsuite.test.content;)>
<!ATTLIST compile-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT link-test (%boost.testsuite.test.content;)>
<!ATTLIST link-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT run-test (%boost.testsuite.test.content;)>
<!ATTLIST run-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT compile-fail-test (%boost.testsuite.test.content;)>
<!ATTLIST compile-fail-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT link-fail-test (%boost.testsuite.test.content;)>
<!ATTLIST link-fail-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT run-fail-test (%boost.testsuite.test.content;)>
<!ATTLIST run-fail-test
filename CDATA #REQUIRED
name CDATA #IMPLIED>
<!ELEMENT source (#PCDATA|snippet)*>
<!ELEMENT snippet EMPTY>
<!ATTLIST snippet
name CDATA #REQUIRED>
<!ELEMENT lib (#PCDATA)>
<!ELEMENT requirement (#PCDATA)>
<!ATTLIST requirement
name CDATA #REQUIRED>
<!ELEMENT if-fails ANY>
<!ELEMENT parameter (paramtype, default?, description?)>
<!ATTLIST parameter
name CDATA #IMPLIED
pack CDATA #IMPLIED>
<!ELEMENT programlisting ANY>
<!ATTLIST programlisting
name CDATA #IMPLIED>
<!--========== Customize the DocBook DTD ==========-->
<!ENTITY % local.tech.char.class "|functionname|libraryname|enumname|headername|macroname|code">
<!ENTITY % local.para.class
"|using-namespace|using-class|librarylist|librarycategorylist">
<!ENTITY % local.descobj.class "|libraryinfo">
<!ENTITY % local.classname.attrib "alt CDATA #IMPLIED">
<!ENTITY % local.methodname.attrib "alt CDATA #IMPLIED">
<!ENTITY % local.refentry.class "|library-reference|testsuite">
<!ENTITY % local.title.char.mix "">
<!ENTITY % programlisting.module "IGNORE">
<!ENTITY % parameter.module "IGNORE">
<!ENTITY % function.module "IGNORE">
<!ENTITY % type.module "IGNORE">
<!--========== Import DocBook DTD ==========-->
<!ENTITY % DocBook PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
%DocBook;

View File

@@ -1,18 +1,18 @@
[section Consensus and Validation]
# Consensus and Validation
[*This section is a work in progress!!]
**This section is a work in progress!!**
Consensus is the task of reaching agreement within a distributed system in the
presence of faulty or even malicious participants. This document outlines the
[@https://ripple.com/files/ripple/consensus/whitepaper.pdf Ripple Consensus
Algorithm] as implemented in [@https://github.com/ripple/rippled rippled], but
[Ripple Consensus Algorithm](https://ripple.com/files/ripple/consensus/whitepaper.pdf)
as implemented in [rippled](https://github.com/ripple/rippled), but
focuses on its utility as a generic consensus algorithm independent of the
detailed mechanics of the Ripple Consensus Ledger. Most notably, the algorithm
does not require fully synchronous communication between all nodes in the
network, or even a fixed network topology, but instead achieves consensus via
collectively trusted subnetworks.
[heading Distributed Agreement]
## Distributed Agreement
A challenge for distributed systems is reaching agreement on changes in shared
state. For the Ripple network, the shared state is the current ledger--account
@@ -20,7 +20,7 @@ information, account balances, order books and other financial data. We will
refer to shared distributed state as a /ledger/ throughout the remainder of this
document.
[$images/consensus/ledger_chain.png [width 50%] [height 50%] ]
![Ledger Chain](images/consensus/ledger_chain.png "Ledger Chain")
As shown above, new ledgers are made by applying a set of transactions to the
prior ledger. For the Ripple network, transactions include payments,
@@ -33,14 +33,14 @@ the set of transactions to include, the order to apply those transactions, and
even the resulting ledger after applying the transactions. This is even more
difficult when some participants are faulty or malicious.
The Ripple network is a decentralized and _trust-full_ network. Anyone is free
The Ripple network is a decentralized and **trust-full** network. Anyone is free
to join and participants are free to choose a subset of peers that are
collectively trusted to not collude in an attempt to defraud the participant.
Leveraging this network of trust, the Ripple algorithm has two main components.
* /Consensus/ in which network participants agree on the transactions to apply
* *Consensus* in which network participants agree on the transactions to apply
to a prior ledger, based on the positions of their chosen peers.
* /Validation/ in which network participants agree on what ledger was
* *Validation* in which network participants agree on what ledger was
generated, based on the ledgers generated by chosen peers.
These phases are continually repeated to process transactions submitted to the
@@ -50,46 +50,46 @@ links between ledgers point backward to the parent. Also note the alternate
Ledger 2 that was generated by some participants, but which failed validation
and was abandoned.
[$images/consensus/block_chain.png]
![Block Chain](images/consensus/block_chain.png "Block Chain")
The remainder of this section describes the Consensus and Validation algorithms
in more detail and is meant as a companion guide to understanding the generic
implementation in =rippled=. The document *does not* discuss correctness,
implementation in `rippled`. The document **does not** discuss correctness,
fault-tolerance or liveness properties of the algorithms or the full details of
how they integrate within =rippled= to support the Ripple Consensus Ledger.
how they integrate within `rippled` to support the Ripple Consensus Ledger.
[section Consensus Overview]
## Consensus Overview
[heading Definitions]
### Definitions
* The /ledger/ is the shared distributed state. Each ledger has a unique ID to
distinguish it from all other ledgers. During consensus, the /previous/,
/prior/ or /last-closed/ ledger is the most recent ledger seen by consensus
* The *ledger* is the shared distributed state. Each ledger has a unique ID to
distinguish it from all other ledgers. During consensus, the *previous*,
*prior* or *last-closed* ledger is the most recent ledger seen by consensus
and is the basis upon which it will build the next ledger.
* A /transaction/ is an instruction for an atomic change in the ledger state. A
* A *transaction* is an instruction for an atomic change in the ledger state. A
unique ID distinguishes a transaction from other transactions.
* A /transaction set/ is a set of transactions under consideration by consensus.
* A *transaction set* is a set of transactions under consideration by consensus.
The goal of consensus is to reach agreement on this set. The generic
consensus algorithm does not rely on an ordering of transactions within the
set, nor does it specify how to apply a transaction set to a ledger to
generate a new ledger. A unique ID distinguishes a set of transactions from
all other sets of transactions.
* A /node/ is one of the distributed actors running the consensus algorithm. It
* A *node* is one of the distributed actors running the consensus algorithm. It
has a unique ID to distinguish it from all other nodes.
* A /peer/ of a node is another node that it has chosen to follow and which it
* A *peer* of a node is another node that it has chosen to follow and which it
believes will not collude with other chosen peers. The choice of peers is not
symmetric, since participants can decide on their chosen sets independently.
* A /position/ is the current belief of the next ledger's transaction set and
close time. Position can refer to the node's own position or the position of a
peer.
* A /proposal/ is one of a sequence of positions a node shares during consensus.
* A *proposal* is one of a sequence of positions a node shares during consensus.
An initial proposal contains the starting position taken by a node before it
considers any peer positions. If a node subsequently updates its position in
response to its peers, it will issue an updated proposal. A proposal is
uniquely identified by the ID of the proposing node, the ID of the position
taken, the ID of the prior ledger the proposal is for, and the sequence number
of the proposal.
* A /dispute/ is a transaction that is either not part of a node's position or
* A *dispute* is a transaction that is either not part of a node's position or
not in a peer's position. During consensus, the node will add or remove
disputed transactions from its position based on that transaction's support
amongst its peers.
@@ -101,61 +101,61 @@ contain the ID of the position of a peer. Since many peers likely have the same
position, this reduces the need to send the full transaction set multiple times.
Instead, a node can request the transaction set from the network if necessary.
[heading Overview ]
[$images/consensus/consensus_overview.png [width 50%] [height 50%] ]
### Overview
![Consensus Overview](images/consensus/consensus_overview.png "Consensus Overview")
The diagram above is an overview of the consensus process from the perspective
of a single participant. Recall that during a single consensus round, a node is
trying to agree with its peers on which transactions to apply to its prior
ledger when generating the next ledger. It also attempts to agree on the
[link effective_close_time network time when the ledger closed]. There are
[network time when the ledger closed](#effective_close_time). There are
3 main phases to a consensus round:
* A call to =startRound= places the node in the =Open= phase. In this phase,
* A call to `startRound` places the node in the `Open` phase. In this phase,
the node is waiting for transactions to include in its open ledger.
* At some point, the node will =Close= the open ledger and transition to the
=Establish= phase. In this phase, the node shares/receives peer proposals on
* At some point, the node will `Close` the open ledger and transition to the
`Establish` phase. In this phase, the node shares/receives peer proposals on
which transactions should be accepted in the closed ledger.
* At some point, the node determines it has reached consensus with its peers on
which transactions to include. It transitions to the =Accept= phase. In this
which transactions to include. It transitions to the `Accept` phase. In this
phase, the node works on applying the transactions to the prior ledger to
generate a new closed ledger. Once the new ledger is completed, the node shares
the validated ledger hash with the network and makes a call to =startRound= to
the validated ledger hash with the network and makes a call to `startRound` to
start the cycle again for the next ledger.
Throughout, a heartbeat timer calls =timerEntry= at a regular frequency to drive
the process forward. Although the =startRound= call occurs at arbitrary times
Throughout, a heartbeat timer calls `timerEntry` at a regular frequency to drive
the process forward. Although the `startRound` call occurs at arbitrary times
based on when the initial round began and the time it takes to apply
transactions, the transitions from =Open= to =Establish= and =Establish= to
=Accept= only occur during calls to =timerEntry=. Similarly, transactions can
transactions, the transitions from `Open` to `Establish` and `Establish` to
`Accept` only occur during calls to `timerEntry`. Similarly, transactions can
arrive at arbitrary times, independent of the heartbeat timer. Transactions
received after the =Open= to =Close= transition and not part of peer proposals
received after the `Open` to `Close` transition and not part of peer proposals
won't be considered until the next consensus round. They are represented above
by the light green triangles.
Peer proposals are issued by a node during a =timerEntry= call, but since peers
do not synchronize =timerEntry= calls, they are received by other peers at
Peer proposals are issued by a node during a `timerEntry` call, but since peers
do not synchronize `timerEntry` calls, they are received by other peers at
arbitrary times. Peer proposals are only considered if received prior to the
=Establish= to =Accept= transition, and only if the peer is working on the same
`Establish` to `Accept` transition, and only if the peer is working on the same
prior ledger. Peer proposals received after consensus is reached will not be
meaningful and are represented above by the circle with the X in it. Only
proposals from chosen peers are considered.
[#effective_close_time]
[heading Effective Close Time]
### Effective Close Time ### {#effective_close_time}
In addition to agreeing on a transaction set, each consensus round tries to
agree on the time the ledger closed. Each node calculates its own close time
when it closes the open ledger. This exact close time is rounded to the nearest
multiple of the current /effective close time resolution/. It is this
/effective close time/ that nodes seek to agree on. This allows servers to
multiple of the current *effective close time resolution*. It is this
*effective close time* that nodes seek to agree on. This allows servers to
derive a common time for a ledger without the need for perfectly synchronized
clocks. As depicted below, the 3 pink arrows represent exact close times from 3
consensus nodes that round to the same effective close time given the current
resolution. The purple arrow represents a peer whose estimate rounds to a
different effective close time given the current resolution.
[$images/consensus/EffCloseTime.png]
![Effective Close Time](images/consensus/EffCloseTime.png "Effective Close Time")
The effective close time is part of the node's position and is shared with peers
in its proposals. Just like the position on the consensus transaction set, a
@@ -168,14 +168,14 @@ subsequent consensus rounds if nodes are unable to reach consensus on an
effective close time and increasing (finer) resolution if nodes consistently
reach close time consensus.
[heading Modes]
### Modes
Internally, a node operates under one of the following consensus modes. Either
of the first two modes may be chosen when a consensus round starts.
* /Proposing/ indicates the node is a full-fledged consensus participant. It
* *Proposing* indicates the node is a full-fledged consensus participant. It
takes on positions and sends proposals to its peers.
* /Observing/ indicates the node is a passive consensus participant. It
* *Observing* indicates the node is a passive consensus participant. It
maintains a position internally, but does not propose that position to its
peers. Instead, it receives peer proposals and updates its position
to track the majority of its peers. This may be preferred if the node is only
@@ -184,21 +184,21 @@ of the first two modes may be chosen when a consensus round starts.
The other two modes are set internally during the consensus round when the node
believes it is no longer working on the dominant ledger chain based on peer
validations. It checks this on every call to =timerEntry=.
validations. It checks this on every call to `timerEntry`.
* /Wrong Ledger/ indicates the node is not working on the correct prior ledger
* *Wrong Ledger* indicates the node is not working on the correct prior ledger
and does not have it available. It requests that ledger from the network, but
continues to work towards consensus this round while waiting. If it had been
/proposing/, it will send a special "bowout" proposal to its peers to indicate
*proposing*, it will send a special "bowout" proposal to its peers to indicate
its change in mode for the rest of this round. For the duration of the round,
it defers to peer positions for determining the consensus outcome as if it
were just /observing/.
* /Switch Ledger/ indicates that the node has acquired the correct prior ledger
were just *observing*.
* *Switch Ledger* indicates that the node has acquired the correct prior ledger
from the network. Although it now has the correct prior ledger, the fact that
it had the wrong one at some point during this round means it is likely behind
and should defer to peer positions for determining the consensus outcome.
[$images/consensus/consensus_modes.png]
![Consensus Modes](images/consensus/consensus_modes.png "Consensus Modes")
Once either wrong ledger or switch ledger are reached, the node cannot
return to proposing or observing until the next consensus round. However,
@@ -212,49 +212,49 @@ time to share over the network, whereas the smaller ID could be shared in a peer
validation much more quickly. Distinguishing the two states allows the node to
decide how best to generate the next ledger once it declares consensus.
[heading Phases]
### Phases
As depicted in the overview diagram, consensus is best viewed as a progression
through 3 phases. There are 4 public methods of the generic consensus algorithm
that determine this progression
* =startRound= begins a consensus round.
* =timerEntry= is called at a regular frequency (=LEDGER_MIN_CLOSE=) and is the
only call to consensus that can change the phase from =Open= to =Establish=
or =Accept=.
* =peerProposal= is called whenever a peer proposal is received and is what
allows a node to update its position in a subsequent =timerEntry= call.
* =gotTxSet= is called when a transaction set is received from the network. This
* `startRound` begins a consensus round.
* `timerEntry` is called at a regular frequency (`LEDGER_MIN_CLOSE`) and is the
only call to consensus that can change the phase from `Open` to `Establish`
or `Accept`.
* `peerProposal` is called whenever a peer proposal is received and is what
allows a node to update its position in a subsequent `timerEntry` call.
* `gotTxSet` is called when a transaction set is received from the network. This
is typically in response to a prior request from the node to acquire the
transaction set corresponding to a disagreeing peer's position.
The following subsections describe each consensus phase in more detail and what
actions are taken in response to these calls.
[h6 Open]
#### Open
The =Open= phase is a quiescent period to allow transactions to build up in the
The `Open` phase is a quiescent period to allow transactions to build up in the
node's open ledger. The duration is a trade-off between latency and throughput.
A shorter window reduces the latency to generating the next ledger, but also
reduces transaction throughput due to fewer transactions accepted into the
ledger.
A call to =startRound= would forcibly begin the next consensus round, skipping
A call to `startRound` would forcibly begin the next consensus round, skipping
completion of the current round. This is not expected during normal operation.
Calls to =peerProposal= or =gotTxSet= simply store the proposal or transaction
set for use in the coming =Establish= phase.
Calls to `peerProposal` or `gotTxSet` simply store the proposal or transaction
set for use in the coming `Establish` phase.
A call to =timerEntry= first checks that the node is working on the correct
A call to `timerEntry` first checks that the node is working on the correct
prior ledger. If not, it will update the mode and request the correct ledger.
Otherwise, the node checks whether to switch to the =Establish= phase and close
Otherwise, the node checks whether to switch to the `Establish` phase and close
the ledger.
['Ledger Close]
##### Ledger Close
Under normal circumstances, the open ledger period ends when one of the following
is true
* if there are transactions in the open ledger and more than =LEDGER_MIN_CLOSE=
* if there are transactions in the open ledger and more than `LEDGER_MIN_CLOSE`
have elapsed. This is the typical behavior.
* if there are no open transactions and a suitably longer idle interval has
elapsed. This increases the opportunity to get some transaction into
@@ -275,48 +275,48 @@ transaction.
In the example below, we suppose our node has closed with transactions 1,2 and 3. It creates disputes
for transactions 2,3 and 4, since at least one peer position differs on each.
[#disputes_image]
[$images/consensus/disputes.png [width 20%] [height 20%]]
##### disputes ##### {#disputes_image}
![Disputes](images/consensus/disputes.png "Disputes")
[h6 Establish]
#### Establish
The establish phase is the active period of consensus in which the node
exchanges proposals with peers in an attempt to reach agreement on the consensus
transactions and effective close time.
A call to =startRound= would forcibly begin the next consensus round, skipping
A call to `startRound` would forcibly begin the next consensus round, skipping
completion of the current round. This is not expected during normal operation.
Calls to =peerProposal= or =gotTxSet= that reflect new positions will generate
Calls to `peerProposal` or `gotTxSet` that reflect new positions will generate
disputed transactions for any new disagreements and will update the peer's vote
for all disputed transactions.
A call to =timerEntry= first checks that the node is working from the correct
A call to `timerEntry` first checks that the node is working from the correct
prior ledger. If not, the node will update the mode and request the correct
ledger. Otherwise, the node updates the node's position and considers whether
to switch to the =Accepted= phase and declare consensus reached. However, at
least =LEDGER_MIN_CONSENSUS= time must have elapsed before doing either. This
to switch to the `Accepted` phase and declare consensus reached. However, at
least `LEDGER_MIN_CONSENSUS` time must have elapsed before doing either. This
allows peers an opportunity to take an initial position and share it.
['Update Position]
##### Update Position
In order to achieve consensus, the node is looking for a transaction set that is
supported by a super-majority of peers. The node works towards this set by
adding or removing disputed transactions from its position based on an
increasing threshold for inclusion.
[$images/consensus/threshold.png [width 50%] [height 50%]]
![Threshold](images/consensus/threshold.png "Threshold")
By starting with a lower threshold, a node initially allows a wide set of
transactions into its position. If the establish round continues and the node is
"stuck", a higher threshold can focus on accepting transactions with the most
support. The constants that define the thresholds and durations at which the
thresholds change are given by `AV_XXX_CONSENSUS_PCT` and
`AV_XXX_CONSENSUS_TIME` respectively, where =XXX= is =INIT=,=MID=,=LATE= and
=STUCK=. The effective close time position is updated using the same
`AV_XXX_CONSENSUS_TIME` respectively, where `XXX` is `INIT`,`MID`,`LATE` and
`STUCK`. The effective close time position is updated using the same
thresholds.
Given the [link disputes_image example disputes above] and an initial threshold
Given the [example disputes above](#disputes_image) and an initial threshold
of 50%, our node would retain its position since transaction 1 was not in
dispute and transactions 2 and 3 have 75% support. Since its position did not
change, it would not need to send a new proposal to peers. Peer C would not
@@ -333,7 +333,7 @@ Lastly, if our node were not in the proposing mode, it would not include its own
vote and just take the majority (>50%) position of its peers. In this example,
our node would maintain its position of transactions 1, 2 and 3.
['Checking Consensus]
##### Checking Consensus
After updating its position, the node checks for supermajority agreement with
its peers on its current position. This agreement is of the exact transaction
@@ -347,11 +347,11 @@ Consensus is declared when the following 3 clauses are true:
* `LEDGER_MIN_CONSENSUS` time has elapsed in the establish phase
* At least 75% of the prior round proposers have proposed OR this establish
phase is `LEDGER_MIN_CONSENSUS` longer than the last round's establish phase
* =minimumConsensusPercentage= of ourself and our peers share the same position
* `minimumConsensusPercentage` of ourself and our peers share the same position
The middle condition ensures slower peers have a chance to share positions, but
prevents waiting too long on peers that have disconnected. Additionally, a node
can declare that consensus has moved on if =minimumConsensusPercentage= peers
can declare that consensus has moved on if `minimumConsensusPercentage` peers
have sent validations and moved on to the next ledger. This outcome indicates
the node has fallen behind its peers and needs to catch up.
@@ -359,45 +359,43 @@ If a node is not proposing, it does not include its own position when
calculating the percent of agreeing participants but otherwise follows the above
logic.
['Accepting Consensus]
##### Accepting Consensus
Once consensus is reached (or moved on), the node switches to the =Accept= phase
Once consensus is reached (or moved on), the node switches to the `Accept` phase
and signals to the implementing code that the round is complete. That code is
responsible for using the consensus transaction set to generate the next ledger
and calling =startRound= to begin the next round. The implementation has total
and calling `startRound` to begin the next round. The implementation has total
freedom on ordering transactions, deciding what to do if consensus moved on,
determining whether to retry or abandon local transactions that did not make the
consensus set and updating any internal state based on the consensus progress.
#### Accept
[h6 Accept]
The =Accept= phase is the terminal phase of the consensus algorithm. Calls to
=timerEntry=, =peerProposal= and =gotTxSet= will not change the internal
The `Accept` phase is the terminal phase of the consensus algorithm. Calls to
`timerEntry`, `peerProposal` and `gotTxSet` will not change the internal
consensus state while in the accept phase. The expectation is that the
application specific code is working to generate the new ledger based on the
consensus outcome. Once complete, that code should make a call to =startRound=
to kick off the next consensus round. The =startRound= call includes the new
consensus outcome. Once complete, that code should make a call to `startRound`
to kick off the next consensus round. The `startRound` call includes the new
prior ledger, prior ledger ID and whether the round should begin in the
proposing or observing mode. After setting some initial state, the phase
transitions to =Open=. The node will also check if the provided prior ledger
transitions to `Open`. The node will also check if the provided prior ledger
and ID are correct, updating the mode and requesting the proper ledger from the
network if necessary.
[endsect] [/Consensus Overview]
[section Consensus Type Requirements]
## Consensus Type Requirements
The consensus type requirements are given below as minimal implementation stubs.
Actual implementations would augment these stubs with members appropriate for
managing the details of transactions and ledgers within the larger application
framework.
[heading Transaction]
The transaction type =Tx= encapsulates a single transaction under consideration
### Transaction
The transaction type `Tx` encapsulates a single transaction under consideration
by consensus.
```
```{.cpp}
struct Tx
{
using ID = ...;
@@ -407,13 +405,14 @@ struct Tx
};
```
[heading Transaction Set]
The transaction set type =TxSet= represents a set of [^Tx]s that are collectively
under consideration by consensus. A =TxSet= can be compared against other [^TxSet]s
### Transaction Set
The transaction set type `TxSet` represents a set of `Tx`s that are collectively
under consideration by consensus. A `TxSet` can be compared against other `TxSet`s
(typically from peers) and can be modified to add or remove transactions via
the mutable subtype.
```
```{.cpp}
struct TxSet
{
using Tx = Tx;
@@ -446,14 +445,16 @@ struct TxSet
};
```
[heading Ledger] The =Ledger= type represents the state shared amongst the
### Ledger
The `Ledger` type represents the state shared amongst the
distributed participants. Notice that the details of how the next ledger is
generated from the prior ledger and the consensus accepted transaction set is
not part of the interface. Within the generic code, this type is primarily used
to know that peers are working on the same tip of the ledger chain and to
provide some basic timing data for consensus.
```
```{.cpp}
struct Ledger
{
using ID = ...;
@@ -483,10 +484,13 @@ struct Ledger
};
```
[heading PeerProposal] The =PeerProposal= type represents the signed position taken
### PeerProposal
The `PeerProposal` type represents the signed position taken
by a peer during consensus. The only type requirement is owning an instance of a
generic =ConsensusProposal=.
```
generic `ConsensusProposal`.
```{.cpp}
// Represents our proposed position or a peer's proposed position
// and is provided with the generic code
template <class NodeID_t, class LedgerID_t, class Position_t> class ConsensusProposal;
@@ -502,15 +506,16 @@ struct PeerPosition
// ... implementation specific
};
```
[heading Generic Consensus Interface]
The generic =Consensus= relies on =Adaptor= template class to implement a set
### Generic Consensus Interface
The generic `Consensus` relies on `Adaptor` template class to implement a set
of helper functions that plug the consensus algorithm into a specific application.
The =Adaptor= class also defines the types above needed by the algorithm. Below
The `Adaptor` class also defines the types above needed by the algorithm. Below
are excerpts of the generic consensus implementation and of helper types that will
interact with the concrete implementing class.
```
```{.cpp}
// Represents a transction under dispute this round
template <class Tx_t, class NodeID_t> class DisputedTx;
@@ -583,11 +588,12 @@ public:
// ... details
};
```
[heading Adapting Generic Consensus]
### Adapting Generic Consensus
The stub below shows the set of callback/helper functions required in the implementing class.
```
```{.cpp}
struct Adaptor
{
using Ledger_t = Ledger;
@@ -651,30 +657,27 @@ struct Adaptor
The implementing class hides many details of the peer communication
model from the generic code.
* The =share= member functions are responsible for sharing the given type with a
* The `share` member functions are responsible for sharing the given type with a
node's peers, but are agnostic to the mechanism. Ideally, messages are delivered
faster than =LEDGER_GRANULARITY=.
faster than `LEDGER_GRANULARITY`.
* The generic code does not specify how transactions are submitted by clients,
propagated through the network or stored in the open ledger. Indeed, the open
ledger is only conceptual from the perspective of the generic code---the
initial position and transaction set are opaquely generated in a
`Consensus::Result` instance returned from the =onClose= callback.
* The calls to =acquireLedger= and =acquireTxSet= only have non-trivial return
`Consensus::Result` instance returned from the `onClose` callback.
* The calls to `acquireLedger` and `acquireTxSet` only have non-trivial return
if the ledger or transaction set of interest is available. The implementing
class is free to block while acquiring, or return the empty option while
servicing the request asynchronously. Due to legacy reasons, the two calls
are not symmetric. =acquireTxSet= requires the host application to call
=gotTxSet= when an asynchronous =acquire= completes. Conversely,
=acquireLedger= will be called again later by the consensus code if it still
are not symmetric. `acquireTxSet` requires the host application to call
`gotTxSet` when an asynchronous `acquire` completes. Conversely,
`acquireLedger` will be called again later by the consensus code if it still
desires the ledger with the hope that the asynchronous acquisition is
complete.
[endsect] [/Consensus Type Requirements]
[section Validation]
## Validation
Coming Soon!
[endsect] [/Validation]
[endsect] [/Consensus and Validation]

Submodule docs/docca deleted from 335dbf9c36

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/images/flow1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

BIN
docs/images/flow2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "boostbook.dtd">
<!--
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-->
<section id="rippled.index">
<title>Index</title>
<index/>
</section>

View File

@@ -1,39 +0,0 @@
[/
Copyright (c) Copyright (c) 2012-2017 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
]
[library rippled
[quickbook 1.6]
[copyright 2012 - 2017 Ripple Labs Inc.]
[purpose C++ Library]
[license
Distributed under the ISC License
]
[authors [Labs, Ripple]]
[category template]
[category generic]
]
[template mdash[] '''&mdash; ''']
[template indexterm1[term1] '''<indexterm><primary>'''[term1]'''</primary></indexterm>''']
[template indexterm2[term1 term2] '''<indexterm><primary>'''[term1]'''</primary><secondary>'''[term2]'''</secondary></indexterm>''']
[include consensus.qbk]
[section:ref Reference]
[include temp/reference.qbk]
[endsect]
[xinclude index.xml]

View File

@@ -1,11 +0,0 @@
#!/bin/bash
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
mkdir -p temp
doxygen source.dox
xsltproc temp/combine.xslt temp/index.xml > temp/all.xml
xsltproc reference.xsl temp/all.xml > temp/reference.qbk

View File

@@ -1,61 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "boostbook.dtd">
<!--
Copyright (c) Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-->
<informaltable frame="all">
<tgroup cols="3">
<colspec colname="a"/>
<colspec colname="b"/>
<colspec colname="c"/>
<thead>
<row>
<entry valign="center" namest="a" nameend="c">
<bridgehead renderas="sect2">Core</bridgehead>
</entry>
</row>
</thead>
<tbody>
<row>
<entry valign="top">
<bridgehead renderas="sect3">Classes</bridgehead>
<simplelist type="vert" columns="1">
</simplelist>
<bridgehead renderas="sect3">Constants</bridgehead>
<simplelist type="vert" columns="1">
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">Functions</bridgehead>
<simplelist type="vert" columns="1">
</simplelist>
<bridgehead renderas="sect3">Type Traits</bridgehead>
<simplelist type="vert" columns="1">
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">Types</bridgehead>
<simplelist type="vert" columns="1">
</simplelist>
<bridgehead renderas="sect3">Concepts</bridgehead>
<simplelist type="vert" columns="1">
</simplelist>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- Variables (Edit for your project) -->
<xsl:variable name="doc-ref" select="'rippled.ref.'"/>
<xsl:variable name="doc-ns" select="'ripple'"/>
<xsl:variable name="debug" select="0"/>
<xsl:variable name="private" select="0"/>
<!-- End Variables -->
<xsl:include href="docca/include/docca/doxygen.xsl"/>
</xsl:stylesheet>

24
docs/sample_chart.doc Normal file
View File

@@ -0,0 +1,24 @@
/*!
\page somestatechart Example state diagram
\startuml SomeState "my state diagram"
scale 600 width
[*] -> State1
State1 --> State2 : Succeeded
State1 --> [*] : Aborted
State2 --> State3 : Succeeded
State2 --> [*] : Aborted
state State3 {
state "Accumulate Enough Data\nLong State Name" as long1
long1 : Just a test
[*] --> long1
long1 --> long1 : New Data
long1 --> ProcessData : Enough Data
}
State3 --> State3 : Failed
State3 --> [*] : Succeeded / Save Result
State3 --> [*] : Aborted
\enduml
*/

View File

@@ -6,6 +6,7 @@ PROJECT_NAME = "rippled"
PROJECT_NUMBER =
PROJECT_BRIEF = C++ Library
PROJECT_LOGO =
PROJECT_LOGO = images/LogoForDocumentation.png
OUTPUT_DIRECTORY =
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
@@ -125,6 +126,41 @@ INPUT = \
../src/ripple/app/tx/applySteps.h \
../src/ripple/app/tx/impl/InvariantCheck.h \
../src/ripple/app/consensus/RCLValidations.h \
../src/README.md \
../src/ripple/README.md \
../README.md \
../RELEASENOTES.md \
../docs/CodingStyle.md \
../docs/CheatSheet.md \
../docs/README.md \
../docs/sample_chart.doc \
../docs/HeapProfiling.md \
../docs/Docker.md \
../docs/consensus.md \
../Builds/XCode/README.md \
../Builds/VisualStudio2015/README.md \
../src/ripple/consensus/README.md \
../src/ripple/app/consensus/README.md \
../src/test/csf/README.md \
../src/ripple/basics/README.md \
../src/ripple/crypto/README.md \
../src/ripple/peerfinder/README.md \
../src/ripple/app/misc/README.md \
../src/ripple/app/misc/FeeEscalation.md \
../src/ripple/app/ledger/README.md \
../src/ripple/app/paths/README.md \
../src/ripple/app/tx/README.md \
../src/ripple/proto/README.md \
../src/ripple/shamap/README.md \
../src/ripple/protocol/README.md \
../src/ripple/json/README.md \
../src/ripple/json/TODO.md \
../src/ripple/resource/README.md \
../src/ripple/rpc/README.md \
../src/ripple/overlay/README.md \
../src/ripple/nodestore/README.md \
../src/ripple/nodestore/Benchmarks.md \
INPUT_ENCODING = UTF-8
FILE_PATTERNS =
@@ -136,12 +172,16 @@ EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
IMAGE_PATH = \
./images/ \
./images/consensus/ \
../src/test/csf/ \
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
USE_MDFILE_AS_MAINPAGE = ../src/README.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
@@ -168,8 +208,8 @@ IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = NO
HTML_OUTPUT = dhtm
GENERATE_HTML = YES
HTML_OUTPUT = html_doc
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
@@ -269,8 +309,8 @@ MAN_LINKS = NO
#---------------------------------------------------------------------------
# Configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = YES
XML_OUTPUT = temp/
GENERATE_XML = NO
XML_OUTPUT = temp
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
@@ -346,7 +386,7 @@ DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
PLANTUML_JAR_PATH = $(PLANTUML_JAR)
PLANTUML_INCLUDE_PATH =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

View File

@@ -1,4 +1,4 @@
### Newest Style
# Ripple Source Guidelines
Each folder contains a single module following the newest style:

View File

@@ -1 +0,0 @@
# Overlay