Files
rippled/md____w_rippled_rippled_docs_consensus.html
2022-07-19 15:12:23 +00:00

473 lines
54 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.17"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>rippled: Consensus and Validation</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">rippled
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.17 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
var searchBox = new SearchBox("searchBox", "search",false,'Search');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */
$(function() {
initMenu('',true,false,'search.php','Search');
$(document).ready(function() { init_search(); });
});
/* @license-end */</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
</div><!-- top -->
<div class="PageDoc"><div class="header">
<div class="headertitle">
<div class="title">Consensus and Validation </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><b>This section is a work in progress!!</b></p>
<p>Consensus is the task of reaching agreement within a distributed system in the presence of faulty or even malicious participants. This document outlines the <a href="https://arxiv.org/abs/1802.07242">XRP Ledger Consensus Algorithm</a> as implemented in <a href="https://github.com/ripple/rippled">rippled</a>, 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.</p>
<h1><a class="anchor" id="autotoc_md39"></a>
Distributed Agreement</h1>
<p>A challenge for distributed systems is reaching agreement on changes in shared state. For the Ripple network, the shared state is the current ledger&ndash;account 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.</p>
<div class="image">
<img src="ledger_chain.png" alt=""/>
<div class="caption">
Ledger Chain</div></div>
<p>As shown above, new ledgers are made by applying a set of transactions to the prior ledger. For the Ripple network, transactions include payments, modification of account settings, updates to offers and more.</p>
<p>In a centralized system, generating the next ledger is trivial since there is a single unique arbiter of which transactions to include and how to apply them to a ledger. For decentralized systems, participants must resolve disagreements on 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.</p>
<p>The Ripple network is a decentralized and <b>trust-full</b> 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.</p>
<ul>
<li><em>Consensus</em> in which network participants agree on the transactions to apply to a prior ledger, based on the positions of their chosen peers.</li>
<li><em>Validation</em> in which network participants agree on what ledger was generated, based on the ledgers generated by chosen peers.</li>
</ul>
<p>These phases are continually repeated to process transactions submitted to the network, generating successive ledgers and giving rise to the blockchain ledger history depicted below. In this diagram, time is flowing to the right, but 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.</p>
<div class="image">
<img src="block_chain.png" alt=""/>
<div class="caption">
Block Chain</div></div>
<p>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 <code>rippled</code>. The document <b>does not</b> discuss correctness, fault-tolerance or liveness properties of the algorithms or the full details of how they integrate within <code>rippled</code> to support the Ripple Consensus Ledger.</p>
<h1><a class="anchor" id="autotoc_md40"></a>
Consensus Overview</h1>
<h2><a class="anchor" id="autotoc_md41"></a>
Definitions</h2>
<ul>
<li>The <em>ledger</em> is the shared distributed state. Each ledger has a unique ID to distinguish it from all other ledgers. During consensus, the <em>previous</em>, <em>prior</em> or <em>last-closed</em> ledger is the most recent ledger seen by consensus and is the basis upon which it will build the next ledger.</li>
<li>A <em>transaction</em> is an instruction for an atomic change in the ledger state. A unique ID distinguishes a transaction from other transactions.</li>
<li>A <em>transaction set</em> 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.</li>
<li>A <em>node</em> is one of the distributed actors running the consensus algorithm. It has a unique ID to distinguish it from all other nodes.</li>
<li>A <em>peer</em> 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.</li>
<li>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.</li>
<li>A <em>proposal</em> 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.</li>
<li>A <em>dispute</em> 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.</li>
</ul>
<p>Note that most types have an ID as a lightweight identifier of instances of that type. Consensus often operates on the IDs directly since the underlying type is potentially expensive to share over the network. For example, proposal's only 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.</p>
<h2><a class="anchor" id="autotoc_md42"></a>
Overview</h2>
<div class="image">
<img src="consensus_overview.png" alt=""/>
<div class="caption">
Consensus Overview</div></div>
<p>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 <a href="#effective_close_time">network time when the ledger closed</a>. There are 3 main phases to a consensus round:</p>
<ul>
<li>A call to <code>startRound</code> places the node in the <code>Open</code> phase. In this phase, the node is waiting for transactions to include in its open ledger.</li>
<li>At some point, the node will <code>Close</code> the open ledger and transition to the <code>Establish</code> phase. In this phase, the node shares/receives peer proposals on which transactions should be accepted in the closed ledger.</li>
<li>At some point, the node determines it has reached consensus with its peers on which transactions to include. It transitions to the <code>Accept</code> 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 <code>startRound</code> to start the cycle again for the next ledger.</li>
</ul>
<p>Throughout, a heartbeat timer calls <code>timerEntry</code> at a regular frequency to drive the process forward. Although the <code>startRound</code> call occurs at arbitrary times based on when the initial round began and the time it takes to apply transactions, the transitions from <code>Open</code> to <code>Establish</code> and <code>Establish</code> to <code>Accept</code> only occur during calls to <code>timerEntry</code>. Similarly, transactions can arrive at arbitrary times, independent of the heartbeat timer. Transactions received after the <code>Open</code> to <code>Close</code> 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.</p>
<p>Peer proposals are issued by a node during a <code>timerEntry</code> call, but since peers do not synchronize <code>timerEntry</code> calls, they are received by other peers at arbitrary times. Peer proposals are only considered if received prior to the <code>Establish</code> to <code>Accept</code> 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.</p>
<h2><a class="anchor" id="effective_close_time"></a>
Effective Close Time</h2>
<p>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 <em>effective close time resolution</em>. It is this <em>effective close time</em> 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.</p>
<div class="image">
<img src="EffCloseTime.png" alt=""/>
<div class="caption">
Effective Close Time</div></div>
<p>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 node will update its close time position in response to its peers' effective close time positions. Peers can agree to disagree on the close time, in which case the effective close time is taken as 1 second past the prior close.</p>
<p>The close time resolution is itself dynamic, decreasing (coarser) resolution in 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.</p>
<h2><a class="anchor" id="autotoc_md43"></a>
Modes</h2>
<p>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.</p>
<ul>
<li><em>Proposing</em> indicates the node is a full-fledged consensus participant. It takes on positions and sends proposals to its peers.</li>
<li><em>Observing</em> 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 being used to track the state of the network or during a start-up phase while it is still synchronizing with the network.</li>
</ul>
<p>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 <code>timerEntry</code>.</p>
<ul>
<li><em>Wrong Ledger</em> 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 <em>proposing</em>, 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 <em>observing</em>.</li>
<li><em>Switch Ledger</em> 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.</li>
</ul>
<div class="image">
<img src="consensus_modes.png" alt=""/>
<div class="caption">
Consensus Modes</div></div>
<p>Once either wrong ledger or switch ledger are reached, the node cannot return to proposing or observing until the next consensus round. However, the node could change its view of the correct prior ledger, so going from switch ledger to wrong ledger and back again is possible.</p>
<p>The distinction between the wrong and switched ledger modes arises because a ledger's unique identifier may be known by a node before the ledger itself. This reflects that fact that the data corresponding to a ledger may be large and take 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.</p>
<h2><a class="anchor" id="autotoc_md44"></a>
Phases</h2>
<p>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</p>
<ul>
<li><code>startRound</code> begins a consensus round.</li>
<li><code>timerEntry</code> is called at a regular frequency (<code>LEDGER_MIN_CLOSE</code>) and is the only call to consensus that can change the phase from <code>Open</code> to <code>Establish</code> or <code>Accept</code>.</li>
<li><code>peerProposal</code> is called whenever a peer proposal is received and is what allows a node to update its position in a subsequent <code>timerEntry</code> call.</li>
<li><code>gotTxSet</code> 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.</li>
</ul>
<p>The following subsections describe each consensus phase in more detail and what actions are taken in response to these calls.</p>
<h3><a class="anchor" id="autotoc_md45"></a>
Open</h3>
<p>The <code>Open</code> 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.</p>
<p>A call to <code>startRound</code> would forcibly begin the next consensus round, skipping completion of the current round. This is not expected during normal operation. Calls to <code>peerProposal</code> or <code>gotTxSet</code> simply store the proposal or transaction set for use in the coming <code>Establish</code> phase.</p>
<p>A call to <code>timerEntry</code> 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 <code>Establish</code> phase and close the ledger.</p>
<h4><a class="anchor" id="autotoc_md46"></a>
Ledger Close</h4>
<p>Under normal circumstances, the open ledger period ends when one of the following is true</p>
<ul>
<li>if there are transactions in the open ledger and more than <code>LEDGER_MIN_CLOSE</code> have elapsed. This is the typical behavior.</li>
<li>if there are no open transactions and a suitably longer idle interval has elapsed. This increases the opportunity to get some transaction into the next ledger and avoids doing useless work closing an empty ledger.</li>
<li>if more than half the number of prior round peers have already closed or finished this round. This indicates the node is falling behind and needs to catch up.</li>
</ul>
<p>When closing the ledger, the node takes its initial position based on the transactions in the open ledger and uses the current time as its initial close time estimate. If in the proposing mode, the node shares its initial position with peers. Now that the node has taken a position, it will consider any peer positions for this round that arrived earlier. The node generates disputed transactions for each transaction not in common with a peer's position. The node also records the vote of each peer for each disputed transaction.</p>
<p>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.</p>
<h4><a class="anchor" id="disputes_image"></a>
disputes</h4>
<div class="image">
<img src="disputes.png" alt=""/>
<div class="caption">
Disputes</div></div>
<h3><a class="anchor" id="autotoc_md47"></a>
Establish</h3>
<p>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.</p>
<p>A call to <code>startRound</code> would forcibly begin the next consensus round, skipping completion of the current round. This is not expected during normal operation. Calls to <code>peerProposal</code> or <code>gotTxSet</code> that reflect new positions will generate disputed transactions for any new disagreements and will update the peer's vote for all disputed transactions.</p>
<p>A call to <code>timerEntry</code> 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 <code>Accepted</code> phase and declare consensus reached. However, at least <code>LEDGER_MIN_CONSENSUS</code> time must have elapsed before doing either. This allows peers an opportunity to take an initial position and share it.</p>
<h4><a class="anchor" id="autotoc_md48"></a>
Update Position</h4>
<p>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.</p>
<div class="image">
<img src="threshold.png" alt=""/>
<div class="caption">
Threshold</div></div>
<p>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 <code>AV_XXX_CONSENSUS_PCT</code> and <code>AV_XXX_CONSENSUS_TIME</code> respectively, where <code>XXX</code> is <code>INIT</code>,<code>MID</code>,<code>LATE</code> and <code>STUCK</code>. The effective close time position is updated using the same thresholds.</p>
<p>Given the <a href="#disputes_image">example disputes above</a> 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 change either. Peer A would add transaction 3 to its position and Peer B would remove transaction 4 from its position; both would then send an updated position.</p>
<p>Conversely, if the diagram reflected a later call to =timerEntry= that occurs in the stuck region with a threshold of say 95%, our node would remove transactions 2 and 3 from its candidate set and send an updated position. Likewise, all the other peers would end up with only transaction 1 in their position.</p>
<p>Lastly, if our node were not in the proposing mode, it would not include its own vote and just take the majority (&gt;50%) position of its peers. In this example, our node would maintain its position of transactions 1, 2 and 3.</p>
<h4><a class="anchor" id="autotoc_md49"></a>
Checking Consensus</h4>
<p>After updating its position, the node checks for supermajority agreement with its peers on its current position. This agreement is of the exact transaction set, not just the support of individual transactions. That is, if our position is a subset of a peer's position, that counts as a disagreement. Also recall that effective close time agreement allows a supermajority of participants agreeing to disagree.</p>
<p>Consensus is declared when the following 3 clauses are true:</p>
<ul>
<li><code>LEDGER_MIN_CONSENSUS</code> time has elapsed in the establish phase</li>
<li>At least 75% of the prior round proposers have proposed OR this establish phase is <code>LEDGER_MIN_CONSENSUS</code> longer than the last round's establish phase</li>
<li><code>minimumConsensusPercentage</code> of ourself and our peers share the same position</li>
</ul>
<p>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 <code>minimumConsensusPercentage</code> 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.</p>
<p>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.</p>
<h4><a class="anchor" id="autotoc_md50"></a>
Accepting Consensus</h4>
<p>Once consensus is reached (or moved on), the node switches to the <code>Accept</code> 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 <code>startRound</code> 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.</p>
<h3><a class="anchor" id="autotoc_md51"></a>
Accept</h3>
<p>The <code>Accept</code> phase is the terminal phase of the consensus algorithm. Calls to <code>timerEntry</code>, <code>peerProposal</code> and <code>gotTxSet</code> 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 <code>startRound</code> to kick off the next consensus round. The <code>startRound</code> 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 <code>Open</code>. 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.</p>
<h1><a class="anchor" id="autotoc_md52"></a>
Consensus Type Requirements</h1>
<p>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.</p>
<h2><a class="anchor" id="autotoc_md53"></a>
Transaction</h2>
<p>The transaction type <code>Tx</code> encapsulates a single transaction under consideration by consensus.</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>Tx</div>
<div class="line">{</div>
<div class="line"> <span class="keyword">using</span> ID = ...;</div>
<div class="line"> ID <span class="keyword">const</span> &amp; id() <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">//... implementation specific</span></div>
<div class="line">};</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md54"></a>
Transaction Set</h2>
<p>The transaction set type <code>TxSet</code> represents a set of <code>Tx</code>s that are collectively under consideration by consensus. A <code>TxSet</code> can be compared against other <code>TxSet</code>s (typically from peers) and can be modified to add or remove transactions via the mutable subtype.</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>TxSet</div>
<div class="line">{</div>
<div class="line"> <span class="keyword">using</span> Tx = Tx;</div>
<div class="line"> <span class="keyword">using</span> ID = ...;</div>
<div class="line"> </div>
<div class="line"> ID <span class="keyword">const</span> &amp; id() <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="keywordtype">bool</span> <a class="codeRef" href="http://en.cppreference.com/w/cpp/experimental/fs/exists.html">exists</a>(Tx::ID <span class="keyword">const</span> &amp;) <span class="keyword">const</span>;</div>
<div class="line"> Tx <span class="keyword">const</span> * <a class="codeRef" href="http://en.cppreference.com/w/cpp/algorithm/find.html">find</a>(Tx::ID <span class="keyword">const</span> &amp;) <span class="keyword">const</span> ;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Return set of transactions that are not common with another set</span></div>
<div class="line"> <span class="comment">// Bool in map is true if in our set, false if in other</span></div>
<div class="line"> <a class="codeRef" href="http://en.cppreference.com/w/cpp/container/map.html">std::map&lt;Tx::ID, bool&gt;</a> <a class="code" href="namespaceripple.html#ad584345ad1d39fa2234a298a991f8e66">compare</a>(TxSet <span class="keyword">const</span> &amp; other) <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// A mutable view that allows changing transactions in the set</span></div>
<div class="line"> <span class="keyword">struct </span>MutableTxSet</div>
<div class="line"> {</div>
<div class="line"> MutableTxSet(TxSet <span class="keyword">const</span> &amp;);</div>
<div class="line"> <span class="keywordtype">bool</span> insert(Tx <span class="keyword">const</span> &amp;);</div>
<div class="line"> <span class="keywordtype">bool</span> <a class="code" href="namespaceripple.html#aa761b49f905eb9fd8c8ae754a0eb7504">erase</a>(Tx::ID <span class="keyword">const</span> &amp;);</div>
<div class="line"> };</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Construct from a mutable view.</span></div>
<div class="line"> TxSet(MutableTxSet <span class="keyword">const</span> &amp;);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Alternatively, if the TxSet is itself mutable</span></div>
<div class="line"> <span class="comment">// just alias MutableTxSet = TxSet</span></div>
<div class="line"> </div>
<div class="line"> <span class="comment">//... implementation specific</span></div>
<div class="line">};</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md55"></a>
Ledger</h2>
<p>The <code>Ledger</code> 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.</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>Ledger</div>
<div class="line">{</div>
<div class="line"> <span class="keyword">using</span> ID = ...;</div>
<div class="line"> </div>
<div class="line"> <span class="keyword">using</span> Seq = <span class="comment">//std::uint32_t?...;</span></div>
<div class="line"> </div>
<div class="line"> ID <span class="keyword">const</span> &amp; id() <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Sequence number that is 1 more than the parent ledger&#39;s seq()</span></div>
<div class="line"> Seq seq() <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Whether the ledger&#39;s close time was a non-trivial consensus result</span></div>
<div class="line"> <span class="keywordtype">bool</span> closeAgree() <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// The close time resolution used in determining the close time</span></div>
<div class="line"> NetClock::duration closeTimeResolution() <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// The (effective) close time, based on the closeTimeResolution</span></div>
<div class="line"> NetClock::time_point closeTime() <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// The parent ledger&#39;s close time</span></div>
<div class="line"> NetClock::time_point parentCloseTime() <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <a class="code" href="classJson_1_1Value.html">Json::Value</a> <a class="code" href="namespaceripple.html#ad30131b5a5b7cf60d9b392ab868b8c0e">getJson</a>() <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">//... implementation specific</span></div>
<div class="line">};</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md56"></a>
PeerProposal</h2>
<p>The <code>PeerProposal</code> type represents the signed position taken by a peer during consensus. The only type requirement is owning an instance of a generic <code>ConsensusProposal</code>.</p>
<div class="fragment"><div class="line"><span class="comment">// Represents our proposed position or a peer&#39;s proposed position</span></div>
<div class="line"><span class="comment">// and is provided with the generic code</span></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> NodeID_t, <span class="keyword">class</span> LedgerID_t, <span class="keyword">class</span> Position_t&gt; <span class="keyword">class </span>ConsensusProposal;</div>
<div class="line"> </div>
<div class="line"><span class="keyword">struct </span>PeerPosition</div>
<div class="line">{</div>
<div class="line"> ConsensusProposal&lt;</div>
<div class="line"> NodeID_t,</div>
<div class="line"> <span class="keyword">typename</span> Ledger::ID,</div>
<div class="line"> <span class="keyword">typename</span> TxSet::ID&gt; <span class="keyword">const</span> &amp;</div>
<div class="line"> <a class="code" href="namespaceripple.html#ad5143ceada01141772ae4aab984f94bdab314439bc1697845de3749d51dca7c15">proposal</a>() <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// ... implementation specific</span></div>
<div class="line">};</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md57"></a>
Generic Consensus Interface</h2>
<p>The generic <code>Consensus</code> relies on <code>Adaptor</code> template class to implement a set of helper functions that plug the consensus algorithm into a specific application. The <code>Adaptor</code> 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.</p>
<div class="fragment"><div class="line"><span class="comment">// Represents a transction under dispute this round</span></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> Tx_t, <span class="keyword">class</span> NodeID_t&gt; <span class="keyword">class </span>DisputedTx;</div>
<div class="line"> </div>
<div class="line"><span class="comment">// Represents how the node participates in Consensus this round</span></div>
<div class="line"><span class="keyword">enum class</span> <a class="code" href="namespaceripple.html#a33f8b6e68b5f63faf2e9755cc251563e">ConsensusMode</a> { <a class="code" href="namespaceripple.html#a33f8b6e68b5f63faf2e9755cc251563ea80dcf57f5ecd4be3cbfa37eccbcb6f44">proposing</a>, <a class="code" href="namespaceripple.html#a33f8b6e68b5f63faf2e9755cc251563eaea5234685f43dcab142e132c0e7be2ce">observing</a>, <a class="code" href="namespaceripple.html#a33f8b6e68b5f63faf2e9755cc251563ea1dde5f68261b60a2e4655f5ad1f13e0b">wrongLedger</a>, <a class="code" href="namespaceripple.html#a33f8b6e68b5f63faf2e9755cc251563eabc8904337817db1a59f2a10ed405b817">switchedLedger</a>};</div>
<div class="line"> </div>
<div class="line"><span class="comment">// Measure duration of phases of consensus</span></div>
<div class="line"><span class="keyword">class </span>ConsensusTimer</div>
<div class="line">{</div>
<div class="line"><span class="keyword">public</span>:</div>
<div class="line"> <a class="codeRef" href="http://en.cppreference.com/w/cpp/chrono/duration.html">std::chrono::milliseconds</a> <a class="code" href="namespaceripple_1_1NodeStore.html#a842656443a02cf834bf2c521a28a1236">read</a>() <span class="keyword">const</span>;</div>
<div class="line"> <span class="comment">// details omitted ...</span></div>
<div class="line">};</div>
<div class="line"> </div>
<div class="line"><span class="comment">// Initial ledger close times, not rounded by closeTimeResolution</span></div>
<div class="line"><span class="comment">// Used to gauge degree of synchronization between a node and its peers</span></div>
<div class="line"><span class="keyword">struct </span>ConsensusCloseTimes</div>
<div class="line">{</div>
<div class="line"> <a class="codeRef" href="http://en.cppreference.com/w/cpp/container/map.html">std::map&lt;NetClock::time_point, int&gt;</a> peers;</div>
<div class="line"> NetClock::time_point <span class="keyword">self</span>;</div>
<div class="line">};</div>
<div class="line"> </div>
<div class="line"><span class="comment">// Encapsulates the result of consensus.</span></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> Adaptor&gt;</div>
<div class="line"><span class="keyword">struct </span>ConsensusResult</div>
<div class="line">{</div>
<div class="line"> Adaptor::TxSet_t <a class="code" href="namespaceripple.html#a53f80df10254751781250aa20704e98f">set</a>;</div>
<div class="line"> </div>
<div class="line"> ConsensusProposal&lt;...&gt; position;</div>
<div class="line"> </div>
<div class="line"> <a class="code" href="namespaceripple.html#a46c521271235f4e2715d7fa8b68940ca">hash_map</a>&lt;Adaptor::Tx_t::ID, DisputedTx&lt;...&gt;&gt; disputes;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Set of TxSet ids we have already compared/created disputes</span></div>
<div class="line"> hash_set&lt;typename Adaptor::TxSet_t::ID&gt; compares;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Measures the duration of the establish phase for this consensus round</span></div>
<div class="line"> ConsensusTimer roundTime;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Indicates state in which consensus ended. Once in the accept phase</span></div>
<div class="line"> <span class="comment">// will be either Yes or MovedOn</span></div>
<div class="line"> <a class="code" href="namespaceripple.html#a79cc3b590c118bd551b693bb333fb9d1">ConsensusState</a> state = ConsensusState::No;</div>
<div class="line">};</div>
<div class="line"> </div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> Adaptor&gt;</div>
<div class="line"><span class="keyword">class </span>Consensus</div>
<div class="line">{</div>
<div class="line"><span class="keyword">public</span>:</div>
<div class="line"> Consensus(clock_type, Adaptor &amp;, beast::journal);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Kick-off the next round of consensus.</span></div>
<div class="line"> <span class="keywordtype">void</span> startRound(</div>
<div class="line"> NetClock::time_point <span class="keyword">const</span>&amp; now,</div>
<div class="line"> <span class="keyword">typename</span> Ledger_t::ID <span class="keyword">const</span>&amp; prevLedgerID,</div>
<div class="line"> Ledger_t <span class="keyword">const</span>&amp; prevLedger,</div>
<div class="line"> <span class="keywordtype">bool</span> proposing);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Call periodically to drive consensus forward.</span></div>
<div class="line"> <span class="keywordtype">void</span> timerEntry(NetClock::time_point <span class="keyword">const</span>&amp; now);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// A peer has proposed a new position, adjust our tracking. Return true if the proposal</span></div>
<div class="line"> <span class="comment">// was used.</span></div>
<div class="line"> <span class="keywordtype">bool</span> peerProposal(NetClock::time_point <span class="keyword">const</span>&amp; now, Proposal_t <span class="keyword">const</span>&amp; newProposal);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Process a transaction set acquired from the network</span></div>
<div class="line"> <span class="keywordtype">void</span> gotTxSet(NetClock::time_point <span class="keyword">const</span>&amp; now, TxSet_t <span class="keyword">const</span>&amp; txSet);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// ... details</span></div>
<div class="line">};</div>
</div><!-- fragment --><h2><a class="anchor" id="autotoc_md58"></a>
Adapting Generic Consensus</h2>
<p>The stub below shows the set of callback/helper functions required in the implementing class.</p>
<div class="fragment"><div class="line"><span class="keyword">struct </span>Adaptor</div>
<div class="line">{</div>
<div class="line"> <span class="keyword">using</span> Ledger_t = Ledger;</div>
<div class="line"> <span class="keyword">using</span> TxSet_t = TxSet;</div>
<div class="line"> <span class="keyword">using</span> PeerProposal_t = PeerProposal;</div>
<div class="line"> <span class="keyword">using</span> NodeID_t = ...; <span class="comment">// Integer-like std::uint32_t to uniquely identify a node</span></div>
<div class="line"> </div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Attempt to acquire a specific ledger from the network.</span></div>
<div class="line"> boost::optional&lt;Ledger&gt; acquireLedger(Ledger::ID <span class="keyword">const</span> &amp; ledgerID);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Acquire the transaction set associated with a proposed position.</span></div>
<div class="line"> boost::optional&lt;TxSet&gt; acquireTxSet(TxSet::ID <span class="keyword">const</span> &amp; setID);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Whether any transactions are in the open ledger</span></div>
<div class="line"> <span class="keywordtype">bool</span> hasOpenTransactions() <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Number of proposers that have validated the given ledger</span></div>
<div class="line"> <a class="codeRef" href="http://en.cppreference.com/w/cpp/types/size_t.html">std::size_t</a> proposersValidated(Ledger::ID <span class="keyword">const</span> &amp; prevLedger) <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Number of proposers that have validated a ledger descended from the</span></div>
<div class="line"> <span class="comment">// given ledger</span></div>
<div class="line"> <a class="codeRef" href="http://en.cppreference.com/w/cpp/types/size_t.html">std::size_t</a> proposersFinished(Ledger::ID <span class="keyword">const</span> &amp; prevLedger) <span class="keyword">const</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Return the ID of the last closed (and validated) ledger that the</span></div>
<div class="line"> <span class="comment">// application thinks consensus should use as the prior ledger.</span></div>
<div class="line"> Ledger::ID getPrevLedger(Ledger::ID <span class="keyword">const</span> &amp; prevLedgerID,</div>
<div class="line"> Ledger <span class="keyword">const</span> &amp; prevLedger,</div>
<div class="line"> ConsensusMode mode);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Called when consensus operating mode changes</span></div>
<div class="line"> <span class="keywordtype">void</span> onModeChange(ConsensuMode before, ConsensusMode after);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Called when ledger closes. Implementation should generate an initial Result</span></div>
<div class="line"> <span class="comment">// with position based on the current open ledger&#39;s transactions.</span></div>
<div class="line"> ConsensusResult onClose(Ledger <span class="keyword">const</span> &amp;, Ledger <span class="keyword">const</span> &amp; prev, ConsensusMode mode);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Called when ledger is accepted by consensus</span></div>
<div class="line"> <span class="keywordtype">void</span> onAccept(ConsensusResult <span class="keyword">const</span> &amp; result,</div>
<div class="line"> RCLCxLedger <span class="keyword">const</span> &amp; prevLedger,</div>
<div class="line"> NetClock::duration closeResolution,</div>
<div class="line"> ConsensusCloseTimes <span class="keyword">const</span> &amp; rawCloseTimes,</div>
<div class="line"> ConsensusMode <span class="keyword">const</span> &amp; mode);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Propose the position to peers.</span></div>
<div class="line"> <span class="keywordtype">void</span> propose(ConsensusProposal&lt;...&gt; <span class="keyword">const</span> &amp; pos);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Share a received peer proposal with other peers.</span></div>
<div class="line"> <span class="keywordtype">void</span> share(PeerPosition_t <span class="keyword">const</span> &amp; pos);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Share a disputed transaction with peers</span></div>
<div class="line"> <span class="keywordtype">void</span> share(TxSet::Tx <span class="keyword">const</span> &amp; tx);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// Share given transaction set with peers</span></div>
<div class="line"> <span class="keywordtype">void</span> share(TxSet <span class="keyword">const</span> &amp;s);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">//... implementation specific</span></div>
<div class="line">};</div>
</div><!-- fragment --><p>The implementing class hides many details of the peer communication model from the generic code.</p>
<ul>
<li>The <code>share</code> 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 <code>LEDGER_GRANULARITY</code>.</li>
<li>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&mdash;the initial position and transaction set are opaquely generated in a <code>Consensus::Result</code> instance returned from the <code>onClose</code> callback.</li>
<li>The calls to <code>acquireLedger</code> and <code>acquireTxSet</code> 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. <code>acquireTxSet</code> requires the host application to call <code>gotTxSet</code> when an asynchronous <code>acquire</code> completes. Conversely, <code>acquireLedger</code> will be called again later by the consensus code if it still desires the ledger with the hope that the asynchronous acquisition is complete.</li>
</ul>
<h1><a class="anchor" id="autotoc_md59"></a>
Validation</h1>
<p>Coming Soon! </p>
</div></div><!-- contents -->
</div><!-- PageDoc -->
<div class="ttc" id="anamespaceripple_html_a79cc3b590c118bd551b693bb333fb9d1"><div class="ttname"><a href="namespaceripple.html#a79cc3b590c118bd551b693bb333fb9d1">ripple::ConsensusState</a></div><div class="ttdeci">ConsensusState</div><div class="ttdoc">Whether we have or don't have a consensus.</div><div class="ttdef"><b>Definition:</b> <a href="ConsensusTypes_8h_source.html#l00186">ConsensusTypes.h:186</a></div></div>
<div class="ttc" id="anamespaceripple_html_a46c521271235f4e2715d7fa8b68940ca"><div class="ttname"><a href="namespaceripple.html#a46c521271235f4e2715d7fa8b68940ca">ripple::hash_map</a></div><div class="ttdeci">std::unordered_map&lt; Key, Value, Hash, Pred, Allocator &gt; hash_map</div><div class="ttdef"><b>Definition:</b> <a href="UnorderedContainers_8h_source.html#l00053">UnorderedContainers.h:53</a></div></div>
<div class="ttc" id="anamespaceripple_1_1NodeStore_html_a842656443a02cf834bf2c521a28a1236"><div class="ttname"><a href="namespaceripple_1_1NodeStore.html#a842656443a02cf834bf2c521a28a1236">ripple::NodeStore::read</a></div><div class="ttdeci">void read(nudb::detail::istream &amp;is, std::size_t &amp;u)</div><div class="ttdef"><b>Definition:</b> <a href="varint_8h_source.html#l00120">varint.h:120</a></div></div>
<div class="ttc" id="anamespaceripple_html_a33f8b6e68b5f63faf2e9755cc251563ea80dcf57f5ecd4be3cbfa37eccbcb6f44"><div class="ttname"><a href="namespaceripple.html#a33f8b6e68b5f63faf2e9755cc251563ea80dcf57f5ecd4be3cbfa37eccbcb6f44">ripple::ConsensusMode::proposing</a></div><div class="ttdeci">@ proposing</div><div class="ttdoc">We are normal participant in consensus and propose our position.</div></div>
<div class="ttc" id="anamespaceripple_html_a33f8b6e68b5f63faf2e9755cc251563ea1dde5f68261b60a2e4655f5ad1f13e0b"><div class="ttname"><a href="namespaceripple.html#a33f8b6e68b5f63faf2e9755cc251563ea1dde5f68261b60a2e4655f5ad1f13e0b">ripple::ConsensusMode::wrongLedger</a></div><div class="ttdeci">@ wrongLedger</div><div class="ttdoc">We have the wrong ledger and are attempting to acquire it.</div></div>
<div class="ttc" id="afind_html"><div class="ttname"><a href="http://en.cppreference.com/w/cpp/algorithm/find.html">std::find</a></div><div class="ttdeci">T find(T... args)</div></div>
<div class="ttc" id="aduration_html"><div class="ttname"><a href="http://en.cppreference.com/w/cpp/chrono/duration.html">std::chrono::milliseconds</a></div></div>
<div class="ttc" id="anamespaceripple_html_a33f8b6e68b5f63faf2e9755cc251563eabc8904337817db1a59f2a10ed405b817"><div class="ttname"><a href="namespaceripple.html#a33f8b6e68b5f63faf2e9755cc251563eabc8904337817db1a59f2a10ed405b817">ripple::ConsensusMode::switchedLedger</a></div><div class="ttdeci">@ switchedLedger</div><div class="ttdoc">We switched ledgers since we started this consensus round but are now running on what we believe is t...</div></div>
<div class="ttc" id="anamespaceripple_html_a33f8b6e68b5f63faf2e9755cc251563eaea5234685f43dcab142e132c0e7be2ce"><div class="ttname"><a href="namespaceripple.html#a33f8b6e68b5f63faf2e9755cc251563eaea5234685f43dcab142e132c0e7be2ce">ripple::ConsensusMode::observing</a></div><div class="ttdeci">@ observing</div><div class="ttdoc">We are observing peer positions, but not proposing our position.</div></div>
<div class="ttc" id="anamespaceripple_html_aa761b49f905eb9fd8c8ae754a0eb7504"><div class="ttname"><a href="namespaceripple.html#aa761b49f905eb9fd8c8ae754a0eb7504">ripple::erase</a></div><div class="ttdeci">void erase(STObject &amp;st, TypedField&lt; U &gt; const &amp;f)</div><div class="ttdoc">Remove a field in an STObject.</div><div class="ttdef"><b>Definition:</b> <a href="STExchange_8h_source.html#l00171">STExchange.h:171</a></div></div>
<div class="ttc" id="anamespaceripple_html_ad584345ad1d39fa2234a298a991f8e66"><div class="ttname"><a href="namespaceripple.html#ad584345ad1d39fa2234a298a991f8e66">ripple::compare</a></div><div class="ttdeci">int compare(base_uint&lt; Bits, Tag &gt; const &amp;a, base_uint&lt; Bits, Tag &gt; const &amp;b)</div><div class="ttdef"><b>Definition:</b> <a href="base__uint_8h_source.html#l00553">base_uint.h:553</a></div></div>
<div class="ttc" id="anamespaceripple_html_a53f80df10254751781250aa20704e98f"><div class="ttname"><a href="namespaceripple.html#a53f80df10254751781250aa20704e98f">ripple::set</a></div><div class="ttdeci">bool set(T &amp;target, std::string const &amp;name, Section const &amp;section)</div><div class="ttdoc">Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...</div><div class="ttdef"><b>Definition:</b> <a href="BasicConfig_8h_source.html#l00313">BasicConfig.h:313</a></div></div>
<div class="ttc" id="anamespaceripple_html_ad5143ceada01141772ae4aab984f94bdab314439bc1697845de3749d51dca7c15"><div class="ttname"><a href="namespaceripple.html#ad5143ceada01141772ae4aab984f94bdab314439bc1697845de3749d51dca7c15">ripple::HashPrefix::proposal</a></div><div class="ttdeci">@ proposal</div><div class="ttdoc">proposal for signing</div></div>
<div class="ttc" id="amap_html"><div class="ttname"><a href="http://en.cppreference.com/w/cpp/container/map.html">std::map</a></div><div class="ttdoc">STL class.</div></div>
<div class="ttc" id="anamespaceripple_html_ad30131b5a5b7cf60d9b392ab868b8c0e"><div class="ttname"><a href="namespaceripple.html#ad30131b5a5b7cf60d9b392ab868b8c0e">ripple::getJson</a></div><div class="ttdeci">Json::Value getJson(LedgerFill const &amp;fill)</div><div class="ttdoc">Return a new Json::Value representing the ledger with given options.</div><div class="ttdef"><b>Definition:</b> <a href="LedgerToJson_8cpp_source.html#l00291">LedgerToJson.cpp:291</a></div></div>
<div class="ttc" id="anamespaceripple_html_a33f8b6e68b5f63faf2e9755cc251563e"><div class="ttname"><a href="namespaceripple.html#a33f8b6e68b5f63faf2e9755cc251563e">ripple::ConsensusMode</a></div><div class="ttdeci">ConsensusMode</div><div class="ttdoc">Represents how a node currently participates in Consensus.</div><div class="ttdef"><b>Definition:</b> <a href="ConsensusTypes_8h_source.html#l00055">ConsensusTypes.h:55</a></div></div>
<div class="ttc" id="asize_t_html"><div class="ttname"><a href="http://en.cppreference.com/w/cpp/types/size_t.html">std::size_t</a></div></div>
<div class="ttc" id="aexists_html"><div class="ttname"><a href="http://en.cppreference.com/w/cpp/experimental/fs/exists.html">std::experimental::filesystem::exists</a></div><div class="ttdeci">T exists(T... args)</div></div>
<div class="ttc" id="aclassJson_1_1Value_html"><div class="ttname"><a href="classJson_1_1Value.html">Json::Value</a></div><div class="ttdoc">Represents a JSON value.</div><div class="ttdef"><b>Definition:</b> <a href="json__value_8h_source.html#l00145">json_value.h:145</a></div></div>
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/>
</a> 1.8.17
</small></address>
</body>
</html>