mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Refactor consensus for simulation (RIPD-1011):
This is a substantial refactor of the consensus code and also introduces a basic consensus simulation and testing framework. The new generic/templated version is in src/ripple/consensus and documents the current type requirements. The version adapted for the RCL is in src/ripple/app/consensus. The testing framework is in src/test/csf. Minor behavioral changes/fixes include: * Adjust close time offset even when not validating. * Remove spurious proposing_ = false call at end of handleLCL. * Remove unused functionality provided by checkLastValidation. * Separate open and converge time * Don't send a bow out if we're not proposing * Prevent consensus stopping if NetworkOPs switches to disconnect mode while consensus accepts a ledger * Prevent a corner case in which Consensus::gotTxSet or Consensus::peerProposal has the potential to update internal state while an dispatched accept job is running. * Distinguish external and internal calls to startNewRound. Only external calls can reset the proposing_ state of consensus
This commit is contained in:
@@ -819,9 +819,19 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\protobuf\vsprojects\config.h">
|
<ClInclude Include="..\..\src\protobuf\vsprojects\config.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxPos.h">
|
<ClCompile Include="..\..\src\ripple\app\consensus\RCLConsensus.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\app\consensus\RCLConsensus.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxTraits.h">
|
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxLedger.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\app\consensus\RCLCxPeerPos.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxPeerPos.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxTx.h">
|
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxTx.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -851,22 +861,12 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\BookListeners.h">
|
<ClInclude Include="..\..\src\ripple\app\ledger\BookListeners.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\Consensus.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\ConsensusTransSetSF.cpp">
|
<ClCompile Include="..\..\src\ripple\app\ledger\ConsensusTransSetSF.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\ConsensusTransSetSF.h">
|
<ClInclude Include="..\..\src\ripple\app\ledger\ConsensusTransSetSF.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\ConsensusImp.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\impl\ConsensusImp.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\impl\DisputedTx.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\InboundLedger.cpp">
|
<ClCompile Include="..\..\src\ripple\app\ledger\impl\InboundLedger.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
@@ -883,20 +883,10 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerConsensusImp.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\impl\LedgerConsensusImp.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerMaster.cpp">
|
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerMaster.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerTiming.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerToJson.cpp">
|
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerToJson.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
@@ -933,8 +923,6 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerCleaner.h">
|
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerCleaner.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerConsensus.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\LedgerHistory.cpp">
|
<ClCompile Include="..\..\src\ripple\app\ledger\LedgerHistory.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
@@ -945,14 +933,6 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerMaster.h">
|
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerMaster.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\LedgerProposal.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerProposal.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerTiming.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerToJson.h">
|
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerToJson.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LocalTxs.h">
|
<ClInclude Include="..\..\src\ripple\app\ledger\LocalTxs.h">
|
||||||
@@ -1841,6 +1821,18 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
|
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\consensus\Consensus.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\consensus\ConsensusProposal.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\consensus\DisputedTx.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\consensus\LedgerTiming.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\consensus\LedgerTiming.h">
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\core\ConfigSections.h">
|
<ClInclude Include="..\..\src\ripple\core\ConfigSections.h">
|
||||||
@@ -3143,6 +3135,10 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\shamap\TreeNodeCache.h">
|
<ClInclude Include="..\..\src\ripple\shamap\TreeNodeCache.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\unity\app_consensus.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\unity\app_ledger.cpp">
|
<ClCompile Include="..\..\src\ripple\unity\app_ledger.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
@@ -3173,6 +3169,10 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\ripple\unity\consensus.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\unity\core.cpp">
|
<ClCompile Include="..\..\src\ripple\unity\core.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
@@ -4397,6 +4397,14 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\consensus\Consensus_test.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\consensus\LedgerTiming_test.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\core\Config_test.cpp">
|
<ClCompile Include="..\..\src\test\core\Config_test.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
@@ -4425,6 +4433,28 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\test\csf.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\BasicNetwork.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\test\csf\BasicNetwork_test.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\csf\impl\UNL.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\Ledger.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\Peer.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\Sim.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\Tx.h">
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\UNL.h">
|
||||||
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\test\json\json_value_test.cpp">
|
<ClCompile Include="..\..\src\test\json\json_value_test.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
@@ -4453,12 +4483,6 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\test\jtx\balance.h">
|
<ClInclude Include="..\..\src\test\jtx\balance.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\test\jtx\BasicNetwork.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\test\jtx\BasicNetwork_test.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\test\jtx\basic_prop.h">
|
<ClInclude Include="..\..\src\test\jtx\basic_prop.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\test\jtx\delivermin.h">
|
<ClInclude Include="..\..\src\test\jtx\delivermin.h">
|
||||||
@@ -4931,14 +4955,26 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\unity\consensus_test_unity.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\unity\core_test_unity.cpp">
|
<ClCompile Include="..\..\src\test\unity\core_test_unity.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\unity\csf_unity.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\unity\json_test_unity.cpp">
|
<ClCompile Include="..\..\src\test\unity\json_test_unity.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\unity\jtx_unity.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\unity\ledger_test_unity.cpp">
|
<ClCompile Include="..\..\src\test\unity\ledger_test_unity.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
@@ -4977,10 +5013,6 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\unity\support_unity.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|||||||
@@ -214,6 +214,9 @@
|
|||||||
<Filter Include="ripple\conditions\impl">
|
<Filter Include="ripple\conditions\impl">
|
||||||
<UniqueIdentifier>{155DC1A3-8A60-BC74-A7E4-1AC1A679FFF9}</UniqueIdentifier>
|
<UniqueIdentifier>{155DC1A3-8A60-BC74-A7E4-1AC1A679FFF9}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="ripple\consensus">
|
||||||
|
<UniqueIdentifier>{75481992-909B-CAA9-859B-91F15AFD2AD0}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
<Filter Include="ripple\core">
|
<Filter Include="ripple\core">
|
||||||
<UniqueIdentifier>{235DCF23-2CF8-4F03-1A54-C159823A7E8D}</UniqueIdentifier>
|
<UniqueIdentifier>{235DCF23-2CF8-4F03-1A54-C159823A7E8D}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
@@ -448,9 +451,18 @@
|
|||||||
<Filter Include="test\conditions">
|
<Filter Include="test\conditions">
|
||||||
<UniqueIdentifier>{F421E9A0-BB69-E638-F7AC-A3BD9B7D4827}</UniqueIdentifier>
|
<UniqueIdentifier>{F421E9A0-BB69-E638-F7AC-A3BD9B7D4827}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="test\consensus">
|
||||||
|
<UniqueIdentifier>{330C919A-D367-9106-B0FF-BCE5B46A76B2}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
<Filter Include="test\core">
|
<Filter Include="test\core">
|
||||||
<UniqueIdentifier>{26D7F11B-5BF1-54BC-8BF5-D45F68A6A408}</UniqueIdentifier>
|
<UniqueIdentifier>{26D7F11B-5BF1-54BC-8BF5-D45F68A6A408}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="test\csf">
|
||||||
|
<UniqueIdentifier>{8E0BEDEF-0473-BB6D-7AD3-877644873E62}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="test\csf\impl">
|
||||||
|
<UniqueIdentifier>{2B6B8B80-5419-52D9-8CB9-758C3FB7FD0A}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
<Filter Include="test\json">
|
<Filter Include="test\json">
|
||||||
<UniqueIdentifier>{87249A3B-D8F5-1A8C-6C1D-F1CDCCF5242B}</UniqueIdentifier>
|
<UniqueIdentifier>{87249A3B-D8F5-1A8C-6C1D-F1CDCCF5242B}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
@@ -1323,10 +1335,19 @@
|
|||||||
<ClInclude Include="..\..\src\protobuf\vsprojects\config.h">
|
<ClInclude Include="..\..\src\protobuf\vsprojects\config.h">
|
||||||
<Filter>protobuf\vsprojects</Filter>
|
<Filter>protobuf\vsprojects</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxPos.h">
|
<ClCompile Include="..\..\src\ripple\app\consensus\RCLConsensus.cpp">
|
||||||
|
<Filter>ripple\app\consensus</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\app\consensus\RCLConsensus.h">
|
||||||
<Filter>ripple\app\consensus</Filter>
|
<Filter>ripple\app\consensus</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxTraits.h">
|
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxLedger.h">
|
||||||
|
<Filter>ripple\app\consensus</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\app\consensus\RCLCxPeerPos.cpp">
|
||||||
|
<Filter>ripple\app\consensus</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxPeerPos.h">
|
||||||
<Filter>ripple\app\consensus</Filter>
|
<Filter>ripple\app\consensus</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxTx.h">
|
<ClInclude Include="..\..\src\ripple\app\consensus\RCLCxTx.h">
|
||||||
@@ -1359,24 +1380,12 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\app\ledger\BookListeners.h">
|
<ClInclude Include="..\..\src\ripple\app\ledger\BookListeners.h">
|
||||||
<Filter>ripple\app\ledger</Filter>
|
<Filter>ripple\app\ledger</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\Consensus.h">
|
|
||||||
<Filter>ripple\app\ledger</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\ConsensusTransSetSF.cpp">
|
<ClCompile Include="..\..\src\ripple\app\ledger\ConsensusTransSetSF.cpp">
|
||||||
<Filter>ripple\app\ledger</Filter>
|
<Filter>ripple\app\ledger</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\ConsensusTransSetSF.h">
|
<ClInclude Include="..\..\src\ripple\app\ledger\ConsensusTransSetSF.h">
|
||||||
<Filter>ripple\app\ledger</Filter>
|
<Filter>ripple\app\ledger</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\ConsensusImp.cpp">
|
|
||||||
<Filter>ripple\app\ledger\impl</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\impl\ConsensusImp.h">
|
|
||||||
<Filter>ripple\app\ledger\impl</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\impl\DisputedTx.h">
|
|
||||||
<Filter>ripple\app\ledger\impl</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\InboundLedger.cpp">
|
<ClCompile Include="..\..\src\ripple\app\ledger\impl\InboundLedger.cpp">
|
||||||
<Filter>ripple\app\ledger\impl</Filter>
|
<Filter>ripple\app\ledger\impl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -1389,18 +1398,9 @@
|
|||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerCleaner.cpp">
|
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerCleaner.cpp">
|
||||||
<Filter>ripple\app\ledger\impl</Filter>
|
<Filter>ripple\app\ledger\impl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerConsensusImp.cpp">
|
|
||||||
<Filter>ripple\app\ledger\impl</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\impl\LedgerConsensusImp.h">
|
|
||||||
<Filter>ripple\app\ledger\impl</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerMaster.cpp">
|
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerMaster.cpp">
|
||||||
<Filter>ripple\app\ledger\impl</Filter>
|
<Filter>ripple\app\ledger\impl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerTiming.cpp">
|
|
||||||
<Filter>ripple\app\ledger\impl</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerToJson.cpp">
|
<ClCompile Include="..\..\src\ripple\app\ledger\impl\LedgerToJson.cpp">
|
||||||
<Filter>ripple\app\ledger\impl</Filter>
|
<Filter>ripple\app\ledger\impl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -1437,9 +1437,6 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerCleaner.h">
|
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerCleaner.h">
|
||||||
<Filter>ripple\app\ledger</Filter>
|
<Filter>ripple\app\ledger</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerConsensus.h">
|
|
||||||
<Filter>ripple\app\ledger</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\LedgerHistory.cpp">
|
<ClCompile Include="..\..\src\ripple\app\ledger\LedgerHistory.cpp">
|
||||||
<Filter>ripple\app\ledger</Filter>
|
<Filter>ripple\app\ledger</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -1452,15 +1449,6 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerMaster.h">
|
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerMaster.h">
|
||||||
<Filter>ripple\app\ledger</Filter>
|
<Filter>ripple\app\ledger</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ripple\app\ledger\LedgerProposal.cpp">
|
|
||||||
<Filter>ripple\app\ledger</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerProposal.h">
|
|
||||||
<Filter>ripple\app\ledger</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerTiming.h">
|
|
||||||
<Filter>ripple\app\ledger</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerToJson.h">
|
<ClInclude Include="..\..\src\ripple\app\ledger\LedgerToJson.h">
|
||||||
<Filter>ripple\app\ledger</Filter>
|
<Filter>ripple\app\ledger</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -2460,6 +2448,21 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
|
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
|
||||||
<Filter>ripple\conditions\impl</Filter>
|
<Filter>ripple\conditions\impl</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\consensus\Consensus.h">
|
||||||
|
<Filter>ripple\consensus</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\consensus\ConsensusProposal.h">
|
||||||
|
<Filter>ripple\consensus</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\consensus\DisputedTx.h">
|
||||||
|
<Filter>ripple\consensus</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\consensus\LedgerTiming.cpp">
|
||||||
|
<Filter>ripple\consensus</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\consensus\LedgerTiming.h">
|
||||||
|
<Filter>ripple\consensus</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
||||||
<Filter>ripple\core</Filter>
|
<Filter>ripple\core</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -3738,6 +3741,9 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\shamap\TreeNodeCache.h">
|
<ClInclude Include="..\..\src\ripple\shamap\TreeNodeCache.h">
|
||||||
<Filter>ripple\shamap</Filter>
|
<Filter>ripple\shamap</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\unity\app_consensus.cpp">
|
||||||
|
<Filter>ripple\unity</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\unity\app_ledger.cpp">
|
<ClCompile Include="..\..\src\ripple\unity\app_ledger.cpp">
|
||||||
<Filter>ripple\unity</Filter>
|
<Filter>ripple\unity</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -3762,6 +3768,9 @@
|
|||||||
<ClCompile Include="..\..\src\ripple\unity\conditions.cpp">
|
<ClCompile Include="..\..\src\ripple\unity\conditions.cpp">
|
||||||
<Filter>ripple\unity</Filter>
|
<Filter>ripple\unity</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\ripple\unity\consensus.cpp">
|
||||||
|
<Filter>ripple\unity</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\unity\core.cpp">
|
<ClCompile Include="..\..\src\ripple\unity\core.cpp">
|
||||||
<Filter>ripple\unity</Filter>
|
<Filter>ripple\unity</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -5136,6 +5145,12 @@
|
|||||||
<ClCompile Include="..\..\src\test\conditions\PreimageSha256_test.cpp">
|
<ClCompile Include="..\..\src\test\conditions\PreimageSha256_test.cpp">
|
||||||
<Filter>test\conditions</Filter>
|
<Filter>test\conditions</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\consensus\Consensus_test.cpp">
|
||||||
|
<Filter>test\consensus</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\consensus\LedgerTiming_test.cpp">
|
||||||
|
<Filter>test\consensus</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\core\Config_test.cpp">
|
<ClCompile Include="..\..\src\test\core\Config_test.cpp">
|
||||||
<Filter>test\core</Filter>
|
<Filter>test\core</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -5157,6 +5172,33 @@
|
|||||||
<ClCompile Include="..\..\src\test\core\Workers_test.cpp">
|
<ClCompile Include="..\..\src\test\core\Workers_test.cpp">
|
||||||
<Filter>test\core</Filter>
|
<Filter>test\core</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\test\csf.h">
|
||||||
|
<Filter>test</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\BasicNetwork.h">
|
||||||
|
<Filter>test\csf</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\test\csf\BasicNetwork_test.cpp">
|
||||||
|
<Filter>test\csf</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\csf\impl\UNL.cpp">
|
||||||
|
<Filter>test\csf\impl</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\Ledger.h">
|
||||||
|
<Filter>test\csf</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\Peer.h">
|
||||||
|
<Filter>test\csf</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\Sim.h">
|
||||||
|
<Filter>test\csf</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\Tx.h">
|
||||||
|
<Filter>test\csf</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\test\csf\UNL.h">
|
||||||
|
<Filter>test\csf</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\test\json\json_value_test.cpp">
|
<ClCompile Include="..\..\src\test\json\json_value_test.cpp">
|
||||||
<Filter>test\json</Filter>
|
<Filter>test\json</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -5187,12 +5229,6 @@
|
|||||||
<ClInclude Include="..\..\src\test\jtx\balance.h">
|
<ClInclude Include="..\..\src\test\jtx\balance.h">
|
||||||
<Filter>test\jtx</Filter>
|
<Filter>test\jtx</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\test\jtx\BasicNetwork.h">
|
|
||||||
<Filter>test\jtx</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\test\jtx\BasicNetwork_test.cpp">
|
|
||||||
<Filter>test\jtx</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\test\jtx\basic_prop.h">
|
<ClInclude Include="..\..\src\test\jtx\basic_prop.h">
|
||||||
<Filter>test\jtx</Filter>
|
<Filter>test\jtx</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -5598,12 +5634,21 @@
|
|||||||
<ClCompile Include="..\..\src\test\unity\conditions_test_unity.cpp">
|
<ClCompile Include="..\..\src\test\unity\conditions_test_unity.cpp">
|
||||||
<Filter>test\unity</Filter>
|
<Filter>test\unity</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\unity\consensus_test_unity.cpp">
|
||||||
|
<Filter>test\unity</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\unity\core_test_unity.cpp">
|
<ClCompile Include="..\..\src\test\unity\core_test_unity.cpp">
|
||||||
<Filter>test\unity</Filter>
|
<Filter>test\unity</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\unity\csf_unity.cpp">
|
||||||
|
<Filter>test\unity</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\unity\json_test_unity.cpp">
|
<ClCompile Include="..\..\src\test\unity\json_test_unity.cpp">
|
||||||
<Filter>test\unity</Filter>
|
<Filter>test\unity</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\unity\jtx_unity.cpp">
|
||||||
|
<Filter>test\unity</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\unity\ledger_test_unity.cpp">
|
<ClCompile Include="..\..\src\test\unity\ledger_test_unity.cpp">
|
||||||
<Filter>test\unity</Filter>
|
<Filter>test\unity</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -5631,8 +5676,5 @@
|
|||||||
<ClCompile Include="..\..\src\test\unity\shamap_test_unity.cpp">
|
<ClCompile Include="..\..\src\test\unity\shamap_test_unity.cpp">
|
||||||
<Filter>test\unity</Filter>
|
<Filter>test\unity</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\unity\support_unity.cpp">
|
|
||||||
<Filter>test\unity</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -179,12 +179,14 @@ beast_utility_unity.cpp)
|
|||||||
|
|
||||||
prepend(ripple_unity_srcs
|
prepend(ripple_unity_srcs
|
||||||
src/ripple/unity/
|
src/ripple/unity/
|
||||||
|
app_consensus.cpp
|
||||||
app_ledger.cpp
|
app_ledger.cpp
|
||||||
app_main.cpp
|
app_main.cpp
|
||||||
app_misc.cpp
|
app_misc.cpp
|
||||||
app_paths.cpp
|
app_paths.cpp
|
||||||
app_tx.cpp
|
app_tx.cpp
|
||||||
conditions.cpp
|
conditions.cpp
|
||||||
|
consensus.cpp
|
||||||
core.cpp
|
core.cpp
|
||||||
basics.cpp
|
basics.cpp
|
||||||
crypto.cpp
|
crypto.cpp
|
||||||
@@ -204,6 +206,7 @@ app_test_unity.cpp
|
|||||||
basics_test_unity.cpp
|
basics_test_unity.cpp
|
||||||
beast_test_unity.cpp
|
beast_test_unity.cpp
|
||||||
conditions_test_unity.cpp
|
conditions_test_unity.cpp
|
||||||
|
consensus_test_unity.cpp
|
||||||
core_test_unity.cpp
|
core_test_unity.cpp
|
||||||
json_test_unity.cpp
|
json_test_unity.cpp
|
||||||
ledger_test_unity.cpp
|
ledger_test_unity.cpp
|
||||||
@@ -214,7 +217,8 @@ resource_test_unity.cpp
|
|||||||
rpc_test_unity.cpp
|
rpc_test_unity.cpp
|
||||||
server_test_unity.cpp
|
server_test_unity.cpp
|
||||||
shamap_test_unity.cpp
|
shamap_test_unity.cpp
|
||||||
support_unity.cpp)
|
jtx_unity.cpp
|
||||||
|
csf_unity.cpp)
|
||||||
|
|
||||||
list(APPEND rippled_src_unity ${beast_unity_srcs} ${ripple_unity_srcs} ${test_unity_srcs})
|
list(APPEND rippled_src_unity ${beast_unity_srcs} ${ripple_unity_srcs} ${test_unity_srcs})
|
||||||
|
|
||||||
@@ -257,6 +261,7 @@ foreach(curdir
|
|||||||
basics
|
basics
|
||||||
conditions
|
conditions
|
||||||
crypto
|
crypto
|
||||||
|
consensus
|
||||||
json
|
json
|
||||||
ledger
|
ledger
|
||||||
legacy
|
legacy
|
||||||
@@ -300,7 +305,8 @@ foreach(curdir
|
|||||||
rpc
|
rpc
|
||||||
server
|
server
|
||||||
shamap
|
shamap
|
||||||
jtx)
|
jtx
|
||||||
|
csf)
|
||||||
file(GLOB_RECURSE cursrcs src/test/${curdir}/*.cpp)
|
file(GLOB_RECURSE cursrcs src/test/${curdir}/*.cpp)
|
||||||
list(APPEND test_srcs "${cursrcs}")
|
list(APPEND test_srcs "${cursrcs}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|||||||
@@ -949,6 +949,7 @@ def get_classic_sources(toolchain):
|
|||||||
append_sources(result, *list_sources('src/ripple/basics', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/basics', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/conditions', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/conditions', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/crypto', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/crypto', '.cpp'))
|
||||||
|
append_sources(result, *list_sources('src/ripple/consensus', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/json', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/json', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/ledger', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/ledger', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/ripple/legacy', '.cpp'))
|
append_sources(result, *list_sources('src/ripple/legacy', '.cpp'))
|
||||||
@@ -963,6 +964,7 @@ def get_classic_sources(toolchain):
|
|||||||
append_sources(result, *list_sources('src/test/basics', '.cpp'))
|
append_sources(result, *list_sources('src/test/basics', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/test/beast', '.cpp'))
|
append_sources(result, *list_sources('src/test/beast', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/test/conditions', '.cpp'))
|
append_sources(result, *list_sources('src/test/conditions', '.cpp'))
|
||||||
|
append_sources(result, *list_sources('src/test/consensus', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/test/core', '.cpp'))
|
append_sources(result, *list_sources('src/test/core', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/test/json', '.cpp'))
|
append_sources(result, *list_sources('src/test/json', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/test/ledger', '.cpp'))
|
append_sources(result, *list_sources('src/test/ledger', '.cpp'))
|
||||||
@@ -974,6 +976,7 @@ def get_classic_sources(toolchain):
|
|||||||
append_sources(result, *list_sources('src/test/server', '.cpp'))
|
append_sources(result, *list_sources('src/test/server', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/test/shamap', '.cpp'))
|
append_sources(result, *list_sources('src/test/shamap', '.cpp'))
|
||||||
append_sources(result, *list_sources('src/test/jtx', '.cpp'))
|
append_sources(result, *list_sources('src/test/jtx', '.cpp'))
|
||||||
|
append_sources(result, *list_sources('src/test/csf', '.cpp'))
|
||||||
|
|
||||||
|
|
||||||
if use_shp(toolchain):
|
if use_shp(toolchain):
|
||||||
@@ -1003,12 +1006,14 @@ def get_unity_sources(toolchain):
|
|||||||
'src/ripple/beast/unity/beast_insight_unity.cpp',
|
'src/ripple/beast/unity/beast_insight_unity.cpp',
|
||||||
'src/ripple/beast/unity/beast_net_unity.cpp',
|
'src/ripple/beast/unity/beast_net_unity.cpp',
|
||||||
'src/ripple/beast/unity/beast_utility_unity.cpp',
|
'src/ripple/beast/unity/beast_utility_unity.cpp',
|
||||||
|
'src/ripple/unity/app_consensus.cpp',
|
||||||
'src/ripple/unity/app_ledger.cpp',
|
'src/ripple/unity/app_ledger.cpp',
|
||||||
'src/ripple/unity/app_main.cpp',
|
'src/ripple/unity/app_main.cpp',
|
||||||
'src/ripple/unity/app_misc.cpp',
|
'src/ripple/unity/app_misc.cpp',
|
||||||
'src/ripple/unity/app_paths.cpp',
|
'src/ripple/unity/app_paths.cpp',
|
||||||
'src/ripple/unity/app_tx.cpp',
|
'src/ripple/unity/app_tx.cpp',
|
||||||
'src/ripple/unity/conditions.cpp',
|
'src/ripple/unity/conditions.cpp',
|
||||||
|
'src/ripple/unity/consensus.cpp',
|
||||||
'src/ripple/unity/core.cpp',
|
'src/ripple/unity/core.cpp',
|
||||||
'src/ripple/unity/basics.cpp',
|
'src/ripple/unity/basics.cpp',
|
||||||
'src/ripple/unity/crypto.cpp',
|
'src/ripple/unity/crypto.cpp',
|
||||||
@@ -1024,6 +1029,7 @@ def get_unity_sources(toolchain):
|
|||||||
'src/test/unity/app_test_unity.cpp',
|
'src/test/unity/app_test_unity.cpp',
|
||||||
'src/test/unity/basics_test_unity.cpp',
|
'src/test/unity/basics_test_unity.cpp',
|
||||||
'src/test/unity/beast_test_unity.cpp',
|
'src/test/unity/beast_test_unity.cpp',
|
||||||
|
'src/test/unity/consensus_test_unity.cpp',
|
||||||
'src/test/unity/core_test_unity.cpp',
|
'src/test/unity/core_test_unity.cpp',
|
||||||
'src/test/unity/conditions_test_unity.cpp',
|
'src/test/unity/conditions_test_unity.cpp',
|
||||||
'src/test/unity/json_test_unity.cpp',
|
'src/test/unity/json_test_unity.cpp',
|
||||||
@@ -1035,7 +1041,8 @@ def get_unity_sources(toolchain):
|
|||||||
'src/test/unity/rpc_test_unity.cpp',
|
'src/test/unity/rpc_test_unity.cpp',
|
||||||
'src/test/unity/server_test_unity.cpp',
|
'src/test/unity/server_test_unity.cpp',
|
||||||
'src/test/unity/shamap_test_unity.cpp',
|
'src/test/unity/shamap_test_unity.cpp',
|
||||||
'src/test/unity/support_unity.cpp'
|
'src/test/unity/jtx_unity.cpp',
|
||||||
|
'src/test/unity/csf_unity.cpp'
|
||||||
)
|
)
|
||||||
|
|
||||||
if use_shp(toolchain):
|
if use_shp(toolchain):
|
||||||
|
|||||||
@@ -106,10 +106,17 @@ INPUT = \
|
|||||||
\
|
\
|
||||||
../src/ripple/protocol/STObject.h \
|
../src/ripple/protocol/STObject.h \
|
||||||
../src/ripple/protocol/JsonFields.h \
|
../src/ripple/protocol/JsonFields.h \
|
||||||
../src/test/support/AbstractClient.h \
|
../src/test/jtx/AbstractClient.h \
|
||||||
../src/test/support/JSONRPCClient.h \
|
../src/test/jtx/JSONRPCClient.h \
|
||||||
../src/test/support/WSClient.h \
|
../src/test/jtx/WSClient.h \
|
||||||
|
../src/ripple/consensus/Consensus.h \
|
||||||
|
../src/ripple/consensus/ConsensusProposal.h \
|
||||||
|
../src/ripple/consensus/DisputedTx.h \
|
||||||
|
../src/ripple/consensus/LedgerTiming.h \
|
||||||
|
../src/ripple/app/consensus/RCLCxTx.h \
|
||||||
|
../src/ripple/app/consensus/RCLCxLedger.h \
|
||||||
|
../src/ripple/app/consensus/RCLConsensus.h \
|
||||||
|
../src/ripple/app/consensus/RCLCxPeerPos.h \
|
||||||
|
|
||||||
INPUT_ENCODING = UTF-8
|
INPUT_ENCODING = UTF-8
|
||||||
FILE_PATTERNS =
|
FILE_PATTERNS =
|
||||||
|
|||||||
909
src/ripple/app/consensus/RCLConsensus.cpp
Normal file
909
src/ripple/app/consensus/RCLConsensus.cpp
Normal file
@@ -0,0 +1,909 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <BeastConfig.h>
|
||||||
|
#include <ripple/beast/core/LexicalCast.h>
|
||||||
|
#include <ripple/app/consensus/RCLConsensus.h>
|
||||||
|
#include <ripple/app/ledger/InboundTransactions.h>
|
||||||
|
#include <ripple/app/misc/NetworkOPs.h>
|
||||||
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
|
#include <ripple/app/ledger/InboundLedgers.h>
|
||||||
|
#include <ripple/overlay/Overlay.h>
|
||||||
|
#include <ripple/app/ledger/OpenLedger.h>
|
||||||
|
#include <ripple/protocol/digest.h>
|
||||||
|
#include <ripple/overlay/predicates.h>
|
||||||
|
#include <ripple/app/misc/AmendmentTable.h>
|
||||||
|
#include <ripple/app/misc/HashRouter.h>
|
||||||
|
#include <ripple/consensus/LedgerTiming.h>
|
||||||
|
#include <ripple/basics/make_lock.h>
|
||||||
|
#include <ripple/app/ledger/LocalTxs.h>
|
||||||
|
#include <ripple/app/misc/TxQ.h>
|
||||||
|
#include <ripple/app/tx/apply.h>
|
||||||
|
#include <ripple/protocol/Feature.h>
|
||||||
|
#include <ripple/app/misc/LoadFeeTrack.h>
|
||||||
|
#include <ripple/app/misc/ValidatorList.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
|
||||||
|
RCLConsensus::RCLConsensus(
|
||||||
|
Application& app,
|
||||||
|
std::unique_ptr<FeeVote> && feeVote,
|
||||||
|
LedgerMaster& ledgerMaster,
|
||||||
|
LocalTxs& localTxs,
|
||||||
|
InboundTransactions& inboundTransactions,
|
||||||
|
typename Base::clock_type const & clock,
|
||||||
|
beast::Journal journal)
|
||||||
|
: Base(clock, journal)
|
||||||
|
, app_ (app)
|
||||||
|
, feeVote_ (std::move(feeVote))
|
||||||
|
, ledgerMaster_ (ledgerMaster)
|
||||||
|
, localTxs_(localTxs)
|
||||||
|
, inboundTransactions_{ inboundTransactions }
|
||||||
|
, j_ (journal)
|
||||||
|
, nodeID_{ calcNodeID(app.nodeIdentity().first) }
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RCLConsensus::onStartRound(RCLCxLedger const & ledger)
|
||||||
|
{
|
||||||
|
inboundTransactions_.newRound(ledger.seq());
|
||||||
|
}
|
||||||
|
|
||||||
|
// First bool is whether or not we can propose
|
||||||
|
// Second bool is whether or not we can validate
|
||||||
|
std::pair <bool, bool>
|
||||||
|
RCLConsensus::getMode ()
|
||||||
|
{
|
||||||
|
bool propose = false;
|
||||||
|
bool validate = false;
|
||||||
|
|
||||||
|
if (! app_.getOPs().isNeedNetworkLedger() && (valPublic_.size() != 0))
|
||||||
|
{
|
||||||
|
// We have a key, and we have some idea what the ledger is
|
||||||
|
validate = true;
|
||||||
|
|
||||||
|
// propose only if we're in sync with the network
|
||||||
|
propose = app_.getOPs().getOperatingMode() == NetworkOPs::omFULL;
|
||||||
|
}
|
||||||
|
return { propose, validate };
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<RCLCxLedger>
|
||||||
|
RCLConsensus::acquireLedger(LedgerHash const & ledger)
|
||||||
|
{
|
||||||
|
|
||||||
|
// we need to switch the ledger we're working from
|
||||||
|
auto buildLCL = ledgerMaster_.getLedgerByHash(ledger);
|
||||||
|
if (! buildLCL)
|
||||||
|
{
|
||||||
|
if (acquiringLedger_ != ledger)
|
||||||
|
{
|
||||||
|
// need to start acquiring the correct consensus LCL
|
||||||
|
JLOG (j_.warn()) <<
|
||||||
|
"Need consensus ledger " << ledger;
|
||||||
|
|
||||||
|
// Tell the ledger acquire system that we need the consensus ledger
|
||||||
|
acquiringLedger_ = ledger;
|
||||||
|
|
||||||
|
auto app = &app_;
|
||||||
|
auto hash = acquiringLedger_;
|
||||||
|
app_.getJobQueue().addJob (
|
||||||
|
jtADVANCE, "getConsensusLedger",
|
||||||
|
[app, hash] (Job&) {
|
||||||
|
app->getInboundLedgers().acquire(
|
||||||
|
hash, 0, InboundLedger::fcCONSENSUS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (!buildLCL->open() && buildLCL->isImmutable ());
|
||||||
|
assert (buildLCL->info().hash == ledger);
|
||||||
|
|
||||||
|
return RCLCxLedger(buildLCL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<RCLCxPeerPos>
|
||||||
|
RCLConsensus::proposals (LedgerHash const& prevLedger)
|
||||||
|
{
|
||||||
|
std::vector <RCLCxPeerPos> ret;
|
||||||
|
{
|
||||||
|
std::lock_guard <std::mutex> _(peerPositionsLock_);
|
||||||
|
|
||||||
|
for (auto const& it : peerPositions_)
|
||||||
|
for (auto const& pos : it.second)
|
||||||
|
if (pos->proposal().prevLedger() == prevLedger)
|
||||||
|
ret.emplace_back (*pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RCLConsensus::storeProposal (
|
||||||
|
RCLCxPeerPos::ref peerPos,
|
||||||
|
NodeID const& nodeID)
|
||||||
|
{
|
||||||
|
std::lock_guard <std::mutex> _(peerPositionsLock_);
|
||||||
|
|
||||||
|
auto& props = peerPositions_[nodeID];
|
||||||
|
|
||||||
|
if (props.size () >= 10)
|
||||||
|
props.pop_front ();
|
||||||
|
|
||||||
|
props.push_back (peerPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RCLConsensus::relay(RCLCxPeerPos const & peerPos)
|
||||||
|
{
|
||||||
|
protocol::TMProposeSet prop;
|
||||||
|
|
||||||
|
auto const & proposal = peerPos.proposal();
|
||||||
|
|
||||||
|
prop.set_proposeseq (
|
||||||
|
proposal.proposeSeq ());
|
||||||
|
prop.set_closetime (
|
||||||
|
proposal.closeTime ().time_since_epoch().count());
|
||||||
|
|
||||||
|
prop.set_currenttxhash (
|
||||||
|
proposal.position().begin(), proposal.position().size());
|
||||||
|
prop.set_previousledger (
|
||||||
|
proposal.prevLedger().begin(), proposal.position().size());
|
||||||
|
|
||||||
|
auto const pk = peerPos.getPublicKey().slice();
|
||||||
|
prop.set_nodepubkey (pk.data(), pk.size());
|
||||||
|
|
||||||
|
auto const sig = peerPos.getSignature();
|
||||||
|
prop.set_signature (sig.data(), sig.size());
|
||||||
|
|
||||||
|
app_.overlay().relay (prop, peerPos.getSuppressionID ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RCLConsensus::relay(DisputedTx <RCLCxTx, NodeID> const & dispute)
|
||||||
|
{
|
||||||
|
// If we didn't relay this transaction recently, relay it to all peers
|
||||||
|
auto const & tx = dispute.tx();
|
||||||
|
if (app_.getHashRouter ().shouldRelay (tx.id()))
|
||||||
|
{
|
||||||
|
auto const slice = tx.tx_.slice();
|
||||||
|
|
||||||
|
protocol::TMTransaction msg;
|
||||||
|
msg.set_rawtransaction (slice.data(), slice.size());
|
||||||
|
msg.set_status (protocol::tsNEW);
|
||||||
|
msg.set_receivetimestamp (
|
||||||
|
app_.timeKeeper().now().time_since_epoch().count());
|
||||||
|
app_.overlay ().foreach (send_always (
|
||||||
|
std::make_shared<Message> (
|
||||||
|
msg, protocol::mtTRANSACTION)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void
|
||||||
|
RCLConsensus::propose (RCLCxPeerPos::Proposal const& proposal)
|
||||||
|
{
|
||||||
|
JLOG (j_.trace()) << "We propose: " <<
|
||||||
|
(proposal.isBowOut () ? std::string ("bowOut") :
|
||||||
|
to_string (proposal.position ()));
|
||||||
|
|
||||||
|
protocol::TMProposeSet prop;
|
||||||
|
|
||||||
|
prop.set_currenttxhash (proposal.position().begin(),
|
||||||
|
proposal.position().size());
|
||||||
|
prop.set_previousledger (proposal.prevLedger().begin(),
|
||||||
|
proposal.position().size());
|
||||||
|
prop.set_proposeseq (proposal.proposeSeq());
|
||||||
|
prop.set_closetime (
|
||||||
|
proposal.closeTime().time_since_epoch().count());
|
||||||
|
|
||||||
|
prop.set_nodepubkey (valPublic_.data(), valPublic_.size());
|
||||||
|
|
||||||
|
auto signingHash = sha512Half(
|
||||||
|
HashPrefix::proposal,
|
||||||
|
std::uint32_t(proposal.proposeSeq()),
|
||||||
|
proposal.closeTime().time_since_epoch().count(),
|
||||||
|
proposal.prevLedger(), proposal.position());
|
||||||
|
|
||||||
|
auto sig = signDigest (
|
||||||
|
valPublic_, valSecret_, signingHash);
|
||||||
|
|
||||||
|
prop.set_signature (sig.data(), sig.size());
|
||||||
|
|
||||||
|
app_.overlay().send(prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RCLConsensus::share (RCLTxSet const& set)
|
||||||
|
{
|
||||||
|
inboundTransactions_.giveSet (set.id(),
|
||||||
|
set.map_, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<RCLTxSet>
|
||||||
|
RCLConsensus::acquireTxSet(RCLTxSet::ID const & setId)
|
||||||
|
{
|
||||||
|
if (auto set = inboundTransactions_.getSet(setId, true))
|
||||||
|
{
|
||||||
|
return RCLTxSet{std::move(set)};
|
||||||
|
}
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
RCLConsensus::hasOpenTransactions() const
|
||||||
|
{
|
||||||
|
return ! app_.openLedger().empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
RCLConsensus::proposersValidated(LedgerHash const & h) const
|
||||||
|
{
|
||||||
|
return app_.getValidations().getTrustedValidationCount(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
RCLConsensus::proposersFinished(LedgerHash const & h) const
|
||||||
|
{
|
||||||
|
return app_.getValidations().getNodesAfter(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256
|
||||||
|
RCLConsensus::getLCL (
|
||||||
|
uint256 const& currentLedger,
|
||||||
|
uint256 const& priorLedger,
|
||||||
|
bool believedCorrect)
|
||||||
|
{
|
||||||
|
// Get validators that are on our ledger, or "close" to being on
|
||||||
|
// our ledger.
|
||||||
|
auto vals =
|
||||||
|
app_.getValidations().getCurrentValidations(
|
||||||
|
currentLedger, priorLedger,
|
||||||
|
ledgerMaster_.getValidLedgerIndex());
|
||||||
|
|
||||||
|
uint256 netLgr = currentLedger;
|
||||||
|
int netLgrCount = 0;
|
||||||
|
for (auto& it : vals)
|
||||||
|
{
|
||||||
|
// Switch to ledger supported by more peers
|
||||||
|
// Or stick with ours on a tie
|
||||||
|
if ((it.second.first > netLgrCount) ||
|
||||||
|
((it.second.first == netLgrCount) && (it.first == currentLedger)))
|
||||||
|
{
|
||||||
|
netLgr = it.first;
|
||||||
|
netLgrCount = it.second.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(netLgr != currentLedger)
|
||||||
|
{
|
||||||
|
if (believedCorrect)
|
||||||
|
app_.getOPs().consensusViewChange();
|
||||||
|
if (auto stream = j_.debug())
|
||||||
|
{
|
||||||
|
for (auto& it : vals)
|
||||||
|
stream << "V: " << it.first << ", " << it.second.first;
|
||||||
|
stream << getJson (true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return netLgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
RCLConsensus::onClose(RCLCxLedger const & ledger, bool haveCorrectLCL)
|
||||||
|
{
|
||||||
|
notify(protocol::neCLOSING_LEDGER, ledger, haveCorrectLCL);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair <RCLTxSet, typename RCLCxPeerPos::Proposal>
|
||||||
|
RCLConsensus::makeInitialPosition (RCLCxLedger const & prevLedgerT,
|
||||||
|
bool proposing,
|
||||||
|
bool correctLCL,
|
||||||
|
NetClock::time_point closeTime,
|
||||||
|
NetClock::time_point now)
|
||||||
|
{
|
||||||
|
auto const &prevLedger = prevLedgerT.ledger_;
|
||||||
|
ledgerMaster_.applyHeldTransactions ();
|
||||||
|
// Tell the ledger master not to acquire the ledger we're probably building
|
||||||
|
ledgerMaster_.setBuildingLedger (prevLedger->info().seq + 1);
|
||||||
|
|
||||||
|
auto initialLedger = app_.openLedger().current();
|
||||||
|
|
||||||
|
auto initialSet = std::make_shared <SHAMap> (
|
||||||
|
SHAMapType::TRANSACTION, app_.family(), SHAMap::version{1});
|
||||||
|
initialSet->setUnbacked ();
|
||||||
|
|
||||||
|
// Build SHAMap containing all transactions in our open ledger
|
||||||
|
for (auto const& tx : initialLedger->txs)
|
||||||
|
{
|
||||||
|
Serializer s (2048);
|
||||||
|
tx.first->add(s);
|
||||||
|
initialSet->addItem (
|
||||||
|
SHAMapItem (tx.first->getTransactionID(), std::move (s)), true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add pseudo-transactions to the set
|
||||||
|
if ((app_.config().standalone() || (proposing && correctLCL))
|
||||||
|
&& ((prevLedger->info().seq % 256) == 0))
|
||||||
|
{
|
||||||
|
// previous ledger was flag ledger, add pseudo-transactions
|
||||||
|
auto const validations =
|
||||||
|
app_.getValidations().getValidations (
|
||||||
|
prevLedger->info().parentHash);
|
||||||
|
|
||||||
|
std::size_t const count = std::count_if (
|
||||||
|
validations.begin(), validations.end(),
|
||||||
|
[](auto const& v)
|
||||||
|
{
|
||||||
|
return v.second->isTrusted();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (count >= app_.validators ().quorum ())
|
||||||
|
{
|
||||||
|
feeVote_->doVoting (
|
||||||
|
prevLedger,
|
||||||
|
validations,
|
||||||
|
initialSet);
|
||||||
|
app_.getAmendmentTable ().doVoting (
|
||||||
|
prevLedger,
|
||||||
|
validations,
|
||||||
|
initialSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we need an immutable snapshot
|
||||||
|
initialSet = initialSet->snapShot(false);
|
||||||
|
auto setHash = initialSet->getHash().as_uint256();
|
||||||
|
|
||||||
|
return std::make_pair<RCLTxSet, RCLCxPeerPos::Proposal> (
|
||||||
|
std::move (initialSet),
|
||||||
|
RCLCxPeerPos::Proposal {
|
||||||
|
initialLedger->info().parentHash,
|
||||||
|
RCLCxPeerPos::Proposal::seqJoin,
|
||||||
|
setHash,
|
||||||
|
closeTime,
|
||||||
|
now,
|
||||||
|
nodeID_ });
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RCLConsensus::dispatchAccept(RCLTxSet const & txSet)
|
||||||
|
{
|
||||||
|
app_.getJobQueue().addJob(jtACCEPT, "acceptLedger",
|
||||||
|
[that = this->shared_from_this(),
|
||||||
|
consensusSet = txSet]
|
||||||
|
(auto &)
|
||||||
|
{
|
||||||
|
that->accept(consensusSet);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RCLConsensus::accept(
|
||||||
|
RCLTxSet const& set,
|
||||||
|
NetClock::time_point consensusCloseTime,
|
||||||
|
bool proposing_,
|
||||||
|
bool validating_,
|
||||||
|
bool haveCorrectLCL_,
|
||||||
|
bool consensusFail_,
|
||||||
|
LedgerHash const &prevLedgerHash_,
|
||||||
|
RCLCxLedger const & previousLedger_,
|
||||||
|
NetClock::duration closeResolution_,
|
||||||
|
NetClock::time_point const & now_,
|
||||||
|
std::chrono::milliseconds const & roundTime_,
|
||||||
|
hash_map<RCLCxTx::ID, DisputedTx <RCLCxTx, NodeID>> const & disputes_,
|
||||||
|
std::map <NetClock::time_point, int> closeTimes_,
|
||||||
|
NetClock::time_point const & closeTime_
|
||||||
|
)
|
||||||
|
{
|
||||||
|
bool closeTimeCorrect;
|
||||||
|
|
||||||
|
if (consensusCloseTime == NetClock::time_point{})
|
||||||
|
{
|
||||||
|
// We agreed to disagree on the close time
|
||||||
|
consensusCloseTime = previousLedger_.closeTime() + 1s;
|
||||||
|
closeTimeCorrect = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We agreed on a close time
|
||||||
|
consensusCloseTime = effectiveCloseTime(consensusCloseTime,
|
||||||
|
closeResolution_, previousLedger_.closeTime());
|
||||||
|
closeTimeCorrect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JLOG (j_.debug())
|
||||||
|
<< "Report: Prop=" << (proposing_ ? "yes" : "no")
|
||||||
|
<< " val=" << (validating_ ? "yes" : "no")
|
||||||
|
<< " corLCL=" << (haveCorrectLCL_ ? "yes" : "no")
|
||||||
|
<< " fail=" << (consensusFail_ ? "yes" : "no");
|
||||||
|
JLOG (j_.debug())
|
||||||
|
<< "Report: Prev = " << prevLedgerHash_
|
||||||
|
<< ":" << previousLedger_.seq();
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Put transactions into a deterministic, but unpredictable, order
|
||||||
|
CanonicalTXSet retriableTxs{ set.id() };
|
||||||
|
|
||||||
|
auto sharedLCL = buildLCL(previousLedger_, set, consensusCloseTime,
|
||||||
|
closeTimeCorrect, closeResolution_, now_, roundTime_, retriableTxs);
|
||||||
|
|
||||||
|
|
||||||
|
auto const newLCLHash = sharedLCL.id();
|
||||||
|
JLOG (j_.debug())
|
||||||
|
<< "Report: NewL = " << newLCLHash
|
||||||
|
<< ":" << sharedLCL.seq();
|
||||||
|
|
||||||
|
// Tell directly connected peers that we have a new LCL
|
||||||
|
notify (protocol::neACCEPTED_LEDGER, sharedLCL, haveCorrectLCL_);
|
||||||
|
|
||||||
|
if (validating_)
|
||||||
|
validating_ = ledgerMaster_.isCompatible(*sharedLCL.ledger_,
|
||||||
|
app_.journal("LedgerConsensus").warn(), "Not validating");
|
||||||
|
|
||||||
|
if (validating_ && ! consensusFail_)
|
||||||
|
{
|
||||||
|
validate(sharedLCL, now_, proposing_);
|
||||||
|
JLOG (j_.info())
|
||||||
|
<< "CNF Val " << newLCLHash;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
JLOG (j_.info())
|
||||||
|
<< "CNF buildLCL " << newLCLHash;
|
||||||
|
|
||||||
|
// See if we can accept a ledger as fully-validated
|
||||||
|
ledgerMaster_.consensusBuilt (sharedLCL.ledger_, getJson(true));
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
// Apply disputed transactions that didn't get in
|
||||||
|
//
|
||||||
|
// The first crack of transactions to get into the new
|
||||||
|
// open ledger goes to transactions proposed by a validator
|
||||||
|
// we trust but not included in the consensus set.
|
||||||
|
//
|
||||||
|
// These are done first because they are the most likely
|
||||||
|
// to receive agreement during consensus. They are also
|
||||||
|
// ordered logically "sooner" than transactions not mentioned
|
||||||
|
// in the previous consensus round.
|
||||||
|
//
|
||||||
|
bool anyDisputes = false;
|
||||||
|
for (auto& it : disputes_)
|
||||||
|
{
|
||||||
|
if (!it.second.getOurVote ())
|
||||||
|
{
|
||||||
|
// we voted NO
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JLOG (j_.debug())
|
||||||
|
<< "Test applying disputed transaction that did"
|
||||||
|
<< " not get in";
|
||||||
|
|
||||||
|
SerialIter sit (it.second.tx().tx_.slice());
|
||||||
|
auto txn = std::make_shared<STTx const>(sit);
|
||||||
|
retriableTxs.insert (txn);
|
||||||
|
|
||||||
|
anyDisputes = true;
|
||||||
|
}
|
||||||
|
catch (std::exception const&)
|
||||||
|
{
|
||||||
|
JLOG (j_.debug())
|
||||||
|
<< "Failed to apply transaction we voted NO on";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build new open ledger
|
||||||
|
auto lock = make_lock(
|
||||||
|
app_.getMasterMutex(), std::defer_lock);
|
||||||
|
auto sl = make_lock(
|
||||||
|
ledgerMaster_.peekMutex (), std::defer_lock);
|
||||||
|
std::lock(lock, sl);
|
||||||
|
|
||||||
|
auto const lastVal = ledgerMaster_.getValidatedLedger();
|
||||||
|
boost::optional<Rules> rules;
|
||||||
|
if (lastVal)
|
||||||
|
rules.emplace(*lastVal, app_.config().features);
|
||||||
|
else
|
||||||
|
rules.emplace(app_.config().features);
|
||||||
|
app_.openLedger().accept(app_, *rules,
|
||||||
|
sharedLCL.ledger_, localTxs_.getTxSet(), anyDisputes, retriableTxs, tapNONE,
|
||||||
|
"consensus",
|
||||||
|
[&](OpenView& view, beast::Journal j)
|
||||||
|
{
|
||||||
|
// Stuff the ledger with transactions from the queue.
|
||||||
|
return app_.getTxQ().accept(app_, view);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Signal a potential fee change to subscribers after the open ledger
|
||||||
|
// is created
|
||||||
|
app_.getOPs().reportFeeChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
ledgerMaster_.switchLCL (sharedLCL.ledger_);
|
||||||
|
|
||||||
|
// Do these need to exist?
|
||||||
|
assert (ledgerMaster_.getClosedLedger()->info().hash == sharedLCL.id());
|
||||||
|
assert (app_.openLedger().current()->info().parentHash == sharedLCL.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
if (haveCorrectLCL_ && ! consensusFail_)
|
||||||
|
{
|
||||||
|
// we entered the round with the network,
|
||||||
|
// see how close our close time is to other node's
|
||||||
|
// close time reports, and update our clock.
|
||||||
|
JLOG (j_.info())
|
||||||
|
<< "We closed at " << closeTime_.time_since_epoch().count();
|
||||||
|
using usec64_t = std::chrono::duration<std::uint64_t>;
|
||||||
|
usec64_t closeTotal = std::chrono::duration_cast<usec64_t>(closeTime_.time_since_epoch());
|
||||||
|
int closeCount = 1;
|
||||||
|
|
||||||
|
for (auto const& p : closeTimes_)
|
||||||
|
{
|
||||||
|
// FIXME: Use median, not average
|
||||||
|
JLOG (j_.info())
|
||||||
|
<< std::to_string(p.second)
|
||||||
|
<< " time votes for "
|
||||||
|
<< std::to_string(p.first.time_since_epoch().count());
|
||||||
|
closeCount += p.second;
|
||||||
|
closeTotal += std::chrono::duration_cast<usec64_t>(p.first.time_since_epoch()) * p.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeTotal += usec64_t(closeCount / 2); // for round to nearest
|
||||||
|
closeTotal /= closeCount;
|
||||||
|
|
||||||
|
// Use signed times since we are subtracting
|
||||||
|
using duration = std::chrono::duration<std::int32_t>;
|
||||||
|
using time_point = std::chrono::time_point<NetClock, duration>;
|
||||||
|
auto offset = time_point{closeTotal} -
|
||||||
|
std::chrono::time_point_cast<duration>(closeTime_);
|
||||||
|
JLOG (j_.info())
|
||||||
|
<< "Our close offset is estimated at "
|
||||||
|
<< offset.count() << " (" << closeCount << ")";
|
||||||
|
|
||||||
|
app_.timeKeeper().adjustCloseTime(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return validating_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RCLConsensus::endConsensus(bool correctLCL)
|
||||||
|
{
|
||||||
|
app_.getOPs ().endConsensus (correctLCL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
RCLConsensus::notify(
|
||||||
|
protocol::NodeEvent ne,
|
||||||
|
RCLCxLedger const & ledger,
|
||||||
|
bool haveCorrectLCL)
|
||||||
|
{
|
||||||
|
|
||||||
|
protocol::TMStatusChange s;
|
||||||
|
|
||||||
|
if (!haveCorrectLCL)
|
||||||
|
s.set_newevent (protocol::neLOST_SYNC);
|
||||||
|
else
|
||||||
|
s.set_newevent(ne);
|
||||||
|
|
||||||
|
s.set_ledgerseq (ledger.seq());
|
||||||
|
s.set_networktime (app_.timeKeeper().now().time_since_epoch().count());
|
||||||
|
s.set_ledgerhashprevious(ledger.parentID().begin (),
|
||||||
|
std::decay_t<decltype(ledger.parentID())>::bytes);
|
||||||
|
s.set_ledgerhash (ledger.id().begin (),
|
||||||
|
std::decay_t<decltype(ledger.id())>::bytes);
|
||||||
|
|
||||||
|
std::uint32_t uMin, uMax;
|
||||||
|
if (! ledgerMaster_.getFullValidatedRange (uMin, uMax))
|
||||||
|
{
|
||||||
|
uMin = 0;
|
||||||
|
uMax = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Don't advertise ledgers we're not willing to serve
|
||||||
|
uMin = std::max(uMin, ledgerMaster_.getEarliestFetch ());
|
||||||
|
}
|
||||||
|
s.set_firstseq (uMin);
|
||||||
|
s.set_lastseq (uMax);
|
||||||
|
app_.overlay ().foreach (send_always (
|
||||||
|
std::make_shared <Message> (
|
||||||
|
s, protocol::mtSTATUS_CHANGE)));
|
||||||
|
JLOG (j_.trace()) << "send status change to peer";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Apply a set of transactions to a ledger.
|
||||||
|
|
||||||
|
Typically the txFilter is used to reject transactions
|
||||||
|
that already accepted in the prior ledger.
|
||||||
|
|
||||||
|
@param set set of transactions to apply
|
||||||
|
@param view ledger to apply to
|
||||||
|
@param txFilter callback, return false to reject txn
|
||||||
|
@return retriable transactions
|
||||||
|
*/
|
||||||
|
|
||||||
|
CanonicalTXSet
|
||||||
|
applyTransactions (
|
||||||
|
Application& app,
|
||||||
|
RCLTxSet const& cSet,
|
||||||
|
OpenView& view,
|
||||||
|
std::function<bool(uint256 const&)> txFilter)
|
||||||
|
{
|
||||||
|
auto j = app.journal ("LedgerConsensus");
|
||||||
|
|
||||||
|
auto& set = *(cSet.map_);
|
||||||
|
CanonicalTXSet retriableTxs (set.getHash().as_uint256());
|
||||||
|
|
||||||
|
|
||||||
|
for (auto const& item : set)
|
||||||
|
{
|
||||||
|
if (! txFilter (item.key()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// The transaction wan't filtered
|
||||||
|
// Add it to the set to be tried in canonical order
|
||||||
|
JLOG (j.debug()) <<
|
||||||
|
"Processing candidate transaction: " << item.key();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
retriableTxs.insert (
|
||||||
|
std::make_shared<STTx const>(SerialIter{item.slice()}));
|
||||||
|
}
|
||||||
|
catch (std::exception const&)
|
||||||
|
{
|
||||||
|
JLOG (j.warn()) << "Txn " << item.key() << " throws";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool certainRetry = true;
|
||||||
|
// Attempt to apply all of the retriable transactions
|
||||||
|
for (int pass = 0; pass < LEDGER_TOTAL_PASSES; ++pass)
|
||||||
|
{
|
||||||
|
JLOG (j.debug()) << "Pass: " << pass << " Txns: "
|
||||||
|
<< retriableTxs.size ()
|
||||||
|
<< (certainRetry ? " retriable" : " final");
|
||||||
|
int changes = 0;
|
||||||
|
|
||||||
|
auto it = retriableTxs.begin ();
|
||||||
|
|
||||||
|
while (it != retriableTxs.end ())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (applyTransaction (app, view,
|
||||||
|
*it->second, certainRetry, tapNO_CHECK_SIGN, j))
|
||||||
|
{
|
||||||
|
case ApplyResult::Success:
|
||||||
|
it = retriableTxs.erase (it);
|
||||||
|
++changes;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ApplyResult::Fail:
|
||||||
|
it = retriableTxs.erase (it);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ApplyResult::Retry:
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception const&)
|
||||||
|
{
|
||||||
|
JLOG (j.warn())
|
||||||
|
<< "Transaction throws";
|
||||||
|
it = retriableTxs.erase (it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JLOG (j.debug()) << "Pass: "
|
||||||
|
<< pass << " finished " << changes << " changes";
|
||||||
|
|
||||||
|
// A non-retry pass made no changes
|
||||||
|
if (!changes && !certainRetry)
|
||||||
|
return retriableTxs;
|
||||||
|
|
||||||
|
// Stop retriable passes
|
||||||
|
if (!changes || (pass >= LEDGER_RETRY_PASSES))
|
||||||
|
certainRetry = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are any transactions left, we must have
|
||||||
|
// tried them in at least one final pass
|
||||||
|
assert (retriableTxs.empty() || !certainRetry);
|
||||||
|
return retriableTxs;
|
||||||
|
}
|
||||||
|
|
||||||
|
RCLCxLedger
|
||||||
|
RCLConsensus::buildLCL(
|
||||||
|
RCLCxLedger const & previousLedger,
|
||||||
|
RCLTxSet const & set,
|
||||||
|
NetClock::time_point closeTime,
|
||||||
|
bool closeTimeCorrect,
|
||||||
|
NetClock::duration closeResolution,
|
||||||
|
NetClock::time_point now,
|
||||||
|
std::chrono::milliseconds roundTime,
|
||||||
|
CanonicalTXSet & retriableTxs)
|
||||||
|
{
|
||||||
|
auto replay = ledgerMaster_.releaseReplay();
|
||||||
|
if (replay)
|
||||||
|
{
|
||||||
|
// replaying, use the time the ledger we're replaying closed
|
||||||
|
closeTime = replay->closeTime_;
|
||||||
|
closeTimeCorrect = ((replay->closeFlags_ & sLCF_NoConsensusTime) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
JLOG (j_.debug())
|
||||||
|
<< "Report: TxSt = " << set.id ()
|
||||||
|
<< ", close " << closeTime.time_since_epoch().count()
|
||||||
|
<< (closeTimeCorrect ? "" : "X");
|
||||||
|
|
||||||
|
|
||||||
|
// Build the new last closed ledger
|
||||||
|
auto buildLCL = std::make_shared<Ledger>(*previousLedger.ledger_, now);
|
||||||
|
|
||||||
|
auto const v2_enabled = buildLCL->rules().enabled(featureSHAMapV2);
|
||||||
|
|
||||||
|
auto v2_transition = false;
|
||||||
|
if (v2_enabled && !buildLCL->stateMap().is_v2())
|
||||||
|
{
|
||||||
|
buildLCL->make_v2();
|
||||||
|
v2_transition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up to write SHAMap changes to our database,
|
||||||
|
// perform updates, extract changes
|
||||||
|
JLOG (j_.debug())
|
||||||
|
<< "Applying consensus set transactions to the"
|
||||||
|
<< " last closed ledger";
|
||||||
|
|
||||||
|
{
|
||||||
|
OpenView accum(&*buildLCL);
|
||||||
|
assert(!accum.open());
|
||||||
|
if (replay)
|
||||||
|
{
|
||||||
|
// Special case, we are replaying a ledger close
|
||||||
|
for (auto& tx : replay->txns_)
|
||||||
|
applyTransaction (app_, accum, *tx.second,
|
||||||
|
false, tapNO_CHECK_SIGN, j_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Normal case, we are not replaying a ledger close
|
||||||
|
retriableTxs = applyTransactions (app_, set, accum,
|
||||||
|
[&buildLCL](uint256 const& txID)
|
||||||
|
{
|
||||||
|
return ! buildLCL->txExists(txID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Update fee computations.
|
||||||
|
app_.getTxQ().processClosedLedger(app_, accum,
|
||||||
|
roundTime > 5s);
|
||||||
|
accum.apply(*buildLCL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// retriableTxs will include any transactions that
|
||||||
|
// made it into the consensus set but failed during application
|
||||||
|
// to the ledger.
|
||||||
|
|
||||||
|
buildLCL->updateSkipList ();
|
||||||
|
|
||||||
|
{
|
||||||
|
// Write the final version of all modified SHAMap
|
||||||
|
// nodes to the node store to preserve the new LCL
|
||||||
|
|
||||||
|
int asf = buildLCL->stateMap().flushDirty (
|
||||||
|
hotACCOUNT_NODE, buildLCL->info().seq);
|
||||||
|
int tmf = buildLCL->txMap().flushDirty (
|
||||||
|
hotTRANSACTION_NODE, buildLCL->info().seq);
|
||||||
|
JLOG (j_.debug()) << "Flushed " <<
|
||||||
|
asf << " accounts and " <<
|
||||||
|
tmf << " transaction nodes";
|
||||||
|
}
|
||||||
|
buildLCL->unshare();
|
||||||
|
|
||||||
|
// Accept ledger
|
||||||
|
buildLCL->setAccepted(closeTime, closeResolution,
|
||||||
|
closeTimeCorrect, app_.config());
|
||||||
|
|
||||||
|
// And stash the ledger in the ledger master
|
||||||
|
if (ledgerMaster_.storeLedger (buildLCL))
|
||||||
|
JLOG (j_.debug())
|
||||||
|
<< "Consensus built ledger we already had";
|
||||||
|
else if (app_.getInboundLedgers().find (buildLCL->info().hash))
|
||||||
|
JLOG (j_.debug())
|
||||||
|
<< "Consensus built ledger we were acquiring";
|
||||||
|
else
|
||||||
|
JLOG (j_.debug())
|
||||||
|
<< "Consensus built new ledger";
|
||||||
|
return RCLCxLedger{std::move(buildLCL)};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RCLConsensus::validate(
|
||||||
|
RCLCxLedger const & ledger,
|
||||||
|
NetClock::time_point now,
|
||||||
|
bool proposing)
|
||||||
|
{
|
||||||
|
auto validationTime = now;
|
||||||
|
if (validationTime <= lastValidationTime_)
|
||||||
|
validationTime = lastValidationTime_ + 1s;
|
||||||
|
lastValidationTime_ = validationTime;
|
||||||
|
|
||||||
|
// Build validation
|
||||||
|
auto v = std::make_shared<STValidation> (ledger.id(),
|
||||||
|
validationTime, valPublic_, proposing);
|
||||||
|
v->setFieldU32 (sfLedgerSequence, ledger.seq());
|
||||||
|
|
||||||
|
// Add our load fee to the validation
|
||||||
|
auto const& feeTrack = app_.getFeeTrack();
|
||||||
|
std::uint32_t fee = std::max(
|
||||||
|
feeTrack.getLocalFee(),
|
||||||
|
feeTrack.getClusterFee());
|
||||||
|
|
||||||
|
if (fee > feeTrack.getLoadBase())
|
||||||
|
v->setFieldU32(sfLoadFee, fee);
|
||||||
|
|
||||||
|
if (((ledger.seq() + 1) % 256) == 0)
|
||||||
|
// next ledger is flag ledger
|
||||||
|
{
|
||||||
|
// Suggest fee changes and new features
|
||||||
|
feeVote_->doValidation (ledger.ledger_, *v);
|
||||||
|
app_.getAmendmentTable ().doValidation (ledger.ledger_, *v);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const signingHash = v->sign (valSecret_);
|
||||||
|
v->setTrusted ();
|
||||||
|
// suppress it if we receive it - FIXME: wrong suppression
|
||||||
|
app_.getHashRouter ().addSuppression (signingHash);
|
||||||
|
app_.getValidations ().addValidation (v, "local");
|
||||||
|
Blob validation = v->getSerialized ();
|
||||||
|
protocol::TMValidation val;
|
||||||
|
val.set_validation (&validation[0], validation.size ());
|
||||||
|
// Send signed validation to all of our directly connected peers
|
||||||
|
app_.overlay().send(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
PublicKey const&
|
||||||
|
RCLConsensus::getValidationPublicKey () const
|
||||||
|
{
|
||||||
|
return valPublic_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RCLConsensus::setValidationKeys (SecretKey const& valSecret,
|
||||||
|
PublicKey const& valPublic)
|
||||||
|
{
|
||||||
|
valSecret_ = valSecret;
|
||||||
|
valPublic_ = valPublic;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
383
src/ripple/app/consensus/RCLConsensus.h
Normal file
383
src/ripple/app/consensus/RCLConsensus.h
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_APP_CONSENSUS_RCLCONSENSUS_H_INCLUDED
|
||||||
|
#define RIPPLE_APP_CONSENSUS_RCLCONSENSUS_H_INCLUDED
|
||||||
|
|
||||||
|
#include <BeastConfig.h>
|
||||||
|
#include <ripple/basics/Log.h>
|
||||||
|
#include <ripple/protocol/STValidation.h>
|
||||||
|
#include <ripple/shamap/SHAMap.h>
|
||||||
|
#include <ripple/beast/utility/Journal.h>
|
||||||
|
#include <ripple/app/misc/FeeVote.h>
|
||||||
|
#include <ripple/protocol/RippleLedgerHash.h>
|
||||||
|
#include <ripple/app/consensus/RCLCxLedger.h>
|
||||||
|
#include <ripple/app/consensus/RCLCxTx.h>
|
||||||
|
#include <ripple/app/consensus/RCLCxPeerPos.h>
|
||||||
|
#include <ripple/core/JobQueue.h>
|
||||||
|
#include <ripple/consensus/Consensus.h>
|
||||||
|
#include <ripple/basics/CountedObject.h>
|
||||||
|
#include <ripple/overlay/Message.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
class InboundTransactions;
|
||||||
|
class LocalTxs;
|
||||||
|
class LedgerMaster;
|
||||||
|
|
||||||
|
//! Types used to adapt consensus for RCL
|
||||||
|
struct RCLCxTraits
|
||||||
|
{
|
||||||
|
//! Ledger type presented to Consensus
|
||||||
|
using Ledger_t = RCLCxLedger;
|
||||||
|
//! Peer identifier type used in Consensus
|
||||||
|
using NodeID_t = NodeID;
|
||||||
|
//! TxSet type presented to Consensus
|
||||||
|
using TxSet_t = RCLTxSet;
|
||||||
|
//! MissingTxException type neede by Consensus
|
||||||
|
using MissingTxException_t = SHAMapMissingNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Adapts the generic Consensus algorithm for use by RCL.
|
||||||
|
|
||||||
|
@note The enabled_shared_from_this base allows the application to properly
|
||||||
|
create a shared instance of RCLConsensus for use in the accept logic..
|
||||||
|
*/
|
||||||
|
class RCLConsensus : public Consensus<RCLConsensus, RCLCxTraits>
|
||||||
|
, public std::enable_shared_from_this <RCLConsensus>
|
||||||
|
, public CountedObject <RCLConsensus>
|
||||||
|
{
|
||||||
|
using Base = Consensus<RCLConsensus, RCLCxTraits>;
|
||||||
|
using Base::accept;
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Constructor
|
||||||
|
RCLConsensus(
|
||||||
|
Application& app,
|
||||||
|
std::unique_ptr<FeeVote> && feeVote,
|
||||||
|
LedgerMaster& ledgerMaster,
|
||||||
|
LocalTxs& localTxs,
|
||||||
|
InboundTransactions& inboundTransactions,
|
||||||
|
typename Base::clock_type const & clock,
|
||||||
|
beast::Journal journal);
|
||||||
|
RCLConsensus(RCLConsensus const&) = delete;
|
||||||
|
RCLConsensus& operator=(RCLConsensus const&) = delete;
|
||||||
|
|
||||||
|
static char const* getCountedObjectName() { return "Consensus"; }
|
||||||
|
|
||||||
|
/** Save the given consensus proposed by a peer with nodeID for later
|
||||||
|
use in consensus.
|
||||||
|
|
||||||
|
@param peerPos Proposed peer position
|
||||||
|
@param nodeID ID of peer
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
storeProposal( RCLCxPeerPos::ref peerPos, NodeID const& nodeID);
|
||||||
|
|
||||||
|
/** Returns validation public key */
|
||||||
|
PublicKey const&
|
||||||
|
getValidationPublicKey () const;
|
||||||
|
|
||||||
|
/** Set validation private and public key pair. */
|
||||||
|
void
|
||||||
|
setValidationKeys (SecretKey const& valSecret, PublicKey const& valPublic);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Consensus<RCLConsensus, RCLCxTraits>;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Consensus type requirements.
|
||||||
|
|
||||||
|
/** Notification that a new consensus round has begun.
|
||||||
|
|
||||||
|
@param ledger The ledger we are building consensus on
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
onStartRound(RCLCxLedger const & ledger);
|
||||||
|
|
||||||
|
//! @return Whether consensus should be (proposing, validating)
|
||||||
|
std::pair <bool, bool>
|
||||||
|
getMode ();
|
||||||
|
|
||||||
|
/** Attempt to acquire a specific ledger.
|
||||||
|
|
||||||
|
If not available, asynchronously acquires from the network.
|
||||||
|
|
||||||
|
@param ledger The ID/hash of the ledger acquire
|
||||||
|
@return Optional ledger, will be seated if we locally had the ledger
|
||||||
|
*/
|
||||||
|
boost::optional<RCLCxLedger>
|
||||||
|
acquireLedger(LedgerHash const & ledger);
|
||||||
|
|
||||||
|
/** Get peers' proposed positions.
|
||||||
|
@param prevLedger The base ledger which proposals are based on
|
||||||
|
@return The set of proposals
|
||||||
|
*/
|
||||||
|
std::vector<RCLCxPeerPos>
|
||||||
|
proposals (LedgerHash const& prevLedger);
|
||||||
|
|
||||||
|
/** Relay the given proposal to all peers
|
||||||
|
|
||||||
|
@param peerPos The peer position to relay.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
relay(RCLCxPeerPos const & peerPos);
|
||||||
|
|
||||||
|
/** Relay disputed transacction to peers.
|
||||||
|
|
||||||
|
Only relay if the provided transaction hasn't been shared recently.
|
||||||
|
|
||||||
|
@param dispute The disputed transaction to relay.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
relay(DisputedTx <RCLCxTx, NodeID> const & dispute);
|
||||||
|
|
||||||
|
/** Acquire the transaction set associated with a proposal.
|
||||||
|
|
||||||
|
If the transaction set is not available locally, will attempt acquire it
|
||||||
|
from the network.
|
||||||
|
|
||||||
|
@param setId The transaction set ID associated with the proposal
|
||||||
|
@return Optional set of transactions, seated if available.
|
||||||
|
*/
|
||||||
|
boost::optional<RCLTxSet>
|
||||||
|
acquireTxSet(RCLTxSet::ID const & setId);
|
||||||
|
|
||||||
|
/** Whether the open ledger has any transactions
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
hasOpenTransactions() const;
|
||||||
|
|
||||||
|
/** Number of proposers that have vallidated the given ledger
|
||||||
|
|
||||||
|
@param h The hash of the ledger of interest
|
||||||
|
@return the number of proposers that validated a ledger
|
||||||
|
*/
|
||||||
|
std::size_t
|
||||||
|
proposersValidated(LedgerHash const & h) const;
|
||||||
|
|
||||||
|
/** Number of proposers that have validated a ledger descended from requested ledger.
|
||||||
|
|
||||||
|
@param h The hash of the ledger of interest.
|
||||||
|
@return The number of validating peers that have validated a ledger
|
||||||
|
succeeding the one provided.
|
||||||
|
*/
|
||||||
|
std::size_t
|
||||||
|
proposersFinished(LedgerHash const & h) const;
|
||||||
|
|
||||||
|
/** Propose the given position to my peers.
|
||||||
|
|
||||||
|
@param proposal Our proposed position
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
propose (RCLCxPeerPos::Proposal const& proposal);
|
||||||
|
|
||||||
|
/** Share the given tx set with peers.
|
||||||
|
|
||||||
|
@param set The TxSet to share.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
share (RCLTxSet const& set);
|
||||||
|
|
||||||
|
/** Get the last closed ledger (LCL) seen on the network
|
||||||
|
|
||||||
|
@param currentLedger Current ledger used in consensus
|
||||||
|
@param priorLedger Prior ledger used in consensus
|
||||||
|
@param believedCorrect Whether consensus believes currentLedger is LCL
|
||||||
|
|
||||||
|
@return The hash of the last closed network
|
||||||
|
*/
|
||||||
|
uint256
|
||||||
|
getLCL (
|
||||||
|
uint256 const& currentLedger,
|
||||||
|
uint256 const& priorLedger,
|
||||||
|
bool believedCorrect);
|
||||||
|
|
||||||
|
|
||||||
|
/** Notification that the ledger has closed.
|
||||||
|
|
||||||
|
@param ledger the ledger we are changing to
|
||||||
|
@param haveCorrectLCL whether we believe this is the correct LCL
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
onClose(RCLCxLedger const & ledger, bool haveCorrectLCL);
|
||||||
|
|
||||||
|
/** Create our initial position of transactions to accept in this round
|
||||||
|
of consensus.
|
||||||
|
|
||||||
|
@param prevLedger The ledger the transactions apply to
|
||||||
|
@param isProposing Whether we are currently proposing
|
||||||
|
@param isCorrectLCL Whether we have the correct LCL
|
||||||
|
@param closeTime When we believe the ledger closed
|
||||||
|
@param now The current network adjusted time
|
||||||
|
|
||||||
|
@return Pair of (i) transactions we believe are in the ledger
|
||||||
|
(ii) the corresponding proposal of those transactions
|
||||||
|
to send to peers
|
||||||
|
*/
|
||||||
|
std::pair <RCLTxSet, typename RCLCxPeerPos::Proposal>
|
||||||
|
makeInitialPosition (
|
||||||
|
RCLCxLedger const & prevLedger,
|
||||||
|
bool isProposing,
|
||||||
|
bool isCorrectLCL,
|
||||||
|
NetClock::time_point closeTime,
|
||||||
|
NetClock::time_point now);
|
||||||
|
|
||||||
|
|
||||||
|
/** Dispatch a call to Consensus::accept
|
||||||
|
|
||||||
|
Accepting a ledger may be expensive, so this function can dispatch
|
||||||
|
that call to another thread if desired and must call the accept
|
||||||
|
method of the generic consensus algorithm.
|
||||||
|
|
||||||
|
@param txSet The transactions to accept.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
dispatchAccept(RCLTxSet const & txSet);
|
||||||
|
|
||||||
|
|
||||||
|
/** Accept a new ledger based on the given transactions.
|
||||||
|
|
||||||
|
TODO: Too many arguments, need to group related types.
|
||||||
|
|
||||||
|
@param set The set of accepted transactions
|
||||||
|
@param consensusCloseTime Consensus agreed upon close time
|
||||||
|
@param proposing_ Whether we are proposing
|
||||||
|
@param validating_ Whether we are validating
|
||||||
|
@param haveCorrectLCL_ Whether we had the correct last closed ledger
|
||||||
|
@param consensusFail_ Whether consensus failed
|
||||||
|
@param prevLedgerHash_ The hash/id of the previous ledger
|
||||||
|
@param previousLedger_ The previous ledger
|
||||||
|
@param closeResolution_ The close time resolution used this round
|
||||||
|
@param now Current network adjsuted time
|
||||||
|
@param roundTime_ Duration of this consensus round
|
||||||
|
@param disputes_ Disputed trarnsactions from this round
|
||||||
|
@param closeTimes_ Histogram of peers close times
|
||||||
|
@param closeTime Our close time
|
||||||
|
@return Whether we should continue validating
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
accept(
|
||||||
|
RCLTxSet const& set,
|
||||||
|
NetClock::time_point consensusCloseTime,
|
||||||
|
bool proposing_,
|
||||||
|
bool validating_,
|
||||||
|
bool haveCorrectLCL_,
|
||||||
|
bool consensusFail_,
|
||||||
|
LedgerHash const &prevLedgerHash_,
|
||||||
|
RCLCxLedger const & previousLedger_,
|
||||||
|
NetClock::duration closeResolution_,
|
||||||
|
NetClock::time_point const & now,
|
||||||
|
std::chrono::milliseconds const & roundTime_,
|
||||||
|
hash_map<RCLCxTx::ID, DisputedTx <RCLCxTx, NodeID>> const & disputes_,
|
||||||
|
std::map <NetClock::time_point, int> closeTimes_,
|
||||||
|
NetClock::time_point const & closeTime
|
||||||
|
);
|
||||||
|
|
||||||
|
/** Signal the end of consensus to the application, which will start the
|
||||||
|
next round.
|
||||||
|
|
||||||
|
@param correctLCL Whether we believe we have the correct LCL
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
endConsensus(bool correctLCL);
|
||||||
|
|
||||||
|
//!-------------------------------------------------------------------------
|
||||||
|
// Additional members (not directly required by Consensus interface)
|
||||||
|
/** Notify peers of a consensus state change
|
||||||
|
|
||||||
|
@param ne Event type for notification
|
||||||
|
@param ledger The ledger at the time of the state change
|
||||||
|
@param haveCorrectLCL Whether we believ we have the correct LCL.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
notify(protocol::NodeEvent ne, RCLCxLedger const & ledger, bool haveCorrectLCL);
|
||||||
|
|
||||||
|
/** Build the new last closed ledger.
|
||||||
|
|
||||||
|
Accept the given the provided set of consensus transactions and build
|
||||||
|
the last closed ledger. Since consensus just agrees on which
|
||||||
|
transactions to apply, but not whether they make it into the closed
|
||||||
|
ledger, this function also populates retriableTxs with those that can
|
||||||
|
be retried in the next round.
|
||||||
|
|
||||||
|
@param previousLedger Prior ledger building upon
|
||||||
|
@param set The set of transactions to apply to the ledger
|
||||||
|
@param closeTime The the ledger closed
|
||||||
|
@param closeTimeCorrect Whether consensus agreed on close time
|
||||||
|
@param closeResolution Resolution used to determine consensus close time
|
||||||
|
@param now Current network adjusted time
|
||||||
|
@param roundTime Duration of this consensus rorund
|
||||||
|
@param retriableTxs Populate with transactions to retry in next round
|
||||||
|
@return The newly built ledger
|
||||||
|
*/
|
||||||
|
RCLCxLedger
|
||||||
|
buildLCL(
|
||||||
|
RCLCxLedger const & previousLedger,
|
||||||
|
RCLTxSet const & set,
|
||||||
|
NetClock::time_point closeTime,
|
||||||
|
bool closeTimeCorrect,
|
||||||
|
NetClock::duration closeResolution,
|
||||||
|
NetClock::time_point now,
|
||||||
|
std::chrono::milliseconds roundTime,
|
||||||
|
CanonicalTXSet & retriableTxs
|
||||||
|
);
|
||||||
|
|
||||||
|
/** Validate the given ledger and share with peers as necessary
|
||||||
|
|
||||||
|
@param ledger The ledger to validate
|
||||||
|
@param now Current network adjusted time
|
||||||
|
@param proposing Whether we were proposing transactions while generating
|
||||||
|
this ledger. If we are not proposing, a validation
|
||||||
|
can still be sent to inform peers that we know we
|
||||||
|
aren't fully participating in consensus but are still
|
||||||
|
around and trying to catch up.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
validate(
|
||||||
|
RCLCxLedger const & ledger,
|
||||||
|
NetClock::time_point now,
|
||||||
|
bool proposing);
|
||||||
|
|
||||||
|
//!-------------------------------------------------------------------------
|
||||||
|
Application& app_;
|
||||||
|
std::unique_ptr <FeeVote> feeVote_;
|
||||||
|
LedgerMaster & ledgerMaster_;
|
||||||
|
LocalTxs & localTxs_;
|
||||||
|
InboundTransactions& inboundTransactions_;
|
||||||
|
beast::Journal j_;
|
||||||
|
|
||||||
|
NodeID nodeID_;
|
||||||
|
PublicKey valPublic_;
|
||||||
|
SecretKey valSecret_;
|
||||||
|
LedgerHash acquiringLedger_;
|
||||||
|
|
||||||
|
// The timestamp of the last validation we used, in network time. This is
|
||||||
|
// only used for our own validations.
|
||||||
|
NetClock::time_point lastValidationTime_;
|
||||||
|
|
||||||
|
using PeerPositions = hash_map <NodeID, std::deque<RCLCxPeerPos::pointer>>;
|
||||||
|
PeerPositions peerPositions_;
|
||||||
|
std::mutex peerPositionsLock_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
121
src/ripple/app/consensus/RCLCxLedger.h
Normal file
121
src/ripple/app/consensus/RCLCxLedger.h
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012-2016 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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_APP_CONSENSUS_RCLCXLEDGER_H_INCLUDED
|
||||||
|
#define RIPPLE_APP_CONSENSUS_RCLCXLEDGER_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/app/ledger/Ledger.h>
|
||||||
|
#include <ripple/ledger/ReadView.h>
|
||||||
|
#include <ripple/app/ledger/LedgerToJson.h>
|
||||||
|
#include <ripple/protocol/RippleLedgerHash.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
|
||||||
|
/** Represents a ledger in RCLConsensus.
|
||||||
|
|
||||||
|
RCLCxLedger is a thin wrapper over `std::shared_ptr<Ledger const>`.
|
||||||
|
*/
|
||||||
|
class RCLCxLedger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! Unique identifier of a ledger
|
||||||
|
using ID = LedgerHash;
|
||||||
|
|
||||||
|
/** Default constructor
|
||||||
|
|
||||||
|
TODO: This may not be needed if we ensure RCLConsensus is handed a valid
|
||||||
|
ledger in its constructor. Its bad now because other members are not
|
||||||
|
checking whether the ledger is valid.
|
||||||
|
*/
|
||||||
|
RCLCxLedger() = default;
|
||||||
|
|
||||||
|
/** Constructor
|
||||||
|
|
||||||
|
@param l The ledger to wrap.
|
||||||
|
*/
|
||||||
|
RCLCxLedger(std::shared_ptr<Ledger const> const & l) : ledger_{ l } {}
|
||||||
|
|
||||||
|
//! Sequence number of the ledger.
|
||||||
|
auto const &
|
||||||
|
seq() const
|
||||||
|
{
|
||||||
|
return ledger_->info().seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Unique identifier (hash) of this ledger.
|
||||||
|
auto const &
|
||||||
|
id() const
|
||||||
|
{
|
||||||
|
return ledger_->info().hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Unique identifier (hash) of this ledger's parent.
|
||||||
|
auto const &
|
||||||
|
parentID() const
|
||||||
|
{
|
||||||
|
return ledger_->info().parentHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Resolution used when calculating this ledger's close time.
|
||||||
|
auto
|
||||||
|
closeTimeResolution() const
|
||||||
|
{
|
||||||
|
return ledger_->info().closeTimeResolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Whether consensus process agreed on close time of the ledger.
|
||||||
|
bool
|
||||||
|
closeAgree() const
|
||||||
|
{
|
||||||
|
return ripple::getCloseAgree(ledger_->info());
|
||||||
|
}
|
||||||
|
|
||||||
|
//! The close time of this ledger
|
||||||
|
auto
|
||||||
|
closeTime() const
|
||||||
|
{
|
||||||
|
return ledger_->info().closeTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! The close time of this ledger's parent.
|
||||||
|
auto
|
||||||
|
parentCloseTime() const
|
||||||
|
{
|
||||||
|
return ledger_->info().parentCloseTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! JSON representation of this ledger.
|
||||||
|
Json::Value
|
||||||
|
getJson() const
|
||||||
|
{
|
||||||
|
return ripple::getJson(*ledger_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The ledger instance.
|
||||||
|
|
||||||
|
TODO: Make this shared_ptr<ReadView const> .. requires ability to create
|
||||||
|
a new ledger from a readView?
|
||||||
|
*/
|
||||||
|
std::shared_ptr<Ledger const> ledger_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/app/ledger/LedgerProposal.h>
|
#include <ripple/app/consensus/RCLCxPeerPos.h>
|
||||||
#include <ripple/protocol/digest.h>
|
#include <ripple/protocol/digest.h>
|
||||||
#include <ripple/core/Config.h>
|
#include <ripple/core/Config.h>
|
||||||
#include <ripple/protocol/JsonFields.h>
|
#include <ripple/protocol/JsonFields.h>
|
||||||
@@ -28,97 +28,40 @@
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
// Used to construct received proposals
|
// Used to construct received proposals
|
||||||
LedgerProposal::LedgerProposal (
|
RCLCxPeerPos::RCLCxPeerPos (
|
||||||
uint256 const& pLgr,
|
|
||||||
std::uint32_t seq,
|
|
||||||
uint256 const& tx,
|
|
||||||
NetClock::time_point closeTime,
|
|
||||||
NetClock::time_point now,
|
|
||||||
PublicKey const& publicKey,
|
PublicKey const& publicKey,
|
||||||
NodeID const& nodeID,
|
|
||||||
Slice const& signature,
|
Slice const& signature,
|
||||||
uint256 const& suppression)
|
uint256 const& suppression,
|
||||||
: mPreviousLedger (pLgr)
|
Proposal && proposal)
|
||||||
, mCurrentHash (tx)
|
: proposal_{ std::move(proposal)}
|
||||||
, mSuppression (suppression)
|
, mSuppression {suppression}
|
||||||
, mCloseTime (closeTime)
|
, publicKey_{publicKey}
|
||||||
, mProposeSeq (seq)
|
, signature_{signature}
|
||||||
, publicKey_ (publicKey)
|
|
||||||
, mPeerID (nodeID)
|
|
||||||
, mTime (now)
|
|
||||||
{
|
{
|
||||||
signature_.resize (signature.size());
|
|
||||||
std::memcpy(signature_.data(),
|
|
||||||
signature.data(), signature.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to construct local proposals
|
|
||||||
// CAUTION: publicKey_ not set
|
|
||||||
LedgerProposal::LedgerProposal (
|
|
||||||
uint256 const& prevLgr,
|
|
||||||
uint256 const& position,
|
|
||||||
NetClock::time_point closeTime,
|
|
||||||
NetClock::time_point now)
|
|
||||||
: mPreviousLedger (prevLgr)
|
|
||||||
, mCurrentHash (position)
|
|
||||||
, mCloseTime (closeTime)
|
|
||||||
, mProposeSeq (seqJoin)
|
|
||||||
, mTime (now)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
uint256 RCLCxPeerPos::getSigningHash () const
|
||||||
uint256 LedgerProposal::getSigningHash () const
|
|
||||||
{
|
{
|
||||||
return sha512Half(
|
return sha512Half(
|
||||||
HashPrefix::proposal,
|
HashPrefix::proposal,
|
||||||
std::uint32_t(mProposeSeq),
|
std::uint32_t(proposal().proposeSeq()),
|
||||||
mCloseTime.time_since_epoch().count(),
|
proposal().closeTime().time_since_epoch().count(),
|
||||||
mPreviousLedger,
|
proposal().prevLedger(),
|
||||||
mCurrentHash);
|
proposal().position());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LedgerProposal::checkSign () const
|
bool RCLCxPeerPos::checkSign () const
|
||||||
{
|
{
|
||||||
return verifyDigest (
|
return verifyDigest (
|
||||||
publicKey_,
|
publicKey_,
|
||||||
getSigningHash(),
|
getSigningHash(),
|
||||||
makeSlice (signature_),
|
signature_,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LedgerProposal::changePosition (
|
Json::Value RCLCxPeerPos::getJson () const
|
||||||
uint256 const& newPosition,
|
|
||||||
NetClock::time_point closeTime,
|
|
||||||
NetClock::time_point now)
|
|
||||||
{
|
{
|
||||||
if (mProposeSeq == seqLeave)
|
auto ret = proposal().getJson();
|
||||||
return false;
|
|
||||||
|
|
||||||
mCurrentHash = newPosition;
|
|
||||||
mCloseTime = closeTime;
|
|
||||||
mTime = now;
|
|
||||||
++mProposeSeq;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LedgerProposal::bowOut (NetClock::time_point now)
|
|
||||||
{
|
|
||||||
mTime = now;
|
|
||||||
mProposeSeq = seqLeave;
|
|
||||||
}
|
|
||||||
|
|
||||||
Json::Value LedgerProposal::getJson () const
|
|
||||||
{
|
|
||||||
Json::Value ret = Json::objectValue;
|
|
||||||
ret[jss::previous_ledger] = to_string (mPreviousLedger);
|
|
||||||
|
|
||||||
if (mProposeSeq != seqLeave)
|
|
||||||
{
|
|
||||||
ret[jss::transaction_hash] = to_string (mCurrentHash);
|
|
||||||
ret[jss::propose_seq] = mProposeSeq;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret[jss::close_time] = mCloseTime.time_since_epoch().count();
|
|
||||||
|
|
||||||
if (publicKey_.size())
|
if (publicKey_.size())
|
||||||
ret[jss::peer_id] = toBase58 (
|
ret[jss::peer_id] = toBase58 (
|
||||||
@@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef RIPPLE_APP_LEDGER_LEDGERPROPOSAL_H_INCLUDED
|
#ifndef RIPPLE_APP_CONSENSUS_RCLCXPEERPOS_H_INCLUDED
|
||||||
#define RIPPLE_APP_LEDGER_LEDGERPROPOSAL_H_INCLUDED
|
#define RIPPLE_APP_CONSENSUS_RCLCXPEERPOS_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/basics/CountedObject.h>
|
#include <ripple/basics/CountedObject.h>
|
||||||
#include <ripple/basics/base_uint.h>
|
#include <ripple/basics/base_uint.h>
|
||||||
@@ -27,105 +27,84 @@
|
|||||||
#include <ripple/protocol/PublicKey.h>
|
#include <ripple/protocol/PublicKey.h>
|
||||||
#include <ripple/protocol/SecretKey.h>
|
#include <ripple/protocol/SecretKey.h>
|
||||||
#include <ripple/beast/hash/hash_append.h>
|
#include <ripple/beast/hash/hash_append.h>
|
||||||
|
#include <ripple/consensus/ConsensusProposal.h>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
class LedgerProposal
|
/** A peer's signed, proposed position for use in RCLConsensus.
|
||||||
: public CountedObject <LedgerProposal>
|
|
||||||
|
Carries a ConsensusProposal signed by a peer.
|
||||||
|
*/
|
||||||
|
class RCLCxPeerPos
|
||||||
|
: public CountedObject <RCLCxPeerPos>
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
// A peer initial joins the consensus process
|
|
||||||
static std::uint32_t const seqJoin = 0;
|
|
||||||
|
|
||||||
// A peer wants to bow out and leave the consensus process
|
|
||||||
static std::uint32_t const seqLeave = 0xffffffff;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char const* getCountedObjectName () { return "LedgerProposal"; }
|
static char const* getCountedObjectName () { return "RCLCxPeerPos"; }
|
||||||
|
using pointer = std::shared_ptr<RCLCxPeerPos>;
|
||||||
using pointer = std::shared_ptr<LedgerProposal>;
|
|
||||||
using ref = const pointer&;
|
using ref = const pointer&;
|
||||||
|
|
||||||
// proposal from peer
|
//< The type of the proposed position
|
||||||
LedgerProposal (
|
using Proposal = ConsensusProposal<NodeID, uint256, uint256>;
|
||||||
uint256 const& prevLgr,
|
|
||||||
std::uint32_t proposeSeq,
|
|
||||||
uint256 const& propose,
|
/** Constructor
|
||||||
NetClock::time_point closeTime,
|
|
||||||
NetClock::time_point now,
|
Constructs a signed peer position.
|
||||||
|
|
||||||
|
@param publicKey Public key of the peer
|
||||||
|
@param signature Signature provided with the proposal
|
||||||
|
@param suppress ????
|
||||||
|
@param proposal The consensus proposal
|
||||||
|
*/
|
||||||
|
|
||||||
|
RCLCxPeerPos (
|
||||||
PublicKey const& publicKey,
|
PublicKey const& publicKey,
|
||||||
NodeID const& nodeID,
|
|
||||||
Slice const& signature,
|
Slice const& signature,
|
||||||
uint256 const& suppress);
|
uint256 const& suppress,
|
||||||
|
Proposal && proposal);
|
||||||
// Our own proposal:
|
|
||||||
LedgerProposal (
|
|
||||||
uint256 const& prevLedger,
|
|
||||||
uint256 const& position,
|
|
||||||
NetClock::time_point closeTime,
|
|
||||||
NetClock::time_point now);
|
|
||||||
|
|
||||||
|
//! Create the signing hash for the proposal
|
||||||
uint256 getSigningHash () const;
|
uint256 getSigningHash () const;
|
||||||
|
|
||||||
|
//! Verify the signing hash of the proposal
|
||||||
bool checkSign () const;
|
bool checkSign () const;
|
||||||
|
|
||||||
NodeID const& getPeerID () const
|
//! Signature of the proposal (not necessarily verified)
|
||||||
|
Slice getSignature () const
|
||||||
{
|
{
|
||||||
return mPeerID;
|
return signature_;
|
||||||
}
|
|
||||||
uint256 const& getCurrentHash () const
|
|
||||||
{
|
|
||||||
return mCurrentHash;
|
|
||||||
}
|
|
||||||
uint256 const& getPrevLedger () const
|
|
||||||
{
|
|
||||||
return mPreviousLedger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Public key of peer that sent the proposal
|
||||||
PublicKey const& getPublicKey () const
|
PublicKey const& getPublicKey () const
|
||||||
{
|
{
|
||||||
return publicKey_;
|
return publicKey_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! ?????
|
||||||
uint256 const& getSuppressionID () const
|
uint256 const& getSuppressionID () const
|
||||||
{
|
{
|
||||||
return mSuppression;
|
return mSuppression;
|
||||||
}
|
}
|
||||||
std::uint32_t getProposeSeq () const
|
|
||||||
|
//! The consensus proposal
|
||||||
|
Proposal const & proposal() const
|
||||||
{
|
{
|
||||||
return mProposeSeq;
|
return proposal_;
|
||||||
}
|
|
||||||
NetClock::time_point getCloseTime () const
|
|
||||||
{
|
|
||||||
return mCloseTime;
|
|
||||||
}
|
|
||||||
NetClock::time_point getSeenTime () const
|
|
||||||
{
|
|
||||||
return mTime;
|
|
||||||
}
|
|
||||||
Blob const& getSignature () const
|
|
||||||
{
|
|
||||||
return signature_;
|
|
||||||
}
|
|
||||||
bool isInitial () const
|
|
||||||
{
|
|
||||||
return mProposeSeq == seqJoin;
|
|
||||||
}
|
|
||||||
bool isBowOut () const
|
|
||||||
{
|
|
||||||
return mProposeSeq == seqLeave;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isStale (NetClock::time_point cutoff) const
|
/// @cond Ignore
|
||||||
|
//! Add a conversion operator to conform to the Consensus interface
|
||||||
|
operator Proposal const &() const
|
||||||
{
|
{
|
||||||
return mTime <= cutoff;
|
return proposal_;
|
||||||
}
|
}
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
bool changePosition (
|
//! JSON representation of proposal
|
||||||
uint256 const& newPosition,
|
|
||||||
NetClock::time_point newCloseTime,
|
|
||||||
NetClock::time_point now);
|
|
||||||
void bowOut (NetClock::time_point now);
|
|
||||||
Json::Value getJson () const;
|
Json::Value getJson () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -135,21 +114,16 @@ private:
|
|||||||
{
|
{
|
||||||
using beast::hash_append;
|
using beast::hash_append;
|
||||||
hash_append(h, HashPrefix::proposal);
|
hash_append(h, HashPrefix::proposal);
|
||||||
hash_append(h, std::uint32_t(mProposeSeq));
|
hash_append(h, std::uint32_t(proposal().proposeSeq()));
|
||||||
hash_append(h, mCloseTime);
|
hash_append(h, proposal().closeTime());
|
||||||
hash_append(h, mPreviousLedger);
|
hash_append(h, proposal().prevLedger());
|
||||||
hash_append(h, mCurrentHash);
|
hash_append(h, proposal().position());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 mPreviousLedger, mCurrentHash, mSuppression;
|
Proposal proposal_;
|
||||||
NetClock::time_point mCloseTime;
|
uint256 mSuppression;
|
||||||
std::uint32_t mProposeSeq;
|
|
||||||
|
|
||||||
PublicKey publicKey_;
|
PublicKey publicKey_;
|
||||||
NodeID mPeerID;
|
Buffer signature_;
|
||||||
Blob signature_;
|
|
||||||
|
|
||||||
NetClock::time_point mTime;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Calculate a unique identifier for a signed proposal.
|
/** Calculate a unique identifier for a signed proposal.
|
||||||
@@ -160,6 +134,13 @@ private:
|
|||||||
present. Recipients of the proposal will inject the last closed ledger in
|
present. Recipients of the proposal will inject the last closed ledger in
|
||||||
order to validate the signature. If the last closed ledger is left out, then
|
order to validate the signature. If the last closed ledger is left out, then
|
||||||
it is considered as all zeroes for the purposes of signing.
|
it is considered as all zeroes for the purposes of signing.
|
||||||
|
|
||||||
|
@param proposeHash The hash of the proposed position
|
||||||
|
@param previousLedger The hash of the ledger the proposal is based upon
|
||||||
|
@param proposeSeq Sequence number of the proposal
|
||||||
|
@param closeTime Close time of the proposal
|
||||||
|
@param publicKey Signer's public key
|
||||||
|
@param signature Proposal signature
|
||||||
*/
|
*/
|
||||||
uint256 proposalUniqueId (
|
uint256 proposalUniqueId (
|
||||||
uint256 const& proposeHash,
|
uint256 const& proposeHash,
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
Copyright (c) 2012-2016 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.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef RIPPLE_APP_CONSENSUS_RCLCXPOSITION_H_INCLUDED
|
|
||||||
#define RIPPLE_APP_CONSENSUS_RCLCXPOSITION_H_INCLUDED
|
|
||||||
|
|
||||||
#include <ripple/app/ledger/LedgerProposal.h>
|
|
||||||
#include <ripple/json/json_value.h>
|
|
||||||
#include <ripple/basics/chrono.h>
|
|
||||||
#include <ripple/protocol/UintTypes.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
// A position taken during a consensus round
|
|
||||||
// As seen by the RCL consensus process
|
|
||||||
class RCLCxPos
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
static std::uint32_t constexpr seqInitial = 0;
|
|
||||||
static std::uint32_t constexpr seqLeave = 0xffffffff;
|
|
||||||
|
|
||||||
RCLCxPos (LedgerProposal const& prop) :
|
|
||||||
proposal_ (prop)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
std::uint32_t getSequence() const
|
|
||||||
{
|
|
||||||
return proposal_.getProposeSeq();
|
|
||||||
}
|
|
||||||
|
|
||||||
NetClock::time_point getCloseTime () const
|
|
||||||
{
|
|
||||||
return proposal_.getCloseTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
NetClock::time_point getSeenTime() const
|
|
||||||
{
|
|
||||||
return proposal_.getSeenTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isStale (NetClock::time_point lastValid) const
|
|
||||||
{
|
|
||||||
return getSeenTime() < lastValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeID const& getNodeID() const
|
|
||||||
{
|
|
||||||
return proposal_.getPeerID();
|
|
||||||
}
|
|
||||||
|
|
||||||
LedgerHash const& getPosition() const
|
|
||||||
{
|
|
||||||
return proposal_.getCurrentHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
LedgerHash const& getPrevLedger() const
|
|
||||||
{
|
|
||||||
return proposal_.getPrevLedger();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool changePosition (
|
|
||||||
LedgerHash const& position,
|
|
||||||
NetClock::time_point closeTime,
|
|
||||||
NetClock::time_point now)
|
|
||||||
{
|
|
||||||
return proposal_.changePosition (position, closeTime, now);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bowOut (NetClock::time_point now)
|
|
||||||
{
|
|
||||||
if (isBowOut ())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
proposal_.bowOut (now);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Json::Value getJson() const
|
|
||||||
{
|
|
||||||
return proposal_.getJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isInitial () const
|
|
||||||
{
|
|
||||||
return getSequence() == seqInitial;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isBowOut() const
|
|
||||||
{
|
|
||||||
return getSequence() == seqLeave;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These three functions will be removed. New code
|
|
||||||
// should use getPosition, getSequence and getNodeID
|
|
||||||
LedgerHash const& getCurrentHash() const
|
|
||||||
{
|
|
||||||
return getPosition();
|
|
||||||
}
|
|
||||||
NodeID const& getPeerID() const
|
|
||||||
{
|
|
||||||
return getNodeID();
|
|
||||||
}
|
|
||||||
std::uint32_t getProposeSeq() const
|
|
||||||
{
|
|
||||||
return getSequence();
|
|
||||||
}
|
|
||||||
|
|
||||||
LedgerProposal const& peek() const
|
|
||||||
{
|
|
||||||
return proposal_;
|
|
||||||
}
|
|
||||||
|
|
||||||
LedgerProposal& peek()
|
|
||||||
{
|
|
||||||
return proposal_;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
LedgerProposal proposal_;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -23,108 +23,160 @@
|
|||||||
#include <ripple/basics/chrono.h>
|
#include <ripple/basics/chrono.h>
|
||||||
#include <ripple/protocol/UintTypes.h>
|
#include <ripple/protocol/UintTypes.h>
|
||||||
#include <ripple/shamap/SHAMap.h>
|
#include <ripple/shamap/SHAMap.h>
|
||||||
|
#include <ripple/app/misc/CanonicalTXSet.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
// Transactions, as seen by the consensus code in the rippled app
|
/** Represents a transaction in RCLConsensus.
|
||||||
|
|
||||||
|
RCLCxTx is a thin wrapper over the SHAMapItem that corresponds to the
|
||||||
|
transaction.
|
||||||
|
*/
|
||||||
class RCLCxTx
|
class RCLCxTx
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
//! Unique identifier/hash of transaction
|
||||||
|
using ID = uint256;
|
||||||
|
|
||||||
RCLCxTx (SHAMapItem const& txn) : txn_ (txn)
|
/** Constructor
|
||||||
|
|
||||||
|
@param txn The transaction to wrap
|
||||||
|
*/
|
||||||
|
RCLCxTx(SHAMapItem const& txn) : tx_{ txn }
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
uint256 const& getID() const
|
//! The unique identifier/hash of the transaction
|
||||||
|
ID const&
|
||||||
|
id() const
|
||||||
{
|
{
|
||||||
return txn_.key ();
|
return tx_.key ();
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapItem const& txn() const
|
//! The SHAMapItem that represents the transaction.
|
||||||
{
|
SHAMapItem const tx_;
|
||||||
return txn_;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
SHAMapItem const txn_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RCLTxSet;
|
/** Represents a set of transactions in RCLConsensus.
|
||||||
|
|
||||||
class MutableRCLTxSet
|
RCLTxSet is a thin wrapper over a SHAMap that stores the set of
|
||||||
{
|
transactions.
|
||||||
public:
|
*/
|
||||||
|
|
||||||
MutableRCLTxSet (RCLTxSet const&);
|
|
||||||
|
|
||||||
bool
|
|
||||||
addEntry (RCLCxTx const& p)
|
|
||||||
{
|
|
||||||
return map_->addItem (
|
|
||||||
SHAMapItem {p.getID(), p.txn().peekData()},
|
|
||||||
true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
removeEntry (uint256 const& entry)
|
|
||||||
{
|
|
||||||
return map_->delItem (entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr <SHAMap> const& map() const
|
|
||||||
{
|
|
||||||
return map_;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
std::shared_ptr <SHAMap> map_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Sets of transactions
|
|
||||||
// as seen by the consensus code in the rippled app
|
|
||||||
class RCLTxSet
|
class RCLTxSet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
//! Unique identifier/hash of the set of transactions
|
||||||
|
using ID = uint256;
|
||||||
|
//! The type that corresponds to a single transaction
|
||||||
|
using Tx = RCLCxTx;
|
||||||
|
|
||||||
using mutable_t = MutableRCLTxSet;
|
//< Provide a mutable view of a TxSet
|
||||||
|
class MutableTxSet
|
||||||
RCLTxSet (std::shared_ptr<SHAMap> map) :
|
|
||||||
map_ (std::move(map))
|
|
||||||
{
|
{
|
||||||
assert (map_);
|
friend class RCLTxSet;
|
||||||
|
//! The SHAMap representing the transactions.
|
||||||
|
std::shared_ptr <SHAMap> map_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MutableTxSet(RCLTxSet const & src)
|
||||||
|
: map_{ src.map_->snapShot(true) }
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Insert a new transaction into the set.
|
||||||
|
|
||||||
|
@param t The transaction to insert.
|
||||||
|
@return Whether the transaction took place.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
insert(Tx const& t)
|
||||||
|
{
|
||||||
|
return map_->addItem(
|
||||||
|
SHAMapItem{ t.id(), t.tx_.peekData() },
|
||||||
|
true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove a transaction from the set.
|
||||||
|
|
||||||
|
@param entry The ID of the transaction to remove.
|
||||||
|
@return Whether the transaction was removed.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
erase(Tx::ID const& entry)
|
||||||
|
{
|
||||||
|
return map_->delItem(entry);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Constructor
|
||||||
|
|
||||||
|
@param m SHAMap to wrap
|
||||||
|
*/
|
||||||
|
RCLTxSet (std::shared_ptr<SHAMap> m)
|
||||||
|
: map_{ std::move(m) }
|
||||||
|
{
|
||||||
|
assert(map_);
|
||||||
}
|
}
|
||||||
|
|
||||||
RCLTxSet (MutableRCLTxSet const& set) :
|
/** Constructor from a previosly created MutableTxSet
|
||||||
map_ (set.map()->snapShot (false))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
bool hasEntry (uint256 const& entry) const
|
@param m MutableTxSet that will become fixed
|
||||||
|
*/
|
||||||
|
RCLTxSet(MutableTxSet const & m)
|
||||||
|
: map_{m.map_->snapShot(false)}
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test if a transaction is in the set.
|
||||||
|
|
||||||
|
@param entry The ID of transaction to test.
|
||||||
|
@return Whether the transaction is in the set.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
exists(Tx::ID const& entry) const
|
||||||
{
|
{
|
||||||
return map_->hasItem (entry);
|
return map_->hasItem (entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::optional <RCLCxTx const>
|
/** Lookup a transaction.
|
||||||
getEntry (uint256 const& entry) const
|
|
||||||
|
@param entry The ID of the transaction to find.
|
||||||
|
@return A shared pointer to the SHAMapItem.
|
||||||
|
|
||||||
|
@note Since find may not succeed, this returns a
|
||||||
|
`std::shared_ptr<const SHAMapItem>` rather than a Tx, which
|
||||||
|
cannot refer to a missing transaction. The generic consensus
|
||||||
|
code use the shared_ptr semantics to know whether the find
|
||||||
|
was succesfully and properly creates a Tx as needed.
|
||||||
|
*/
|
||||||
|
std::shared_ptr<const SHAMapItem> const &
|
||||||
|
find(Tx::ID const& entry) const
|
||||||
{
|
{
|
||||||
auto item = map_->peekItem (entry);
|
return map_->peekItem (entry);
|
||||||
if (item)
|
|
||||||
return RCLCxTx(*item);
|
|
||||||
return boost::none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 getID() const
|
//! The unique ID/hash of the transaction set
|
||||||
|
ID
|
||||||
|
id() const
|
||||||
{
|
{
|
||||||
return map_->getHash().as_uint256();
|
return map_->getHash().as_uint256();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map <uint256, bool>
|
/** Find transactions not in common between this and another transaction set.
|
||||||
getDifferences (RCLTxSet const& j) const
|
|
||||||
|
@param j The set to compare with
|
||||||
|
@return Map of transactions in this set and `j` but not both. The key
|
||||||
|
is the transaction ID and the value is a bool of the transaction
|
||||||
|
exists in this set.
|
||||||
|
*/
|
||||||
|
std::map<Tx::ID, bool>
|
||||||
|
compare (RCLTxSet const& j) const
|
||||||
{
|
{
|
||||||
SHAMap::Delta delta;
|
SHAMap::Delta delta;
|
||||||
|
|
||||||
// Bound the work we do in case of a malicious
|
// Bound the work we do in case of a malicious
|
||||||
// map from a trusted validator
|
// map_ from a trusted validator
|
||||||
map_->compare (*(j.map_), delta, 65536);
|
map_->compare (*(j.map_), delta, 65536);
|
||||||
|
|
||||||
std::map <uint256, bool> ret;
|
std::map <uint256, bool> ret;
|
||||||
@@ -138,19 +190,9 @@ public:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SHAMap> const& map() const
|
//! The SHAMap representing the transactions.
|
||||||
{
|
|
||||||
return map_;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
std::shared_ptr <SHAMap> map_;
|
std::shared_ptr <SHAMap> map_;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline MutableRCLTxSet::MutableRCLTxSet (RCLTxSet const& set)
|
|
||||||
: map_ (set.map()->snapShot (true))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,115 +1,13 @@
|
|||||||
# Consensus Algorithm
|
# RCL Consensus
|
||||||
|
|
||||||
This directory holds the types and classes needed
|
This directory holds the types and classes needed
|
||||||
to connect consensus to rippled.
|
to connect the generic consensus algorithm to the
|
||||||
|
rippled-specific instance of consensus.
|
||||||
|
|
||||||
## Types
|
* `RCLCxTx` adapts a `SHAMapItem` transaction.
|
||||||
|
* `RCLCxTxSet` adapts a `SHAMap` to represent a set of transactions.
|
||||||
|
* `RCLCxLedger` adapts a `Ledger`.
|
||||||
|
* `RCLConsensus` is implements the requirements of the generic
|
||||||
|
`Consensus` class by connecting to the rest of the `rippled`
|
||||||
|
application.
|
||||||
|
|
||||||
All types must be copy constructible and assignable.
|
|
||||||
|
|
||||||
* `LgrID_t`
|
|
||||||
Represents a ledger identifier.
|
|
||||||
Typically a 256-bit hash of the ledger header.
|
|
||||||
|
|
||||||
* `TxID_t`
|
|
||||||
Represents a transaction identifier.
|
|
||||||
Typically a 256-bit hash of the transaction data.
|
|
||||||
|
|
||||||
* `TxSetID_t`
|
|
||||||
Represents an identifier of a set of transactions.
|
|
||||||
Typically a 256-bit hash of the set's root tree node.
|
|
||||||
|
|
||||||
* `NodeID_t`
|
|
||||||
Represents an identifier for a node that can take positions during
|
|
||||||
the consenus process.
|
|
||||||
|
|
||||||
* `Time_t`
|
|
||||||
Encodes absolute times. Used for the close times of ledgers and the
|
|
||||||
expiration times of positions.
|
|
||||||
|
|
||||||
* `Pos_t`
|
|
||||||
Represents a position on a consensus taken by a participant.
|
|
||||||
Typically it encodes the previous ledger identifier, the transaction
|
|
||||||
set identifier, the participant, and a sequence number. It also includes
|
|
||||||
either the time it was signed or the time it was first seen. It may also
|
|
||||||
include additional information such as the participant's public key or
|
|
||||||
signature
|
|
||||||
|
|
||||||
* `Tx_t`
|
|
||||||
Represent a transaction. Has an identifier and also whatever information
|
|
||||||
is needed to add it to a set.
|
|
||||||
|
|
||||||
* `TxSet_t`
|
|
||||||
Represents a set of transactions. It has an identifier and can report
|
|
||||||
which transactions it has and provide the actual transaction data.
|
|
||||||
If non-const, it can be modified.
|
|
||||||
|
|
||||||
## `Pos_t`
|
|
||||||
|
|
||||||
Represents a position taken by a validator during a consensus round.
|
|
||||||
Must provide:
|
|
||||||
|
|
||||||
static std::uint32_t seqInitial;
|
|
||||||
|
|
||||||
static std::uint32_t seqLeave;
|
|
||||||
|
|
||||||
std::uint32_t getSequence() const;
|
|
||||||
|
|
||||||
Time_t getCloseTime() const;
|
|
||||||
|
|
||||||
Time_t getSeenTime() const;
|
|
||||||
|
|
||||||
bool isStale (Time_t) const;
|
|
||||||
|
|
||||||
NodeID_t getNodeID() const;
|
|
||||||
|
|
||||||
TxSetID_t getPosition() const;
|
|
||||||
|
|
||||||
LgrID_t getPrevLedger() const;
|
|
||||||
|
|
||||||
bool isInitial() const;
|
|
||||||
|
|
||||||
bool isBowOut() const;
|
|
||||||
|
|
||||||
Json::Value getJson() const;
|
|
||||||
|
|
||||||
bool changePosition (TxSetID_t const& position, Time_t closeTime, Time_t now);
|
|
||||||
|
|
||||||
bool bowOut (Time_t now);
|
|
||||||
|
|
||||||
|
|
||||||
### `Tx_t`
|
|
||||||
|
|
||||||
Represents a transaction.
|
|
||||||
Must provide:
|
|
||||||
|
|
||||||
TxID_t getID() const;
|
|
||||||
|
|
||||||
|
|
||||||
### TxSet_t
|
|
||||||
|
|
||||||
Represents a set of transactions.
|
|
||||||
Must provide:
|
|
||||||
|
|
||||||
TxSet_t (TxSet_t::mutable_t const&);
|
|
||||||
|
|
||||||
TxSetID_t getID() const;
|
|
||||||
|
|
||||||
bool hasEntry (TxID_t const&) const;
|
|
||||||
|
|
||||||
bool hasEntry (Tx_t const&) const;
|
|
||||||
|
|
||||||
boost::optional <Tx_t const> const getEntry (TxID_t const&) const;
|
|
||||||
|
|
||||||
std::map <TxID_t, bool> getDifferences(TxSet_t const&) const;
|
|
||||||
|
|
||||||
## TxSet_t::mutable_t
|
|
||||||
|
|
||||||
Represents a set of transactions that can be modified.
|
|
||||||
Must provide:
|
|
||||||
|
|
||||||
TxSet_t::mutable_t (TxSet_t const &);
|
|
||||||
|
|
||||||
bool addEntry (Tx_t const&);
|
|
||||||
|
|
||||||
bool removeEntry (TxID_t const&);
|
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef RIPPLE_APP_LEDGER_CONSENSUS_H_INCLUDED
|
|
||||||
#define RIPPLE_APP_LEDGER_CONSENSUS_H_INCLUDED
|
|
||||||
|
|
||||||
#include <ripple/app/ledger/LedgerConsensus.h>
|
|
||||||
#include <ripple/app/ledger/LedgerMaster.h>
|
|
||||||
#include <ripple/app/ledger/InboundTransactions.h>
|
|
||||||
#include <ripple/app/consensus/RCLCxTraits.h>
|
|
||||||
#include <ripple/app/main/Application.h>
|
|
||||||
#include <ripple/basics/Log.h>
|
|
||||||
#include <ripple/core/Config.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
class LocalTxs;
|
|
||||||
|
|
||||||
/** Implements the consensus process and provides inter-round state. */
|
|
||||||
class Consensus
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Proposals = hash_map <NodeID, std::deque<LedgerProposal::pointer>>;
|
|
||||||
|
|
||||||
virtual
|
|
||||||
~Consensus () = default;
|
|
||||||
|
|
||||||
/** Returns whether we are issuing proposals currently. */
|
|
||||||
virtual
|
|
||||||
bool
|
|
||||||
isProposing () const = 0;
|
|
||||||
|
|
||||||
/** Returns whether we are issuing validations currently. */
|
|
||||||
virtual
|
|
||||||
bool
|
|
||||||
isValidating () const = 0;
|
|
||||||
|
|
||||||
/** Returns the number of unique proposers we observed for the LCL. */
|
|
||||||
virtual
|
|
||||||
int
|
|
||||||
getLastCloseProposers () const = 0;
|
|
||||||
|
|
||||||
/** Returns the time (in milliseconds) that the last close took. */
|
|
||||||
virtual
|
|
||||||
std::chrono::milliseconds
|
|
||||||
getLastCloseDuration () const = 0;
|
|
||||||
|
|
||||||
/** Called to create a LedgerConsensus instance */
|
|
||||||
virtual
|
|
||||||
std::shared_ptr<LedgerConsensus<RCLCxTraits>>
|
|
||||||
makeLedgerConsensus (
|
|
||||||
Application& app,
|
|
||||||
InboundTransactions& inboundTransactions,
|
|
||||||
LedgerMaster& ledgerMaster,
|
|
||||||
LocalTxs& localTxs) = 0;
|
|
||||||
|
|
||||||
/** Called when a new round of consensus is about to begin */
|
|
||||||
virtual
|
|
||||||
void
|
|
||||||
startRound (
|
|
||||||
LedgerConsensus<RCLCxTraits>& consensus,
|
|
||||||
LedgerHash const &prevLCLHash,
|
|
||||||
std::shared_ptr<Ledger const> const& previousLedger,
|
|
||||||
NetClock::time_point closeTime) = 0;
|
|
||||||
|
|
||||||
/** Specified the network time when the last ledger closed */
|
|
||||||
virtual
|
|
||||||
void
|
|
||||||
setLastCloseTime (NetClock::time_point t) = 0;
|
|
||||||
|
|
||||||
virtual
|
|
||||||
void
|
|
||||||
storeProposal (
|
|
||||||
LedgerProposal::ref proposal,
|
|
||||||
NodeID const& nodeID) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<Consensus>
|
|
||||||
make_Consensus (Config const& config, Logs& logs);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
#include <ripple/app/ledger/AcceptedLedger.h>
|
#include <ripple/app/ledger/AcceptedLedger.h>
|
||||||
#include <ripple/app/ledger/InboundLedgers.h>
|
#include <ripple/app/ledger/InboundLedgers.h>
|
||||||
#include <ripple/app/ledger/LedgerMaster.h>
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
#include <ripple/app/ledger/LedgerTiming.h>
|
#include <ripple/consensus/LedgerTiming.h>
|
||||||
#include <ripple/app/ledger/LedgerToJson.h>
|
#include <ripple/app/ledger/LedgerToJson.h>
|
||||||
#include <ripple/app/ledger/OrderBookDB.h>
|
#include <ripple/app/ledger/OrderBookDB.h>
|
||||||
#include <ripple/app/ledger/PendingSaves.h>
|
#include <ripple/app/ledger/PendingSaves.h>
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef RIPPLE_APP_LEDGER_LEDGERCONSENSUS_H_INCLUDED
|
|
||||||
#define RIPPLE_APP_LEDGER_LEDGERCONSENSUS_H_INCLUDED
|
|
||||||
|
|
||||||
#include <ripple/app/ledger/Ledger.h>
|
|
||||||
#include <ripple/app/ledger/LedgerProposal.h>
|
|
||||||
#include <ripple/app/ledger/InboundTransactions.h>
|
|
||||||
#include <ripple/app/consensus/RCLCxTraits.h>
|
|
||||||
#include <ripple/app/main/Application.h>
|
|
||||||
#include <ripple/app/misc/CanonicalTXSet.h>
|
|
||||||
#include <ripple/app/misc/FeeVote.h>
|
|
||||||
#include <ripple/json/json_value.h>
|
|
||||||
#include <ripple/overlay/Peer.h>
|
|
||||||
#include <ripple/protocol/RippleLedgerHash.h>
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
/** Manager for achieving consensus on the next ledger.
|
|
||||||
*/
|
|
||||||
template <class Traits>
|
|
||||||
class LedgerConsensus : public Traits
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
using typename Traits::Time_t;
|
|
||||||
using typename Traits::Pos_t;
|
|
||||||
using typename Traits::TxSet_t;
|
|
||||||
using typename Traits::Tx_t;
|
|
||||||
using typename Traits::LgrID_t;
|
|
||||||
using typename Traits::TxID_t;
|
|
||||||
using typename Traits::TxSetID_t;
|
|
||||||
using typename Traits::NodeID_t;
|
|
||||||
|
|
||||||
virtual ~LedgerConsensus() = default;
|
|
||||||
|
|
||||||
virtual Json::Value getJson (bool full) = 0;
|
|
||||||
|
|
||||||
virtual LgrID_t getLCL () = 0;
|
|
||||||
|
|
||||||
virtual void gotMap (TxSet_t const& map) = 0;
|
|
||||||
|
|
||||||
virtual void timerEntry () = 0;
|
|
||||||
|
|
||||||
virtual bool peerPosition (Pos_t const& position) = 0;
|
|
||||||
|
|
||||||
virtual PublicKey const& getValidationPublicKey () const = 0;
|
|
||||||
|
|
||||||
virtual void setValidationKeys (
|
|
||||||
SecretKey const& valSecret, PublicKey const& valPublic) = 0;
|
|
||||||
|
|
||||||
virtual void startRound (
|
|
||||||
LgrID_t const& prevLCLHash,
|
|
||||||
std::shared_ptr<Ledger const> const& prevLedger,
|
|
||||||
Time_t closeTime,
|
|
||||||
int previousProposers,
|
|
||||||
std::chrono::milliseconds previousConvergeTime) = 0;
|
|
||||||
|
|
||||||
/** Simulate the consensus process without any network traffic.
|
|
||||||
|
|
||||||
The end result, is that consensus begins and completes as if everyone
|
|
||||||
had agreed with whatever we propose.
|
|
||||||
|
|
||||||
This function is only called from the rpc "ledger_accept" path with the
|
|
||||||
server in standalone mode and SHOULD NOT be used during the normal
|
|
||||||
consensus process.
|
|
||||||
*/
|
|
||||||
virtual void simulate (
|
|
||||||
boost::optional<std::chrono::milliseconds> consensusDelay) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // ripple
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
|
||||||
#include <ripple/app/ledger/LedgerTiming.h>
|
|
||||||
#include <ripple/app/ledger/impl/ConsensusImp.h>
|
|
||||||
#include <ripple/app/ledger/impl/LedgerConsensusImp.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
ConsensusImp::ConsensusImp (
|
|
||||||
FeeVote::Setup const& voteSetup,
|
|
||||||
Logs& logs)
|
|
||||||
: journal_ (logs.journal("Consensus"))
|
|
||||||
, feeVote_ (make_FeeVote (voteSetup,
|
|
||||||
logs.journal("FeeVote")))
|
|
||||||
, proposing_ (false)
|
|
||||||
, validating_ (false)
|
|
||||||
, lastCloseProposers_ (0)
|
|
||||||
, lastCloseConvergeTook_ (LEDGER_IDLE_INTERVAL)
|
|
||||||
, lastValidationTimestamp_ (0s)
|
|
||||||
, lastCloseTime_ (0s)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ConsensusImp::isProposing () const
|
|
||||||
{
|
|
||||||
return proposing_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ConsensusImp::isValidating () const
|
|
||||||
{
|
|
||||||
return validating_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ConsensusImp::getLastCloseProposers () const
|
|
||||||
{
|
|
||||||
return lastCloseProposers_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::chrono::milliseconds
|
|
||||||
ConsensusImp::getLastCloseDuration () const
|
|
||||||
{
|
|
||||||
return lastCloseConvergeTook_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<LedgerConsensus<RCLCxTraits>>
|
|
||||||
ConsensusImp::makeLedgerConsensus (
|
|
||||||
Application& app,
|
|
||||||
InboundTransactions& inboundTransactions,
|
|
||||||
LedgerMaster& ledgerMaster,
|
|
||||||
LocalTxs& localTxs)
|
|
||||||
{
|
|
||||||
return make_LedgerConsensus (app, *this,
|
|
||||||
inboundTransactions, localTxs, ledgerMaster, *feeVote_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ConsensusImp::startRound (
|
|
||||||
LedgerConsensus<RCLCxTraits>& consensus,
|
|
||||||
LedgerHash const &prevLCLHash,
|
|
||||||
std::shared_ptr<Ledger const> const& previousLedger,
|
|
||||||
NetClock::time_point closeTime)
|
|
||||||
{
|
|
||||||
consensus.startRound (
|
|
||||||
prevLCLHash,
|
|
||||||
previousLedger,
|
|
||||||
closeTime,
|
|
||||||
lastCloseProposers_,
|
|
||||||
lastCloseConvergeTook_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ConsensusImp::setProposing (bool p, bool v)
|
|
||||||
{
|
|
||||||
proposing_ = p;
|
|
||||||
validating_ = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
STValidation::ref
|
|
||||||
ConsensusImp::getLastValidation () const
|
|
||||||
{
|
|
||||||
return lastValidation_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ConsensusImp::setLastValidation (STValidation::ref v)
|
|
||||||
{
|
|
||||||
lastValidation_ = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ConsensusImp::newLCL (
|
|
||||||
int proposers,
|
|
||||||
std::chrono::milliseconds convergeTime)
|
|
||||||
{
|
|
||||||
lastCloseProposers_ = proposers;
|
|
||||||
lastCloseConvergeTook_ = convergeTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetClock::time_point
|
|
||||||
ConsensusImp::validationTimestamp (NetClock::time_point vt)
|
|
||||||
{
|
|
||||||
if (vt <= lastValidationTimestamp_)
|
|
||||||
vt = lastValidationTimestamp_ + 1s;
|
|
||||||
|
|
||||||
lastValidationTimestamp_ = vt;
|
|
||||||
return vt;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetClock::time_point
|
|
||||||
ConsensusImp::getLastCloseTime () const
|
|
||||||
{
|
|
||||||
return lastCloseTime_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ConsensusImp::setLastCloseTime (NetClock::time_point t)
|
|
||||||
{
|
|
||||||
lastCloseTime_ = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ConsensusImp::storeProposal (
|
|
||||||
LedgerProposal::ref proposal,
|
|
||||||
NodeID const& nodeID)
|
|
||||||
{
|
|
||||||
std::lock_guard <std::mutex> _(lock_);
|
|
||||||
|
|
||||||
auto& props = storedProposals_[nodeID];
|
|
||||||
|
|
||||||
if (props.size () >= 10)
|
|
||||||
props.pop_front ();
|
|
||||||
|
|
||||||
props.push_back (proposal);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector <RCLCxPos>
|
|
||||||
ConsensusImp::getStoredProposals (uint256 const& prevLedger)
|
|
||||||
{
|
|
||||||
|
|
||||||
std::vector <RCLCxPos> ret;
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard <std::mutex> _(lock_);
|
|
||||||
|
|
||||||
for (auto const& it : storedProposals_)
|
|
||||||
for (auto const& prop : it.second)
|
|
||||||
if (prop->getPrevLedger() == prevLedger)
|
|
||||||
ret.emplace_back (*prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr <Consensus>
|
|
||||||
make_Consensus (Config const& config, Logs& logs)
|
|
||||||
{
|
|
||||||
return std::make_unique<ConsensusImp> (
|
|
||||||
setup_FeeVote (config.section ("voting")),
|
|
||||||
logs);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef RIPPLE_APP_LEDGER_IMPL_CONSENSUSIMP_H_INCLUDED
|
|
||||||
#define RIPPLE_APP_LEDGER_IMPL_CONSENSUSIMP_H_INCLUDED
|
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
|
||||||
#include <ripple/app/ledger/Consensus.h>
|
|
||||||
#include <ripple/app/ledger/LedgerConsensus.h>
|
|
||||||
#include <ripple/app/misc/FeeVote.h>
|
|
||||||
#include <ripple/basics/Log.h>
|
|
||||||
#include <ripple/protocol/STValidation.h>
|
|
||||||
#include <ripple/shamap/SHAMap.h>
|
|
||||||
#include <ripple/beast/utility/Journal.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
/** Implements the consensus process and provides inter-round state. */
|
|
||||||
class ConsensusImp
|
|
||||||
: public Consensus
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ConsensusImp (FeeVote::Setup const& voteSetup, Logs& logs);
|
|
||||||
|
|
||||||
~ConsensusImp () = default;
|
|
||||||
|
|
||||||
bool
|
|
||||||
isProposing () const override;
|
|
||||||
|
|
||||||
bool
|
|
||||||
isValidating () const override;
|
|
||||||
|
|
||||||
int
|
|
||||||
getLastCloseProposers () const override;
|
|
||||||
|
|
||||||
std::chrono::milliseconds
|
|
||||||
getLastCloseDuration () const override;
|
|
||||||
|
|
||||||
std::shared_ptr<LedgerConsensus<RCLCxTraits>>
|
|
||||||
makeLedgerConsensus (
|
|
||||||
Application& app,
|
|
||||||
InboundTransactions& inboundTransactions,
|
|
||||||
LedgerMaster& ledgerMaster,
|
|
||||||
LocalTxs& localTxs) override;
|
|
||||||
|
|
||||||
void
|
|
||||||
startRound (
|
|
||||||
LedgerConsensus<RCLCxTraits>& ledgerConsensus,
|
|
||||||
LedgerHash const& prevLCLHash,
|
|
||||||
std::shared_ptr<Ledger const> const& previousLedger,
|
|
||||||
NetClock::time_point closeTime) override;
|
|
||||||
|
|
||||||
void
|
|
||||||
setLastCloseTime (NetClock::time_point t) override;
|
|
||||||
|
|
||||||
void
|
|
||||||
storeProposal (
|
|
||||||
LedgerProposal::ref proposal,
|
|
||||||
NodeID const& nodeID) override;
|
|
||||||
|
|
||||||
void
|
|
||||||
setProposing (bool p, bool v);
|
|
||||||
|
|
||||||
STValidation::ref
|
|
||||||
getLastValidation () const;
|
|
||||||
|
|
||||||
void
|
|
||||||
setLastValidation (STValidation::ref v);
|
|
||||||
|
|
||||||
void
|
|
||||||
newLCL (
|
|
||||||
int proposers,
|
|
||||||
std::chrono::milliseconds convergeTime);
|
|
||||||
|
|
||||||
NetClock::time_point
|
|
||||||
validationTimestamp (NetClock::time_point vt);
|
|
||||||
|
|
||||||
NetClock::time_point
|
|
||||||
getLastCloseTime () const;
|
|
||||||
|
|
||||||
std::vector <RCLCxPos>
|
|
||||||
getStoredProposals (uint256 const& previousLedger);
|
|
||||||
|
|
||||||
private:
|
|
||||||
beast::Journal journal_;
|
|
||||||
std::unique_ptr <FeeVote> feeVote_;
|
|
||||||
|
|
||||||
bool proposing_;
|
|
||||||
bool validating_;
|
|
||||||
|
|
||||||
// A pointer to the last validation that we issued
|
|
||||||
STValidation::pointer lastValidation_;
|
|
||||||
|
|
||||||
// The number of proposers who participated in the last ledger close
|
|
||||||
int lastCloseProposers_;
|
|
||||||
|
|
||||||
// How long the last ledger close took, in milliseconds
|
|
||||||
std::chrono::milliseconds lastCloseConvergeTook_;
|
|
||||||
|
|
||||||
// The timestamp of the last validation we used, in network time. This is
|
|
||||||
// only used for our own validations.
|
|
||||||
NetClock::time_point lastValidationTimestamp_;
|
|
||||||
|
|
||||||
// The last close time
|
|
||||||
NetClock::time_point lastCloseTime_;
|
|
||||||
|
|
||||||
Consensus::Proposals storedProposals_;
|
|
||||||
|
|
||||||
// lock to protect storedProposals_
|
|
||||||
std::mutex lock_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,402 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef RIPPLE_APP_LEDGER_IMPL_LEDGERCONSENSUSIMP_H_INCLUDED
|
|
||||||
#define RIPPLE_APP_LEDGER_IMPL_LEDGERCONSENSUSIMP_H_INCLUDED
|
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
|
||||||
#include <ripple/app/ledger/LedgerMaster.h>
|
|
||||||
#include <ripple/app/ledger/impl/ConsensusImp.h>
|
|
||||||
#include <ripple/app/ledger/impl/DisputedTx.h>
|
|
||||||
#include <ripple/app/main/Application.h>
|
|
||||||
#include <ripple/app/misc/CanonicalTXSet.h>
|
|
||||||
#include <ripple/app/misc/FeeVote.h>
|
|
||||||
#include <ripple/basics/CountedObject.h>
|
|
||||||
#include <ripple/protocol/STValidation.h>
|
|
||||||
#include <ripple/protocol/UintTypes.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Provides the implementation for LedgerConsensus.
|
|
||||||
|
|
||||||
Achieves consensus on the next ledger.
|
|
||||||
|
|
||||||
Two things need consensus:
|
|
||||||
1. The set of transactions.
|
|
||||||
2. The close time for the ledger.
|
|
||||||
*/
|
|
||||||
template <class Traits>
|
|
||||||
class LedgerConsensusImp
|
|
||||||
: public LedgerConsensus<Traits>
|
|
||||||
, public std::enable_shared_from_this <LedgerConsensusImp<Traits>>
|
|
||||||
, public CountedObject <LedgerConsensusImp<Traits>>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
enum class State
|
|
||||||
{
|
|
||||||
// We haven't closed our ledger yet, but others might have
|
|
||||||
open,
|
|
||||||
|
|
||||||
// Establishing consensus
|
|
||||||
establish,
|
|
||||||
|
|
||||||
// We have closed on a transaction set and are
|
|
||||||
// processing the new ledger
|
|
||||||
processing,
|
|
||||||
|
|
||||||
// We have accepted / validated a new last closed ledger
|
|
||||||
// and need to start a new round
|
|
||||||
accepted,
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
using typename Traits::Time_t;
|
|
||||||
using typename Traits::Pos_t;
|
|
||||||
using typename Traits::TxSet_t;
|
|
||||||
using typename Traits::Tx_t;
|
|
||||||
using typename Traits::LgrID_t;
|
|
||||||
using typename Traits::TxID_t;
|
|
||||||
using typename Traits::TxSetID_t;
|
|
||||||
using typename Traits::NodeID_t;
|
|
||||||
using Dispute_t = DisputedTx <Traits>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The result of applying a transaction to a ledger.
|
|
||||||
*/
|
|
||||||
enum {resultSuccess, resultFail, resultRetry};
|
|
||||||
|
|
||||||
static char const* getCountedObjectName () { return "LedgerConsensus"; }
|
|
||||||
|
|
||||||
LedgerConsensusImp(LedgerConsensusImp const&) = delete;
|
|
||||||
LedgerConsensusImp& operator=(LedgerConsensusImp const&) = delete;
|
|
||||||
|
|
||||||
~LedgerConsensusImp () = default;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
@param localtx transactions issued by local clients
|
|
||||||
@param inboundTransactions set of inbound transaction sets
|
|
||||||
@param localtx A set of local transactions to apply
|
|
||||||
@param feeVote Our desired fee levels and voting logic.
|
|
||||||
*/
|
|
||||||
LedgerConsensusImp (
|
|
||||||
Application& app,
|
|
||||||
ConsensusImp& consensus,
|
|
||||||
InboundTransactions& inboundTransactions,
|
|
||||||
LocalTxs& localtx,
|
|
||||||
LedgerMaster& ledgerMaster,
|
|
||||||
FeeVote& feeVote);
|
|
||||||
|
|
||||||
/**
|
|
||||||
@param prevLCLHash The hash of the Last Closed Ledger (LCL).
|
|
||||||
@param previousLedger Best guess of what the LCL was.
|
|
||||||
@param closeTime Closing time point of the LCL.
|
|
||||||
@param previousProposers the number of participants in the last round
|
|
||||||
@param previousConvergeTime how long the last round took (ms)
|
|
||||||
*/
|
|
||||||
void startRound (
|
|
||||||
LgrID_t const& prevLCLHash,
|
|
||||||
std::shared_ptr<Ledger const> const& prevLedger,
|
|
||||||
Time_t closeTime,
|
|
||||||
int previousProposers,
|
|
||||||
std::chrono::milliseconds previousConvergeTime) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the Json state of the consensus process.
|
|
||||||
Called by the consensus_info RPC.
|
|
||||||
|
|
||||||
@param full True if verbose response desired.
|
|
||||||
@return The Json state.
|
|
||||||
*/
|
|
||||||
Json::Value getJson (bool full) override;
|
|
||||||
|
|
||||||
/* The hash of the last closed ledger */
|
|
||||||
LgrID_t getLCL () override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
We have a complete transaction set, typically acquired from the network
|
|
||||||
|
|
||||||
@param map the transaction set.
|
|
||||||
*/
|
|
||||||
void gotMap (TxSet_t const& map) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
On timer call the correct handler for each state.
|
|
||||||
*/
|
|
||||||
void timerEntry () override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
A server has taken a new position, adjust our tracking
|
|
||||||
Called when a peer takes a new postion.
|
|
||||||
|
|
||||||
@param newPosition the new position
|
|
||||||
@return true if we should do delayed relay of this position.
|
|
||||||
*/
|
|
||||||
bool peerPosition (Pos_t const& newPosition) override;
|
|
||||||
|
|
||||||
void simulate(
|
|
||||||
boost::optional<std::chrono::milliseconds> consensusDelay) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Put a transaction set where peers can find it
|
|
||||||
*/
|
|
||||||
void shareSet (TxSet_t const&);
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
Handle pre-close state.
|
|
||||||
*/
|
|
||||||
void statePreClose ();
|
|
||||||
|
|
||||||
/** We are establishing a consensus
|
|
||||||
Update our position only on the timer, and in this state.
|
|
||||||
If we have consensus, move to the finish state
|
|
||||||
*/
|
|
||||||
void stateEstablish ();
|
|
||||||
|
|
||||||
/** Check if we've reached consensus */
|
|
||||||
bool haveConsensus ();
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check if our last closed ledger matches the network's.
|
|
||||||
This tells us if we are still in sync with the network.
|
|
||||||
This also helps us if we enter the consensus round with
|
|
||||||
the wrong ledger, to leave it with the correct ledger so
|
|
||||||
that we can participate in the next round.
|
|
||||||
*/
|
|
||||||
void checkLCL ();
|
|
||||||
|
|
||||||
/**
|
|
||||||
Change our view of the last closed ledger
|
|
||||||
|
|
||||||
@param lclHash Hash of the last closed ledger.
|
|
||||||
*/
|
|
||||||
void handleLCL (LgrID_t const& lclHash);
|
|
||||||
|
|
||||||
/**
|
|
||||||
We have a complete transaction set, typically acquired from the network
|
|
||||||
|
|
||||||
@param map the transaction set.
|
|
||||||
@param acquired true if we have acquired the transaction set.
|
|
||||||
*/
|
|
||||||
void mapCompleteInternal (
|
|
||||||
TxSet_t const& map,
|
|
||||||
bool acquired);
|
|
||||||
|
|
||||||
/** We have a new last closed ledger, process it. Final accept logic
|
|
||||||
|
|
||||||
@param set Our consensus set
|
|
||||||
*/
|
|
||||||
void accept (TxSet_t const& set);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Compare two proposed transaction sets and create disputed
|
|
||||||
transctions structures for any mismatches
|
|
||||||
|
|
||||||
@param m1 One transaction set
|
|
||||||
@param m2 The other transaction set
|
|
||||||
*/
|
|
||||||
void createDisputes (TxSet_t const& m1,
|
|
||||||
TxSet_t const& m2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Add a disputed transaction (one that at least one node wants
|
|
||||||
in the consensus set and at least one node does not) to our tracking
|
|
||||||
|
|
||||||
@param tx The disputed transaction
|
|
||||||
*/
|
|
||||||
void addDisputedTransaction (Tx_t const& tx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Adjust the votes on all disputed transactions based
|
|
||||||
on the set of peers taking this position
|
|
||||||
|
|
||||||
@param map A disputed position
|
|
||||||
@param peers peers which are taking the position map
|
|
||||||
*/
|
|
||||||
void adjustCount (TxSet_t const& map,
|
|
||||||
std::vector<NodeID_t> const& peers);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Revoke our outstanding proposal, if any, and
|
|
||||||
cease proposing at least until this round ends
|
|
||||||
*/
|
|
||||||
void leaveConsensus ();
|
|
||||||
|
|
||||||
/** Make and send a proposal
|
|
||||||
*/
|
|
||||||
void propose ();
|
|
||||||
|
|
||||||
/** Send a node status change message to our directly connected peers
|
|
||||||
|
|
||||||
@param event The event which caused the status change. This is
|
|
||||||
typically neACCEPTED_LEDGER or neCLOSING_LEDGER.
|
|
||||||
@param ledger The ledger associated with the event.
|
|
||||||
*/
|
|
||||||
void statusChange (protocol::NodeEvent event, ReadView const& ledger);
|
|
||||||
|
|
||||||
/** Determine our initial proposed transaction set based on
|
|
||||||
our open ledger
|
|
||||||
*/
|
|
||||||
std::pair <TxSet_t, Pos_t> makeInitialPosition();
|
|
||||||
|
|
||||||
/** Take an initial position on what we think the consensus set should be
|
|
||||||
*/
|
|
||||||
void takeInitialPosition ();
|
|
||||||
|
|
||||||
/**
|
|
||||||
Called while trying to avalanche towards consensus.
|
|
||||||
Adjusts our positions to try to agree with other validators.
|
|
||||||
*/
|
|
||||||
void updateOurPositions ();
|
|
||||||
|
|
||||||
/** If we radically changed our consensus context for some reason,
|
|
||||||
we need to replay recent proposals so that they're not lost.
|
|
||||||
*/
|
|
||||||
void playbackProposals ();
|
|
||||||
|
|
||||||
/** We have just decided to close the ledger. Start the consensus timer,
|
|
||||||
stash the close time, inform peers, and take a position
|
|
||||||
*/
|
|
||||||
void closeLedger ();
|
|
||||||
|
|
||||||
/**
|
|
||||||
If we missed a consensus round, we may be missing a validation.
|
|
||||||
This will send an older owed validation if we previously missed it.
|
|
||||||
*/
|
|
||||||
void checkOurValidation ();
|
|
||||||
|
|
||||||
/** We have a new LCL and must accept it */
|
|
||||||
void beginAccept (bool synchronous);
|
|
||||||
|
|
||||||
void endConsensus (bool correctLCL);
|
|
||||||
|
|
||||||
|
|
||||||
/** Add our load fee to our validation */
|
|
||||||
void addLoad(STValidation::ref val);
|
|
||||||
|
|
||||||
/** Convert an advertised close time to an effective close time */
|
|
||||||
NetClock::time_point effectiveCloseTime(NetClock::time_point closeTime);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Application& app_;
|
|
||||||
ConsensusImp& consensus_;
|
|
||||||
InboundTransactions& inboundTransactions_;
|
|
||||||
LocalTxs& localTX_;
|
|
||||||
LedgerMaster& ledgerMaster_;
|
|
||||||
FeeVote& feeVote_;
|
|
||||||
std::recursive_mutex lock_;
|
|
||||||
|
|
||||||
NodeID_t ourID_;
|
|
||||||
State state_;
|
|
||||||
|
|
||||||
// The wall time this ledger closed
|
|
||||||
Time_t closeTime_;
|
|
||||||
|
|
||||||
LgrID_t prevLedgerHash_;
|
|
||||||
LgrID_t acquiringLedger_;
|
|
||||||
|
|
||||||
std::shared_ptr<Ledger const> previousLedger_;
|
|
||||||
boost::optional<Pos_t> ourPosition_;
|
|
||||||
boost::optional<TxSet_t> ourSet_;
|
|
||||||
PublicKey valPublic_;
|
|
||||||
SecretKey valSecret_;
|
|
||||||
bool proposing_, validating_, haveCorrectLCL_, consensusFail_;
|
|
||||||
|
|
||||||
// How much time has elapsed since the round started
|
|
||||||
std::chrono::milliseconds roundTime_;
|
|
||||||
|
|
||||||
// How long the close has taken, expressed as a percentage of the time that
|
|
||||||
// we expected it to take.
|
|
||||||
int closePercent_;
|
|
||||||
|
|
||||||
NetClock::duration closeResolution_;
|
|
||||||
|
|
||||||
bool haveCloseTimeConsensus_;
|
|
||||||
|
|
||||||
std::chrono::steady_clock::time_point consensusStartTime_;
|
|
||||||
int previousProposers_;
|
|
||||||
|
|
||||||
// Time it took for the last consensus round to converge
|
|
||||||
std::chrono::milliseconds previousRoundTime_;
|
|
||||||
|
|
||||||
// Convergence tracking, trusted peers indexed by hash of public key
|
|
||||||
hash_map<NodeID_t, Pos_t> peerPositions_;
|
|
||||||
|
|
||||||
// Transaction Sets, indexed by hash of transaction tree
|
|
||||||
hash_map<TxSetID_t, const TxSet_t> acquired_;
|
|
||||||
|
|
||||||
// Disputed transactions
|
|
||||||
hash_map<TxID_t, Dispute_t> disputes_;
|
|
||||||
hash_set<TxSetID_t> compares_;
|
|
||||||
|
|
||||||
// Close time estimates, keep ordered for predictable traverse
|
|
||||||
std::map <Time_t, int> closeTimes_;
|
|
||||||
|
|
||||||
// nodes that have bowed out of this consensus process
|
|
||||||
hash_set<NodeID_t> deadNodes_;
|
|
||||||
beast::Journal j_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/** Returns validation public key */
|
|
||||||
PublicKey const&
|
|
||||||
getValidationPublicKey () const override;
|
|
||||||
|
|
||||||
/** Set validation private and public key pair. */
|
|
||||||
void
|
|
||||||
setValidationKeys (
|
|
||||||
SecretKey const& valSecret, PublicKey const& valPublic) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
std::shared_ptr <LedgerConsensus <RCLCxTraits>>
|
|
||||||
make_LedgerConsensus (
|
|
||||||
Application& app,
|
|
||||||
ConsensusImp& consensus,
|
|
||||||
InboundTransactions& inboundTransactions,
|
|
||||||
LocalTxs& localtx,
|
|
||||||
LedgerMaster& ledgerMaster,
|
|
||||||
FeeVote& feeVote);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
/** Apply a set of transactions to a ledger
|
|
||||||
|
|
||||||
Typically the txFilter is used to reject transactions
|
|
||||||
that already got in the prior ledger
|
|
||||||
|
|
||||||
@param set set of transactions to apply
|
|
||||||
@param view ledger to apply to
|
|
||||||
@param txFilter callback, return false to reject txn
|
|
||||||
@return retriable transactions
|
|
||||||
*/
|
|
||||||
CanonicalTXSet
|
|
||||||
applyTransactions (
|
|
||||||
Application& app,
|
|
||||||
RCLTxSet const& set,
|
|
||||||
OpenView& view,
|
|
||||||
std::function<bool(uint256 const&)> txFilter);
|
|
||||||
|
|
||||||
extern template class LedgerConsensusImp <RCLCxTraits>;
|
|
||||||
|
|
||||||
} // ripple
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -828,6 +828,8 @@ LedgerMaster::consensusBuilt(
|
|||||||
if (standalone_)
|
if (standalone_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
mLedgerHistory.builtLedger (ledger, std::move (consensus));
|
||||||
|
|
||||||
if (ledger->info().seq <= mValidLedgerSeq)
|
if (ledger->info().seq <= mValidLedgerSeq)
|
||||||
{
|
{
|
||||||
auto stream = app_.journal ("LedgerConsensus").info();
|
auto stream = app_.journal ("LedgerConsensus").info();
|
||||||
@@ -912,8 +914,6 @@ LedgerMaster::consensusBuilt(
|
|||||||
<< "Consensus triggered check of ledger";
|
<< "Consensus triggered check of ledger";
|
||||||
checkAccept (maxLedger, maxSeq);
|
checkAccept (maxLedger, maxSeq);
|
||||||
}
|
}
|
||||||
|
|
||||||
mLedgerHistory.builtLedger (ledger, std::move (consensus));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
#include <ripple/resource/Fees.h>
|
#include <ripple/resource/Fees.h>
|
||||||
#include <ripple/beast/asio/io_latency_probe.h>
|
#include <ripple/beast/asio/io_latency_probe.h>
|
||||||
#include <ripple/beast/core/LexicalCast.h>
|
#include <ripple/beast/core/LexicalCast.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
@@ -1338,7 +1339,6 @@ ApplicationImp::startGenesisLedger()
|
|||||||
*genesis, timeKeeper().closeTime());
|
*genesis, timeKeeper().closeTime());
|
||||||
next->updateSkipList ();
|
next->updateSkipList ();
|
||||||
next->setImmutable (*config_);
|
next->setImmutable (*config_);
|
||||||
m_networkOPs->setLastCloseTime (next->info().closeTime);
|
|
||||||
openLedger_.emplace(next, cachedSLEs_,
|
openLedger_.emplace(next, cachedSLEs_,
|
||||||
logs_->journal("OpenLedger"));
|
logs_->journal("OpenLedger"));
|
||||||
m_ledgerMaster->storeLedger(next);
|
m_ledgerMaster->storeLedger(next);
|
||||||
@@ -1648,7 +1648,6 @@ bool ApplicationImp::loadOldLedger (
|
|||||||
m_ledgerMaster->switchLCL (loadLedger);
|
m_ledgerMaster->switchLCL (loadLedger);
|
||||||
loadLedger->setValidated();
|
loadLedger->setValidated();
|
||||||
m_ledgerMaster->setFullLedger(loadLedger, true, false);
|
m_ledgerMaster->setFullLedger(loadLedger, true, false);
|
||||||
m_networkOPs->setLastCloseTime (loadLedger->info().closeTime);
|
|
||||||
openLedger_.emplace(loadLedger, cachedSLEs_,
|
openLedger_.emplace(loadLedger, cachedSLEs_,
|
||||||
logs_->journal("OpenLedger"));
|
logs_->journal("OpenLedger"));
|
||||||
|
|
||||||
|
|||||||
@@ -21,15 +21,14 @@
|
|||||||
#include <ripple/app/misc/NetworkOPs.h>
|
#include <ripple/app/misc/NetworkOPs.h>
|
||||||
#include <ripple/protocol/Quality.h>
|
#include <ripple/protocol/Quality.h>
|
||||||
#include <ripple/core/DatabaseCon.h>
|
#include <ripple/core/DatabaseCon.h>
|
||||||
|
#include <ripple/consensus/Consensus.h>
|
||||||
#include <ripple/app/main/Application.h>
|
#include <ripple/app/main/Application.h>
|
||||||
#include <ripple/app/consensus/RCLCxTraits.h>
|
#include <ripple/app/consensus/RCLConsensus.h>
|
||||||
#include <ripple/app/ledger/Consensus.h>
|
|
||||||
#include <ripple/app/ledger/LedgerConsensus.h>
|
|
||||||
#include <ripple/app/ledger/AcceptedLedger.h>
|
#include <ripple/app/ledger/AcceptedLedger.h>
|
||||||
#include <ripple/app/ledger/InboundLedger.h>
|
#include <ripple/app/ledger/InboundLedger.h>
|
||||||
#include <ripple/app/ledger/InboundLedgers.h>
|
#include <ripple/app/ledger/InboundLedgers.h>
|
||||||
#include <ripple/app/ledger/LedgerMaster.h>
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
#include <ripple/app/ledger/LedgerTiming.h>
|
#include <ripple/consensus/LedgerTiming.h>
|
||||||
#include <ripple/app/ledger/LedgerToJson.h>
|
#include <ripple/app/ledger/LedgerToJson.h>
|
||||||
#include <ripple/app/ledger/LocalTxs.h>
|
#include <ripple/app/ledger/LocalTxs.h>
|
||||||
#include <ripple/app/ledger/OpenLedger.h>
|
#include <ripple/app/ledger/OpenLedger.h>
|
||||||
@@ -222,9 +221,14 @@ public:
|
|||||||
, m_amendmentBlocked (false)
|
, m_amendmentBlocked (false)
|
||||||
, m_heartbeatTimer (this)
|
, m_heartbeatTimer (this)
|
||||||
, m_clusterTimer (this)
|
, m_clusterTimer (this)
|
||||||
, mConsensus (make_Consensus (app_.config(), app_.logs()))
|
, mConsensus (std::make_shared<RCLConsensus>(app,
|
||||||
, mLedgerConsensus (mConsensus->makeLedgerConsensus (
|
make_FeeVote(setup_FeeVote (app_.config().section ("voting")),
|
||||||
app, app.getInboundTransactions(), ledgerMaster, *m_localTX))
|
app_.logs().journal("FeeVote")),
|
||||||
|
ledgerMaster,
|
||||||
|
*m_localTX,
|
||||||
|
app.getInboundTransactions(),
|
||||||
|
stopwatch(),
|
||||||
|
app_.logs().journal("LedgerConsensus")))
|
||||||
, m_ledgerMaster (ledgerMaster)
|
, m_ledgerMaster (ledgerMaster)
|
||||||
, m_job_queue (job_queue)
|
, m_job_queue (job_queue)
|
||||||
, m_standalone (standalone)
|
, m_standalone (standalone)
|
||||||
@@ -308,7 +312,7 @@ public:
|
|||||||
|
|
||||||
// Ledger proposal/close functions.
|
// Ledger proposal/close functions.
|
||||||
void processTrustedProposal (
|
void processTrustedProposal (
|
||||||
LedgerProposal::pointer proposal,
|
RCLCxPeerPos::pointer proposal,
|
||||||
std::shared_ptr<protocol::TMProposeSet> set,
|
std::shared_ptr<protocol::TMProposeSet> set,
|
||||||
NodeID const &node) override;
|
NodeID const &node) override;
|
||||||
|
|
||||||
@@ -372,18 +376,14 @@ public:
|
|||||||
}
|
}
|
||||||
void setAmendmentBlocked () override;
|
void setAmendmentBlocked () override;
|
||||||
void consensusViewChange () override;
|
void consensusViewChange () override;
|
||||||
void setLastCloseTime (NetClock::time_point t) override
|
|
||||||
{
|
|
||||||
mConsensus->setLastCloseTime(t);
|
|
||||||
}
|
|
||||||
PublicKey const& getValidationPublicKey () const override
|
PublicKey const& getValidationPublicKey () const override
|
||||||
{
|
{
|
||||||
return mLedgerConsensus->getValidationPublicKey ();
|
return mConsensus->getValidationPublicKey ();
|
||||||
}
|
}
|
||||||
void setValidationKeys (
|
void setValidationKeys (
|
||||||
SecretKey const& valSecret, PublicKey const& valPublic) override
|
SecretKey const& valSecret, PublicKey const& valPublic) override
|
||||||
{
|
{
|
||||||
mLedgerConsensus->setValidationKeys (valSecret, valPublic);
|
mConsensus->setValidationKeys (valSecret, valPublic);
|
||||||
}
|
}
|
||||||
Json::Value getConsensusInfo () override;
|
Json::Value getConsensusInfo () override;
|
||||||
Json::Value getServerInfo (bool human, bool admin) override;
|
Json::Value getServerInfo (bool human, bool admin) override;
|
||||||
@@ -560,8 +560,7 @@ private:
|
|||||||
DeadlineTimer m_heartbeatTimer;
|
DeadlineTimer m_heartbeatTimer;
|
||||||
DeadlineTimer m_clusterTimer;
|
DeadlineTimer m_clusterTimer;
|
||||||
|
|
||||||
std::unique_ptr<Consensus> mConsensus;
|
std::shared_ptr<RCLConsensus> mConsensus;
|
||||||
std::shared_ptr<LedgerConsensus<RCLCxTraits>> mLedgerConsensus;
|
|
||||||
|
|
||||||
LedgerMaster& m_ledgerMaster;
|
LedgerMaster& m_ledgerMaster;
|
||||||
std::shared_ptr<InboundLedger> mAcquiringLedger;
|
std::shared_ptr<InboundLedger> mAcquiringLedger;
|
||||||
@@ -700,7 +699,8 @@ void NetworkOPsImp::processHeartbeatTimer ()
|
|||||||
<< "Node count (" << numPeers << ") "
|
<< "Node count (" << numPeers << ") "
|
||||||
<< "has fallen below quorum (" << m_network_quorum << ").";
|
<< "has fallen below quorum (" << m_network_quorum << ").";
|
||||||
}
|
}
|
||||||
|
// We do not call mConsensus->timerEntry until there
|
||||||
|
// are enough peers providing meaningful inputs to consensus
|
||||||
setHeartbeatTimer ();
|
setHeartbeatTimer ();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -722,7 +722,7 @@ void NetworkOPsImp::processHeartbeatTimer ()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mLedgerConsensus->timerEntry ();
|
mConsensus->timerEntry (app_.timeKeeper().closeTime());
|
||||||
|
|
||||||
setHeartbeatTimer ();
|
setHeartbeatTimer ();
|
||||||
}
|
}
|
||||||
@@ -776,12 +776,12 @@ void NetworkOPsImp::processClusterTimer ()
|
|||||||
|
|
||||||
std::string NetworkOPsImp::strOperatingMode () const
|
std::string NetworkOPsImp::strOperatingMode () const
|
||||||
{
|
{
|
||||||
if (mMode == omFULL)
|
if (mMode == omFULL && mConsensus->haveCorrectLCL())
|
||||||
{
|
{
|
||||||
if (mConsensus->isProposing ())
|
if (mConsensus->proposing ())
|
||||||
return "proposing";
|
return "proposing";
|
||||||
|
|
||||||
if (mConsensus->isValidating ())
|
if (mConsensus->validating ())
|
||||||
return "validating";
|
return "validating";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1282,8 +1282,7 @@ void NetworkOPsImp::tryStartConsensus ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mMode != omDISCONNECTED)
|
beginConsensus (networkClosed);
|
||||||
beginConsensus (networkClosed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NetworkOPsImp::checkLastClosedLedger (
|
bool NetworkOPsImp::checkLastClosedLedger (
|
||||||
@@ -1522,10 +1521,9 @@ bool NetworkOPsImp::beginConsensus (uint256 const& networkClosed)
|
|||||||
app_.getValidations().getCurrentPublicKeys ());
|
app_.getValidations().getCurrentPublicKeys ());
|
||||||
|
|
||||||
mConsensus->startRound (
|
mConsensus->startRound (
|
||||||
*mLedgerConsensus,
|
app_.timeKeeper().closeTime(),
|
||||||
networkClosed,
|
networkClosed,
|
||||||
prevLedger,
|
prevLedger);
|
||||||
closingInfo.closeTime);
|
|
||||||
|
|
||||||
JLOG(m_journal.debug()) << "Initiating consensus engine";
|
JLOG(m_journal.debug()) << "Initiating consensus engine";
|
||||||
return true;
|
return true;
|
||||||
@@ -1533,18 +1531,19 @@ bool NetworkOPsImp::beginConsensus (uint256 const& networkClosed)
|
|||||||
|
|
||||||
uint256 NetworkOPsImp::getConsensusLCL ()
|
uint256 NetworkOPsImp::getConsensusLCL ()
|
||||||
{
|
{
|
||||||
return mLedgerConsensus->getLCL ();
|
return mConsensus->LCL ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkOPsImp::processTrustedProposal (
|
void NetworkOPsImp::processTrustedProposal (
|
||||||
LedgerProposal::pointer proposal,
|
RCLCxPeerPos::pointer peerPos,
|
||||||
std::shared_ptr<protocol::TMProposeSet> set,
|
std::shared_ptr<protocol::TMProposeSet> set,
|
||||||
NodeID const& node)
|
NodeID const& node)
|
||||||
{
|
{
|
||||||
mConsensus->storeProposal (proposal, node);
|
mConsensus->storeProposal (peerPos, node);
|
||||||
|
|
||||||
if (mLedgerConsensus->peerPosition (*proposal))
|
if (mConsensus->peerProposal (
|
||||||
app_.overlay().relay(*set, proposal->getSuppressionID());
|
app_.timeKeeper().closeTime(), peerPos->proposal()))
|
||||||
|
app_.overlay().relay(*set, peerPos->getSuppressionID());
|
||||||
else
|
else
|
||||||
JLOG(m_journal.info()) << "Not relaying trusted proposal";
|
JLOG(m_journal.info()) << "Not relaying trusted proposal";
|
||||||
}
|
}
|
||||||
@@ -1567,7 +1566,9 @@ NetworkOPsImp::mapComplete (
|
|||||||
|
|
||||||
// We acquired it because consensus asked us to
|
// We acquired it because consensus asked us to
|
||||||
if (fromAcquire)
|
if (fromAcquire)
|
||||||
mLedgerConsensus->gotMap (RCLTxSet{map});
|
mConsensus->gotTxSet (
|
||||||
|
app_.timeKeeper().closeTime(),
|
||||||
|
RCLTxSet{map});
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkOPsImp::endConsensus (bool correctLCL)
|
void NetworkOPsImp::endConsensus (bool correctLCL)
|
||||||
@@ -1647,7 +1648,7 @@ NetworkOPsImp::ServerFeeSummary::operator !=(NetworkOPsImp::ServerFeeSummary con
|
|||||||
em.is_initialized() != b.em.is_initialized())
|
em.is_initialized() != b.em.is_initialized())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if(em)
|
if(em && b.em)
|
||||||
{
|
{
|
||||||
return (em->minFeeLevel != b.em->minFeeLevel ||
|
return (em->minFeeLevel != b.em->minFeeLevel ||
|
||||||
em->expFeeLevel != b.em->expFeeLevel ||
|
em->expFeeLevel != b.em->expFeeLevel ||
|
||||||
@@ -2113,7 +2114,7 @@ bool NetworkOPsImp::recvValidation (
|
|||||||
|
|
||||||
Json::Value NetworkOPsImp::getConsensusInfo ()
|
Json::Value NetworkOPsImp::getConsensusInfo ()
|
||||||
{
|
{
|
||||||
return mLedgerConsensus->getJson (true);
|
return mConsensus->getJson (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin)
|
Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin)
|
||||||
@@ -2175,17 +2176,17 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin)
|
|||||||
{
|
{
|
||||||
lastClose[jss::converge_time_s] =
|
lastClose[jss::converge_time_s] =
|
||||||
std::chrono::duration<double>{
|
std::chrono::duration<double>{
|
||||||
mConsensus->getLastCloseDuration()}.count();
|
mConsensus->getLastConvergeDuration()}.count();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lastClose[jss::converge_time] =
|
lastClose[jss::converge_time] =
|
||||||
Json::Int (mConsensus->getLastCloseDuration().count());
|
Json::Int (mConsensus->getLastConvergeDuration().count());
|
||||||
}
|
}
|
||||||
|
|
||||||
info[jss::last_close] = lastClose;
|
info[jss::last_close] = lastClose;
|
||||||
|
|
||||||
// info[jss::consensus] = mLedgerConsensus->getJson();
|
// info[jss::consensus] = mConsensus->getJson();
|
||||||
|
|
||||||
if (admin)
|
if (admin)
|
||||||
info[jss::load] = m_job_queue.getJson ();
|
info[jss::load] = m_job_queue.getJson ();
|
||||||
@@ -2757,9 +2758,11 @@ std::uint32_t NetworkOPsImp::acceptLedger (
|
|||||||
Throw<std::runtime_error> ("Operation only possible in STANDALONE mode.");
|
Throw<std::runtime_error> ("Operation only possible in STANDALONE mode.");
|
||||||
|
|
||||||
// FIXME Could we improve on this and remove the need for a specialized
|
// FIXME Could we improve on this and remove the need for a specialized
|
||||||
// API in LedgerConsensus?
|
// API in Consensus?
|
||||||
beginConsensus (m_ledgerMaster.getClosedLedger()->info().hash);
|
beginConsensus (m_ledgerMaster.getClosedLedger()->info().hash);
|
||||||
mLedgerConsensus->simulate (consensusDelay);
|
mConsensus->simulate (
|
||||||
|
app_.timeKeeper().closeTime(),
|
||||||
|
consensusDelay);
|
||||||
return m_ledgerMaster.getCurrentLedger ()->info().seq;
|
return m_ledgerMaster.getCurrentLedger ()->info().seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#include <ripple/core/JobQueue.h>
|
#include <ripple/core/JobQueue.h>
|
||||||
#include <ripple/protocol/STValidation.h>
|
#include <ripple/protocol/STValidation.h>
|
||||||
#include <ripple/app/ledger/Ledger.h>
|
#include <ripple/app/ledger/Ledger.h>
|
||||||
#include <ripple/app/ledger/LedgerProposal.h>
|
#include <ripple/app/consensus/RCLCxPeerPos.h>
|
||||||
#include <ripple/ledger/ReadView.h>
|
#include <ripple/ledger/ReadView.h>
|
||||||
#include <ripple/net/InfoSub.h>
|
#include <ripple/net/InfoSub.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -150,7 +150,7 @@ public:
|
|||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
// ledger proposal/close functions
|
// ledger proposal/close functions
|
||||||
virtual void processTrustedProposal (LedgerProposal::pointer proposal,
|
virtual void processTrustedProposal (RCLCxPeerPos::pointer peerPos,
|
||||||
std::shared_ptr<protocol::TMProposeSet> set,
|
std::shared_ptr<protocol::TMProposeSet> set,
|
||||||
NodeID const& node) = 0;
|
NodeID const& node) = 0;
|
||||||
|
|
||||||
@@ -174,9 +174,6 @@ public:
|
|||||||
virtual bool isAmendmentBlocked () = 0;
|
virtual bool isAmendmentBlocked () = 0;
|
||||||
virtual void setAmendmentBlocked () = 0;
|
virtual void setAmendmentBlocked () = 0;
|
||||||
virtual void consensusViewChange () = 0;
|
virtual void consensusViewChange () = 0;
|
||||||
|
|
||||||
// FIXME(NIKB): Remove the need for this function
|
|
||||||
virtual void setLastCloseTime (NetClock::time_point t) = 0;
|
|
||||||
virtual PublicKey const& getValidationPublicKey () const = 0;
|
virtual PublicKey const& getValidationPublicKey () const = 0;
|
||||||
virtual void setValidationKeys (
|
virtual void setValidationKeys (
|
||||||
SecretKey const& valSecret, PublicKey const& valPublic) = 0;
|
SecretKey const& valSecret, PublicKey const& valPublic) = 0;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include <ripple/app/misc/Validations.h>
|
#include <ripple/app/misc/Validations.h>
|
||||||
#include <ripple/core/DatabaseCon.h>
|
#include <ripple/core/DatabaseCon.h>
|
||||||
#include <ripple/app/ledger/LedgerMaster.h>
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
#include <ripple/app/ledger/LedgerTiming.h>
|
#include <ripple/consensus/LedgerTiming.h>
|
||||||
#include <ripple/app/main/Application.h>
|
#include <ripple/app/main/Application.h>
|
||||||
#include <ripple/app/misc/NetworkOPs.h>
|
#include <ripple/app/misc/NetworkOPs.h>
|
||||||
#include <ripple/app/misc/ValidatorList.h>
|
#include <ripple/app/misc/ValidatorList.h>
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <boost/container/flat_set.hpp>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
@@ -324,6 +325,18 @@ template <class Hasher, class Key, class Hash, class Pred, class Alloc>
|
|||||||
void
|
void
|
||||||
hash_append(Hasher& h, std::unordered_set<Key, Hash, Pred, Alloc> const& s);
|
hash_append(Hasher& h, std::unordered_set<Key, Hash, Pred, Alloc> const& s);
|
||||||
|
|
||||||
|
template <class Hasher, class Key, class Compare, class Alloc>
|
||||||
|
std::enable_if_t
|
||||||
|
<
|
||||||
|
!is_contiguously_hashable<Key, Hasher>::value
|
||||||
|
>
|
||||||
|
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
|
||||||
|
template <class Hasher, class Key, class Compare, class Alloc>
|
||||||
|
std::enable_if_t
|
||||||
|
<
|
||||||
|
is_contiguously_hashable<Key, Hasher>::value
|
||||||
|
>
|
||||||
|
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
|
||||||
template <class Hasher, class T0, class T1, class ...T>
|
template <class Hasher, class T0, class T1, class ...T>
|
||||||
void
|
void
|
||||||
hash_append (Hasher& h, T0 const& t0, T1 const& t1, T const& ...t) noexcept;
|
hash_append (Hasher& h, T0 const& t0, T1 const& t1, T const& ...t) noexcept;
|
||||||
@@ -421,6 +434,25 @@ hash_append(Hasher& h, std::array<T, N> const& a) noexcept
|
|||||||
hash_append(h, t);
|
hash_append(h, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Hasher, class Key, class Compare, class Alloc>
|
||||||
|
std::enable_if_t
|
||||||
|
<
|
||||||
|
!is_contiguously_hashable<Key, Hasher>::value
|
||||||
|
>
|
||||||
|
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
|
||||||
|
{
|
||||||
|
for (auto const& t : v)
|
||||||
|
hash_append(h, t);
|
||||||
|
}
|
||||||
|
template <class Hasher, class Key, class Compare, class Alloc>
|
||||||
|
std::enable_if_t
|
||||||
|
<
|
||||||
|
is_contiguously_hashable<Key, Hasher>::value
|
||||||
|
>
|
||||||
|
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
|
||||||
|
{
|
||||||
|
h(&(v.begin()), v.size()*sizeof(Key));
|
||||||
|
}
|
||||||
// tuple
|
// tuple
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
|
|||||||
1791
src/ripple/consensus/Consensus.h
Normal file
1791
src/ripple/consensus/Consensus.h
Normal file
File diff suppressed because it is too large
Load Diff
262
src/ripple/consensus/ConsensusProposal.h
Normal file
262
src/ripple/consensus/ConsensusProposal.h
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012-2016 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 PROVID_tED "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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
#ifndef RIPPLE_CONSENSUS_ConsensusProposal_H_INCLUDED
|
||||||
|
#define RIPPLE_CONSENSUS_ConsensusProposal_H_INCLUDED
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <ripple/json/json_value.h>
|
||||||
|
#include <ripple/protocol/JsonFields.h>
|
||||||
|
#include <ripple/basics/chrono.h>
|
||||||
|
|
||||||
|
namespace ripple
|
||||||
|
{
|
||||||
|
/** Represents a proposed position taken during a round of consensus.
|
||||||
|
|
||||||
|
During consensus, peers seek agreement on a set of transactions to
|
||||||
|
apply to the prior ledger to generate the next ledger. Each peer takes a
|
||||||
|
position on whether to include or exclude potential transactions.
|
||||||
|
The position on the set of transactions is proposed to its peers as an
|
||||||
|
instance of the ConsensusProposal class.
|
||||||
|
|
||||||
|
An instance of ConsensusProposal can be either our own proposal or one of
|
||||||
|
our peer's.
|
||||||
|
|
||||||
|
As consensus proceeds, peers may change their position on the transaction,
|
||||||
|
or choose to abstain. Each successive proposal includes a strictly
|
||||||
|
monotonically increasing number (or, if a peer is choosing to abstain,
|
||||||
|
the special value `seqLeave`).
|
||||||
|
|
||||||
|
Refer to @ref Consensus for requirements of the template arguments.
|
||||||
|
|
||||||
|
@tparam NodeID_t Type used to uniquely identify nodes/peers
|
||||||
|
@tparam LedgerID_t Type used to uniquely identify ledgers
|
||||||
|
@tparam Position_t Type used to represent the position taken on transactions
|
||||||
|
under consideration during this round of consensus
|
||||||
|
*/
|
||||||
|
template <
|
||||||
|
class NodeID_t,
|
||||||
|
class LedgerID_t,
|
||||||
|
class Position_t>
|
||||||
|
class ConsensusProposal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using NodeID = NodeID_t;
|
||||||
|
|
||||||
|
//< Sequence value when a peer initially joins consensus
|
||||||
|
static std::uint32_t const seqJoin = 0;
|
||||||
|
|
||||||
|
//< Sequence number when a peer wants to bow out and leave consensus
|
||||||
|
static std::uint32_t const seqLeave = 0xffffffff;
|
||||||
|
|
||||||
|
|
||||||
|
/** Constructor
|
||||||
|
|
||||||
|
@param prevLedger The previous ledger this proposal is building on.
|
||||||
|
@param seq The sequence number of this proposal.
|
||||||
|
@param position The position taken on transactions in this round.
|
||||||
|
@param closeTime Position of when this ledger closed.
|
||||||
|
@param now Time when the proposal was taken.
|
||||||
|
@param nodeID ID of node/peer taking this position.
|
||||||
|
*/
|
||||||
|
ConsensusProposal(
|
||||||
|
LedgerID_t const& prevLedger,
|
||||||
|
std::uint32_t seq,
|
||||||
|
Position_t const& position,
|
||||||
|
NetClock::time_point closeTime,
|
||||||
|
NetClock::time_point now,
|
||||||
|
NodeID_t const& nodeID)
|
||||||
|
: previousLedger_(prevLedger)
|
||||||
|
, position_(position)
|
||||||
|
, closeTime_(closeTime)
|
||||||
|
, time_(now)
|
||||||
|
, proposeSeq_(seq)
|
||||||
|
, nodeID_(nodeID)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Identifying which peer took this position.
|
||||||
|
NodeID_t const&
|
||||||
|
nodeID () const
|
||||||
|
{
|
||||||
|
return nodeID_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get the proposed position.
|
||||||
|
Position_t const&
|
||||||
|
position () const
|
||||||
|
{
|
||||||
|
return position_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get the prior accepted ledger this position is based on.
|
||||||
|
LedgerID_t const&
|
||||||
|
prevLedger () const
|
||||||
|
{
|
||||||
|
return previousLedger_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the sequence number of this proposal
|
||||||
|
|
||||||
|
Starting with an initial sequence number of `seqJoin`, successive
|
||||||
|
proposals from a peer will increase the sequence number.
|
||||||
|
|
||||||
|
@return the sequence number
|
||||||
|
*/
|
||||||
|
std::uint32_t
|
||||||
|
proposeSeq () const
|
||||||
|
{
|
||||||
|
return proposeSeq_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! The current position on the consensus close time.
|
||||||
|
NetClock::time_point const &
|
||||||
|
closeTime () const
|
||||||
|
{
|
||||||
|
return closeTime_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get when this position was taken.
|
||||||
|
NetClock::time_point const &
|
||||||
|
seenTime () const
|
||||||
|
{
|
||||||
|
return time_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether this is the first position taken during the current
|
||||||
|
consensus round.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
isInitial () const
|
||||||
|
{
|
||||||
|
return proposeSeq_ == seqJoin;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get whether this node left the consensus process
|
||||||
|
bool
|
||||||
|
isBowOut () const
|
||||||
|
{
|
||||||
|
return proposeSeq_ == seqLeave;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get whether this position is stale relative to the provided cutoff
|
||||||
|
bool
|
||||||
|
isStale (NetClock::time_point cutoff) const
|
||||||
|
{
|
||||||
|
return time_ <= cutoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update the position during the consensus process. This will increment
|
||||||
|
the proposal's sequence number.
|
||||||
|
|
||||||
|
@param newPosition The new position taken.
|
||||||
|
@param newCloseTime The new close time.
|
||||||
|
@param now the time The new position was taken.
|
||||||
|
|
||||||
|
@return `true` if the position was updated or `false` if this node has
|
||||||
|
already left this consensus round.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
changePosition(
|
||||||
|
Position_t const& newPosition,
|
||||||
|
NetClock::time_point newCloseTime,
|
||||||
|
NetClock::time_point now)
|
||||||
|
{
|
||||||
|
if (proposeSeq_ == seqLeave)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
position_ = newPosition;
|
||||||
|
closeTime_ = newCloseTime;
|
||||||
|
time_ = now;
|
||||||
|
++proposeSeq_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Leave consensus
|
||||||
|
|
||||||
|
Update position to indicate the node left consensus.
|
||||||
|
|
||||||
|
@param now Time when this node left consensus.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
bowOut(NetClock::time_point now)
|
||||||
|
{
|
||||||
|
time_ = now;
|
||||||
|
proposeSeq_ = seqLeave;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get JSON representation for debugging
|
||||||
|
Json::Value
|
||||||
|
getJson () const
|
||||||
|
{
|
||||||
|
using std::to_string;
|
||||||
|
|
||||||
|
Json::Value ret = Json::objectValue;
|
||||||
|
ret[jss::previous_ledger] = to_string (prevLedger());
|
||||||
|
|
||||||
|
if (!isBowOut())
|
||||||
|
{
|
||||||
|
ret[jss::transaction_hash] = to_string (position());
|
||||||
|
ret[jss::propose_seq] = proposeSeq();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[jss::close_time] = to_string(closeTime().time_since_epoch().count());
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//! Unique identifier of prior ledger this proposal is based on
|
||||||
|
LedgerID_t previousLedger_;
|
||||||
|
|
||||||
|
//! Unique identifier of the position this proposal is taking
|
||||||
|
Position_t position_;
|
||||||
|
|
||||||
|
//! The ledger close time this position is taking
|
||||||
|
NetClock::time_point closeTime_;
|
||||||
|
|
||||||
|
// !The time this position was last updated
|
||||||
|
NetClock::time_point time_;
|
||||||
|
|
||||||
|
//! The sequence number of these positions taken by this node
|
||||||
|
std::uint32_t proposeSeq_;
|
||||||
|
|
||||||
|
//! The identifier of the node taking this position
|
||||||
|
NodeID_t nodeID_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class NodeID_t,
|
||||||
|
class LedgerID_t,
|
||||||
|
class Position_t>
|
||||||
|
bool
|
||||||
|
operator==(ConsensusProposal<NodeID_t, LedgerID_t, Position_t> const & a,
|
||||||
|
ConsensusProposal<NodeID_t, LedgerID_t, Position_t> const & b)
|
||||||
|
{
|
||||||
|
return a.nodeID() == b.nodeID() &&
|
||||||
|
a.proposeSeq() == b.proposeSeq() &&
|
||||||
|
a.prevLedger() == b.prevLedger() &&
|
||||||
|
a.position() == b.position() &&
|
||||||
|
a.closeTime() == b.closeTime() &&
|
||||||
|
a.seenTime() == b.seenTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
#include <ripple/protocol/Serializer.h>
|
#include <ripple/protocol/Serializer.h>
|
||||||
#include <ripple/basics/base_uint.h>
|
#include <ripple/basics/base_uint.h>
|
||||||
#include <ripple/beast/utility/Journal.h>
|
#include <ripple/beast/utility/Journal.h>
|
||||||
|
#include <ripple/consensus/LedgerTiming.h>
|
||||||
|
#include <ripple/basics/Log.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -35,70 +37,110 @@ namespace ripple {
|
|||||||
the dispute.
|
the dispute.
|
||||||
|
|
||||||
Undisputed transactions have no corresponding @ref DisputedTx object.
|
Undisputed transactions have no corresponding @ref DisputedTx object.
|
||||||
|
|
||||||
|
Refer to @ref Consensus for details on the template type requirements.
|
||||||
|
|
||||||
|
@tparam Tx_t The type for a transaction
|
||||||
|
@tparam NodeID_t The type for a node identifier
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template <class Traits>
|
template <class Tx_t, class NodeID_t>
|
||||||
class DisputedTx
|
class DisputedTx
|
||||||
{
|
{
|
||||||
|
using TxID_t = typename Tx_t::ID;
|
||||||
public:
|
public:
|
||||||
|
/** Constructor
|
||||||
|
|
||||||
using Tx_t = typename Traits::Tx_t;
|
@param tx The transaction under dispute
|
||||||
using TxID_t = typename Traits::TxID_t;
|
@param ourVote Our vote on whether tx should be included
|
||||||
using NodeID_t = typename Traits::NodeID_t;
|
@param j Journal for debugging
|
||||||
|
*/
|
||||||
DisputedTx (Tx_t const& tx,
|
DisputedTx (Tx_t const& tx,
|
||||||
bool ourVote, beast::Journal j)
|
bool ourVote,
|
||||||
: mTransactionID (tx.getID())
|
beast::Journal j)
|
||||||
, mYays (0)
|
: yays_ (0)
|
||||||
, mNays (0)
|
, nays_ (0)
|
||||||
, mOurVote (ourVote)
|
, ourVote_ (ourVote)
|
||||||
, transaction (tx)
|
, tx_ (tx)
|
||||||
, j_ (j)
|
, j_ (j)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
TxID_t const& getID () const
|
//! The unique id/hash of the disputed transaction.
|
||||||
|
TxID_t
|
||||||
|
const& ID () const
|
||||||
{
|
{
|
||||||
return mTransactionID;
|
return tx_.id();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getOurVote () const
|
//! Our vote on whether the transaction should be included.
|
||||||
|
bool
|
||||||
|
getOurVote () const
|
||||||
{
|
{
|
||||||
return mOurVote;
|
return ourVote_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tx_t const& tx () const
|
//! The disputed transaction.
|
||||||
|
Tx_t
|
||||||
|
const& tx () const
|
||||||
{
|
{
|
||||||
return transaction;
|
return tx_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOurVote (bool o)
|
//! Change our vote
|
||||||
|
void
|
||||||
|
setOurVote (bool o)
|
||||||
{
|
{
|
||||||
mOurVote = o;
|
ourVote_ = o;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setVote (NodeID_t const& peer, bool votesYes);
|
/** Change a peer's vote
|
||||||
void unVote (NodeID_t const& peer);
|
|
||||||
|
|
||||||
bool updateVote (int percentTime, bool proposing);
|
@param peer Identifier of peer.
|
||||||
Json::Value getJson ();
|
@param votesYes Whether peer votes to include the disputed transaction.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
setVote (NodeID_t const& peer, bool votesYes);
|
||||||
|
|
||||||
|
/** Remove a peer's vote
|
||||||
|
|
||||||
|
@param peer Identifier of peer.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
unVote (NodeID_t const& peer);
|
||||||
|
|
||||||
|
/** Update our vote given progression of consensus.
|
||||||
|
|
||||||
|
Updates our vote on this disputed transaction based on our peers' votes
|
||||||
|
and how far along consensus has proceeded.
|
||||||
|
|
||||||
|
@param percentTime Percentage progress through consensus, e.g. 50%
|
||||||
|
through or 90%.
|
||||||
|
@param proposing Whether we are proposing to our peers in this round.
|
||||||
|
@return Whether our vote changed
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
updateVote (int percentTime, bool proposing);
|
||||||
|
|
||||||
|
//! JSON representation of dispute, used for debugging
|
||||||
|
Json::Value
|
||||||
|
getJson () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TxID_t mTransactionID;
|
int yays_; //< Number of yes votes
|
||||||
int mYays;
|
int nays_; //< Number of no votes
|
||||||
int mNays;
|
bool ourVote_; //< Our vote (true is yes)
|
||||||
bool mOurVote;
|
Tx_t tx_; //< Transaction under dispute
|
||||||
Tx_t transaction;
|
|
||||||
|
|
||||||
hash_map <NodeID_t, bool> mVotes;
|
hash_map <NodeID_t, bool> votes_; //< Votes of our peers
|
||||||
beast::Journal j_;
|
beast::Journal j_; //< Debug journal
|
||||||
};
|
};
|
||||||
|
|
||||||
// Track a peer's yes/no vote on a particular disputed transaction
|
// Track a peer's yes/no vote on a particular disputed tx_
|
||||||
template <class Traits>
|
template <class Tx_t, class NodeID_t>
|
||||||
void DisputedTx<Traits>::setVote (NodeID_t const& peer, bool votesYes)
|
void DisputedTx<Tx_t, NodeID_t>::setVote (NodeID_t const& peer, bool votesYes)
|
||||||
{
|
{
|
||||||
auto res = mVotes.insert (std::make_pair (peer, votesYes));
|
auto res = votes_.insert (std::make_pair (peer, votesYes));
|
||||||
|
|
||||||
// new vote
|
// new vote
|
||||||
if (res.second)
|
if (res.second)
|
||||||
@@ -106,60 +148,60 @@ void DisputedTx<Traits>::setVote (NodeID_t const& peer, bool votesYes)
|
|||||||
if (votesYes)
|
if (votesYes)
|
||||||
{
|
{
|
||||||
JLOG (j_.debug())
|
JLOG (j_.debug())
|
||||||
<< "Peer " << peer << " votes YES on " << mTransactionID;
|
<< "Peer " << peer << " votes YES on " << tx_.id();
|
||||||
++mYays;
|
++yays_;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JLOG (j_.debug())
|
JLOG (j_.debug())
|
||||||
<< "Peer " << peer << " votes NO on " << mTransactionID;
|
<< "Peer " << peer << " votes NO on " << tx_.id();
|
||||||
++mNays;
|
++nays_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// changes vote to yes
|
// changes vote to yes
|
||||||
else if (votesYes && !res.first->second)
|
else if (votesYes && !res.first->second)
|
||||||
{
|
{
|
||||||
JLOG (j_.debug())
|
JLOG (j_.debug())
|
||||||
<< "Peer " << peer << " now votes YES on " << mTransactionID;
|
<< "Peer " << peer << " now votes YES on " << tx_.id();
|
||||||
--mNays;
|
--nays_;
|
||||||
++mYays;
|
++yays_;
|
||||||
res.first->second = true;
|
res.first->second = true;
|
||||||
}
|
}
|
||||||
// changes vote to no
|
// changes vote to no
|
||||||
else if (!votesYes && res.first->second)
|
else if (!votesYes && res.first->second)
|
||||||
{
|
{
|
||||||
JLOG (j_.debug())
|
JLOG (j_.debug())
|
||||||
<< "Peer " << peer << " now votes NO on " << mTransactionID;
|
<< "Peer " << peer << " now votes NO on " << tx_.id();
|
||||||
++mNays;
|
++nays_;
|
||||||
--mYays;
|
--yays_;
|
||||||
res.first->second = false;
|
res.first->second = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a peer's vote on this disputed transasction
|
// Remove a peer's vote on this disputed transasction
|
||||||
template <class Traits>
|
template <class Tx_t, class NodeID_t>
|
||||||
void DisputedTx<Traits>::unVote (NodeID_t const& peer)
|
void DisputedTx<Tx_t, NodeID_t>::unVote (NodeID_t const& peer)
|
||||||
{
|
{
|
||||||
auto it = mVotes.find (peer);
|
auto it = votes_.find (peer);
|
||||||
|
|
||||||
if (it != mVotes.end ())
|
if (it != votes_.end ())
|
||||||
{
|
{
|
||||||
if (it->second)
|
if (it->second)
|
||||||
--mYays;
|
--yays_;
|
||||||
else
|
else
|
||||||
--mNays;
|
--nays_;
|
||||||
|
|
||||||
mVotes.erase (it);
|
votes_.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Traits>
|
template <class Tx_t, class NodeID_t>
|
||||||
bool DisputedTx<Traits>::updateVote (int percentTime, bool proposing)
|
bool DisputedTx<Tx_t, NodeID_t>::updateVote (int percentTime, bool proposing)
|
||||||
{
|
{
|
||||||
if (mOurVote && (mNays == 0))
|
if (ourVote_ && (nays_ == 0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!mOurVote && (mYays == 0))
|
if (!ourVote_ && (yays_ == 0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool newPosition;
|
bool newPosition;
|
||||||
@@ -168,7 +210,7 @@ bool DisputedTx<Traits>::updateVote (int percentTime, bool proposing)
|
|||||||
if (proposing) // give ourselves full weight
|
if (proposing) // give ourselves full weight
|
||||||
{
|
{
|
||||||
// This is basically the percentage of nodes voting 'yes' (including us)
|
// This is basically the percentage of nodes voting 'yes' (including us)
|
||||||
weight = (mYays * 100 + (mOurVote ? 100 : 0)) / (mNays + mYays + 1);
|
weight = (yays_ * 100 + (ourVote_ ? 100 : 0)) / (nays_ + yays_ + 1);
|
||||||
|
|
||||||
// VFALCO TODO Rename these macros and turn them into language
|
// VFALCO TODO Rename these macros and turn them into language
|
||||||
// constructs. consolidate them into a class that collects
|
// constructs. consolidate them into a class that collects
|
||||||
@@ -189,39 +231,41 @@ bool DisputedTx<Traits>::updateVote (int percentTime, bool proposing)
|
|||||||
{
|
{
|
||||||
// don't let us outweigh a proposing node, just recognize consensus
|
// don't let us outweigh a proposing node, just recognize consensus
|
||||||
weight = -1;
|
weight = -1;
|
||||||
newPosition = mYays > mNays;
|
newPosition = yays_ > nays_;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newPosition == mOurVote)
|
if (newPosition == ourVote_)
|
||||||
{
|
{
|
||||||
JLOG (j_.info())
|
JLOG (j_.info())
|
||||||
<< "No change (" << (mOurVote ? "YES" : "NO") << ") : weight "
|
<< "No change (" << (ourVote_ ? "YES" : "NO") << ") : weight "
|
||||||
<< weight << ", percent " << percentTime;
|
<< weight << ", percent " << percentTime;
|
||||||
JLOG (j_.debug()) << getJson ();
|
JLOG (j_.debug()) << getJson ();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mOurVote = newPosition;
|
ourVote_ = newPosition;
|
||||||
JLOG (j_.debug())
|
JLOG (j_.debug())
|
||||||
<< "We now vote " << (mOurVote ? "YES" : "NO")
|
<< "We now vote " << (ourVote_ ? "YES" : "NO")
|
||||||
<< " on " << mTransactionID;
|
<< " on " << tx_.id();
|
||||||
JLOG (j_.debug()) << getJson ();
|
JLOG (j_.debug()) << getJson ();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Traits>
|
template <class Tx_t, class NodeID_t>
|
||||||
Json::Value DisputedTx<Traits>::getJson ()
|
Json::Value DisputedTx<Tx_t, NodeID_t>::getJson () const
|
||||||
{
|
{
|
||||||
|
using std::to_string;
|
||||||
|
|
||||||
Json::Value ret (Json::objectValue);
|
Json::Value ret (Json::objectValue);
|
||||||
|
|
||||||
ret["yays"] = mYays;
|
ret["yays"] = yays_;
|
||||||
ret["nays"] = mNays;
|
ret["nays"] = nays_;
|
||||||
ret["our_vote"] = mOurVote;
|
ret["our_vote"] = ourVote_;
|
||||||
|
|
||||||
if (!mVotes.empty ())
|
if (!votes_.empty ())
|
||||||
{
|
{
|
||||||
Json::Value votesj (Json::objectValue);
|
Json::Value votesj (Json::objectValue);
|
||||||
for (auto& vote : mVotes)
|
for (auto& vote : votes_)
|
||||||
votesj[to_string (vote.first)] = vote.second;
|
votesj[to_string (vote.first)] = vote.second;
|
||||||
ret["votes"] = std::move (votesj);
|
ret["votes"] = std::move (votesj);
|
||||||
}
|
}
|
||||||
@@ -18,68 +18,19 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/app/ledger/LedgerTiming.h>
|
#include <ripple/consensus/LedgerTiming.h>
|
||||||
#include <ripple/basics/Log.h>
|
#include <ripple/basics/Log.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
NetClock::duration
|
|
||||||
getNextLedgerTimeResolution (
|
|
||||||
NetClock::duration previousResolution,
|
|
||||||
bool previousAgree,
|
|
||||||
std::uint32_t ledgerSeq)
|
|
||||||
{
|
|
||||||
assert (ledgerSeq);
|
|
||||||
|
|
||||||
using namespace std::chrono;
|
|
||||||
// Find the current resolution:
|
|
||||||
auto iter = std::find (std::begin (ledgerPossibleTimeResolutions),
|
|
||||||
std::end (ledgerPossibleTimeResolutions), previousResolution);
|
|
||||||
assert (iter != std::end (ledgerPossibleTimeResolutions));
|
|
||||||
|
|
||||||
// This should never happen, but just as a precaution
|
|
||||||
if (iter == std::end (ledgerPossibleTimeResolutions))
|
|
||||||
return previousResolution;
|
|
||||||
|
|
||||||
// If we did not previously agree, we try to decrease the resolution to
|
|
||||||
// improve the chance that we will agree now.
|
|
||||||
if (!previousAgree && ledgerSeq % decreaseLedgerTimeResolutionEvery == 0)
|
|
||||||
{
|
|
||||||
if (++iter != std::end (ledgerPossibleTimeResolutions))
|
|
||||||
return *iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we previously agreed, we try to increase the resolution to determine
|
|
||||||
// if we can continue to agree.
|
|
||||||
if (previousAgree && ledgerSeq % increaseLedgerTimeResolutionEvery == 0)
|
|
||||||
{
|
|
||||||
if (iter-- != std::begin (ledgerPossibleTimeResolutions))
|
|
||||||
return *iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
return previousResolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetClock::time_point
|
|
||||||
roundCloseTime (
|
|
||||||
NetClock::time_point closeTime,
|
|
||||||
NetClock::duration closeResolution)
|
|
||||||
{
|
|
||||||
if (closeTime == NetClock::time_point{})
|
|
||||||
return closeTime;
|
|
||||||
|
|
||||||
closeTime += (closeResolution / 2);
|
|
||||||
return closeTime - (closeTime.time_since_epoch() % closeResolution);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
shouldCloseLedger (
|
shouldCloseLedger (
|
||||||
bool anyTransactions,
|
bool anyTransactions,
|
||||||
int previousProposers,
|
std::size_t previousProposers,
|
||||||
int proposersClosed,
|
std::size_t proposersClosed,
|
||||||
int proposersValidated,
|
std::size_t proposersValidated,
|
||||||
std::chrono::milliseconds previousTime,
|
std::chrono::milliseconds previousTime,
|
||||||
std::chrono::milliseconds currentTime, // Time since last ledger's close time
|
std::chrono::milliseconds currentTime, // Time since last ledger's close time
|
||||||
std::chrono::milliseconds openTime, // Time waiting to close this ledger
|
std::chrono::milliseconds openTime, // Time waiting to close this ledger
|
||||||
@@ -135,7 +86,10 @@ shouldCloseLedger (
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
checkConsensusReached (int agreeing, int total, bool count_self)
|
checkConsensusReached (
|
||||||
|
std::size_t agreeing,
|
||||||
|
std::size_t total,
|
||||||
|
bool count_self)
|
||||||
{
|
{
|
||||||
// If we are alone, we have a consensus
|
// If we are alone, we have a consensus
|
||||||
if (total == 0)
|
if (total == 0)
|
||||||
@@ -154,10 +108,10 @@ checkConsensusReached (int agreeing, int total, bool count_self)
|
|||||||
|
|
||||||
ConsensusState
|
ConsensusState
|
||||||
checkConsensus (
|
checkConsensus (
|
||||||
int previousProposers,
|
std::size_t previousProposers,
|
||||||
int currentProposers,
|
std::size_t currentProposers,
|
||||||
int currentAgree,
|
std::size_t currentAgree,
|
||||||
int currentFinished,
|
std::size_t currentFinished,
|
||||||
std::chrono::milliseconds previousAgreeTime,
|
std::chrono::milliseconds previousAgreeTime,
|
||||||
std::chrono::milliseconds currentAgreeTime,
|
std::chrono::milliseconds currentAgreeTime,
|
||||||
bool proposing,
|
bool proposing,
|
||||||
@@ -27,6 +27,117 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// These are protocol parameters used to control the behavior of the system and
|
||||||
|
// they should not be changed arbitrarily.
|
||||||
|
|
||||||
|
//! The percentage threshold above which we can declare consensus.
|
||||||
|
auto constexpr minimumConsensusPercentage = 80;
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
/** Possible close time resolutions.
|
||||||
|
|
||||||
|
Values should not be duplicated.
|
||||||
|
@see getNextLedgerTimeResolution
|
||||||
|
*/
|
||||||
|
std::chrono::seconds constexpr ledgerPossibleTimeResolutions[] =
|
||||||
|
{ 10s, 20s, 30s, 60s, 90s, 120s };
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
//! Initial resolution of ledger close time.
|
||||||
|
auto constexpr ledgerDefaultTimeResolution = ledgerPossibleTimeResolutions[2];
|
||||||
|
#else
|
||||||
|
// HH Remove this workaround of a VS bug when possible
|
||||||
|
//! Initial resolution of ledger close time.
|
||||||
|
auto constexpr ledgerDefaultTimeResolution = 30s;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! How often we increase the close time resolution (in numbers of ledgers)
|
||||||
|
auto constexpr increaseLedgerTimeResolutionEvery = 8;
|
||||||
|
|
||||||
|
//! How often we decrease the close time resolution (in numbers of ledgers)
|
||||||
|
auto constexpr decreaseLedgerTimeResolutionEvery = 1;
|
||||||
|
|
||||||
|
//! The number of seconds a ledger may remain idle before closing
|
||||||
|
auto constexpr LEDGER_IDLE_INTERVAL = 15s;
|
||||||
|
|
||||||
|
/** The number of seconds a validation remains current after its ledger's close
|
||||||
|
time.
|
||||||
|
|
||||||
|
This is a safety to protect against very old validations and the time
|
||||||
|
it takes to adjust the close time accuracy window.
|
||||||
|
*/
|
||||||
|
auto constexpr VALIDATION_VALID_WALL = 5min;
|
||||||
|
|
||||||
|
/** Duration a validation remains current after first observed.
|
||||||
|
|
||||||
|
The number of seconds a validation remains current after the time we first
|
||||||
|
saw it. This provides faster recovery in very rare cases where the number
|
||||||
|
of validations produced by the network is lower than normal
|
||||||
|
*/
|
||||||
|
auto constexpr VALIDATION_VALID_LOCAL = 3min;
|
||||||
|
|
||||||
|
/** Duration pre-close in which validations are acceptable.
|
||||||
|
|
||||||
|
The number of seconds before a close time that we consider a validation
|
||||||
|
acceptable. This protects against extreme clock errors
|
||||||
|
*/
|
||||||
|
auto constexpr VALIDATION_VALID_EARLY = 3min;
|
||||||
|
|
||||||
|
//! The number of seconds we wait minimum to ensure participation
|
||||||
|
auto constexpr LEDGER_MIN_CONSENSUS = 1950ms;
|
||||||
|
|
||||||
|
//! Minimum number of seconds to wait to ensure others have computed the LCL
|
||||||
|
auto constexpr LEDGER_MIN_CLOSE = 2s;
|
||||||
|
|
||||||
|
//! How often we check state or change positions
|
||||||
|
auto constexpr LEDGER_GRANULARITY = 1s;
|
||||||
|
|
||||||
|
//! How long we consider a proposal fresh
|
||||||
|
auto constexpr PROPOSE_FRESHNESS = 20s;
|
||||||
|
|
||||||
|
//! How often we force generating a new proposal to keep ours fresh
|
||||||
|
auto constexpr PROPOSE_INTERVAL = 12s;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Avalanche tuning
|
||||||
|
//! Percentage of nodes on our UNL that must vote yes
|
||||||
|
auto constexpr AV_INIT_CONSENSUS_PCT = 50;
|
||||||
|
|
||||||
|
//! Percentage of previous close time before we advance
|
||||||
|
auto constexpr AV_MID_CONSENSUS_TIME = 50;
|
||||||
|
|
||||||
|
//! Percentage of nodes that most vote yes after advancing
|
||||||
|
auto constexpr AV_MID_CONSENSUS_PCT = 65;
|
||||||
|
|
||||||
|
//! Percentage of previous close time before we advance
|
||||||
|
auto constexpr AV_LATE_CONSENSUS_TIME = 85;
|
||||||
|
|
||||||
|
//! Percentage of nodes that most vote yes after advancing
|
||||||
|
auto constexpr AV_LATE_CONSENSUS_PCT = 70;
|
||||||
|
|
||||||
|
//! Percentage of previous close time before we are stuck
|
||||||
|
auto constexpr AV_STUCK_CONSENSUS_TIME = 200;
|
||||||
|
|
||||||
|
//! Percentage of nodes that must vote yes after we are stuck
|
||||||
|
auto constexpr AV_STUCK_CONSENSUS_PCT = 95;
|
||||||
|
|
||||||
|
//! Percentage of nodes required to reach agreement on ledger close time
|
||||||
|
auto constexpr AV_CT_CONSENSUS_PCT = 75;
|
||||||
|
|
||||||
|
/** The minimum amount of time to consider the previous round
|
||||||
|
to have taken.
|
||||||
|
|
||||||
|
The minimum amount of time to consider the previous round
|
||||||
|
to have taken. This ensures that there is an opportunity
|
||||||
|
for a round at each avalanche threshold even if the
|
||||||
|
previous consensus was very fast. This should be at least
|
||||||
|
twice the interval between proposals (0.7s) divided by
|
||||||
|
the interval between mid and late consensus ([85-50]/100).
|
||||||
|
*/
|
||||||
|
auto constexpr AV_MIN_CONSENSUS_TIME = 5s;
|
||||||
|
|
||||||
/** Calculates the close time resolution for the specified ledger.
|
/** Calculates the close time resolution for the specified ledger.
|
||||||
|
|
||||||
The Ripple protocol uses binning to represent time intervals using only one
|
The Ripple protocol uses binning to represent time intervals using only one
|
||||||
@@ -34,22 +145,95 @@ namespace ripple {
|
|||||||
without the need for perfectly synchronized clocks.
|
without the need for perfectly synchronized clocks.
|
||||||
The time resolution (i.e. the size of the intervals) is adjusted dynamically
|
The time resolution (i.e. the size of the intervals) is adjusted dynamically
|
||||||
based on what happened in the last ledger, to try to avoid disagreements.
|
based on what happened in the last ledger, to try to avoid disagreements.
|
||||||
|
|
||||||
|
@param previousResolution the resolution used for the prior ledger
|
||||||
|
@param previousAgree whether consensus agreed on the close time of the prior
|
||||||
|
ledger
|
||||||
|
@param ledgerSeq the sequence number of the new ledger
|
||||||
|
|
||||||
|
@pre previousResolution must be a valid bin
|
||||||
|
from @ref ledgerPossibleTimeResolutions
|
||||||
*/
|
*/
|
||||||
NetClock::duration
|
template <class duration>
|
||||||
getNextLedgerTimeResolution (
|
duration
|
||||||
NetClock::duration previousResolution,
|
getNextLedgerTimeResolution(
|
||||||
|
duration previousResolution,
|
||||||
bool previousAgree,
|
bool previousAgree,
|
||||||
std::uint32_t ledgerSeq);
|
std::uint32_t ledgerSeq)
|
||||||
|
{
|
||||||
|
assert (ledgerSeq);
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
// Find the current resolution:
|
||||||
|
auto iter = std::find (std::begin (ledgerPossibleTimeResolutions),
|
||||||
|
std::end (ledgerPossibleTimeResolutions), previousResolution);
|
||||||
|
assert (iter != std::end (ledgerPossibleTimeResolutions));
|
||||||
|
|
||||||
|
// This should never happen, but just as a precaution
|
||||||
|
if (iter == std::end (ledgerPossibleTimeResolutions))
|
||||||
|
return previousResolution;
|
||||||
|
|
||||||
|
// If we did not previously agree, we try to decrease the resolution to
|
||||||
|
// improve the chance that we will agree now.
|
||||||
|
if (!previousAgree && ledgerSeq % decreaseLedgerTimeResolutionEvery == 0)
|
||||||
|
{
|
||||||
|
if (++iter != std::end (ledgerPossibleTimeResolutions))
|
||||||
|
return *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we previously agreed, we try to increase the resolution to determine
|
||||||
|
// if we can continue to agree.
|
||||||
|
if (previousAgree && ledgerSeq % increaseLedgerTimeResolutionEvery == 0)
|
||||||
|
{
|
||||||
|
if (iter-- != std::begin (ledgerPossibleTimeResolutions))
|
||||||
|
return *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return previousResolution;
|
||||||
|
}
|
||||||
|
|
||||||
/** Calculates the close time for a ledger, given a close time resolution.
|
/** Calculates the close time for a ledger, given a close time resolution.
|
||||||
|
|
||||||
@param closeTime The time to be rouned.
|
@param closeTime The time to be rouned.
|
||||||
@param closeResolution The resolution
|
@param closeResolution The resolution
|
||||||
|
@return @b closeTime rounded to the nearest multiple of @b closeResolution.
|
||||||
|
Rounds up if @b closeTime is midway between multiples of @b closeResolution.
|
||||||
*/
|
*/
|
||||||
NetClock::time_point
|
template <class time_point>
|
||||||
roundCloseTime (
|
time_point
|
||||||
NetClock::time_point closeTime,
|
roundCloseTime(
|
||||||
NetClock::duration closeResolution);
|
time_point closeTime,
|
||||||
|
typename time_point::duration closeResolution)
|
||||||
|
{
|
||||||
|
if (closeTime == time_point{})
|
||||||
|
return closeTime;
|
||||||
|
|
||||||
|
closeTime += (closeResolution / 2);
|
||||||
|
return closeTime - (closeTime.time_since_epoch() % closeResolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Calculate the effective ledger close time
|
||||||
|
|
||||||
|
After adjusting the ledger close time based on the current resolution, also
|
||||||
|
ensure it is sufficiently separated from the prior close time.
|
||||||
|
|
||||||
|
@param closeTime The raw ledger close time
|
||||||
|
@param resolution The current close time resolution
|
||||||
|
@param priorCloseTime The close time of the prior ledger
|
||||||
|
*/
|
||||||
|
template <class time_point>
|
||||||
|
time_point effectiveCloseTime(time_point closeTime,
|
||||||
|
typename time_point::duration const resolution,
|
||||||
|
time_point priorCloseTime)
|
||||||
|
{
|
||||||
|
if (closeTime == time_point{})
|
||||||
|
return closeTime;
|
||||||
|
|
||||||
|
return std::max<time_point>(
|
||||||
|
roundCloseTime (closeTime, resolution),
|
||||||
|
(priorCloseTime + 1s));
|
||||||
|
}
|
||||||
|
|
||||||
/** Determines whether the current ledger should close at this time.
|
/** Determines whether the current ledger should close at this time.
|
||||||
|
|
||||||
@@ -71,9 +255,9 @@ roundCloseTime (
|
|||||||
bool
|
bool
|
||||||
shouldCloseLedger (
|
shouldCloseLedger (
|
||||||
bool anyTransactions,
|
bool anyTransactions,
|
||||||
int previousProposers,
|
std::size_t previousProposers,
|
||||||
int proposersClosed,
|
std::size_t proposersClosed,
|
||||||
int proposersValidated,
|
std::size_t proposersValidated,
|
||||||
std::chrono::milliseconds previousTime,
|
std::chrono::milliseconds previousTime,
|
||||||
std::chrono::milliseconds currentTime, // Time since last ledger's close time
|
std::chrono::milliseconds currentTime, // Time since last ledger's close time
|
||||||
std::chrono::milliseconds openTime, // Time waiting to close this ledger
|
std::chrono::milliseconds openTime, // Time waiting to close this ledger
|
||||||
@@ -91,14 +275,17 @@ shouldCloseLedger (
|
|||||||
@return True if a consensus has been reached
|
@return True if a consensus has been reached
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
checkConsensusReached (int agreeing, int total, bool count_self);
|
checkConsensusReached (
|
||||||
|
std::size_t agreeing,
|
||||||
|
std::size_t total,
|
||||||
|
bool count_self);
|
||||||
|
|
||||||
/** Whether we have or don't have a consensus */
|
/** Whether we have or don't have a consensus */
|
||||||
enum class ConsensusState
|
enum class ConsensusState
|
||||||
{
|
{
|
||||||
No, // We do not have consensus
|
No, //!< We do not have consensus
|
||||||
MovedOn, // The network has consensus without us
|
MovedOn, //!< The network has consensus without us
|
||||||
Yes // We have consensus along with the network
|
Yes //!< We have consensus along with the network
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Determine whether the network reached consensus and whether we joined.
|
/** Determine whether the network reached consensus and whether we joined.
|
||||||
@@ -116,103 +303,15 @@ enum class ConsensusState
|
|||||||
*/
|
*/
|
||||||
ConsensusState
|
ConsensusState
|
||||||
checkConsensus (
|
checkConsensus (
|
||||||
int previousProposers,
|
std::size_t previousProposers,
|
||||||
int currentProposers,
|
std::size_t currentProposers,
|
||||||
int currentAgree,
|
std::size_t currentAgree,
|
||||||
int currentFinished,
|
std::size_t currentFinished,
|
||||||
std::chrono::milliseconds previousAgreeTime,
|
std::chrono::milliseconds previousAgreeTime,
|
||||||
std::chrono::milliseconds currentAgreeTime,
|
std::chrono::milliseconds currentAgreeTime,
|
||||||
bool proposing,
|
bool proposing,
|
||||||
beast::Journal j);
|
beast::Journal j);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// These are protocol parameters used to control the behavior of the system and
|
|
||||||
// they should not be changed arbitrarily.
|
|
||||||
|
|
||||||
// The percentage threshold above which we can declare consensus.
|
|
||||||
auto constexpr minimumConsensusPercentage = 80;
|
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
// All possible close time resolutions. Values should not be duplicated.
|
|
||||||
std::chrono::seconds constexpr ledgerPossibleTimeResolutions[] =
|
|
||||||
{ 10s, 20s, 30s, 60s, 90s, 120s };
|
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
// Initial resolution of ledger close time.
|
|
||||||
auto constexpr ledgerDefaultTimeResolution = ledgerPossibleTimeResolutions[2];
|
|
||||||
#else
|
|
||||||
// HH Remove this workaround of a VS bug when possible
|
|
||||||
auto constexpr ledgerDefaultTimeResolution = 30s;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// How often we increase the close time resolution
|
|
||||||
auto constexpr increaseLedgerTimeResolutionEvery = 8;
|
|
||||||
|
|
||||||
// How often we decrease the close time resolution
|
|
||||||
auto constexpr decreaseLedgerTimeResolutionEvery = 1;
|
|
||||||
|
|
||||||
// The number of seconds a ledger may remain idle before closing
|
|
||||||
auto constexpr LEDGER_IDLE_INTERVAL = 15s;
|
|
||||||
|
|
||||||
// The number of seconds a validation remains current after its ledger's close
|
|
||||||
// time. This is a safety to protect against very old validations and the time
|
|
||||||
// it takes to adjust the close time accuracy window
|
|
||||||
auto constexpr VALIDATION_VALID_WALL = 5min;
|
|
||||||
|
|
||||||
// The number of seconds a validation remains current after the time we first
|
|
||||||
// saw it. This provides faster recovery in very rare cases where the number
|
|
||||||
// of validations produced by the network is lower than normal
|
|
||||||
auto constexpr VALIDATION_VALID_LOCAL = 3min;
|
|
||||||
|
|
||||||
// The number of seconds before a close time that we consider a validation
|
|
||||||
// acceptable. This protects against extreme clock errors
|
|
||||||
auto constexpr VALIDATION_VALID_EARLY = 3min;
|
|
||||||
|
|
||||||
// The number of seconds we wait minimum to ensure participation
|
|
||||||
auto constexpr LEDGER_MIN_CONSENSUS = 1950ms;
|
|
||||||
|
|
||||||
// Minimum number of seconds to wait to ensure others have computed the LCL
|
|
||||||
auto constexpr LEDGER_MIN_CLOSE = 2s;
|
|
||||||
|
|
||||||
// How often we check state or change positions (in milliseconds)
|
|
||||||
auto constexpr LEDGER_GRANULARITY = 1s;
|
|
||||||
|
|
||||||
// How long we consider a proposal fresh
|
|
||||||
auto constexpr PROPOSE_FRESHNESS = 20s;
|
|
||||||
|
|
||||||
// How often we force generating a new proposal to keep ours fresh
|
|
||||||
auto constexpr PROPOSE_INTERVAL = 12s;
|
|
||||||
|
|
||||||
// Avalanche tuning
|
|
||||||
// percentage of nodes on our UNL that must vote yes
|
|
||||||
auto constexpr AV_INIT_CONSENSUS_PCT = 50;
|
|
||||||
|
|
||||||
// percentage of previous close time before we advance
|
|
||||||
auto constexpr AV_MID_CONSENSUS_TIME = 50;
|
|
||||||
|
|
||||||
// percentage of nodes that most vote yes after advancing
|
|
||||||
auto constexpr AV_MID_CONSENSUS_PCT = 65;
|
|
||||||
|
|
||||||
// percentage of previous close time before we advance
|
|
||||||
auto constexpr AV_LATE_CONSENSUS_TIME = 85;
|
|
||||||
|
|
||||||
// percentage of nodes that most vote yes after advancing
|
|
||||||
auto constexpr AV_LATE_CONSENSUS_PCT = 70;
|
|
||||||
|
|
||||||
auto constexpr AV_STUCK_CONSENSUS_TIME = 200;
|
|
||||||
auto constexpr AV_STUCK_CONSENSUS_PCT = 95;
|
|
||||||
|
|
||||||
auto constexpr AV_CT_CONSENSUS_PCT = 75;
|
|
||||||
|
|
||||||
// The minimum amount of time to consider the previous round
|
|
||||||
// to have taken. This ensures that there is an opportunity
|
|
||||||
// for a round at each avalanche threshold even if the
|
|
||||||
// previous consensus was very fast. This should be at least
|
|
||||||
// twice the interval between proposals (0.7s) divided by
|
|
||||||
// the interval between mid and late consensus ([85-50]/100).
|
|
||||||
auto constexpr AV_MIN_CONSENSUS_TIME = 5s;
|
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
9
src/ripple/consensus/README.md
Normal file
9
src/ripple/consensus/README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Consensus
|
||||||
|
|
||||||
|
This directory contains the implementation of a
|
||||||
|
generic consensus algorithm. The implementation
|
||||||
|
follows a CRTP design, requiring client code to implement
|
||||||
|
specific functions and types to use consensus in their
|
||||||
|
application. The interface is undergoing refactoring and
|
||||||
|
is not yet finalized.
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
#include <ripple/overlay/impl/Tuning.h>
|
#include <ripple/overlay/impl/Tuning.h>
|
||||||
#include <ripple/app/ledger/InboundLedgers.h>
|
#include <ripple/app/ledger/InboundLedgers.h>
|
||||||
#include <ripple/app/ledger/LedgerMaster.h>
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
#include <ripple/app/ledger/LedgerTiming.h>
|
#include <ripple/consensus/LedgerTiming.h>
|
||||||
#include <ripple/app/ledger/InboundTransactions.h>
|
#include <ripple/app/ledger/InboundTransactions.h>
|
||||||
#include <ripple/app/misc/HashRouter.h>
|
#include <ripple/app/misc/HashRouter.h>
|
||||||
#include <ripple/app/misc/LoadFeeTrack.h>
|
#include <ripple/app/misc/LoadFeeTrack.h>
|
||||||
@@ -1275,10 +1275,10 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMProposeSet> const& m)
|
|||||||
JLOG(p_journal_.trace()) <<
|
JLOG(p_journal_.trace()) <<
|
||||||
"Proposal: " << (isTrusted ? "trusted" : "UNTRUSTED");
|
"Proposal: " << (isTrusted ? "trusted" : "UNTRUSTED");
|
||||||
|
|
||||||
auto proposal = std::make_shared<LedgerProposal> (
|
auto proposal = std::make_shared<RCLCxPeerPos> (
|
||||||
prevLedger, set.proposeseq (), proposeHash, closeTime,
|
publicKey, signature, suppression,
|
||||||
app_.timeKeeper().closeTime(), publicKey, calcNodeID(publicKey),
|
RCLCxPeerPos::Proposal{prevLedger, set.proposeseq (), proposeHash, closeTime,
|
||||||
signature, suppression);
|
app_.timeKeeper().closeTime(),calcNodeID(publicKey)});
|
||||||
|
|
||||||
std::weak_ptr<PeerImp> weak = shared_from_this();
|
std::weak_ptr<PeerImp> weak = shared_from_this();
|
||||||
app_.getJobQueue ().addJob (
|
app_.getJobQueue ().addJob (
|
||||||
@@ -1878,7 +1878,7 @@ PeerImp::checkTransaction (int flags,
|
|||||||
void
|
void
|
||||||
PeerImp::checkPropose (Job& job,
|
PeerImp::checkPropose (Job& job,
|
||||||
std::shared_ptr <protocol::TMProposeSet> const& packet,
|
std::shared_ptr <protocol::TMProposeSet> const& packet,
|
||||||
LedgerProposal::pointer proposal)
|
RCLCxPeerPos::pointer peerPos)
|
||||||
{
|
{
|
||||||
bool isTrusted = (job.getType () == jtPROPOSAL_t);
|
bool isTrusted = (job.getType () == jtPROPOSAL_t);
|
||||||
|
|
||||||
@@ -1888,7 +1888,7 @@ PeerImp::checkPropose (Job& job,
|
|||||||
assert (packet);
|
assert (packet);
|
||||||
protocol::TMProposeSet& set = *packet;
|
protocol::TMProposeSet& set = *packet;
|
||||||
|
|
||||||
if (! cluster() && ! proposal->checkSign ())
|
if (! cluster() && !peerPos->checkSign ())
|
||||||
{
|
{
|
||||||
JLOG(p_journal_.warn()) <<
|
JLOG(p_journal_.warn()) <<
|
||||||
"Proposal fails sig check";
|
"Proposal fails sig check";
|
||||||
@@ -1899,16 +1899,16 @@ PeerImp::checkPropose (Job& job,
|
|||||||
if (isTrusted)
|
if (isTrusted)
|
||||||
{
|
{
|
||||||
app_.getOPs ().processTrustedProposal (
|
app_.getOPs ().processTrustedProposal (
|
||||||
proposal, packet, calcNodeID (publicKey_));
|
peerPos, packet, calcNodeID (publicKey_));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (app_.getOPs().getConsensusLCL() == proposal->getPrevLedger())
|
if (app_.getOPs().getConsensusLCL() == peerPos->proposal().prevLedger())
|
||||||
{
|
{
|
||||||
// relay untrusted proposal
|
// relay untrusted proposal
|
||||||
JLOG(p_journal_.trace()) <<
|
JLOG(p_journal_.trace()) <<
|
||||||
"relaying UNTRUSTED proposal";
|
"relaying UNTRUSTED proposal";
|
||||||
overlay_.relay(set, proposal->getSuppressionID());
|
overlay_.relay(set, peerPos->getSuppressionID());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#ifndef RIPPLE_OVERLAY_PEERIMP_H_INCLUDED
|
#ifndef RIPPLE_OVERLAY_PEERIMP_H_INCLUDED
|
||||||
#define RIPPLE_OVERLAY_PEERIMP_H_INCLUDED
|
#define RIPPLE_OVERLAY_PEERIMP_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/app/ledger/LedgerProposal.h>
|
#include <ripple/app/consensus/RCLCxPeerPos.h>
|
||||||
#include <ripple/basics/Log.h> // deprecated
|
#include <ripple/basics/Log.h> // deprecated
|
||||||
#include <ripple/nodestore/Database.h>
|
#include <ripple/nodestore/Database.h>
|
||||||
#include <ripple/overlay/predicates.h>
|
#include <ripple/overlay/predicates.h>
|
||||||
@@ -452,7 +452,7 @@ private:
|
|||||||
void
|
void
|
||||||
checkPropose (Job& job,
|
checkPropose (Job& job,
|
||||||
std::shared_ptr<protocol::TMProposeSet> const& packet,
|
std::shared_ptr<protocol::TMProposeSet> const& packet,
|
||||||
LedgerProposal::pointer proposal);
|
RCLCxPeerPos::pointer peerPos);
|
||||||
|
|
||||||
void
|
void
|
||||||
checkValidation (STValidation::pointer val,
|
checkValidation (STValidation::pointer val,
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ JSS ( check_nodes ); // in: LedgerCleaner
|
|||||||
JSS ( clear ); // in/out: FetchInfo
|
JSS ( clear ); // in/out: FetchInfo
|
||||||
JSS ( close_flags ); // out: LedgerToJson
|
JSS ( close_flags ); // out: LedgerToJson
|
||||||
JSS ( close_time ); // in: Application, out: NetworkOPs,
|
JSS ( close_time ); // in: Application, out: NetworkOPs,
|
||||||
// LedgerProposal, LedgerToJson
|
// RCLCxPeerPos, LedgerToJson
|
||||||
JSS ( close_time_estimated ); // in: Application, out: LedgerToJson
|
JSS ( close_time_estimated ); // in: Application, out: LedgerToJson
|
||||||
JSS ( close_time_human ); // out: LedgerToJson
|
JSS ( close_time_human ); // out: LedgerToJson
|
||||||
JSS ( close_time_offset ); // out: NetworkOPs
|
JSS ( close_time_offset ); // out: NetworkOPs
|
||||||
@@ -316,7 +316,7 @@ JSS ( paths_canonical ); // out: RipplePathFind
|
|||||||
JSS ( paths_computed ); // out: PathRequest, RipplePathFind
|
JSS ( paths_computed ); // out: PathRequest, RipplePathFind
|
||||||
JSS ( peer ); // in: AccountLines
|
JSS ( peer ); // in: AccountLines
|
||||||
JSS ( peer_authorized ); // out: AccountLines
|
JSS ( peer_authorized ); // out: AccountLines
|
||||||
JSS ( peer_id ); // out: LedgerProposal
|
JSS ( peer_id ); // out: RCLCxPeerPos
|
||||||
JSS ( peers ); // out: InboundLedger, handlers/Peers, Overlay
|
JSS ( peers ); // out: InboundLedger, handlers/Peers, Overlay
|
||||||
JSS ( port ); // in: Connect
|
JSS ( port ); // in: Connect
|
||||||
JSS ( previous_ledger ); // out: LedgerPropose
|
JSS ( previous_ledger ); // out: LedgerPropose
|
||||||
@@ -408,7 +408,7 @@ JSS ( total_coins ); // out: LedgerToJson
|
|||||||
JSS ( transTreeHash ); // out: ledger/Ledger.cpp
|
JSS ( transTreeHash ); // out: ledger/Ledger.cpp
|
||||||
JSS ( transaction ); // in: Tx
|
JSS ( transaction ); // in: Tx
|
||||||
// out: NetworkOPs, AcceptedLedgerTx,
|
// out: NetworkOPs, AcceptedLedgerTx,
|
||||||
JSS ( transaction_hash ); // out: LedgerProposal, LedgerToJson
|
JSS ( transaction_hash ); // out: RCLCxPeerPos, LedgerToJson
|
||||||
JSS ( transactions ); // out: LedgerToJson,
|
JSS ( transactions ); // out: LedgerToJson,
|
||||||
// in: AccountTx*, Unsubscribe
|
// in: AccountTx*, Unsubscribe
|
||||||
JSS ( transitions ); // out: NetworkOPs
|
JSS ( transitions ); // out: NetworkOPs
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ public:
|
|||||||
{
|
{
|
||||||
mSeen = s;
|
mSeen = s;
|
||||||
}
|
}
|
||||||
Blob getSigned () const;
|
Blob getSerialized () const;
|
||||||
Blob getSignature () const;
|
Blob getSignature () const;
|
||||||
|
|
||||||
// Signs the validation and returns the signing hash
|
// Signs the validation and returns the signing hash
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ Blob STValidation::getSignature () const
|
|||||||
return getFieldVL (sfSignature);
|
return getFieldVL (sfSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
Blob STValidation::getSigned () const
|
Blob STValidation::getSerialized () const
|
||||||
{
|
{
|
||||||
Serializer s;
|
Serializer s;
|
||||||
add (s);
|
add (s);
|
||||||
|
|||||||
@@ -16,40 +16,7 @@
|
|||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
#include <BeastConfig.h>
|
||||||
|
|
||||||
#ifndef RIPPLE_APP_CONSENSUS_RCLCXTRAITS_H_INCLUDED
|
#include <ripple/app/consensus/RCLConsensus.cpp>
|
||||||
#define RIPPLE_APP_CONSENSUS_RCLCXTRAITS_H_INCLUDED
|
#include <ripple/app/consensus/RCLCxPeerPos.cpp>
|
||||||
|
|
||||||
#include <ripple/basics/chrono.h>
|
|
||||||
#include <ripple/basics/base_uint.h>
|
|
||||||
|
|
||||||
#include <ripple/protocol/UintTypes.h>
|
|
||||||
#include <ripple/protocol/RippleLedgerHash.h>
|
|
||||||
|
|
||||||
#include <ripple/app/consensus/RCLCxPos.h>
|
|
||||||
#include <ripple/app/consensus/RCLCxTx.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
|
|
||||||
// Consensus traits class
|
|
||||||
// For adapting consensus to RCL
|
|
||||||
|
|
||||||
class RCLCxTraits
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
using Time_t = NetClock::time_point;
|
|
||||||
|
|
||||||
using Pos_t = RCLCxPos;
|
|
||||||
using TxSet_t = RCLTxSet;
|
|
||||||
using Tx_t = RCLCxTx;
|
|
||||||
|
|
||||||
using LgrID_t = LedgerHash;
|
|
||||||
using TxID_t = uint256;
|
|
||||||
using TxSetID_t = uint256;
|
|
||||||
using NodeID_t = NodeID;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -26,18 +26,14 @@
|
|||||||
#include <ripple/app/ledger/ConsensusTransSetSF.cpp>
|
#include <ripple/app/ledger/ConsensusTransSetSF.cpp>
|
||||||
#include <ripple/app/ledger/Ledger.cpp>
|
#include <ripple/app/ledger/Ledger.cpp>
|
||||||
#include <ripple/app/ledger/LedgerHistory.cpp>
|
#include <ripple/app/ledger/LedgerHistory.cpp>
|
||||||
#include <ripple/app/ledger/LedgerProposal.cpp>
|
|
||||||
#include <ripple/app/ledger/OrderBookDB.cpp>
|
#include <ripple/app/ledger/OrderBookDB.cpp>
|
||||||
#include <ripple/app/ledger/TransactionStateSF.cpp>
|
#include <ripple/app/ledger/TransactionStateSF.cpp>
|
||||||
|
|
||||||
#include <ripple/app/ledger/impl/ConsensusImp.cpp>
|
|
||||||
#include <ripple/app/ledger/impl/InboundLedger.cpp>
|
#include <ripple/app/ledger/impl/InboundLedger.cpp>
|
||||||
#include <ripple/app/ledger/impl/InboundLedgers.cpp>
|
#include <ripple/app/ledger/impl/InboundLedgers.cpp>
|
||||||
#include <ripple/app/ledger/impl/InboundTransactions.cpp>
|
#include <ripple/app/ledger/impl/InboundTransactions.cpp>
|
||||||
#include <ripple/app/ledger/impl/LedgerCleaner.cpp>
|
#include <ripple/app/ledger/impl/LedgerCleaner.cpp>
|
||||||
#include <ripple/app/ledger/impl/LedgerConsensusImp.cpp>
|
|
||||||
#include <ripple/app/ledger/impl/LedgerMaster.cpp>
|
#include <ripple/app/ledger/impl/LedgerMaster.cpp>
|
||||||
#include <ripple/app/ledger/impl/LedgerTiming.cpp>
|
|
||||||
#include <ripple/app/ledger/impl/LocalTxs.cpp>
|
#include <ripple/app/ledger/impl/LocalTxs.cpp>
|
||||||
#include <ripple/app/ledger/impl/OpenLedger.cpp>
|
#include <ripple/app/ledger/impl/OpenLedger.cpp>
|
||||||
#include <ripple/app/ledger/impl/LedgerToJson.cpp>
|
#include <ripple/app/ledger/impl/LedgerToJson.cpp>
|
||||||
|
|||||||
21
src/ripple/unity/consensus.cpp
Normal file
21
src/ripple/unity/consensus.cpp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012-2016 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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
#include <BeastConfig.h>
|
||||||
|
|
||||||
|
#include <ripple/consensus/LedgerTiming.cpp>
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
#include <ripple/app/main/Application.h>
|
#include <ripple/app/main/Application.h>
|
||||||
#include <ripple/app/misc/LoadFeeTrack.h>
|
#include <ripple/app/misc/LoadFeeTrack.h>
|
||||||
#include <ripple/app/misc/TxQ.h>
|
#include <ripple/app/misc/TxQ.h>
|
||||||
#include <ripple/app/ledger/LedgerConsensus.h>
|
|
||||||
#include <ripple/app/tx/apply.h>
|
#include <ripple/app/tx/apply.h>
|
||||||
#include <ripple/basics/Log.h>
|
#include <ripple/basics/Log.h>
|
||||||
#include <ripple/basics/mulDiv.h>
|
#include <ripple/basics/mulDiv.h>
|
||||||
|
|||||||
474
src/test/consensus/Consensus_test.cpp
Normal file
474
src/test/consensus/Consensus_test.cpp
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012-2016 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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
#include <BeastConfig.h>
|
||||||
|
#include <ripple/beast/unit_test.h>
|
||||||
|
#include <ripple/consensus/Consensus.h>
|
||||||
|
#include <ripple/consensus/ConsensusProposal.h>
|
||||||
|
#include <ripple/beast/clock/manual_clock.h>
|
||||||
|
#include <boost/function_output_iterator.hpp>
|
||||||
|
#include <test/csf.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
class Consensus_test : public beast::unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
void
|
||||||
|
testStandalone()
|
||||||
|
{
|
||||||
|
using namespace csf;
|
||||||
|
|
||||||
|
auto tg = TrustGraph::makeComplete(1);
|
||||||
|
Sim s(tg, topology(tg, fixed{LEDGER_GRANULARITY}));
|
||||||
|
|
||||||
|
auto & p = s.peers[0];
|
||||||
|
|
||||||
|
p.targetLedgers = 1;
|
||||||
|
p.start();
|
||||||
|
p.submit(Tx{ 1 });
|
||||||
|
|
||||||
|
s.net.step();
|
||||||
|
|
||||||
|
// Inspect that the proper ledger was created
|
||||||
|
BEAST_EXPECT(p.LCL().seq == 1);
|
||||||
|
BEAST_EXPECT(p.LCL() == p.lastClosedLedger.id());
|
||||||
|
BEAST_EXPECT(p.lastClosedLedger.id().txs.size() == 1);
|
||||||
|
BEAST_EXPECT(p.lastClosedLedger.id().txs.find(Tx{ 1 })
|
||||||
|
!= p.lastClosedLedger.id().txs.end());
|
||||||
|
BEAST_EXPECT(p.getLastCloseProposers() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testPeersAgree()
|
||||||
|
{
|
||||||
|
using namespace csf;
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
auto tg = TrustGraph::makeComplete(5);
|
||||||
|
Sim sim(tg,
|
||||||
|
topology(tg, fixed{round<milliseconds>(0.2 * LEDGER_GRANULARITY)}));
|
||||||
|
|
||||||
|
// everyone submits their own ID as a TX and relay it to peers
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
p.submit(Tx(p.id));
|
||||||
|
|
||||||
|
// Verify all peers have the same LCL and it has all the Txs
|
||||||
|
sim.run(1);
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
auto const &lgrID = p.LCL();
|
||||||
|
BEAST_EXPECT(lgrID.seq == 1);
|
||||||
|
BEAST_EXPECT(p.getLastCloseProposers() == sim.peers.size() - 1);
|
||||||
|
for(std::uint32_t i = 0; i < sim.peers.size(); ++i)
|
||||||
|
BEAST_EXPECT(lgrID.txs.find(Tx{ i }) != lgrID.txs.end());
|
||||||
|
// Matches peer 0 ledger
|
||||||
|
BEAST_EXPECT(lgrID.txs == sim.peers[0].LCL().txs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testSlowPeer()
|
||||||
|
{
|
||||||
|
using namespace csf;
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
// Run two tests
|
||||||
|
// 1. The slow peer is participating inconsensus
|
||||||
|
// 2. The slow peer is just observing
|
||||||
|
|
||||||
|
for(auto isParticipant : {true, false})
|
||||||
|
{
|
||||||
|
auto tg = TrustGraph::makeComplete(5);
|
||||||
|
|
||||||
|
Sim sim(tg, topology(tg,[](PeerID i, PeerID j)
|
||||||
|
{
|
||||||
|
auto delayFactor = (i == 0 || j == 0) ? 1.1 : 0.2;
|
||||||
|
return round<milliseconds>(delayFactor* LEDGER_GRANULARITY);
|
||||||
|
}));
|
||||||
|
|
||||||
|
sim.peers[0].proposing = sim.peers[0].validating = isParticipant;
|
||||||
|
|
||||||
|
// All peers submit their own ID as a transaction and relay it to peers
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
p.submit(Tx{ p.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
sim.run(1);
|
||||||
|
|
||||||
|
// Verify all peers have same LCL but are missing transaction 0 which
|
||||||
|
// was not received by all peers before the ledger closed
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
auto const &lgrID = p.LCL();
|
||||||
|
BEAST_EXPECT(lgrID.seq == 1);
|
||||||
|
|
||||||
|
|
||||||
|
// If peer 0 is participating
|
||||||
|
if(isParticipant)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(p.getLastCloseProposers()
|
||||||
|
== sim.peers.size() - 1);
|
||||||
|
// Peer 0 closes first because it sees a quorum of agreeing positions
|
||||||
|
// from all other peers in one hop (1->0, 2->0, ..)
|
||||||
|
// The other peers take an extra timer period before they find that
|
||||||
|
// Peer 0 agrees with them ( 1->0->1, 2->0->2, ...)
|
||||||
|
if(p.id != 0)
|
||||||
|
BEAST_EXPECT(p.getLastConvergeDuration()
|
||||||
|
> sim.peers[0].getLastConvergeDuration());
|
||||||
|
}
|
||||||
|
else // peer 0 is not participating
|
||||||
|
{
|
||||||
|
auto const proposers = p.getLastCloseProposers();
|
||||||
|
if(p.id == 0)
|
||||||
|
BEAST_EXPECT(proposers == sim.peers.size() - 1);
|
||||||
|
else
|
||||||
|
BEAST_EXPECT(proposers == sim.peers.size() - 2);
|
||||||
|
|
||||||
|
// so all peers should have closed together
|
||||||
|
BEAST_EXPECT(p.getLastConvergeDuration()
|
||||||
|
== sim.peers[0].getLastConvergeDuration());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BEAST_EXPECT(lgrID.txs.find(Tx{ 0 }) == lgrID.txs.end());
|
||||||
|
for(std::uint32_t i = 1; i < sim.peers.size(); ++i)
|
||||||
|
BEAST_EXPECT(lgrID.txs.find(Tx{ i }) != lgrID.txs.end());
|
||||||
|
// Matches peer 0 ledger
|
||||||
|
BEAST_EXPECT(lgrID.txs == sim.peers[0].LCL().txs);
|
||||||
|
}
|
||||||
|
BEAST_EXPECT(sim.peers[0].openTxs.find(Tx{ 0 })
|
||||||
|
!= sim.peers[0].openTxs.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testCloseTimeDisagree()
|
||||||
|
{
|
||||||
|
using namespace csf;
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
// This is a very specialized test to get ledgers to disagree on
|
||||||
|
// the close time. It unfortunately assumes knowledge about current
|
||||||
|
// timing constants. This is a necessary evil to get coverage up
|
||||||
|
// pending more extensive refactorings of timing constants.
|
||||||
|
|
||||||
|
// In order to agree-to-disagree on the close time, there must be no
|
||||||
|
// clear majority of nodes agreeing on a close time. This test
|
||||||
|
// sets a relative offset to the peers internal clocks so that they
|
||||||
|
// send proposals with differing times.
|
||||||
|
|
||||||
|
// However, they have to agree on the effective close time, not the
|
||||||
|
// exact close time. The minimum closeTimeResolution is given by
|
||||||
|
// ledgerPossibleTimeResolutions[0], which is currently 10s. This means
|
||||||
|
// the skews need to be at least 10 seconds.
|
||||||
|
|
||||||
|
// Complicating this matter is that nodes will ignore proposals
|
||||||
|
// with times more than PROPOSE_FRESHNESS =20s in the past. So at
|
||||||
|
// the minimum granularity, we have at most 3 types of skews (0s,10s,20s).
|
||||||
|
|
||||||
|
// This test therefore has 6 nodes, with 2 nodes having each type of
|
||||||
|
// skew. Then no majority (1/3 < 1/2) of nodes will agree on an
|
||||||
|
// actual close time.
|
||||||
|
|
||||||
|
auto tg = TrustGraph::makeComplete(6);
|
||||||
|
Sim sim(tg,
|
||||||
|
topology(tg, fixed{round<milliseconds>(0.2 * LEDGER_GRANULARITY)}));
|
||||||
|
|
||||||
|
// Run consensus without skew until we have a short close time resolution
|
||||||
|
while(sim.peers.front().lastClosedLedger.closeTimeResolution() >=
|
||||||
|
PROPOSE_FRESHNESS)
|
||||||
|
sim.run(1);
|
||||||
|
|
||||||
|
// Introduce a shift on the time of half the peers
|
||||||
|
sim.peers[0].clockSkew = PROPOSE_FRESHNESS/2;
|
||||||
|
sim.peers[1].clockSkew = PROPOSE_FRESHNESS/2;
|
||||||
|
sim.peers[2].clockSkew = PROPOSE_FRESHNESS;
|
||||||
|
sim.peers[3].clockSkew = PROPOSE_FRESHNESS;
|
||||||
|
|
||||||
|
// Verify all peers have the same LCL and it has all the Txs
|
||||||
|
sim.run(1);
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(! p.lastClosedLedger.closeAgree());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testWrongLCL()
|
||||||
|
{
|
||||||
|
using namespace csf;
|
||||||
|
using namespace std::chrono;
|
||||||
|
// Specialized test to exercise a temporary fork in which some peers
|
||||||
|
// are working on an incorrect prior ledger.
|
||||||
|
|
||||||
|
// Vary the time it takes to process validations to exercise detecting
|
||||||
|
// the wrong LCL at different phases of consensus
|
||||||
|
for(auto validationDelay : {0s, LEDGER_MIN_CLOSE})
|
||||||
|
{
|
||||||
|
|
||||||
|
// Consider 10 peers:
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9
|
||||||
|
//
|
||||||
|
// Nodes 0-1 trust nodes 0-4
|
||||||
|
// Nodes 2-9 trust nodes 2-9
|
||||||
|
//
|
||||||
|
// By submitting tx 0 to nodes 0-4 and tx 1 to nodes 5-9,
|
||||||
|
// nodes 0-1 will generate the wrong LCL (with tx 0). The remaining
|
||||||
|
// nodes will instead accept the ledger with tx 1.
|
||||||
|
|
||||||
|
// Nodes 0-1 will detect this mismatch during a subsequent round
|
||||||
|
// since nodes 2-4 will validate a different ledger.
|
||||||
|
|
||||||
|
// Nodes 0-1 will acquire the proper ledger from the network and
|
||||||
|
// resume consensus and eventually generate the dominant network ledger
|
||||||
|
|
||||||
|
std::vector<UNL> unls;
|
||||||
|
unls.push_back({2,3,4,5,6,7,8,9});
|
||||||
|
unls.push_back({0,1,2,3,4});
|
||||||
|
std::vector<int> membership(10,0);
|
||||||
|
membership[0] = 1;
|
||||||
|
membership[1] = 1;
|
||||||
|
|
||||||
|
TrustGraph tg{unls, membership};
|
||||||
|
|
||||||
|
// This topology can fork, which is why we are using it for this test.
|
||||||
|
BEAST_EXPECT(tg.canFork(minimumConsensusPercentage/100.));
|
||||||
|
|
||||||
|
auto netDelay = round<milliseconds>(0.2 * LEDGER_GRANULARITY);
|
||||||
|
Sim sim(tg, topology(tg, fixed{netDelay}));
|
||||||
|
|
||||||
|
// initial round to set prior state
|
||||||
|
sim.run(1);
|
||||||
|
|
||||||
|
// Nodes in smaller UNL have seen tx 0, nodes in other unl have seen tx 1
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
p.validationDelay = validationDelay;
|
||||||
|
p.missingLedgerDelay = netDelay;
|
||||||
|
if (unls[1].find(p.id) != unls[1].end())
|
||||||
|
p.openTxs.insert(Tx{0});
|
||||||
|
else
|
||||||
|
p.openTxs.insert(Tx{1});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run for 2 additional rounds
|
||||||
|
// - One round to generate different ledgers
|
||||||
|
// - One round to detect different prior ledgers (but still generate
|
||||||
|
// wrong ones) and recover
|
||||||
|
sim.run(2);
|
||||||
|
|
||||||
|
bc::flat_map<int, bc::flat_set<Ledger::ID>> ledgers;
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
for (auto const & l : p.ledgers)
|
||||||
|
{
|
||||||
|
ledgers[l.first.seq].insert(l.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_EXPECT(ledgers[0].size() == 1);
|
||||||
|
BEAST_EXPECT(ledgers[1].size() == 1);
|
||||||
|
BEAST_EXPECT(ledgers[2].size() == 2);
|
||||||
|
BEAST_EXPECT(ledgers[3].size() == 1);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testFork()
|
||||||
|
{
|
||||||
|
using namespace csf;
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
int numPeers = 10;
|
||||||
|
for(int overlap = 0; overlap <= numPeers; ++overlap)
|
||||||
|
{
|
||||||
|
auto tg = TrustGraph::makeClique(numPeers, overlap);
|
||||||
|
Sim sim(tg, topology(tg,
|
||||||
|
fixed{round<milliseconds>(0.2 * LEDGER_GRANULARITY)}));
|
||||||
|
|
||||||
|
// Initial round to set prior state
|
||||||
|
sim.run(1);
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
// Nodes have only seen transactions from their neighbors
|
||||||
|
p.openTxs.insert(Tx{p.id});
|
||||||
|
for(auto const link : sim.net.links(&p))
|
||||||
|
p.openTxs.insert(Tx{link.to->id});
|
||||||
|
}
|
||||||
|
sim.run(1);
|
||||||
|
|
||||||
|
|
||||||
|
// See if the network forked
|
||||||
|
bc::flat_set<Ledger::ID> ledgers;
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
ledgers.insert(p.LCL());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fork should not happen for 40% or greater overlap
|
||||||
|
// Since the overlapped nodes have a UNL that is the union of the
|
||||||
|
// two cliques, the maximum sized UNL list is the number of peers
|
||||||
|
if(overlap > 0.4 * numPeers)
|
||||||
|
BEAST_EXPECT(ledgers.size() == 1);
|
||||||
|
else // Even if we do fork, there shouldn't be more than 3 ledgers
|
||||||
|
// One for cliqueA, one for cliqueB and one for nodes in both
|
||||||
|
BEAST_EXPECT(ledgers.size() <= 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
simClockSkew()
|
||||||
|
{
|
||||||
|
using namespace csf;
|
||||||
|
|
||||||
|
// Attempting to test what happens if peers enter consensus well
|
||||||
|
// separated in time. Initial round (in which peers are not staggered)
|
||||||
|
// is used to get the network going, then transactions are submitted
|
||||||
|
// together and consensus continues.
|
||||||
|
|
||||||
|
// For all the times below, the same ledger is built but the close times
|
||||||
|
// disgree. BUT THE LEDGER DOES NOT SHOW disagreeing close times.
|
||||||
|
// It is probably because peer proposals are stale, so they get ignored
|
||||||
|
// but with no peer proposals, we always assume close time consensus is
|
||||||
|
// true.
|
||||||
|
|
||||||
|
// Disabled while continuing to understand testt.
|
||||||
|
|
||||||
|
|
||||||
|
for(auto stagger : {800ms, 1600ms, 3200ms, 30000ms, 45000ms, 300000ms})
|
||||||
|
{
|
||||||
|
|
||||||
|
auto tg = TrustGraph::makeComplete(5);
|
||||||
|
Sim sim(tg, topology(tg, [](PeerID i, PeerID)
|
||||||
|
{
|
||||||
|
return 200ms * (i + 1);
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
// all transactions submitted before starting
|
||||||
|
// Initial round to set prior state
|
||||||
|
sim.run(1);
|
||||||
|
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
p.openTxs.insert(Tx{ 0 });
|
||||||
|
p.targetLedgers = p.completedLedgers + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// stagger start of consensus
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
p.start();
|
||||||
|
sim.net.step_for(stagger);
|
||||||
|
}
|
||||||
|
|
||||||
|
// run until all peers have accepted all transactions
|
||||||
|
sim.net.step_while([&]()
|
||||||
|
{
|
||||||
|
for(auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
if(p.LCL().txs.size() != 1)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
simScaleFree()
|
||||||
|
{
|
||||||
|
using namespace std::chrono;
|
||||||
|
using namespace csf;
|
||||||
|
// Generate a quasi-random scale free network and simulate consensus
|
||||||
|
// for a single transaction
|
||||||
|
|
||||||
|
int N = 100; // Peers
|
||||||
|
|
||||||
|
int numUNLs = 15; // UNL lists
|
||||||
|
int minUNLSize = N/4, maxUNLSize = N / 2;
|
||||||
|
|
||||||
|
double transProb = 0.5;
|
||||||
|
|
||||||
|
std::mt19937_64 rng;
|
||||||
|
|
||||||
|
auto tg = TrustGraph::makeRandomRanked(N, numUNLs,
|
||||||
|
PowerLawDistribution{1,3},
|
||||||
|
std::uniform_int_distribution<>{minUNLSize, maxUNLSize},
|
||||||
|
rng);
|
||||||
|
|
||||||
|
Sim sim{tg, topology(tg, fixed{round<milliseconds>(0.2 * LEDGER_GRANULARITY)})};
|
||||||
|
|
||||||
|
// Initial round to set prior state
|
||||||
|
sim.run(1);
|
||||||
|
|
||||||
|
std::uniform_real_distribution<> u{};
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
// 50-50 chance to have seen a transaction
|
||||||
|
if(u(rng) >= transProb)
|
||||||
|
p.openTxs.insert(Tx{0});
|
||||||
|
|
||||||
|
}
|
||||||
|
sim.run(1);
|
||||||
|
|
||||||
|
|
||||||
|
// See if the network forked
|
||||||
|
bc::flat_set<Ledger::ID> ledgers;
|
||||||
|
for (auto & p : sim.peers)
|
||||||
|
{
|
||||||
|
ledgers.insert(p.LCL());
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_EXPECT(ledgers.size() == 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
run() override
|
||||||
|
{
|
||||||
|
testStandalone();
|
||||||
|
testPeersAgree();
|
||||||
|
testSlowPeer();
|
||||||
|
testCloseTimeDisagree();
|
||||||
|
testWrongLCL();
|
||||||
|
testFork();
|
||||||
|
|
||||||
|
simClockSkew();
|
||||||
|
simScaleFree();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(Consensus, consensus, ripple);
|
||||||
|
} // test
|
||||||
|
} // ripple
|
||||||
164
src/test/consensus/LedgerTiming_test.cpp
Normal file
164
src/test/consensus/LedgerTiming_test.cpp
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012-2016 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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
#include <BeastConfig.h>
|
||||||
|
#include <ripple/beast/unit_test.h>
|
||||||
|
#include <ripple/consensus/LedgerTiming.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
class LedgerTiming_test : public beast::unit_test::suite
|
||||||
|
{
|
||||||
|
beast::Journal j;
|
||||||
|
|
||||||
|
void testGetNextLedgerTimeResolution()
|
||||||
|
{
|
||||||
|
// helper to iteratively call into getNextLedgerTimeResolution
|
||||||
|
struct test_res
|
||||||
|
{
|
||||||
|
std::uint32_t decrease = 0;
|
||||||
|
std::uint32_t equal = 0;
|
||||||
|
std::uint32_t increase = 0;
|
||||||
|
|
||||||
|
static test_res run(bool previousAgree, std::uint32_t rounds)
|
||||||
|
{
|
||||||
|
test_res res;
|
||||||
|
auto closeResolution = ledgerDefaultTimeResolution;
|
||||||
|
auto nextCloseResolution = closeResolution;
|
||||||
|
std::uint32_t round = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
nextCloseResolution = getNextLedgerTimeResolution(
|
||||||
|
closeResolution, previousAgree, ++round);
|
||||||
|
if (nextCloseResolution < closeResolution)
|
||||||
|
++res.decrease;
|
||||||
|
else if (nextCloseResolution > closeResolution)
|
||||||
|
++res.increase;
|
||||||
|
else
|
||||||
|
++res.equal;
|
||||||
|
std::swap(nextCloseResolution, closeResolution);
|
||||||
|
} while (round < rounds);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// If we never agree on close time, only can increase resolution
|
||||||
|
// until hit the max
|
||||||
|
auto decreases = test_res::run(false, 10);
|
||||||
|
BEAST_EXPECT(decreases.increase == 3);
|
||||||
|
BEAST_EXPECT(decreases.decrease == 0);
|
||||||
|
BEAST_EXPECT(decreases.equal == 7);
|
||||||
|
|
||||||
|
// If we always agree on close time, only can decrease resolution
|
||||||
|
// until hit the min
|
||||||
|
auto increases = test_res::run(false, 100);
|
||||||
|
BEAST_EXPECT(increases.increase == 3);
|
||||||
|
BEAST_EXPECT(increases.decrease == 0);
|
||||||
|
BEAST_EXPECT(increases.equal == 97);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void testRoundCloseTime()
|
||||||
|
{
|
||||||
|
// A closeTime equal to the epoch is not modified
|
||||||
|
using tp = NetClock::time_point;
|
||||||
|
tp def;
|
||||||
|
BEAST_EXPECT(def == roundCloseTime(def, 30s));
|
||||||
|
|
||||||
|
// Otherwise, the closeTime is rounded to the nearest
|
||||||
|
// rounding up on ties
|
||||||
|
BEAST_EXPECT(tp{ 0s } == roundCloseTime(tp{ 29s }, 60s));
|
||||||
|
BEAST_EXPECT(tp{ 30s } == roundCloseTime(tp{ 30s }, 1s));
|
||||||
|
BEAST_EXPECT(tp{ 60s } == roundCloseTime(tp{ 31s }, 60s));
|
||||||
|
BEAST_EXPECT(tp{ 60s } == roundCloseTime(tp{ 30s }, 60s));
|
||||||
|
BEAST_EXPECT(tp{ 60s } == roundCloseTime(tp{ 59s }, 60s));
|
||||||
|
BEAST_EXPECT(tp{ 60s } == roundCloseTime(tp{ 60s }, 60s));
|
||||||
|
BEAST_EXPECT(tp{ 60s } == roundCloseTime(tp{ 61s }, 60s));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void testShouldCloseLedger()
|
||||||
|
{
|
||||||
|
// Bizarre times forcibly close
|
||||||
|
BEAST_EXPECT(shouldCloseLedger(true, 10, 10, 10, -10s, 10s, 1s, 1s, j));
|
||||||
|
BEAST_EXPECT(shouldCloseLedger(true, 10, 10, 10, 100h, 10s, 1s, 1s, j));
|
||||||
|
BEAST_EXPECT(shouldCloseLedger(true, 10, 10, 10, 10s, 100h, 1s, 1s, j));
|
||||||
|
|
||||||
|
// Rest of network has closed
|
||||||
|
BEAST_EXPECT(shouldCloseLedger(true, 10, 3, 5, 10s, 10s, 10s, 10s, j));
|
||||||
|
|
||||||
|
// No transactions means wait until end of internval
|
||||||
|
BEAST_EXPECT(!shouldCloseLedger(false, 10, 0, 0, 1s, 1s, 1s, 10s, j));
|
||||||
|
BEAST_EXPECT(shouldCloseLedger(false, 10, 0, 0, 1s, 10s, 1s, 10s, j));
|
||||||
|
|
||||||
|
// Enforce minimum ledger open time
|
||||||
|
BEAST_EXPECT(!shouldCloseLedger(true, 10, 0, 0, 10s, 10s, 1s, 10s, j));
|
||||||
|
|
||||||
|
// Don't go too much faster than last time
|
||||||
|
BEAST_EXPECT(!shouldCloseLedger(true, 10, 0, 0, 10s, 10s, 3s, 10s, j));
|
||||||
|
|
||||||
|
BEAST_EXPECT(shouldCloseLedger(true, 10, 0, 0, 10s, 10s, 10s, 10s, j));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void testCheckConsensus()
|
||||||
|
{
|
||||||
|
// Not enough time has elapsed
|
||||||
|
BEAST_EXPECT( ConsensusState::No
|
||||||
|
== checkConsensus(10, 2, 2, 0, 3s, 2s, true, j));
|
||||||
|
|
||||||
|
// If not enough peers have propsed, ensure
|
||||||
|
// more time for proposals
|
||||||
|
BEAST_EXPECT( ConsensusState::No
|
||||||
|
== checkConsensus(10, 2, 2, 0, 3s, 4s, true, j));
|
||||||
|
|
||||||
|
// Enough time has elapsed and we all agree
|
||||||
|
BEAST_EXPECT( ConsensusState::Yes
|
||||||
|
== checkConsensus(10, 2, 2, 0, 3s, 10s, true, j));
|
||||||
|
|
||||||
|
// Enough time has elapsed and we don't yet agree
|
||||||
|
BEAST_EXPECT( ConsensusState::No
|
||||||
|
== checkConsensus(10, 2, 1, 0, 3s, 10s, true, j));
|
||||||
|
|
||||||
|
// Our peers have moved on
|
||||||
|
// Enough time has elapsed and we all agree
|
||||||
|
BEAST_EXPECT( ConsensusState::MovedOn
|
||||||
|
== checkConsensus(10, 2, 1, 8, 3s, 10s, true, j));
|
||||||
|
|
||||||
|
// No peers makes it easy to agree
|
||||||
|
BEAST_EXPECT( ConsensusState::Yes
|
||||||
|
== checkConsensus(0, 0, 0, 0, 3s, 10s, true, j));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
run() override
|
||||||
|
{
|
||||||
|
testGetNextLedgerTimeResolution();
|
||||||
|
testRoundCloseTime();
|
||||||
|
testShouldCloseLedger();
|
||||||
|
testCheckConsensus();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(LedgerTiming, consensus, ripple);
|
||||||
|
} // test
|
||||||
|
} // ripple
|
||||||
26
src/test/csf.h
Normal file
26
src/test/csf.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <test/csf/Tx.h>
|
||||||
|
#include <test/csf/Ledger.h>
|
||||||
|
#include <test/csf/BasicNetwork.h>
|
||||||
|
#include <test/csf/Peer.h>
|
||||||
|
#include <test/csf/UNL.h>
|
||||||
|
#include <test/csf/Sim.h>
|
||||||
|
#include <test/csf/Peer.h>
|
||||||
@@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef RIPPLE_TEST_BASICNETWORK_H_INCLUDED
|
#ifndef RIPPLE_TEST_CSF_BASICNETWORK_H_INCLUDED
|
||||||
#define RIPPLE_TEST_BASICNETWORK_H_INCLUDED
|
#define RIPPLE_TEST_CSF_BASICNETWORK_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/basics/qalloc.h>
|
#include <ripple/basics/qalloc.h>
|
||||||
#include <ripple/beast/clock/manual_clock.h>
|
#include <ripple/beast/clock/manual_clock.h>
|
||||||
@@ -35,14 +35,13 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <random>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace test {
|
namespace test {
|
||||||
|
namespace csf {
|
||||||
/** Peer to peer network simulator.
|
/** Peer to peer network simulator.
|
||||||
|
|
||||||
The network is formed from a set of Peer objects representing
|
The network is formed from a set of Peer objects representing
|
||||||
@@ -73,8 +72,8 @@ namespace test {
|
|||||||
|
|
||||||
After creating the Peer set, constructing the network,
|
After creating the Peer set, constructing the network,
|
||||||
and establishing connections, the caller uses one or more
|
and establishing connections, the caller uses one or more
|
||||||
of the step, step_one, step_for, and step_until functions
|
of the step, step_one, step_for, step_until and step_while
|
||||||
to iterate the network,
|
functions to iterate the network,
|
||||||
|
|
||||||
Peer Requirements:
|
Peer Requirements:
|
||||||
|
|
||||||
@@ -263,7 +262,6 @@ private:
|
|||||||
// VFALCO This is an ugly wart, aged containers
|
// VFALCO This is an ugly wart, aged containers
|
||||||
// want a non-const reference to a clock.
|
// want a non-const reference to a clock.
|
||||||
clock_type mutable clock_;
|
clock_type mutable clock_;
|
||||||
std::mt19937_64 rng_;
|
|
||||||
std::unordered_map<Peer, links_type> links_;
|
std::unordered_map<Peer, links_type> links_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -272,10 +270,6 @@ public:
|
|||||||
|
|
||||||
BasicNetwork();
|
BasicNetwork();
|
||||||
|
|
||||||
/** A source of pseudo-random numbers. */
|
|
||||||
std::mt19937_64&
|
|
||||||
rng();
|
|
||||||
|
|
||||||
/** Return the allocator. */
|
/** Return the allocator. */
|
||||||
qalloc const&
|
qalloc const&
|
||||||
alloc() const;
|
alloc() const;
|
||||||
@@ -291,14 +285,6 @@ public:
|
|||||||
time_point
|
time_point
|
||||||
now() const;
|
now() const;
|
||||||
|
|
||||||
/** Return a random integer in range [0, n) */
|
|
||||||
std::size_t
|
|
||||||
rand (std::size_t n);
|
|
||||||
|
|
||||||
/** Return a random integer in range [first, last) */
|
|
||||||
std::size_t
|
|
||||||
rand (std::size_t first, std::size_t last);
|
|
||||||
|
|
||||||
/** Connect two peers.
|
/** Connect two peers.
|
||||||
|
|
||||||
The link is directed, with `from` establishing
|
The link is directed, with `from` establishing
|
||||||
@@ -447,6 +433,23 @@ public:
|
|||||||
bool
|
bool
|
||||||
step();
|
step();
|
||||||
|
|
||||||
|
/** Run the network while a condition is true.
|
||||||
|
|
||||||
|
Function takes no arguments and will be called
|
||||||
|
repeatedly after each message is processed to
|
||||||
|
decide whether to continue.
|
||||||
|
|
||||||
|
Effects:
|
||||||
|
|
||||||
|
The clock is advanced to the time
|
||||||
|
of the last delivered message.
|
||||||
|
|
||||||
|
@return `true` if any message was processed.
|
||||||
|
*/
|
||||||
|
template <class Function>
|
||||||
|
bool
|
||||||
|
step_while(Function && func);
|
||||||
|
|
||||||
/** Run the network until the specified time.
|
/** Run the network until the specified time.
|
||||||
|
|
||||||
Effects:
|
Effects:
|
||||||
@@ -683,14 +686,6 @@ BasicNetwork<Peer>::BasicNetwork()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Peer>
|
|
||||||
inline
|
|
||||||
std::mt19937_64&
|
|
||||||
BasicNetwork<Peer>::rng()
|
|
||||||
{
|
|
||||||
return rng_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Peer>
|
template <class Peer>
|
||||||
inline
|
inline
|
||||||
qalloc const&
|
qalloc const&
|
||||||
@@ -717,24 +712,6 @@ BasicNetwork<Peer>::now() const ->
|
|||||||
return clock_.now();
|
return clock_.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Peer>
|
|
||||||
inline
|
|
||||||
std::size_t
|
|
||||||
BasicNetwork<Peer>::rand(std::size_t n)
|
|
||||||
{
|
|
||||||
return std::uniform_int_distribution<
|
|
||||||
std::size_t>(0, n - 1)(rng_);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Peer>
|
|
||||||
inline
|
|
||||||
std::size_t
|
|
||||||
BasicNetwork<Peer>::rand(
|
|
||||||
std::size_t first, std::size_t last)
|
|
||||||
{
|
|
||||||
return first + rand(last - first);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Peer>
|
template <class Peer>
|
||||||
bool
|
bool
|
||||||
BasicNetwork<Peer>::connect(
|
BasicNetwork<Peer>::connect(
|
||||||
@@ -857,6 +834,17 @@ BasicNetwork<Peer>::step()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Peer>
|
||||||
|
template <class Function>
|
||||||
|
bool
|
||||||
|
BasicNetwork<Peer>::step_while(Function && f)
|
||||||
|
{
|
||||||
|
bool ran = false;
|
||||||
|
while (f() && step_one())
|
||||||
|
ran = true;
|
||||||
|
return ran;
|
||||||
|
}
|
||||||
|
|
||||||
template <class Peer>
|
template <class Peer>
|
||||||
bool
|
bool
|
||||||
BasicNetwork<Peer>::step_until(
|
BasicNetwork<Peer>::step_until(
|
||||||
@@ -922,6 +910,7 @@ BasicNetwork<Peer>::bfs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // csf
|
||||||
} // test
|
} // test
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <test/jtx/BasicNetwork.h>
|
#include <test/csf/BasicNetwork.h>
|
||||||
#include <ripple/beast/unit_test.h>
|
#include <ripple/beast/unit_test.h>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
|
|
||||||
class BasicNetwork_test : public beast::unit_test::suite
|
class BasicNetwork_test : public beast::unit_test::suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -87,8 +88,7 @@ public:
|
|||||||
pv.emplace_back(0);
|
pv.emplace_back(0);
|
||||||
pv.emplace_back(1);
|
pv.emplace_back(1);
|
||||||
pv.emplace_back(2);
|
pv.emplace_back(2);
|
||||||
BasicNetwork<Peer*> net;
|
csf::BasicNetwork<Peer*> net;
|
||||||
BEAST_EXPECT(net.rand(0, 1) == 0);
|
|
||||||
BEAST_EXPECT(! net.connect(&pv[0], &pv[0]));
|
BEAST_EXPECT(! net.connect(&pv[0], &pv[0]));
|
||||||
BEAST_EXPECT(net.connect(&pv[0], &pv[1], 1s));
|
BEAST_EXPECT(net.connect(&pv[0], &pv[1], 1s));
|
||||||
BEAST_EXPECT(net.connect(&pv[1], &pv[2], 1s));
|
BEAST_EXPECT(net.connect(&pv[1], &pv[2], 1s));
|
||||||
197
src/test/csf/Ledger.h
Normal file
197
src/test/csf/Ledger.h
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
#ifndef RIPPLE_TEST_CSF_LEDGER_H_INCLUDED
|
||||||
|
#define RIPPLE_TEST_CSF_LEDGER_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/basics/chrono.h>
|
||||||
|
#include <test/csf/Tx.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
namespace csf {
|
||||||
|
|
||||||
|
/** A ledger is a set of observed transactions and a sequence number
|
||||||
|
identifying the ledger.
|
||||||
|
|
||||||
|
Peers in the consensus process are trying to agree on a set of transactions
|
||||||
|
to include in a ledger. For unit testing, each transaction is a
|
||||||
|
single integer and the ledger is a set of observed integers. This means
|
||||||
|
future ledgers have prior ledgers as subsets, e.g.
|
||||||
|
|
||||||
|
Ledger 0 : {}
|
||||||
|
Ledger 1 : {1,4,5}
|
||||||
|
Ledger 2 : {1,2,4,5,10}
|
||||||
|
....
|
||||||
|
|
||||||
|
Tx - Integer
|
||||||
|
TxSet - Set of Tx
|
||||||
|
Ledger - Set of Tx and sequence number
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Ledger
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct ID
|
||||||
|
{
|
||||||
|
std::uint32_t seq = 0;
|
||||||
|
TxSetType txs = TxSetType{};
|
||||||
|
|
||||||
|
bool operator==(ID const & o) const
|
||||||
|
{
|
||||||
|
return seq == o.seq && txs == o.txs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(ID const & o) const
|
||||||
|
{
|
||||||
|
return !(*this == o);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(ID const & o) const
|
||||||
|
{
|
||||||
|
return std::tie(seq, txs) < std::tie(o.seq, o.txs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
auto const &
|
||||||
|
id() const
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
seq() const
|
||||||
|
{
|
||||||
|
return id_.seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
closeTimeResolution() const
|
||||||
|
{
|
||||||
|
return closeTimeResolution_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
closeAgree() const
|
||||||
|
{
|
||||||
|
return closeTimeAgree_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
closeTime() const
|
||||||
|
{
|
||||||
|
return closeTime_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
actualCloseTime() const
|
||||||
|
{
|
||||||
|
return actualCloseTime_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto
|
||||||
|
parentCloseTime() const
|
||||||
|
{
|
||||||
|
return parentCloseTime_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const &
|
||||||
|
parentID() const
|
||||||
|
{
|
||||||
|
return parentID_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value
|
||||||
|
getJson() const
|
||||||
|
{
|
||||||
|
Json::Value res(Json::objectValue);
|
||||||
|
res["seq"] = seq();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Apply the given transactions to this ledger
|
||||||
|
Ledger
|
||||||
|
close(TxSetType const & txs,
|
||||||
|
NetClock::duration closeTimeResolution,
|
||||||
|
NetClock::time_point const & consensusCloseTime,
|
||||||
|
bool closeTimeAgree) const
|
||||||
|
{
|
||||||
|
Ledger res{ *this };
|
||||||
|
res.id_.txs.insert(txs.begin(), txs.end());
|
||||||
|
res.id_ .seq= seq() + 1;
|
||||||
|
res.closeTimeResolution_ = closeTimeResolution;
|
||||||
|
res.actualCloseTime_ = consensusCloseTime;
|
||||||
|
res.closeTime_ = effectiveCloseTime(consensusCloseTime,
|
||||||
|
closeTimeResolution, parentCloseTime_);
|
||||||
|
res.closeTimeAgree_ = closeTimeAgree;
|
||||||
|
res.parentCloseTime_ = closeTime();
|
||||||
|
res.parentID_ = id();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//! Unique identifier of ledger is combination of sequence number and id
|
||||||
|
ID id_;
|
||||||
|
|
||||||
|
//! Bucket resolution used to determine close time
|
||||||
|
NetClock::duration closeTimeResolution_ = ledgerDefaultTimeResolution;
|
||||||
|
|
||||||
|
//! When the ledger closed
|
||||||
|
NetClock::time_point closeTime_;
|
||||||
|
|
||||||
|
//! Whether consenssus agreed on the close time
|
||||||
|
bool closeTimeAgree_ = true;
|
||||||
|
|
||||||
|
//! Parent ledger id
|
||||||
|
ID parentID_;
|
||||||
|
|
||||||
|
//! Parent ledger close time
|
||||||
|
NetClock::time_point parentCloseTime_;
|
||||||
|
|
||||||
|
//! Close time unadjusted by closeTimeResolution
|
||||||
|
NetClock::time_point actualCloseTime_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
std::ostream &
|
||||||
|
operator<<(std::ostream & o, Ledger::ID const & id)
|
||||||
|
{
|
||||||
|
return o << id.seq << "," << id.txs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
std::string
|
||||||
|
to_string(Ledger::ID const & id)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << id;
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // csf
|
||||||
|
} // test
|
||||||
|
} // ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
492
src/test/csf/Peer.h
Normal file
492
src/test/csf/Peer.h
Normal file
@@ -0,0 +1,492 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
#ifndef RIPPLE_TEST_CSF_PEER_H_INCLUDED
|
||||||
|
#define RIPPLE_TEST_CSF_PEER_H_INCLUDED
|
||||||
|
|
||||||
|
#include <boost/container/flat_map.hpp>
|
||||||
|
#include <boost/container/flat_set.hpp>
|
||||||
|
|
||||||
|
#include <test/csf/Tx.h>
|
||||||
|
#include <test/csf/Ledger.h>
|
||||||
|
#include <test/csf/UNL.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
namespace csf {
|
||||||
|
|
||||||
|
|
||||||
|
/** Store validations reached by peers */
|
||||||
|
struct Validation
|
||||||
|
{
|
||||||
|
PeerID id;
|
||||||
|
Ledger::ID ledger;
|
||||||
|
Ledger::ID prevLedger;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace bc = boost::container;
|
||||||
|
|
||||||
|
class Validations
|
||||||
|
{
|
||||||
|
//< Ledgers seen by peers, saved in order received (which should be order
|
||||||
|
//< created)
|
||||||
|
bc::flat_map<Ledger::ID, bc::flat_set<PeerID>> nodesFromLedger;
|
||||||
|
bc::flat_map<Ledger::ID, bc::flat_set<PeerID>> nodesFromPrevLedger;
|
||||||
|
bc::flat_map<Ledger::ID, bc::flat_map<Ledger::ID, std::size_t>> childLedgers;
|
||||||
|
public:
|
||||||
|
void
|
||||||
|
update(Validation const & v)
|
||||||
|
{
|
||||||
|
nodesFromLedger[v.ledger].insert(v.id);
|
||||||
|
if(v.ledger.seq > 0)
|
||||||
|
{
|
||||||
|
nodesFromPrevLedger[v.prevLedger].insert(v.id);
|
||||||
|
childLedgers[v.prevLedger][v.ledger]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//< The number of peers who have validated this ledger
|
||||||
|
std::size_t
|
||||||
|
proposersValidated(Ledger::ID const & prevLedger) const
|
||||||
|
{
|
||||||
|
auto it = nodesFromLedger.find(prevLedger);
|
||||||
|
if(it != nodesFromLedger.end())
|
||||||
|
return it->second.size();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The number of peers that are past this ledger, i.e.
|
||||||
|
they have a newer most recent ledger, but have this ledger
|
||||||
|
as an ancestor.
|
||||||
|
*/
|
||||||
|
std::size_t
|
||||||
|
proposersFinished(Ledger::ID const & prevLedger) const
|
||||||
|
{
|
||||||
|
auto it = nodesFromPrevLedger.find(prevLedger);
|
||||||
|
if(it != nodesFromPrevLedger.end())
|
||||||
|
return it->second.size();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the ledger starting from prevLedger with the most validations.
|
||||||
|
*/
|
||||||
|
Ledger::ID
|
||||||
|
getBestLCL(Ledger::ID const & currLedger,
|
||||||
|
Ledger::ID const & prevLedger) const
|
||||||
|
{
|
||||||
|
auto it = childLedgers.find(prevLedger);
|
||||||
|
if (it != childLedgers.end() &&
|
||||||
|
! it->second.empty())
|
||||||
|
{
|
||||||
|
std::size_t bestCount = 0;
|
||||||
|
Ledger::ID bestLedger;
|
||||||
|
|
||||||
|
for (auto const & b : it->second)
|
||||||
|
{
|
||||||
|
auto currCount = b.second;
|
||||||
|
if(currLedger == b.first)
|
||||||
|
currCount++;
|
||||||
|
if(currCount > bestCount)
|
||||||
|
bestLedger = b.first;
|
||||||
|
if(currCount == bestCount && currLedger == b.first)
|
||||||
|
bestLedger = b.first;
|
||||||
|
}
|
||||||
|
return bestLedger;
|
||||||
|
}
|
||||||
|
return currLedger;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Proposal is a position taken in the consensus process and is represented
|
||||||
|
directly from the generic types.
|
||||||
|
*/
|
||||||
|
using Proposal = ConsensusProposal<PeerID, Ledger::ID, TxSetType>;
|
||||||
|
|
||||||
|
struct Traits
|
||||||
|
{
|
||||||
|
using Ledger_t = Ledger;
|
||||||
|
using NodeID_t = PeerID;
|
||||||
|
using TxSet_t = TxSet;
|
||||||
|
using MissingTxException_t = MissingTx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Represents a single node participating in the consensus process.
|
||||||
|
It implements the Callbacks required by Consensus.
|
||||||
|
*/
|
||||||
|
struct Peer : public Consensus<Peer, Traits>
|
||||||
|
{
|
||||||
|
using Base = Consensus<Peer, Traits>;
|
||||||
|
|
||||||
|
//! Our unique ID
|
||||||
|
PeerID id;
|
||||||
|
|
||||||
|
//! openTxs that haven't been closed in a ledger yet
|
||||||
|
TxSetType openTxs;
|
||||||
|
|
||||||
|
//! last ledger this peer closed
|
||||||
|
Ledger lastClosedLedger;
|
||||||
|
|
||||||
|
//! Handle to network for sending messages
|
||||||
|
BasicNetwork<Peer*> & net;
|
||||||
|
|
||||||
|
//! UNL of trusted peers
|
||||||
|
UNL unl;
|
||||||
|
|
||||||
|
//! Most recent ledger completed by peers
|
||||||
|
Validations peerValidations;
|
||||||
|
|
||||||
|
// The ledgers, proposals, TxSets and Txs this peer has seen
|
||||||
|
bc::flat_map<Ledger::ID, Ledger> ledgers;
|
||||||
|
|
||||||
|
//! Map from Ledger::ID to vector of Positions with that ledger
|
||||||
|
//! as the prior ledger
|
||||||
|
bc::flat_map<Ledger::ID, std::vector<Proposal>> peerPositions_;
|
||||||
|
bc::flat_map<TxSet::ID, TxSet> txSets;
|
||||||
|
|
||||||
|
int completedLedgers = 0;
|
||||||
|
int targetLedgers = std::numeric_limits<int>::max();
|
||||||
|
|
||||||
|
//! Skew samples from the network clock; to be refactored into a
|
||||||
|
//! clock time once it is provided separately from the network.
|
||||||
|
std::chrono::seconds clockSkew{0};
|
||||||
|
|
||||||
|
//! Delay in processing validations from remote peers
|
||||||
|
std::chrono::milliseconds validationDelay{0};
|
||||||
|
|
||||||
|
//! Delay in acquiring missing ledger from the network
|
||||||
|
std::chrono::milliseconds missingLedgerDelay{0};
|
||||||
|
|
||||||
|
bool validating = true;
|
||||||
|
bool proposing = true;
|
||||||
|
|
||||||
|
//! All peers start from the default constructed ledger
|
||||||
|
Peer(PeerID i, BasicNetwork<Peer*> & n, UNL const & u)
|
||||||
|
: Consensus<Peer, Traits>( n.clock(), beast::Journal{})
|
||||||
|
, id{i}
|
||||||
|
, net{n}
|
||||||
|
, unl(u)
|
||||||
|
{
|
||||||
|
ledgers[lastClosedLedger.id()] = lastClosedLedger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// @return whether we are proposing,validating
|
||||||
|
// TODO: Bit akward that this is in callbacks, would be nice to extract
|
||||||
|
std::pair<bool, bool>
|
||||||
|
getMode()
|
||||||
|
{
|
||||||
|
// in RCL this hits NetworkOps to decide whether we are proposing
|
||||||
|
// validating
|
||||||
|
return{ proposing, validating };
|
||||||
|
}
|
||||||
|
|
||||||
|
Ledger const *
|
||||||
|
acquireLedger(Ledger::ID const & ledgerHash)
|
||||||
|
{
|
||||||
|
auto it = ledgers.find(ledgerHash);
|
||||||
|
if (it != ledgers.end())
|
||||||
|
return &(it->second);
|
||||||
|
|
||||||
|
// TODO Get from network/oracle properly!
|
||||||
|
|
||||||
|
for (auto const& link : net.links(this))
|
||||||
|
{
|
||||||
|
auto const & p = *link.to;
|
||||||
|
auto it = p.ledgers.find(ledgerHash);
|
||||||
|
if (it != p.ledgers.end())
|
||||||
|
{
|
||||||
|
schedule(missingLedgerDelay,
|
||||||
|
[this, ledgerHash, ledger = it->second]()
|
||||||
|
{
|
||||||
|
ledgers.emplace(ledgerHash, ledger);
|
||||||
|
});
|
||||||
|
if(missingLedgerDelay == 0ms)
|
||||||
|
return &ledgers[ledgerHash];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const &
|
||||||
|
proposals(Ledger::ID const & ledgerHash)
|
||||||
|
{
|
||||||
|
return peerPositions_[ledgerHash];
|
||||||
|
}
|
||||||
|
|
||||||
|
TxSet const *
|
||||||
|
acquireTxSet(TxSet::ID const & setId)
|
||||||
|
{
|
||||||
|
auto it = txSets.find(setId);
|
||||||
|
if(it != txSets.end())
|
||||||
|
return &(it->second);
|
||||||
|
// TODO Get from network/oracle instead!
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
hasOpenTransactions() const
|
||||||
|
{
|
||||||
|
return !openTxs.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
proposersValidated(Ledger::ID const & prevLedger)
|
||||||
|
{
|
||||||
|
return peerValidations.proposersValidated(prevLedger);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
proposersFinished(Ledger::ID const & prevLedger)
|
||||||
|
{
|
||||||
|
return peerValidations.proposersFinished(prevLedger);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
onStartRound(Ledger const &) {}
|
||||||
|
|
||||||
|
void
|
||||||
|
onClose(Ledger const &, bool ) {}
|
||||||
|
|
||||||
|
// don't really offload
|
||||||
|
void
|
||||||
|
dispatchAccept(TxSet const & f)
|
||||||
|
{
|
||||||
|
Base::accept(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
share(TxSet const &s)
|
||||||
|
{
|
||||||
|
relay(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ledger::ID
|
||||||
|
getLCL(Ledger::ID const & currLedger,
|
||||||
|
Ledger::ID const & priorLedger,
|
||||||
|
bool haveCorrectLCL)
|
||||||
|
{
|
||||||
|
// TODO: Use generic validation code
|
||||||
|
if(currLedger.seq > 0 && priorLedger.seq > 0)
|
||||||
|
return peerValidations.getBestLCL(currLedger, priorLedger);
|
||||||
|
return currLedger;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
propose(Proposal const & pos)
|
||||||
|
{
|
||||||
|
if(proposing)
|
||||||
|
relay(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
relay(DisputedTx<Tx, PeerID> const & dispute)
|
||||||
|
{
|
||||||
|
relay(dispute.tx());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair <TxSet, Proposal>
|
||||||
|
makeInitialPosition(
|
||||||
|
Ledger const & prevLedger,
|
||||||
|
bool isProposing,
|
||||||
|
bool isCorrectLCL,
|
||||||
|
NetClock::time_point closeTime,
|
||||||
|
NetClock::time_point now)
|
||||||
|
{
|
||||||
|
TxSet res{ openTxs };
|
||||||
|
|
||||||
|
return { res,
|
||||||
|
Proposal{prevLedger.id(), Proposal::seqJoin, res.id(), closeTime, now, id} };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the accepted transaction set, generating the newly closed ledger
|
||||||
|
// and clearing out the openTxs that were included.
|
||||||
|
// TODO: Kinda nasty it takes so many arguments . . . sign of bad coupling
|
||||||
|
bool
|
||||||
|
accept(TxSet const& set,
|
||||||
|
NetClock::time_point consensusCloseTime,
|
||||||
|
bool proposing_,
|
||||||
|
bool validating_,
|
||||||
|
bool haveCorrectLCL_,
|
||||||
|
bool consensusFail_,
|
||||||
|
Ledger::ID const & prevLedgerHash_,
|
||||||
|
Ledger const & previousLedger_,
|
||||||
|
NetClock::duration closeResolution_,
|
||||||
|
NetClock::time_point const & now,
|
||||||
|
std::chrono::milliseconds const & roundTime_,
|
||||||
|
hash_map<Tx::ID, DisputedTx <Tx, PeerID>> const & disputes_,
|
||||||
|
std::map <NetClock::time_point, int> closeTimes_,
|
||||||
|
NetClock::time_point const & closeTime)
|
||||||
|
{
|
||||||
|
auto newLedger = previousLedger_.close(set.txs_, closeResolution_,
|
||||||
|
closeTime, consensusCloseTime != NetClock::time_point{});
|
||||||
|
ledgers[newLedger.id()] = newLedger;
|
||||||
|
|
||||||
|
lastClosedLedger = newLedger;
|
||||||
|
|
||||||
|
auto it = std::remove_if(openTxs.begin(), openTxs.end(),
|
||||||
|
[&](Tx const & tx)
|
||||||
|
{
|
||||||
|
return set.exists(tx.id());
|
||||||
|
});
|
||||||
|
openTxs.erase(it, openTxs.end());
|
||||||
|
|
||||||
|
if(validating)
|
||||||
|
relay(Validation{id, newLedger.id(), newLedger.parentID()});
|
||||||
|
return validating_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
endConsensus(bool correct)
|
||||||
|
{
|
||||||
|
// kick off the next round...
|
||||||
|
// in the actual implementation, this passes back through
|
||||||
|
// network ops
|
||||||
|
++completedLedgers;
|
||||||
|
// startRound sets the LCL state, so we need to call it once after
|
||||||
|
// the last requested round completes
|
||||||
|
// TODO: reconsider this and instead just save LCL generated here?
|
||||||
|
if(completedLedgers <= targetLedgers)
|
||||||
|
{
|
||||||
|
startRound(now(), lastClosedLedger.id(),
|
||||||
|
lastClosedLedger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// non-callback helpers
|
||||||
|
void
|
||||||
|
receive(Proposal const & p)
|
||||||
|
{
|
||||||
|
if(unl.find(p.nodeID()) == unl.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: Be sure this is a new proposal!!!!!
|
||||||
|
auto & dest = peerPositions_[p.prevLedger()];
|
||||||
|
if(std::find(dest.begin(), dest.end(), p) != dest.end())
|
||||||
|
return;
|
||||||
|
dest.push_back(p);
|
||||||
|
peerProposal(now(), p);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
receive(TxSet const & txs)
|
||||||
|
{
|
||||||
|
// save and map complete?
|
||||||
|
auto it = txSets.insert(std::make_pair(txs.id(), txs));
|
||||||
|
if(it.second)
|
||||||
|
gotTxSet(now(), txs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
receive(Tx const & tx)
|
||||||
|
{
|
||||||
|
if (openTxs.find(tx.id()) == openTxs.end())
|
||||||
|
{
|
||||||
|
openTxs.insert(tx);
|
||||||
|
// relay to peers???
|
||||||
|
relay(tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
receive(Validation const & v)
|
||||||
|
{
|
||||||
|
if(unl.find(v.id) != unl.end())
|
||||||
|
{
|
||||||
|
schedule(validationDelay,
|
||||||
|
[&, v]()
|
||||||
|
{
|
||||||
|
peerValidations.update(v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
relay(T const & t)
|
||||||
|
{
|
||||||
|
for(auto const& link : net.links(this))
|
||||||
|
net.send(this, link.to,
|
||||||
|
[msg = t, to = link.to]
|
||||||
|
{
|
||||||
|
to->receive(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive and relay locally submitted transaction
|
||||||
|
void
|
||||||
|
submit(Tx const & tx)
|
||||||
|
{
|
||||||
|
receive(tx);
|
||||||
|
relay(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
timerEntry()
|
||||||
|
{
|
||||||
|
Base::timerEntry(now());
|
||||||
|
// only reschedule if not completed
|
||||||
|
if(completedLedgers < targetLedgers)
|
||||||
|
net.timer(LEDGER_GRANULARITY, [&]() { timerEntry(); });
|
||||||
|
}
|
||||||
|
void
|
||||||
|
start()
|
||||||
|
{
|
||||||
|
net.timer(LEDGER_GRANULARITY, [&]() { timerEntry(); });
|
||||||
|
// The ID is the one we have seen the most validations for
|
||||||
|
// In practice, we might not actually have that ledger itself yet,
|
||||||
|
// so there is no gaurantee that bestLCL == lastClosedLedger.id()
|
||||||
|
auto bestLCL = peerValidations.getBestLCL(lastClosedLedger.id(),
|
||||||
|
lastClosedLedger.parentID());
|
||||||
|
startRound(now(), bestLCL,
|
||||||
|
lastClosedLedger);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetClock::time_point
|
||||||
|
now() const
|
||||||
|
{
|
||||||
|
// We don't care about the actual epochs, but do want the
|
||||||
|
// generated NetClock time to be well past its epoch to ensure
|
||||||
|
// any subtractions of two NetClock::time_point in the consensu
|
||||||
|
// code are positive. (e.g. PROPOSE_FRESHNESS)
|
||||||
|
using namespace std::chrono;
|
||||||
|
return NetClock::time_point(duration_cast<NetClock::duration>
|
||||||
|
(net.now().time_since_epoch()+ 86400s + clockSkew));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule the provided callback in `when` duration, but if
|
||||||
|
// `when` is 0, call immediately
|
||||||
|
template <class T>
|
||||||
|
void schedule(std::chrono::nanoseconds when, T && what)
|
||||||
|
{
|
||||||
|
if(when == 0ns)
|
||||||
|
what();
|
||||||
|
else
|
||||||
|
net.timer(when, std::forward<T>(what));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // csf
|
||||||
|
} // test
|
||||||
|
} // ripple
|
||||||
|
#endif
|
||||||
104
src/test/csf/Sim.h
Normal file
104
src/test/csf/Sim.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_TEST_CSF_SIM_H_INCLUDED
|
||||||
|
#define RIPPLE_TEST_CSF_SIM_H_INCLUDED
|
||||||
|
|
||||||
|
#include <test/csf/UNL.h>
|
||||||
|
#include <test/csf/BasicNetwork.h>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
namespace csf {
|
||||||
|
|
||||||
|
class Sim
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Create a simulator for the given trust graph and network topology.
|
||||||
|
|
||||||
|
Create a simulator for consensus over the given trust graph and connect
|
||||||
|
the network links between nodes based on the provided topology.
|
||||||
|
|
||||||
|
Topology is is a functor with signature
|
||||||
|
|
||||||
|
boost::optional<std::chrono::duration> (NodeId i, NodeId j)
|
||||||
|
|
||||||
|
that returns the delay sending messages from node i to node j.
|
||||||
|
|
||||||
|
In general, this network graph is distinct from the trust graph, but
|
||||||
|
users can use adaptors to present a TrustGraph as a Topology by
|
||||||
|
specifying the delay between nodes.
|
||||||
|
|
||||||
|
@param g The trust graph between peers.
|
||||||
|
@param top The network topology between peers.
|
||||||
|
|
||||||
|
*/
|
||||||
|
template <class Topology>
|
||||||
|
Sim(TrustGraph const & g, Topology const & top)
|
||||||
|
{
|
||||||
|
peers.reserve(g.numPeers());
|
||||||
|
for(int i = 0; i < g.numPeers(); ++i)
|
||||||
|
peers.emplace_back(i, net, g.unl(i));
|
||||||
|
|
||||||
|
for(int i = 0; i < peers.size(); ++i)
|
||||||
|
{
|
||||||
|
for(int j = 0; j < peers.size(); ++j)
|
||||||
|
{
|
||||||
|
if( i != j)
|
||||||
|
{
|
||||||
|
auto d = top(i,j);
|
||||||
|
if (d)
|
||||||
|
{
|
||||||
|
net.connect(&peers[i], &peers[j], *d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Run consensus protocol to generate the provided number of ledgers.
|
||||||
|
|
||||||
|
Has each peer run consensus until it creates `ledgers` more ledgers.
|
||||||
|
|
||||||
|
@param ledgers The number of additional ledgers to create
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
run(int ledgers)
|
||||||
|
{
|
||||||
|
for (auto & p : peers)
|
||||||
|
{
|
||||||
|
if(p.completedLedgers == 0)
|
||||||
|
p.relay(Validation{p.id, p.LCL(), p.LCL()});
|
||||||
|
p.targetLedgers = p.completedLedgers + ledgers;
|
||||||
|
p.start();
|
||||||
|
}
|
||||||
|
net.step();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Peer> peers;
|
||||||
|
BasicNetwork<Peer*> net;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // csf
|
||||||
|
} // test
|
||||||
|
} // ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
221
src/test/csf/Tx.h
Normal file
221
src/test/csf/Tx.h
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
#ifndef RIPPLE_TEST_CSF_TX_H_INCLUDED
|
||||||
|
#define RIPPLE_TEST_CSF_TX_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/beast/hash/hash_append.h>
|
||||||
|
#include <boost/container/flat_set.hpp>
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
namespace csf {
|
||||||
|
|
||||||
|
//! A single transaction
|
||||||
|
class Tx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using ID = std::uint32_t;
|
||||||
|
|
||||||
|
Tx(ID i) : id_{ i } {}
|
||||||
|
|
||||||
|
ID
|
||||||
|
id() const
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator<(Tx const & o) const
|
||||||
|
{
|
||||||
|
return id_ < o.id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(Tx const & o) const
|
||||||
|
{
|
||||||
|
return id_ == o.id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
ID id_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//!-------------------------------------------------------------------------
|
||||||
|
//! All sets of Tx are represented as a flat_set.
|
||||||
|
using TxSetType = boost::container::flat_set<Tx>;
|
||||||
|
|
||||||
|
//! TxSet is a set of transactions to consider including in the ledger
|
||||||
|
class TxSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using ID = TxSetType;
|
||||||
|
using Tx = csf::Tx;
|
||||||
|
using MutableTxSet = TxSet;
|
||||||
|
|
||||||
|
TxSet() = default;
|
||||||
|
TxSet(TxSetType const & s) : txs_{ s } {}
|
||||||
|
|
||||||
|
bool
|
||||||
|
insert(Tx const & t)
|
||||||
|
{
|
||||||
|
return txs_.insert(t).second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
erase(Tx::ID const & txId)
|
||||||
|
{
|
||||||
|
return txs_.erase(Tx{ txId }) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
exists(Tx::ID const txId) const
|
||||||
|
{
|
||||||
|
auto it = txs_.find(Tx{ txId });
|
||||||
|
return it != txs_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
Tx const *
|
||||||
|
find(Tx::ID const& txId) const
|
||||||
|
{
|
||||||
|
auto it = txs_.find(Tx{ txId });
|
||||||
|
if (it != txs_.end())
|
||||||
|
return &(*it);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const &
|
||||||
|
id() const
|
||||||
|
{
|
||||||
|
return txs_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return Map of Tx::ID that are missing. True means
|
||||||
|
it was in this set and not other. False means
|
||||||
|
it was in the other set and not this
|
||||||
|
*/
|
||||||
|
std::map<Tx::ID, bool>
|
||||||
|
compare(TxSet const& other) const
|
||||||
|
{
|
||||||
|
std::map<Tx::ID, bool> res;
|
||||||
|
|
||||||
|
auto populate_diffs = [&res](auto const & a, auto const & b, bool s)
|
||||||
|
{
|
||||||
|
auto populator = [&](auto const & tx)
|
||||||
|
{
|
||||||
|
res[tx.id()] = s;
|
||||||
|
};
|
||||||
|
std::set_difference(
|
||||||
|
a.begin(), a.end(),
|
||||||
|
b.begin(), b.end(),
|
||||||
|
boost::make_function_output_iterator(
|
||||||
|
std::ref(populator)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
populate_diffs(txs_, other.txs_, true);
|
||||||
|
populate_diffs(other.txs_, txs_, false);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! The set contains the actual transactions
|
||||||
|
TxSetType txs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** The RCL consensus process catches missing node SHAMap error
|
||||||
|
in several points. This exception is meant to represent a similar
|
||||||
|
case for the unit test.
|
||||||
|
*/
|
||||||
|
class MissingTx : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MissingTx()
|
||||||
|
: std::runtime_error("MissingTx")
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Helper functions for debug printing
|
||||||
|
|
||||||
|
inline
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream & o, const Tx & t)
|
||||||
|
{
|
||||||
|
return o << t.id();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream & o, boost::container::flat_set<T> const & ts)
|
||||||
|
{
|
||||||
|
o << "{ ";
|
||||||
|
bool do_comma = false;
|
||||||
|
for (auto const & t : ts)
|
||||||
|
{
|
||||||
|
if (do_comma)
|
||||||
|
o << ", ";
|
||||||
|
else
|
||||||
|
do_comma = true;
|
||||||
|
o << t;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
o << " }";
|
||||||
|
return o;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
std::string
|
||||||
|
to_string(TxSetType const & txs)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << txs;
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Hasher>
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
hash_append(Hasher& h, Tx const & tx)
|
||||||
|
{
|
||||||
|
using beast::hash_append;
|
||||||
|
hash_append(h, tx.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream & o, MissingTx const &m)
|
||||||
|
{
|
||||||
|
return o << m.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // csf
|
||||||
|
} // test
|
||||||
|
} // ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
277
src/test/csf/UNL.h
Normal file
277
src/test/csf/UNL.h
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef RIPPLE_TEST_CSF_UNL_H_INCLUDED
|
||||||
|
#define RIPPLE_TEST_CSF_UNL_H_INCLUDED
|
||||||
|
|
||||||
|
#include <boost/container/flat_set.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include <random>
|
||||||
|
#include <numeric>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
namespace csf {
|
||||||
|
|
||||||
|
/** Return a randomly shuffled copy of vector based on weights w.
|
||||||
|
|
||||||
|
@param v The set of values
|
||||||
|
@param w The set of weights of each value
|
||||||
|
@param g A pseudo-random number generator
|
||||||
|
@return A vector with entries randomly sampled without replacement
|
||||||
|
from the original vector based on the provided weights.
|
||||||
|
I.e. res[0] comes from sample v[i] with weight w[i]/sum_k w[k]
|
||||||
|
*/
|
||||||
|
template <class T, class G>
|
||||||
|
std::vector<T>
|
||||||
|
random_weighted_shuffle(std::vector<T> v, std::vector<double> w, G & g)
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
|
||||||
|
for (int i = 0; i < v.size() - 1; ++i)
|
||||||
|
{
|
||||||
|
// pick a random item weighted by w
|
||||||
|
std::discrete_distribution<> dd(w.begin() + i, w.end());
|
||||||
|
auto idx = dd(g);
|
||||||
|
std::swap(v[i], v[idx]);
|
||||||
|
std::swap(w[i], w[idx]);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Power-law distribution with PDF
|
||||||
|
|
||||||
|
P(x) = (x/xmin)^-a
|
||||||
|
|
||||||
|
for a >= 1 and xmin >= 1
|
||||||
|
*/
|
||||||
|
class PowerLawDistribution
|
||||||
|
{
|
||||||
|
double xmin_;
|
||||||
|
double a_;
|
||||||
|
double inv_;
|
||||||
|
std::uniform_real_distribution<double> uf_{0,1};
|
||||||
|
|
||||||
|
public:
|
||||||
|
PowerLawDistribution(double xmin, double a)
|
||||||
|
: xmin_{xmin}, a_{a}
|
||||||
|
{
|
||||||
|
inv_ = 1.0/(1.0 - a_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Generator>
|
||||||
|
inline
|
||||||
|
double
|
||||||
|
operator()(Generator & g)
|
||||||
|
{
|
||||||
|
// use inverse transform of CDF to sample
|
||||||
|
// CDF is P(X <= x): 1 - (x/xmin)^(1-a)
|
||||||
|
return xmin_ * std::pow(1 - uf_(g), inv_);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//< Unique identifier for each node in the network
|
||||||
|
using PeerID = std::uint32_t;
|
||||||
|
|
||||||
|
//< A unique node list defines a set of trusted peers used in consensus
|
||||||
|
using UNL = boost::container::flat_set<PeerID>;
|
||||||
|
|
||||||
|
/** Trust graph defining the consensus simulation
|
||||||
|
|
||||||
|
Trust is a directed relationship from a node i to node j.
|
||||||
|
If node i trusts node j, then node i has node j in its UNL.
|
||||||
|
|
||||||
|
Note that each node implicitly trusts itself but that need not be
|
||||||
|
explicitly modeled, e.g. UNLS[assignment
|
||||||
|
*/
|
||||||
|
class TrustGraph
|
||||||
|
{
|
||||||
|
//< Unique UNLs for the network
|
||||||
|
std::vector<UNL> UNLs_;
|
||||||
|
|
||||||
|
std::vector<int> assignment_;
|
||||||
|
public:
|
||||||
|
|
||||||
|
//< Constructor
|
||||||
|
TrustGraph(std::vector<UNL> UNLs, std::vector<int> assignment)
|
||||||
|
: UNLs_{UNLs}
|
||||||
|
, assignment_{assignment}
|
||||||
|
{}
|
||||||
|
|
||||||
|
//< Whether node `i` trusts node `j`
|
||||||
|
inline
|
||||||
|
bool
|
||||||
|
trusts(PeerID i, PeerID j) const
|
||||||
|
{
|
||||||
|
return unl(i).find(j) != unl(i).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
//< Get the UNL for node `i`
|
||||||
|
inline
|
||||||
|
UNL const &
|
||||||
|
unl(PeerID i) const
|
||||||
|
{
|
||||||
|
return UNLs_[assignment_[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
//< Check whether this trust graph satisfies the no forking condition
|
||||||
|
bool
|
||||||
|
canFork(double quorum) const;
|
||||||
|
|
||||||
|
|
||||||
|
auto
|
||||||
|
numPeers() const
|
||||||
|
{
|
||||||
|
return assignment_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
//< Save grapviz dot file reprentation of the trust graph
|
||||||
|
void
|
||||||
|
save_dot(std::string const & fileName);
|
||||||
|
|
||||||
|
/** Generate a random trust graph based on random ranking of peers
|
||||||
|
|
||||||
|
Generate a random trust graph by
|
||||||
|
|
||||||
|
1. Randomly ranking the peers acording to RankPDF
|
||||||
|
2. Generating `numUNL` random UNLs by sampling without replacement
|
||||||
|
from the ranked nodes.
|
||||||
|
3. Restricting the size of the random UNLs according to SizePDF
|
||||||
|
|
||||||
|
@param size The number of nodes in the trust graph
|
||||||
|
@param numUNLs The number of UNLs to create
|
||||||
|
@param rankPDF Generates random positive real numbers to use as ranks
|
||||||
|
@param unlSizePDF Generates random integeres between (0,size-1) to
|
||||||
|
restrict the size of generated PDF
|
||||||
|
@param Generator The uniform random bit generator to use
|
||||||
|
|
||||||
|
@note RankPDF/SizePDF can model the full RandomDistribution concept
|
||||||
|
defined in the STL, but for the purposes of this function need
|
||||||
|
only provide:
|
||||||
|
|
||||||
|
auto operator()(Generator & g)
|
||||||
|
|
||||||
|
which should return the random sample.
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
template <class RankPDF, class SizePDF, class Generator>
|
||||||
|
static
|
||||||
|
TrustGraph
|
||||||
|
makeRandomRanked(int size,
|
||||||
|
int numUNLs,
|
||||||
|
RankPDF rankPDF,
|
||||||
|
SizePDF unlSizePDF,
|
||||||
|
Generator & g)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// 1. Generate ranks
|
||||||
|
std::vector<double> weights(size);
|
||||||
|
std::generate(weights.begin(), weights.end(), [&]()
|
||||||
|
{
|
||||||
|
return rankPDF(g);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Generate UNLs based on sampling without replacement according
|
||||||
|
// to weights
|
||||||
|
std::vector<UNL> unls(numUNLs);
|
||||||
|
std::generate(unls.begin(), unls.end(), [&]()
|
||||||
|
{
|
||||||
|
std::vector<PeerID> ids(size);
|
||||||
|
std::iota(ids.begin(), ids.end(), 0);
|
||||||
|
auto res = random_weighted_shuffle(ids, weights, g);
|
||||||
|
return UNL(res.begin(), res.begin() + unlSizePDF(g));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. Assign membership
|
||||||
|
std::vector<int> assignment(size);
|
||||||
|
std::uniform_int_distribution<int> u(0, numUNLs-1);
|
||||||
|
std::generate(assignment.begin(), assignment.end(),
|
||||||
|
[&]()
|
||||||
|
{
|
||||||
|
return u(g);
|
||||||
|
});
|
||||||
|
|
||||||
|
return TrustGraph(unls, assignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Generate a 2 UNL trust graph with some overlap.
|
||||||
|
|
||||||
|
Generates a trust graph for `size` peers formed from
|
||||||
|
two cliques with the given overlap. Nodes in the overlap
|
||||||
|
trust both all other nodes, while nodes outside the overlap
|
||||||
|
only trust nodes in their clique.
|
||||||
|
|
||||||
|
@param size The number of nodes in the trust graph
|
||||||
|
@param overlap The number of nodes trusting both cliques
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
TrustGraph
|
||||||
|
makeClique(int size, int overlap);
|
||||||
|
|
||||||
|
/** Generate a complete (fully-connect) trust graph
|
||||||
|
|
||||||
|
Generatest a trust graph in which all peers trust all
|
||||||
|
other peers.
|
||||||
|
|
||||||
|
@param size The number of nodes in the trust graph
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
TrustGraph
|
||||||
|
makeComplete(int size);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//< Make the TrustGraph into a topology with delays given by DelayModel
|
||||||
|
template <class DelayModel>
|
||||||
|
auto
|
||||||
|
topology(TrustGraph const & tg, DelayModel const & d)
|
||||||
|
{
|
||||||
|
return [&](PeerID i, PeerID j)
|
||||||
|
{
|
||||||
|
return tg.trusts(i,j) ? boost::make_optional(d(i,j)) : boost::none;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class fixed
|
||||||
|
{
|
||||||
|
std::chrono::nanoseconds d_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
fixed(std::chrono::nanoseconds const & d) : d_{d} {}
|
||||||
|
|
||||||
|
inline
|
||||||
|
std::chrono::nanoseconds
|
||||||
|
operator()(PeerID const & i, PeerID const & j) const
|
||||||
|
{
|
||||||
|
return d_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // csf
|
||||||
|
} // test
|
||||||
|
} // ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
135
src/test/csf/impl/UNL.cpp
Normal file
135
src/test/csf/impl/UNL.cpp
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
#include <test/csf/UNL.h>
|
||||||
|
#include <boost/iterator/counting_iterator.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace test {
|
||||||
|
namespace csf {
|
||||||
|
|
||||||
|
bool
|
||||||
|
TrustGraph::canFork(double quorum) const
|
||||||
|
{
|
||||||
|
// Check the forking condition by looking at intersection
|
||||||
|
// between all pairs of UNLs.
|
||||||
|
|
||||||
|
// First check if some nodes uses a UNL they are not members of, since
|
||||||
|
// this creates an implicit UNL with that ndoe.
|
||||||
|
|
||||||
|
auto uniqueUNLs = UNLs_;
|
||||||
|
|
||||||
|
for (int i = 0; i < assignment_.size(); ++i)
|
||||||
|
{
|
||||||
|
auto const & myUNL = UNLs_[assignment_[i]];
|
||||||
|
if(myUNL.find(i) == myUNL.end())
|
||||||
|
{
|
||||||
|
auto myUNLcopy = myUNL;
|
||||||
|
myUNLcopy.insert(i);
|
||||||
|
uniqueUNLs.push_back(std::move(myUNLcopy));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over all pairs of uniqueUNLs
|
||||||
|
for (int i = 0; i < uniqueUNLs.size(); ++i)
|
||||||
|
{
|
||||||
|
for (int j = (i+1); j < uniqueUNLs.size(); ++j)
|
||||||
|
{
|
||||||
|
auto const & unlA = uniqueUNLs[i];
|
||||||
|
auto const & unlB = uniqueUNLs[j];
|
||||||
|
|
||||||
|
double rhs = 2.0*(1.-quorum) *
|
||||||
|
std::max(unlA.size(), unlB.size() );
|
||||||
|
|
||||||
|
int intersectionSize = std::count_if(unlA.begin(), unlA.end(),
|
||||||
|
[&](PeerID id)
|
||||||
|
{
|
||||||
|
return unlB.find(id) != unlB.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
if(intersectionSize < rhs)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TrustGraph
|
||||||
|
TrustGraph::makeClique(int size, int overlap)
|
||||||
|
{
|
||||||
|
using bci = boost::counting_iterator<PeerID>;
|
||||||
|
|
||||||
|
// Split network into two cliques with the given overlap
|
||||||
|
// Clique A has nodes [0,endA) and Clique B has [startB,numPeers)
|
||||||
|
// Note: Clique B will have an extra peer when numPeers - overlap
|
||||||
|
// is odd
|
||||||
|
int endA = (size + overlap)/2;
|
||||||
|
int startB = (size - overlap)/2;
|
||||||
|
|
||||||
|
std::vector<UNL> unls;
|
||||||
|
unls.emplace_back(bci(0), bci(endA));
|
||||||
|
unls.emplace_back(bci(startB), bci(size));
|
||||||
|
unls.emplace_back(bci(0), bci(size));
|
||||||
|
|
||||||
|
std::vector<int> assignment(size,0);
|
||||||
|
|
||||||
|
for (int i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
if(i < startB)
|
||||||
|
assignment[i] = 0;
|
||||||
|
else if(i > endA)
|
||||||
|
assignment[i] = 1;
|
||||||
|
else
|
||||||
|
assignment[i] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return TrustGraph(unls, assignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
TrustGraph
|
||||||
|
TrustGraph::makeComplete(int size)
|
||||||
|
{
|
||||||
|
UNL all{ boost::counting_iterator<PeerID>( 0 ),
|
||||||
|
boost::counting_iterator<PeerID>( size ) };
|
||||||
|
|
||||||
|
return TrustGraph(std::vector<UNL>(1,all),
|
||||||
|
std::vector<int>(size, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void TrustGraph::save_dot(std::string const & fileName)
|
||||||
|
{
|
||||||
|
std::ofstream out(fileName);
|
||||||
|
out << "digraph {\n";
|
||||||
|
for (int i = 0; i < assignment_.size(); ++i)
|
||||||
|
{
|
||||||
|
for (auto & j : UNLs_[assignment_[i]])
|
||||||
|
{
|
||||||
|
out << i << " -> " << j << ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
out << "}\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // csf
|
||||||
|
} // test
|
||||||
|
} // ripple
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
#include <test/jtx/utility.h>
|
#include <test/jtx/utility.h>
|
||||||
#include <test/jtx/JSONRPCClient.h>
|
#include <test/jtx/JSONRPCClient.h>
|
||||||
#include <ripple/app/ledger/LedgerMaster.h>
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
#include <ripple/app/ledger/LedgerTiming.h>
|
#include <ripple/consensus/LedgerTiming.h>
|
||||||
#include <ripple/app/misc/NetworkOPs.h>
|
#include <ripple/app/misc/NetworkOPs.h>
|
||||||
#include <ripple/app/misc/TxQ.h>
|
#include <ripple/app/misc/TxQ.h>
|
||||||
#include <ripple/basics/contract.h>
|
#include <ripple/basics/contract.h>
|
||||||
|
|||||||
21
src/test/unity/consensus_test_unity.cpp
Normal file
21
src/test/unity/consensus_test_unity.cpp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012-2016 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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <test/consensus/Consensus_test.cpp>
|
||||||
|
#include <test/consensus/LedgerTiming_test.cpp>
|
||||||
23
src/test/unity/csf_unity.cpp
Normal file
23
src/test/unity/csf_unity.cpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <BeastConfig.h>
|
||||||
|
|
||||||
|
#include <test/csf/BasicNetwork_test.cpp>
|
||||||
|
#include <test/csf/impl/UNL.cpp>
|
||||||
@@ -49,7 +49,5 @@
|
|||||||
#include <test/jtx/impl/JSONRPCClient.cpp>
|
#include <test/jtx/impl/JSONRPCClient.cpp>
|
||||||
#include <test/jtx/impl/ManualTimeKeeper.cpp>
|
#include <test/jtx/impl/ManualTimeKeeper.cpp>
|
||||||
#include <test/jtx/impl/WSClient.cpp>
|
#include <test/jtx/impl/WSClient.cpp>
|
||||||
|
|
||||||
#include <test/jtx/BasicNetwork_test.cpp>
|
|
||||||
#include <test/jtx/Env_test.cpp>
|
#include <test/jtx/Env_test.cpp>
|
||||||
#include <test/jtx/WSClient_test.cpp>
|
#include <test/jtx/WSClient_test.cpp>
|
||||||
Reference in New Issue
Block a user