mirror of
				https://github.com/Xahau/xahaud.git
				synced 2025-11-04 10:45:50 +00:00 
			
		
		
		
	Autobridging future support:
* Refactor and cleanup transactors * Introduce new direct and bridged transactors * Rename existing transactor to indicate legacy status * New direct transactor defaults to being turned off (preserve legacy behavior)
This commit is contained in:
		
				
					committed by
					
						
						Vinnie Falco
					
				
			
			
				
	
			
			
			
						parent
						
							1a9fbab165
						
					
				
				
					commit
					bee12fb89d
				
			@@ -34,6 +34,12 @@
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple\common\ripple_common.cpp" />
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple\common\tests\cross_offer.test.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple\http\impl\Port.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
@@ -884,27 +890,57 @@
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\AccountSetTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\SetAccount.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\ChangeTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\Change.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\OfferCancelTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\CancelOffer.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\OfferCreateTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\CreateOffer.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\PaymentTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\CreateOfferDirect.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\RegularKeySetTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\CreateOfferBridged.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\CreateOfferLegacy.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\Payment.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\SetRegularKey.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
@@ -912,11 +948,15 @@
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\TrustSetTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\SetTrust.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\WalletAddTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\AddWallet.cpp">
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
 | 
			
		||||
      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
@@ -2107,15 +2147,18 @@
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\shamap\SHAMapSyncFilters.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\shamap\RadixMapTest.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\shamap\SHAMapTreeNode.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\AccountSetTransactor.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\ChangeTransactor.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\OfferCancelTransactor.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\OfferCreateTransactor.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\PaymentTransactor.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\RegularKeySetTransactor.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\SetAccount.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\Change.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\CancelOffer.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\CreateOffer.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\CreateOfferDirect.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\CreateOfferBridged.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\CreateOfferOriginal.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\Payment.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\SetRegularKey.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\Transactor.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\TrustSetTransactor.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\WalletAddTransactor.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\SetTrust.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\AddWallet.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\tx\LocalTxs.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\tx\Transaction.h" />
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\tx\TransactionAcquire.h" />
 | 
			
		||||
 
 | 
			
		||||
@@ -1455,31 +1455,40 @@
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\tx\TxQueueEntry.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\tx</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\AccountSetTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\SetAccount.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\ChangeTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\Change.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\OfferCancelTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\CancelOffer.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\OfferCreateTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\CreateOffer.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\PaymentTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\CreateOfferBridged.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\RegularKeySetTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\CreateOfferDirect.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\CreateOfferLegacy.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\Payment.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\SetRegularKey.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\Transactor.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\TrustSetTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\SetTrust.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\WalletAddTransactor.cpp">
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple_app\transactors\AddWallet.cpp">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClCompile>
 | 
			
		||||
    <ClCompile Include="..\..\src\ripple\common\impl\MultiSocket.cpp">
 | 
			
		||||
@@ -3218,31 +3227,40 @@
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\tx\TxQueueEntry.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\tx</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\AccountSetTransactor.h">
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\SetAccount.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\ChangeTransactor.h">
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\Change.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\OfferCancelTransactor.h">
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\CancelOffer.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\OfferCreateTransactor.h">
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\CreateOffer.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\PaymentTransactor.h">
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\CreateOfferDirect.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\RegularKeySetTransactor.h">
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\CreateOfferBridged.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\CreateOfferOriginal.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\Payment.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\SetRegularKey.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\Transactor.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\TrustSetTransactor.h">
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\SetTrust.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\WalletAddTransactor.h">
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple_app\transactors\AddWallet.h">
 | 
			
		||||
      <Filter>[2] Old Ripple\ripple_app\transactors</Filter>
 | 
			
		||||
    </ClInclude>
 | 
			
		||||
    <ClInclude Include="..\..\src\ripple\common\impl\MultiSocketType.h">
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										100
									
								
								SConstruct
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								SConstruct
									
									
									
									
									
								
							@@ -470,3 +470,103 @@ rippled = env.Program('build/rippled', OBJECT_FILES)
 | 
			
		||||
tags    = env.CTags('tags', TAG_SRCS)
 | 
			
		||||
 | 
			
		||||
Default(rippled, tags)
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
# Returns the list of libraries needed by the test source file. This is
 | 
			
		||||
# accomplished by scanning the source file for a special comment line
 | 
			
		||||
# with this format, which must match exactly:
 | 
			
		||||
#
 | 
			
		||||
# // LIBS: <name>...
 | 
			
		||||
#
 | 
			
		||||
# path = path to source file
 | 
			
		||||
#
 | 
			
		||||
def get_libs(path):
 | 
			
		||||
    prefix = '// LIBS:'
 | 
			
		||||
    with open(path, 'rb') as f:
 | 
			
		||||
        for line in f:
 | 
			
		||||
            line = line.strip()
 | 
			
		||||
            if line.startswith(prefix):
 | 
			
		||||
                items = line.split(prefix, 1)[1].strip()
 | 
			
		||||
                return [x.strip() for x in items.split(' ')]
 | 
			
		||||
 | 
			
		||||
# Returns the list of source modules needed by the test source file. This
 | 
			
		||||
#
 | 
			
		||||
# // MODULES: <module>...
 | 
			
		||||
#
 | 
			
		||||
# path = path to source file
 | 
			
		||||
#
 | 
			
		||||
def get_mods(path):
 | 
			
		||||
    prefix = '// MODULES:'
 | 
			
		||||
    with open(path, 'rb') as f:
 | 
			
		||||
        for line in f:
 | 
			
		||||
            line = line.strip()
 | 
			
		||||
            if line.startswith(prefix):
 | 
			
		||||
                items = line.split(prefix, 1)[1].strip()
 | 
			
		||||
                items = [os.path.normpath(os.path.join(
 | 
			
		||||
                    os.path.dirname(path), x.strip())) for
 | 
			
		||||
                        x in items.split(' ')]
 | 
			
		||||
                return items
 | 
			
		||||
 | 
			
		||||
# Build a stand alone executable that runs
 | 
			
		||||
# all the test suites in one source file
 | 
			
		||||
#
 | 
			
		||||
def build_test(env,path):
 | 
			
		||||
    libs = get_libs(path)
 | 
			
		||||
    mods = get_mods(path)
 | 
			
		||||
    bin = os.path.basename(os.path.splitext(path)[0])
 | 
			
		||||
    bin = os.path.join ("build", bin)
 | 
			
		||||
    srcs = ['src/beast/beast/unit_test/tests/main.cpp']
 | 
			
		||||
    srcs.append (path)
 | 
			
		||||
    if mods:
 | 
			
		||||
        srcs.extend (mods)
 | 
			
		||||
    # All paths get normalized here, so we can use posix
 | 
			
		||||
    # forward slashes for everything including on Windows
 | 
			
		||||
    srcs = [os.path.normpath(os.path.join ('build', x)) for x in srcs]
 | 
			
		||||
    objs = [os.path.splitext(x)[0]+'.o' for x in srcs]
 | 
			
		||||
    env_ = env
 | 
			
		||||
    if libs:
 | 
			
		||||
        env_.Append(LIBS = libs)
 | 
			
		||||
    env_.Program (bin, srcs)
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    env = Environment()
 | 
			
		||||
 | 
			
		||||
    env['PRINT_CMD_LINE_FUNC'] = print_cmd_line
 | 
			
		||||
 | 
			
		||||
    env.VariantDir (os.path.join ('build', 'src'), 'src', duplicate=0)
 | 
			
		||||
 | 
			
		||||
    # Copy important os environment variables into env
 | 
			
		||||
    if os.environ.get ('CC', None):
 | 
			
		||||
        env.Replace (CC = os.environ['CC'])
 | 
			
		||||
    if os.environ.get ('CXX', None):
 | 
			
		||||
        env.Replace (CXX = os.environ['CXX'])
 | 
			
		||||
    if os.environ.get ('PATH', None):
 | 
			
		||||
        env.Replace (PATH = os.environ['PATH'])
 | 
			
		||||
 | 
			
		||||
    # Set up boost variables
 | 
			
		||||
    home = os.environ.get("BOOST_HOME", None)
 | 
			
		||||
    if home is not None:
 | 
			
		||||
        env.Prepend (CPPPATH = home)
 | 
			
		||||
        env.Append (LIBPATH = os.path.join (home, 'stage', 'lib'))
 | 
			
		||||
 | 
			
		||||
    # Set up flags
 | 
			
		||||
    env.Append(CXXFLAGS = [
 | 
			
		||||
        '-std=c++11',
 | 
			
		||||
        '-frtti',
 | 
			
		||||
        '-g'
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
    for root, dirs, files in os.walk('src/ripple'):
 | 
			
		||||
        for path in files:
 | 
			
		||||
            path = os.path.join(root,path)
 | 
			
		||||
            if (path.endswith(".test.cpp")):
 | 
			
		||||
                build_test(env,path)
 | 
			
		||||
 | 
			
		||||
    print_build_config (env)
 | 
			
		||||
 | 
			
		||||
main()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -215,4 +215,11 @@ This determines whether to add any features to the proposed transaction set.
 | 
			
		||||
#define RIPPLE_PROPOSE_AMENDMENTS 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** Config: RIPPLE_USE_OLD_CREATE_TRANSACTOR
 | 
			
		||||
This determines whether ripple uses the legacy OfferCreate transactor.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef RIPPLE_USE_OLD_CREATE_TRANSACTOR
 | 
			
		||||
#define RIPPLE_USE_OLD_CREATE_TRANSACTOR 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										820
									
								
								src/ripple/common/tests/cross_offer.test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										820
									
								
								src/ripple/common/tests/cross_offer.test.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,820 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    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 "../../../beast/beast/unit_test/suite.h"
 | 
			
		||||
 | 
			
		||||
#include "../../../beast/beast/utility/noexcept.h"
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include "../../../beast/beast/cxx14/type_traits.h" // <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
namespace core {
 | 
			
		||||
 | 
			
		||||
/** Represents both a quality and amounts of currencies for trade.
 | 
			
		||||
 | 
			
		||||
    Quality is the ratio of output currency to input currency, where
 | 
			
		||||
    higher means better for the offer taker. The first element of
 | 
			
		||||
    the pair is the amount of currency available for input into
 | 
			
		||||
    the offer. The second element of the pair is the amount of currency
 | 
			
		||||
    that comes out if the full amount of the input currency is provided.
 | 
			
		||||
    This pair also represents a fraction, for example for specifying a
 | 
			
		||||
    minimum quality.
 | 
			
		||||
 | 
			
		||||
    Offer requirements:
 | 
			
		||||
 | 
			
		||||
        `X` is the type `Offer`
 | 
			
		||||
        `a`, `b` are values of type `X`
 | 
			
		||||
 | 
			
		||||
        `X::amount_type`
 | 
			
		||||
            The return type of `in` and `out`
 | 
			
		||||
        
 | 
			
		||||
        `X a;`
 | 
			
		||||
            Constructs an uninitialized offer
 | 
			
		||||
        
 | 
			
		||||
        `a.in();`
 | 
			
		||||
            
 | 
			
		||||
        `a.out();
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/** Returns `true` if the offer is consumed. */
 | 
			
		||||
template <class Offer>
 | 
			
		||||
bool
 | 
			
		||||
is_offer_consumed (Offer const& offer) noexcept
 | 
			
		||||
{
 | 
			
		||||
    assert ((offer.in() != 0 && offer.out() != 0) ||
 | 
			
		||||
            (offer.in() == 0 && offer.out() == 0));
 | 
			
		||||
    return offer.in() == 0 || offer.out() == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
template <class Amount>
 | 
			
		||||
struct AmountTraits
 | 
			
		||||
{
 | 
			
		||||
    /** Returns `true` if `lhs` is of lower quality than `rhs`. */
 | 
			
		||||
    template <class Offer>
 | 
			
		||||
    static
 | 
			
		||||
    bool
 | 
			
		||||
    less (Offer const& lhs, Offer const& rhs) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        assert (! is_offer_consumed (lhs));
 | 
			
		||||
        assert (! is_offer_consumed (rhs));
 | 
			
		||||
        assert (lhs.out() != 0);
 | 
			
		||||
        assert (rhs.out() != 0);
 | 
			
		||||
        return (lhs.out() / lhs.in()) < (rhs.out() / rhs.in());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Calculates the result of multiplying amount by the implied ratio. */
 | 
			
		||||
    template <class Offer>
 | 
			
		||||
    static
 | 
			
		||||
    typename Offer::amount_type
 | 
			
		||||
    multiply (typename Offer::amount_type const& amount, Offer const& rate)
 | 
			
		||||
    {
 | 
			
		||||
        // Avoid math when result is exact
 | 
			
		||||
        if (amount == rate.in())
 | 
			
		||||
            return rate.out();
 | 
			
		||||
        typename Offer::amount_type const result (
 | 
			
		||||
            amount * (rate.out() / rate.in()));
 | 
			
		||||
        if (result > rate.out())
 | 
			
		||||
            return rate.out();
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <class Offer>
 | 
			
		||||
    static
 | 
			
		||||
    Offer
 | 
			
		||||
    inverse (Offer const& value) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return Offer (value.out(), value.in());
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Returns the offer that would result if the input amount is applied. */
 | 
			
		||||
template <class Offer>
 | 
			
		||||
Offer
 | 
			
		||||
consume_offer (
 | 
			
		||||
    typename Offer::amount_type const& input,
 | 
			
		||||
    Offer offer)
 | 
			
		||||
{
 | 
			
		||||
    using Amount = typename Offer::amount_type;
 | 
			
		||||
    // We need to calculate the most that we can take:
 | 
			
		||||
    Amount const input_used (std::min (input, offer.in()));
 | 
			
		||||
    Amount const output (AmountTraits<Amount>::multiply (input_used, offer));
 | 
			
		||||
    offer.in() -= input_used;
 | 
			
		||||
    offer.out() -= output;
 | 
			
		||||
    return offer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Fills an order amount in an order book.
 | 
			
		||||
 | 
			
		||||
    @return The resulting amount of currency in and out.
 | 
			
		||||
*/
 | 
			
		||||
template <class BookIter>
 | 
			
		||||
typename std::iterator_traits<BookIter>::value_type
 | 
			
		||||
cross_offer_in (
 | 
			
		||||
    typename std::iterator_traits<BookIter>::value_type::amount_type const& in,
 | 
			
		||||
    typename std::iterator_traits<BookIter>::value_type const& minimum_quality,
 | 
			
		||||
    BookIter first, BookIter last)
 | 
			
		||||
{
 | 
			
		||||
    using Amount =
 | 
			
		||||
        typename std::iterator_traits<BookIter>::value_type::amount_type;
 | 
			
		||||
    using Offer =
 | 
			
		||||
        typename std::iterator_traits<BookIter>::value_type;
 | 
			
		||||
    Offer result {0, 0};
 | 
			
		||||
    Amount remain (in);
 | 
			
		||||
    for (auto iter (first); (result.in() < in) && (iter != last); ++iter)
 | 
			
		||||
    {
 | 
			
		||||
        Offer const offer (*iter);
 | 
			
		||||
        if (AmountTraits<Amount>::less (offer, minimum_quality))
 | 
			
		||||
            break;
 | 
			
		||||
        Offer const offer_out (consume_offer (remain, offer));
 | 
			
		||||
        result.in() += offer.in() - offer_out.in();
 | 
			
		||||
        result.out() += offer.out() - offer_out.out();
 | 
			
		||||
        *iter = offer_out;
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
/** Returns the composite A->C from offers A->B and B->C, equal liquidity. */
 | 
			
		||||
template <class Offer>
 | 
			
		||||
Offer
 | 
			
		||||
make_bridged_offer (Offer const& leg1,  Offer const& leg2)
 | 
			
		||||
{
 | 
			
		||||
    using Amount = typename Offer::amount_type;
 | 
			
		||||
 | 
			
		||||
    // Skip math if both legs can be fully consumed
 | 
			
		||||
    if (leg1.out() == leg2.in())
 | 
			
		||||
        return Offer (leg1.in(), leg2.out());
 | 
			
		||||
 | 
			
		||||
    // If leg2 has less liquidity, scale down by leg2
 | 
			
		||||
    if (leg1.out() > leg2.in())
 | 
			
		||||
        return Offer (
 | 
			
		||||
            AmountTraits<Amount>::multiply (leg2.in(),
 | 
			
		||||
                AmountTraits<Amount>::inverse (leg1)),
 | 
			
		||||
            leg2.out());
 | 
			
		||||
 | 
			
		||||
    // leg1 has less liquidity
 | 
			
		||||
    return Offer (leg1.in(),
 | 
			
		||||
        AmountTraits<Amount>::multiply (leg1.out(), leg2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace detail {
 | 
			
		||||
 | 
			
		||||
/** Presents a set of order books as a single bridged order book. */
 | 
			
		||||
template <class BookIter>
 | 
			
		||||
class MultiBookIterator
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    using Amount =
 | 
			
		||||
        typename std::iterator_traits<BookIter>::value_type::amount_type;
 | 
			
		||||
 | 
			
		||||
    using Offer =
 | 
			
		||||
        typename std::iterator_traits<BookIter>::value_type;
 | 
			
		||||
 | 
			
		||||
    typedef std::is_const <
 | 
			
		||||
        typename std::iterator_traits<BookIter>::reference
 | 
			
		||||
            > IsConst;
 | 
			
		||||
 | 
			
		||||
    struct forward_iterator_base_tag
 | 
			
		||||
        : std::output_iterator_tag
 | 
			
		||||
        , std::forward_iterator_tag
 | 
			
		||||
    {
 | 
			
		||||
        forward_iterator_base_tag()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct forward_const_iterator_base_tag
 | 
			
		||||
        : std::forward_iterator_tag
 | 
			
		||||
    {
 | 
			
		||||
        forward_const_iterator_base_tag()
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template <class>
 | 
			
		||||
    friend class MultiBookIterator;
 | 
			
		||||
 | 
			
		||||
    BookIter m_direct;
 | 
			
		||||
    BookIter m_direct_end;
 | 
			
		||||
    BookIter m_leg1;
 | 
			
		||||
    BookIter m_leg1_end;
 | 
			
		||||
    BookIter m_leg2;
 | 
			
		||||
    BookIter m_leg2_end;
 | 
			
		||||
    bool m_bridged;
 | 
			
		||||
    Offer m_offer;
 | 
			
		||||
 | 
			
		||||
    class Proxy : public Offer
 | 
			
		||||
    {
 | 
			
		||||
    private:
 | 
			
		||||
        bool m_bridged;
 | 
			
		||||
        BookIter m_direct;
 | 
			
		||||
        BookIter m_leg1;
 | 
			
		||||
        BookIter m_leg2;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        explicit Proxy (BookIter direct)
 | 
			
		||||
            : Offer (*direct)
 | 
			
		||||
            , m_bridged (false)
 | 
			
		||||
            , m_direct (direct)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Proxy (BookIter leg1, BookIter leg2)
 | 
			
		||||
            : Offer (make_bridged_offer (*leg1, *leg2))
 | 
			
		||||
            , m_bridged (true)
 | 
			
		||||
            , m_leg1 (leg1)
 | 
			
		||||
            , m_leg2 (leg2)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Proxy&
 | 
			
		||||
        operator= (Offer const& offer)
 | 
			
		||||
        {
 | 
			
		||||
            if (m_bridged)
 | 
			
		||||
            {
 | 
			
		||||
                Offer const result (consume_offer (
 | 
			
		||||
                    offer.in(), *m_leg1));
 | 
			
		||||
                *m_leg2 = consume_offer (
 | 
			
		||||
                    m_leg1->in() - result.in(), *m_leg2);
 | 
			
		||||
                *m_leg1 = result;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                *m_direct = offer;
 | 
			
		||||
            }
 | 
			
		||||
            ((Offer&)*this) = offer;
 | 
			
		||||
            return *this;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Returns true if this iterator has reached the one past the end marker
 | 
			
		||||
    bool
 | 
			
		||||
    past_end() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return
 | 
			
		||||
            (m_direct == m_direct_end) &&
 | 
			
		||||
            (m_leg1 == m_leg1_end || m_leg2 == m_leg2_end);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    throw_if_past()
 | 
			
		||||
    {
 | 
			
		||||
        if (past_end())
 | 
			
		||||
            throw std::out_of_range ("invalid iterator dereferenced");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Returns true if the iterators are both equal, or both past the end
 | 
			
		||||
    template <class Iter1, class Iter2>
 | 
			
		||||
    static
 | 
			
		||||
    bool
 | 
			
		||||
    iter_eq (Iter1 iter1, Iter1 iter1_end,
 | 
			
		||||
             Iter2 iter2, Iter2 iter2_end) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (iter1 == iter1_end)
 | 
			
		||||
            return iter2 == iter2_end;
 | 
			
		||||
        if (iter2 == iter2_end)
 | 
			
		||||
            return false;
 | 
			
		||||
        return iter1 == iter2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Stores the best offer (if any) in m_offer
 | 
			
		||||
    void
 | 
			
		||||
    calc_offer()
 | 
			
		||||
    {
 | 
			
		||||
        if (past_end())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // FIXME rewrite this - having 3 nested if's is overkill...
 | 
			
		||||
        if ((m_leg1 != m_leg1_end) && (m_leg2 != m_leg2_end))
 | 
			
		||||
        {
 | 
			
		||||
            Offer const bridged (
 | 
			
		||||
                make_bridged_offer (*m_leg1, *m_leg2));
 | 
			
		||||
 | 
			
		||||
            if (m_direct != m_direct_end)
 | 
			
		||||
            {
 | 
			
		||||
                if (AmountTraits<Amount>::less (*m_direct, bridged))
 | 
			
		||||
                {
 | 
			
		||||
                    m_bridged = true;
 | 
			
		||||
                    m_offer = bridged;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    m_bridged = false;
 | 
			
		||||
                    m_offer = *m_direct;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                m_bridged = true;
 | 
			
		||||
                m_offer = bridged;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            m_bridged = false;
 | 
			
		||||
            m_offer = *m_direct;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    typedef std::ptrdiff_t difference_type;
 | 
			
		||||
    typedef typename std::iterator_traits <
 | 
			
		||||
        BookIter>::value_type value_type;
 | 
			
		||||
    typedef value_type* pointer;
 | 
			
		||||
    typedef value_type& reference;
 | 
			
		||||
    typedef std::conditional_t <
 | 
			
		||||
        std::is_const <std::remove_reference_t <reference>>::value,
 | 
			
		||||
            forward_const_iterator_base_tag,
 | 
			
		||||
                forward_iterator_base_tag> iterator_category;
 | 
			
		||||
 | 
			
		||||
    MultiBookIterator () = default;
 | 
			
		||||
 | 
			
		||||
    template <
 | 
			
		||||
        class OtherBookIter,
 | 
			
		||||
        class = std::enable_if_t <
 | 
			
		||||
            std::is_same <value_type, typename OtherBookIter::value_type>::value
 | 
			
		||||
        >
 | 
			
		||||
    >
 | 
			
		||||
    MultiBookIterator (MultiBookIterator <OtherBookIter> const& other)
 | 
			
		||||
        : m_direct (other.m_direct)
 | 
			
		||||
        , m_direct_end (other.m_direct_end)
 | 
			
		||||
        , m_leg1 (other.m_leg1)
 | 
			
		||||
        , m_leg1_end (other.m_leg1_end)
 | 
			
		||||
        , m_leg2 (other.m_leg2)
 | 
			
		||||
        , m_leg2_end (other.m_leg2_end)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <
 | 
			
		||||
        class OtherBookIter,
 | 
			
		||||
        class = std::enable_if_t <
 | 
			
		||||
            std::is_same <value_type, typename OtherBookIter::value_type>::value
 | 
			
		||||
        >
 | 
			
		||||
    >
 | 
			
		||||
    MultiBookIterator (
 | 
			
		||||
        OtherBookIter direct_first, OtherBookIter direct_last,
 | 
			
		||||
        OtherBookIter leg1_first, OtherBookIter leg1_last,
 | 
			
		||||
        OtherBookIter leg2_first, OtherBookIter leg2_last)
 | 
			
		||||
        : m_direct (direct_first)
 | 
			
		||||
        , m_direct_end (direct_last)
 | 
			
		||||
        , m_leg1 (leg1_first)
 | 
			
		||||
        , m_leg1_end (leg1_last)
 | 
			
		||||
        , m_leg2 (leg2_first)
 | 
			
		||||
        , m_leg2_end (leg2_last)
 | 
			
		||||
    {
 | 
			
		||||
        calc_offer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MultiBookIterator&
 | 
			
		||||
    operator++()
 | 
			
		||||
    {
 | 
			
		||||
        throw_if_past ();
 | 
			
		||||
 | 
			
		||||
        if (m_direct != m_direct_end)
 | 
			
		||||
            ++m_direct;
 | 
			
		||||
        if (m_leg1 != m_leg1_end)
 | 
			
		||||
            ++m_leg1;
 | 
			
		||||
        if (m_leg2 != m_leg2_end)
 | 
			
		||||
            ++m_leg2;
 | 
			
		||||
        calc_offer();
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MultiBookIterator
 | 
			
		||||
    operator++(int)
 | 
			
		||||
    {
 | 
			
		||||
        MultiBookIterator prev (*this);
 | 
			
		||||
        this->operator++();
 | 
			
		||||
        return prev;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <class OtherBookIter>
 | 
			
		||||
    bool
 | 
			
		||||
    operator== (
 | 
			
		||||
        MultiBookIterator <OtherBookIter> const& other) const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (! iter_eq (m_direct, m_direct_end,
 | 
			
		||||
                       other.m_direct, other.m_direct_end))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (! iter_eq (m_leg1, m_leg1_end,
 | 
			
		||||
                       other.m_leg1, other.m_leg1_end))
 | 
			
		||||
            return false;
 | 
			
		||||
        
 | 
			
		||||
        if (! iter_eq (m_leg2, m_leg2_end,
 | 
			
		||||
                       other.m_leg2, other.m_leg2_end))
 | 
			
		||||
            return false;
 | 
			
		||||
    
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Offer const*
 | 
			
		||||
    operator->() const
 | 
			
		||||
    {
 | 
			
		||||
        throw_if_past();
 | 
			
		||||
        return &m_offer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Offer const&
 | 
			
		||||
    operator*() const
 | 
			
		||||
    {
 | 
			
		||||
        throw_if_past();
 | 
			
		||||
        return m_offer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifndef _MSC_VER
 | 
			
		||||
    // This blows up Visual Studio
 | 
			
		||||
    template <
 | 
			
		||||
        bool MaybeConst = IsConst::value,
 | 
			
		||||
        class = std::enable_if_t <! MaybeConst>
 | 
			
		||||
    >
 | 
			
		||||
#endif
 | 
			
		||||
    Proxy
 | 
			
		||||
    operator*()
 | 
			
		||||
    {
 | 
			
		||||
        static_assert (! IsConst::value,
 | 
			
		||||
            "invalid call of non-const member function");
 | 
			
		||||
        throw_if_past();
 | 
			
		||||
        if (m_bridged)
 | 
			
		||||
            return Proxy (m_leg1, m_leg2);
 | 
			
		||||
        return Proxy (m_direct);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class LeftBookIter, class RightBookIter>
 | 
			
		||||
bool
 | 
			
		||||
operator!= (
 | 
			
		||||
    MultiBookIterator <LeftBookIter> const& lhs,
 | 
			
		||||
    MultiBookIterator <RightBookIter> const& rhs) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return !(rhs == lhs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // detail
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// TODO Allow const Book
 | 
			
		||||
//
 | 
			
		||||
template <class Book>
 | 
			
		||||
class MultiBook
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    static_assert (! std::is_const <Book>::value,
 | 
			
		||||
        "Book cannot be const");
 | 
			
		||||
 | 
			
		||||
    std::reference_wrapper<Book> m_direct;
 | 
			
		||||
    std::reference_wrapper<Book> m_leg1;
 | 
			
		||||
    std::reference_wrapper<Book> m_leg2;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    typedef typename Book::value_type value_type;
 | 
			
		||||
    typedef typename Book::reference reference;
 | 
			
		||||
    typedef typename Book::const_reference const_reference;
 | 
			
		||||
 | 
			
		||||
    typedef detail::MultiBookIterator <
 | 
			
		||||
        typename Book::iterator> iterator;
 | 
			
		||||
    
 | 
			
		||||
    typedef detail::MultiBookIterator <
 | 
			
		||||
        typename Book::const_iterator> const_iterator;
 | 
			
		||||
 | 
			
		||||
    typedef typename Book::difference_type difference_type;
 | 
			
		||||
    typedef typename Book::size_type size_type;
 | 
			
		||||
 | 
			
		||||
    MultiBook (Book& direct, Book& leg1, Book& leg2)
 | 
			
		||||
        : m_direct (direct)
 | 
			
		||||
        , m_leg1 (leg1)
 | 
			
		||||
        , m_leg2 (leg2)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool
 | 
			
		||||
    empty() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return cbegin() == cend();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Complexity: linear
 | 
			
		||||
    size_type
 | 
			
		||||
    size() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return std::distance (cbegin(), cend());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iterator
 | 
			
		||||
    begin() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return iterator (
 | 
			
		||||
            m_direct.get().begin(), m_direct.get().end(),
 | 
			
		||||
            m_leg1.get().begin(), m_leg1.get().end(),
 | 
			
		||||
            m_leg2.get().begin(), m_leg2.get().end());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    iterator
 | 
			
		||||
    end() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return iterator (
 | 
			
		||||
            m_direct.get().end(), m_direct.get().end(),
 | 
			
		||||
            m_leg1.get().end(), m_leg1.get().end(),
 | 
			
		||||
            m_leg2.get().end(), m_leg2.get().end());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const_iterator
 | 
			
		||||
    begin() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return const_iterator (
 | 
			
		||||
            m_direct.get().cbegin(), m_direct.get().cend(),
 | 
			
		||||
            m_leg1.get().cbegin(), m_leg1.get().cend(),
 | 
			
		||||
            m_leg2.get().cbegin(), m_leg2.get().cend());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const_iterator
 | 
			
		||||
    end() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return const_iterator (
 | 
			
		||||
            m_direct.get().cend(), m_direct.get().cend(),
 | 
			
		||||
            m_leg1.get().cend(), m_leg1.get().cend(),
 | 
			
		||||
            m_leg2.get().cend(), m_leg2.get().cend());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const_iterator
 | 
			
		||||
    cbegin() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return const_iterator (
 | 
			
		||||
            m_direct.get().cbegin(), m_direct.get().cend(),
 | 
			
		||||
            m_leg1.get().cbegin(), m_leg1.get().cend(),
 | 
			
		||||
            m_leg2.get().cbegin(), m_leg2.get().cend());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const_iterator
 | 
			
		||||
    cend() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return const_iterator (
 | 
			
		||||
            m_direct.get().cend(), m_direct.get().cend(),
 | 
			
		||||
            m_leg1.get().cend(), m_leg1.get().cend(),
 | 
			
		||||
            m_leg2.get().cend(), m_leg2.get().cend());
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
template <class Book>
 | 
			
		||||
typename std::iterator_traits<typename Book::iterator>::value_type
 | 
			
		||||
cross_offer_in (
 | 
			
		||||
    typename std::iterator_traits<
 | 
			
		||||
        typename Book::iterator>::value_type::amount_type const& in,
 | 
			
		||||
    typename std::iterator_traits <
 | 
			
		||||
        typename Book::iterator>::value_type const& minimum_quality,
 | 
			
		||||
    Book& book)
 | 
			
		||||
{
 | 
			
		||||
    return cross_offer_in (in, minimum_quality, book.begin(), book.end());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class Book>
 | 
			
		||||
typename std::iterator_traits<typename Book::iterator>::value_type
 | 
			
		||||
cross_offer_in (
 | 
			
		||||
    typename std::iterator_traits<
 | 
			
		||||
        typename Book::iterator>::value_type::amount_type const& in,
 | 
			
		||||
    typename std::iterator_traits<typename Book::iterator>::value_type
 | 
			
		||||
        const& minimum_quality,
 | 
			
		||||
    Book& direct, Book& leg1, Book& leg2)
 | 
			
		||||
{
 | 
			
		||||
    MultiBook <Book> book (direct, leg1, leg2);
 | 
			
		||||
    return cross_offer_in (in, minimum_quality, book);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
class cross_offers_test : public beast::unit_test::suite
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    template <class Amount>
 | 
			
		||||
    class OfferType
 | 
			
		||||
    {
 | 
			
		||||
    private:
 | 
			
		||||
        Amount m_in;
 | 
			
		||||
        Amount m_out;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        typedef Amount amount_type;
 | 
			
		||||
 | 
			
		||||
        OfferType() = default;
 | 
			
		||||
 | 
			
		||||
        OfferType (Amount const& in, Amount const& out) noexcept
 | 
			
		||||
            : m_in (in)
 | 
			
		||||
            , m_out (out)
 | 
			
		||||
        {
 | 
			
		||||
            assert ((m_in != 0 && m_out != 0) || (m_in == 0 && m_out == 0));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Amount const&
 | 
			
		||||
        in() const noexcept
 | 
			
		||||
        {
 | 
			
		||||
            return m_in;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Amount&
 | 
			
		||||
        in() noexcept
 | 
			
		||||
        {
 | 
			
		||||
            return m_in;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Amount const& 
 | 
			
		||||
        out() const noexcept
 | 
			
		||||
        {
 | 
			
		||||
            return m_out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Amount&
 | 
			
		||||
        out() noexcept
 | 
			
		||||
        {
 | 
			
		||||
            return m_out;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    typedef double Amount;
 | 
			
		||||
    typedef OfferType<Amount> Offer;
 | 
			
		||||
    typedef std::vector <Offer> Book;
 | 
			
		||||
 | 
			
		||||
    template <class Amount>
 | 
			
		||||
    OfferType<Amount>
 | 
			
		||||
    static make_offer (Amount from, Amount rate)
 | 
			
		||||
    {
 | 
			
		||||
        return OfferType<Amount> (from, from * rate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <class Book>
 | 
			
		||||
    void
 | 
			
		||||
    check_iterators (Book& b)
 | 
			
		||||
    {
 | 
			
		||||
        using Offer = typename Book::value_type;
 | 
			
		||||
        // These make sure that expressions are well-formed
 | 
			
		||||
        std::for_each (b.begin(), b.end(), [](Offer){});
 | 
			
		||||
        std::for_each (b.cbegin(), b.cend(), [](Offer){});
 | 
			
		||||
        {
 | 
			
		||||
            Book const& cb (b);
 | 
			
		||||
            std::for_each (cb.begin(), cb.end(), [](Offer){});
 | 
			
		||||
            // Should not compile
 | 
			
		||||
            //*cb.begin() = Book::value_type();
 | 
			
		||||
            expect (cb.begin() == cb.end());
 | 
			
		||||
            expect (cb.begin() == cb.cend());
 | 
			
		||||
        }
 | 
			
		||||
        expect (b.cbegin() == b.cend());
 | 
			
		||||
        expect (b.begin() == b.cend());
 | 
			
		||||
        typename Book::iterator iter;
 | 
			
		||||
        typename Book::const_iterator citer (iter);
 | 
			
		||||
        citer = typename Book::iterator();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    test_iterators()
 | 
			
		||||
    {
 | 
			
		||||
        {
 | 
			
		||||
            Book b;
 | 
			
		||||
            check_iterators (b);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            Book b1, b2, b3;
 | 
			
		||||
            MultiBook <Book> b (b1, b2, b3);
 | 
			
		||||
            check_iterators (b);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    test_full_cross_auto_direct ()
 | 
			
		||||
    {
 | 
			
		||||
        testcase ("Autobridge (Full Direct Crossing)");
 | 
			
		||||
 | 
			
		||||
        Book a_to_b;
 | 
			
		||||
 | 
			
		||||
        a_to_b.push_back(make_offer(300., 2.0));
 | 
			
		||||
 | 
			
		||||
        Book a_to_x;
 | 
			
		||||
 | 
			
		||||
        a_to_x.push_back(make_offer(300., 0.5));
 | 
			
		||||
 | 
			
		||||
        Book x_to_b;
 | 
			
		||||
 | 
			
		||||
        x_to_b.push_back(make_offer(150., 0.5));
 | 
			
		||||
 | 
			
		||||
        auto const rate = make_offer(50.0, 1.5);
 | 
			
		||||
 | 
			
		||||
        Offer result = cross_offer_in (
 | 
			
		||||
            50.0,
 | 
			
		||||
            rate,
 | 
			
		||||
            a_to_b, a_to_x, x_to_b);
 | 
			
		||||
 | 
			
		||||
        expect ((result.in() == 50.0) && (result.out() == 100.0),
 | 
			
		||||
            "Expected { 50.0 : 100.0 }");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    test_full_cross_auto_bridge ()
 | 
			
		||||
    {
 | 
			
		||||
        testcase ("Autobridge (Full Bridge Crossing)");
 | 
			
		||||
 | 
			
		||||
        Book a_to_b;
 | 
			
		||||
 | 
			
		||||
        a_to_b.push_back(make_offer(300.00, 1.0));
 | 
			
		||||
 | 
			
		||||
        Book a_to_x;
 | 
			
		||||
 | 
			
		||||
        a_to_x.push_back(make_offer(300.00, 2.0));
 | 
			
		||||
 | 
			
		||||
        Book x_to_b;
 | 
			
		||||
 | 
			
		||||
        x_to_b.push_back(make_offer(300.00, 1.0));
 | 
			
		||||
 | 
			
		||||
        auto const rate = make_offer(50.0, 1.5);
 | 
			
		||||
 | 
			
		||||
        Offer result = cross_offer_in (
 | 
			
		||||
            50.0,
 | 
			
		||||
            rate,
 | 
			
		||||
            a_to_b, a_to_x, x_to_b);
 | 
			
		||||
 | 
			
		||||
        expect ((result.in() == 50.0) && (result.out() == 100.0),
 | 
			
		||||
            "Expected { 50.0 : 100.0 }");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    test_full_cross_direct ()
 | 
			
		||||
    {
 | 
			
		||||
        testcase ("Direct (Full Crossing)");
 | 
			
		||||
 | 
			
		||||
        Book a_to_b;
 | 
			
		||||
 | 
			
		||||
        a_to_b.push_back(make_offer(300.00, 2.0));
 | 
			
		||||
 | 
			
		||||
        auto const rate = make_offer(50.0, 1.5);
 | 
			
		||||
 | 
			
		||||
        Offer result = cross_offer_in (
 | 
			
		||||
            50.0,
 | 
			
		||||
            rate,
 | 
			
		||||
            a_to_b);
 | 
			
		||||
 | 
			
		||||
        expect ((result.in() == 50.0) && (result.out() == 100.0),
 | 
			
		||||
            "Expected { 50.0 : 100.0 }");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    test_partial_cross_direct ()
 | 
			
		||||
    {
 | 
			
		||||
        testcase ("Direct (Partial Crossing)");
 | 
			
		||||
 | 
			
		||||
        Book a_to_b;
 | 
			
		||||
 | 
			
		||||
        a_to_b.push_back(make_offer(25.00, 2.0));
 | 
			
		||||
 | 
			
		||||
        auto const rate = make_offer(50.0, 1.5);
 | 
			
		||||
 | 
			
		||||
        Offer result = cross_offer_in (
 | 
			
		||||
            50.0,
 | 
			
		||||
            rate,
 | 
			
		||||
            a_to_b);
 | 
			
		||||
 | 
			
		||||
        expect ((result.in() == 25.0) && (result.out() == 50.0),
 | 
			
		||||
            "Expected { 25.0 : 50.0 }");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void
 | 
			
		||||
    run()
 | 
			
		||||
    {
 | 
			
		||||
        test_iterators();
 | 
			
		||||
        
 | 
			
		||||
        test_full_cross_direct ();
 | 
			
		||||
        test_full_cross_auto_direct ();
 | 
			
		||||
        test_full_cross_auto_bridge ();
 | 
			
		||||
 | 
			
		||||
        test_partial_cross_direct ();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
BEAST_DEFINE_TESTSUITE_MANUAL(cross_offers,orderbook_logic,ripple);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -24,10 +24,13 @@
 | 
			
		||||
 | 
			
		||||
#ifdef BEAST_WIN32
 | 
			
		||||
# include <Winsock2.h> // for ByteOrder.cpp
 | 
			
		||||
// <Winsock2.h> defines 'max' and does other stupid things
 | 
			
		||||
// <Winsock2.h> defines min, max and does other stupid things
 | 
			
		||||
# ifdef max
 | 
			
		||||
# undef max
 | 
			
		||||
# endif
 | 
			
		||||
# ifdef min
 | 
			
		||||
# undef min
 | 
			
		||||
# endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <set>
 | 
			
		||||
@@ -45,4 +48,5 @@
 | 
			
		||||
#include "impl/RippleIdentifierTests.cpp"
 | 
			
		||||
#include "impl/RippleAssets.cpp"
 | 
			
		||||
 | 
			
		||||
#include "../common/tests/cross_offer.test.cpp"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -43,11 +43,15 @@ public:
 | 
			
		||||
        Options (std::uint32_t tx_flags)
 | 
			
		||||
            : sell (is_bit_set (tx_flags, tfSell))
 | 
			
		||||
            , passive (is_bit_set (tx_flags, tfPassive))
 | 
			
		||||
            , fill_or_kill (is_bit_set (tx_flags, tfFillOrKill))
 | 
			
		||||
            , immediate_or_cancel (is_bit_set (tx_flags, tfImmediateOrCancel))
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool sell;
 | 
			
		||||
        bool passive;
 | 
			
		||||
        bool const sell;
 | 
			
		||||
        bool const passive;
 | 
			
		||||
        bool const fill_or_kill;
 | 
			
		||||
        bool const immediate_or_cancel;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -91,7 +95,7 @@ public:
 | 
			
		||||
        // If this is a passive order (tfPassive), this prevents
 | 
			
		||||
        // offers at the same quality level from being consumed.
 | 
			
		||||
        if (m_options.passive)
 | 
			
		||||
            --m_threshold;
 | 
			
		||||
            ++m_threshold;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LedgerView&
 | 
			
		||||
@@ -125,7 +129,7 @@ public:
 | 
			
		||||
        {
 | 
			
		||||
            // With the sell option, we are finished when
 | 
			
		||||
            // we have consumed all the input currency.
 | 
			
		||||
            if (! m_in.isPositive())
 | 
			
		||||
            if (m_in <= zero)
 | 
			
		||||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
        else if (m_out >= m_amount.out)
 | 
			
		||||
@@ -136,14 +140,14 @@ public:
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // We are finished if the taker is out of funds
 | 
			
		||||
        return ! funds().isPositive();
 | 
			
		||||
        return funds() <= zero;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
Quality
 | 
			
		||||
threshold() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return m_threshold;
 | 
			
		||||
}
 | 
			
		||||
    Quality
 | 
			
		||||
    threshold() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return m_threshold;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns `true` if the quality does not meet the taker's requirements. */
 | 
			
		||||
    bool
 | 
			
		||||
@@ -221,7 +225,7 @@ threshold() const noexcept
 | 
			
		||||
            assert (m_out < m_amount.out);
 | 
			
		||||
            taker_amount = offer.quality().ceil_out (
 | 
			
		||||
                taker_amount, m_amount.out - m_out);
 | 
			
		||||
            assert (! taker_amount.in.isZero());
 | 
			
		||||
            assert (taker_amount.in != zero);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Calculate the amount that will flow through the offer
 | 
			
		||||
@@ -251,6 +255,7 @@ threshold() const noexcept
 | 
			
		||||
 | 
			
		||||
        // VFALCO For the case of !sell, is it possible for the taker
 | 
			
		||||
        //        to get a tiny bit more than he asked for?
 | 
			
		||||
        // DAVIDS Can you verify?
 | 
			
		||||
        assert (m_options.sell || flow.out <= m_amount.out);
 | 
			
		||||
 | 
			
		||||
        // Calculate remaining portion of offer
 | 
			
		||||
 
 | 
			
		||||
@@ -22,11 +22,18 @@
 | 
			
		||||
#include "ripple_app.h"
 | 
			
		||||
 | 
			
		||||
#include "transactors/Transactor.cpp"
 | 
			
		||||
#include "transactors/ChangeTransactor.cpp"
 | 
			
		||||
#include "transactors/OfferCancelTransactor.cpp"
 | 
			
		||||
#include "transactors/OfferCreateTransactor.cpp"
 | 
			
		||||
#include "transactors/PaymentTransactor.cpp"
 | 
			
		||||
#include "transactors/RegularKeySetTransactor.cpp"
 | 
			
		||||
#include "transactors/AccountSetTransactor.cpp"
 | 
			
		||||
#include "transactors/WalletAddTransactor.cpp"
 | 
			
		||||
#include "transactors/TrustSetTransactor.cpp"
 | 
			
		||||
 | 
			
		||||
#include "transactors/Change.cpp"
 | 
			
		||||
#include "transactors/CancelOffer.cpp"
 | 
			
		||||
#include "transactors/Payment.cpp"
 | 
			
		||||
#include "transactors/SetRegularKey.cpp"
 | 
			
		||||
#include "transactors/SetAccount.cpp"
 | 
			
		||||
#include "transactors/AddWallet.cpp"
 | 
			
		||||
#include "transactors/SetTrust.cpp"
 | 
			
		||||
#include "transactors/CreateOffer.cpp"
 | 
			
		||||
#include "transactors/CreateOfferDirect.cpp"
 | 
			
		||||
#include "transactors/CreateOfferBridged.cpp"
 | 
			
		||||
 | 
			
		||||
#if RIPPLE_USE_OLD_CREATE_TRANSACTOR
 | 
			
		||||
#include "transactors/CreateOfferLegacy.cpp"
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										68
									
								
								src/ripple_app/transactors/CreateOffer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/ripple_app/transactors/CreateOffer.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    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 "CreateOfferDirect.h"
 | 
			
		||||
#include "CreateOfferBridged.h"
 | 
			
		||||
 | 
			
		||||
#if RIPPLE_USE_OLD_CREATE_TRANSACTOR
 | 
			
		||||
#include "CreateOfferLegacy.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "../book/OfferStream.h"
 | 
			
		||||
#include "../book/Taker.h"
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
OfferCreateTransactor::OfferCreateTransactor (
 | 
			
		||||
    SerializedTransaction const& txn,
 | 
			
		||||
    TransactionEngineParams params,
 | 
			
		||||
    TransactionEngine* engine)
 | 
			
		||||
    : Transactor (
 | 
			
		||||
        txn,
 | 
			
		||||
        params,
 | 
			
		||||
        engine,
 | 
			
		||||
        LogPartition::getJournal <OfferCreateTransactorLog> ())
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr <Transactor> make_OfferCreateTransactor (
 | 
			
		||||
    SerializedTransaction const& txn,
 | 
			
		||||
    TransactionEngineParams params,
 | 
			
		||||
    TransactionEngine* engine)
 | 
			
		||||
{
 | 
			
		||||
#if RIPPLE_USE_OLD_CREATE_TRANSACTOR
 | 
			
		||||
    return std::make_unique <ClassicOfferCreateTransactor> (txn, params, engine);
 | 
			
		||||
#else
 | 
			
		||||
    STAmount const& amount_in = txn.getFieldAmount (sfTakerPays);
 | 
			
		||||
    STAmount const& amount_out = txn.getFieldAmount (sfTakerGets);
 | 
			
		||||
    
 | 
			
		||||
    // Autobridging is only in effect when an offer does not involve XRP
 | 
			
		||||
    if (!amount_in.isNative() && !amount_out.isNative ())
 | 
			
		||||
    {
 | 
			
		||||
        // no autobridging transactor exists yet - we create a regular, direct
 | 
			
		||||
        // transactor for now.
 | 
			
		||||
        return std::make_unique <DirectOfferCreateTransactor> (txn, params, engine);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return std::make_unique <DirectOfferCreateTransactor> (txn, params, engine);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										69
									
								
								src/ripple_app/transactors/CreateOffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/ripple_app/transactors/CreateOffer.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    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_TX_OFFERCREATE_H_INCLUDED
 | 
			
		||||
#define RIPPLE_TX_OFFERCREATE_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include "../../beast/beast/cxx14/memory.h"
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
class OfferCreateTransactorLog;
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
char const*
 | 
			
		||||
LogPartition::getPartitionName <OfferCreateTransactorLog> ()
 | 
			
		||||
{
 | 
			
		||||
    return "Tx/OfferCreate";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class OfferCreateTransactor
 | 
			
		||||
    : public Transactor
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    template <class T>
 | 
			
		||||
    static std::string
 | 
			
		||||
    get_compare_sign (T const& lhs, T const& rhs)
 | 
			
		||||
    {
 | 
			
		||||
        if (lhs > rhs)
 | 
			
		||||
            return ">";
 | 
			
		||||
 | 
			
		||||
        if (rhs > lhs)
 | 
			
		||||
            return "<";
 | 
			
		||||
 | 
			
		||||
        // If neither is bigger than the other, they must be equal
 | 
			
		||||
        return "=";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    OfferCreateTransactor (
 | 
			
		||||
        SerializedTransaction const& txn,
 | 
			
		||||
        TransactionEngineParams params,
 | 
			
		||||
        TransactionEngine* engine);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
std::unique_ptr <Transactor> make_OfferCreateTransactor (
 | 
			
		||||
    SerializedTransaction const& txn,
 | 
			
		||||
    TransactionEngineParams params,
 | 
			
		||||
    TransactionEngine* engine);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								src/ripple_app/transactors/CreateOfferBridged.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/ripple_app/transactors/CreateOfferBridged.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    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.
 | 
			
		||||
*/
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								src/ripple_app/transactors/CreateOfferBridged.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/ripple_app/transactors/CreateOfferBridged.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    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_TX_BRIDGE_OFFERCREATE_H_INCLUDED
 | 
			
		||||
#define RIPPLE_TX_BRIDGE_OFFERCREATE_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										688
									
								
								src/ripple_app/transactors/CreateOfferDirect.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										688
									
								
								src/ripple_app/transactors/CreateOfferDirect.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,688 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    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 "../book/OfferStream.h"
 | 
			
		||||
#include "../book/Taker.h"
 | 
			
		||||
#include "../../beast/beast/streams/debug_ostream.h"
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// NIKB Move this in the right place
 | 
			
		||||
std::pair<TER,bool>
 | 
			
		||||
process_order (
 | 
			
		||||
    core::LedgerView& view,
 | 
			
		||||
    core::BookRef const book,
 | 
			
		||||
    core::Account const& account,
 | 
			
		||||
    core::Amounts const& amount,
 | 
			
		||||
    core::Amounts& cross_flow,
 | 
			
		||||
    core::Taker::Options const options,
 | 
			
		||||
    core::Clock::time_point const when,
 | 
			
		||||
    beast::Journal& journal)
 | 
			
		||||
{
 | 
			
		||||
    TER result (tesSUCCESS);
 | 
			
		||||
    core::LedgerView view_cancel (view.duplicate());
 | 
			
		||||
    core::OfferStream offers (view, view_cancel, book, when, journal);
 | 
			
		||||
    core::Taker taker (offers.view(), book, account, amount, options);
 | 
			
		||||
 | 
			
		||||
    if (journal.debug) journal.debug <<
 | 
			
		||||
        "process_order: " <<
 | 
			
		||||
        (options.sell? "sell" : "buy") << " " <<
 | 
			
		||||
        (options.passive? "passive" : "") << std::endl <<
 | 
			
		||||
        "     taker: " << taker.account() << std::endl <<
 | 
			
		||||
        "  balances: " <<
 | 
			
		||||
            view.accountFunds (taker.account(), amount.in) << ", " <<
 | 
			
		||||
            view.accountFunds (taker.account(), amount.out);
 | 
			
		||||
 | 
			
		||||
    cross_flow.in.clear (amount.in);
 | 
			
		||||
    cross_flow.out.clear (amount.out);
 | 
			
		||||
 | 
			
		||||
    bool place_order (true);
 | 
			
		||||
 | 
			
		||||
    while (true)
 | 
			
		||||
    {
 | 
			
		||||
        // Modifying the order or logic of these
 | 
			
		||||
        // operations causes a protocol breaking change.
 | 
			
		||||
 | 
			
		||||
        // Checks which remove offers are performed early so we
 | 
			
		||||
        // can reduce the size of the order book as much as possible
 | 
			
		||||
        // before terminating the loop.
 | 
			
		||||
 | 
			
		||||
        if (taker.done())
 | 
			
		||||
        {
 | 
			
		||||
            journal.debug << "The taker reports he's done during crossing!";
 | 
			
		||||
            place_order = false;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (! offers.step())
 | 
			
		||||
        {
 | 
			
		||||
            // Place the order since there are no
 | 
			
		||||
            // more offers and the order has a balance.
 | 
			
		||||
            journal.debug << "No more offers to consider during crossing!";
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto const offer (offers.tip());
 | 
			
		||||
 | 
			
		||||
        if (journal.debug) journal.debug <<
 | 
			
		||||
            "Considering offer: " << std::endl <<
 | 
			
		||||
            "  Id: " << offer.entry()->getIndex() << std::endl <<
 | 
			
		||||
            "  In: " << offer.amount().in << std::endl <<
 | 
			
		||||
            " Out: " << offer.amount().out << std::endl <<
 | 
			
		||||
            "  By: " << offer.account();
 | 
			
		||||
 | 
			
		||||
        if (taker.reject (offer.quality()))
 | 
			
		||||
        {
 | 
			
		||||
            // Place the order since there are no more offers
 | 
			
		||||
            // at the desired quality, and the order has a balance.
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (offer.account() == taker.account())
 | 
			
		||||
        {
 | 
			
		||||
            if (journal.debug) journal.debug <<
 | 
			
		||||
                " skipping self-offer " << offer.entry()->getIndex() << std::endl <<
 | 
			
		||||
                "  pays/gets " << offer.amount().in << ", " << offer.amount().out << std::endl <<
 | 
			
		||||
                " during cross for " << std::endl <<
 | 
			
		||||
                "   pays/gets " << amount.in << ", " << amount.out;
 | 
			
		||||
                ;
 | 
			
		||||
 | 
			
		||||
            // Skip offer from self.
 | 
			
		||||
            // (Offer will be considered expired, and get deleted)
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (journal.debug) journal.debug <<
 | 
			
		||||
            "   offer " << offer.entry()->getIndex() << std::endl <<
 | 
			
		||||
            "  pays/gets " << offer.amount().in << ", " << offer.amount().out
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
        core::Amounts flow;
 | 
			
		||||
        bool consumed;
 | 
			
		||||
        std::tie (flow, consumed) = taker.fill (offer);
 | 
			
		||||
 | 
			
		||||
        result = taker.process (flow, offer);
 | 
			
		||||
 | 
			
		||||
        if (journal.debug) journal.debug <<
 | 
			
		||||
            "       flow " <<
 | 
			
		||||
                flow.in << ", " << flow.out << std::endl <<
 | 
			
		||||
            "   balances " <<
 | 
			
		||||
                view.accountFunds (taker.account(), amount.in) << ", " <<
 | 
			
		||||
                view.accountFunds (taker.account(), amount.out)
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
        if (result != tesSUCCESS)
 | 
			
		||||
        {
 | 
			
		||||
            // VFALCO TODO Return the tec and let a caller higher
 | 
			
		||||
            //             up convert the error if the ledger is open.
 | 
			
		||||
            //result = bOpenLedger ?
 | 
			
		||||
            //    telFAILED_PROCESSING : tecFAILED_PROCESSING;
 | 
			
		||||
            result = tecFAILED_PROCESSING;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        cross_flow.in += flow.in;
 | 
			
		||||
        cross_flow.out += flow.out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (result == tesSUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        // No point in placing an offer for a fill-or-kill offer - the offer
 | 
			
		||||
        // will not succeed, since it wasn't filled.
 | 
			
		||||
        if (options.fill_or_kill)
 | 
			
		||||
            place_order = false;
 | 
			
		||||
 | 
			
		||||
        // An immediate or cancel order will fill however much it is possible
 | 
			
		||||
        // to fill and the remainder is not filled.
 | 
			
		||||
        if (options.immediate_or_cancel)
 | 
			
		||||
            place_order = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (result == tesSUCCESS)
 | 
			
		||||
    {
 | 
			
		||||
        if (place_order)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return std::make_pair(result,place_order);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Take as much as possible.
 | 
			
		||||
    We adjusts account balances and charges fees on top to taker.
 | 
			
		||||
 | 
			
		||||
    @param saTakerPays What the taker offers (w/ issuer)
 | 
			
		||||
    @param saTakerGets What the taker wanted (w/ issuer)
 | 
			
		||||
    @param saTakerPaid What taker could have paid including saved not including
 | 
			
		||||
                       fees. To reduce an offer.
 | 
			
		||||
    @param saTakerGot What taker got not including fees. To reduce an offer.
 | 
			
		||||
    @return tesSUCCESS, terNO_ACCOUNT, telFAILED_PROCESSING, or
 | 
			
		||||
            tecFAILED_PROCESSING
 | 
			
		||||
*/
 | 
			
		||||
std::pair<TER,bool> DirectOfferCreateTransactor::crossOffers (
 | 
			
		||||
    core::LedgerView& view,
 | 
			
		||||
    const STAmount&     saTakerPays,
 | 
			
		||||
    const STAmount&     saTakerGets,
 | 
			
		||||
    STAmount&           saTakerPaid,
 | 
			
		||||
    STAmount&           saTakerGot)
 | 
			
		||||
{
 | 
			
		||||
    if (m_journal.debug) m_journal.debug << "takeOffers: ";
 | 
			
		||||
 | 
			
		||||
    core::Book book (
 | 
			
		||||
        core::AssetRef (
 | 
			
		||||
            saTakerPays.getCurrency(), saTakerPays.getIssuer()), 
 | 
			
		||||
        core::AssetRef (
 | 
			
		||||
            saTakerGets.getCurrency(), saTakerGets.getIssuer()));
 | 
			
		||||
 | 
			
		||||
    core::Amounts cross_flow (
 | 
			
		||||
        core::Amount (saTakerPays.getCurrency(), saTakerPays.getIssuer()),
 | 
			
		||||
        core::Amount (saTakerGets.getCurrency(), saTakerGets.getIssuer()));
 | 
			
		||||
 | 
			
		||||
    auto const result (process_order (
 | 
			
		||||
        view, book, mTxnAccountID,
 | 
			
		||||
        core::Amounts (saTakerPays, saTakerGets), cross_flow, 
 | 
			
		||||
        core::Taker::Options (mTxn.getFlags()),
 | 
			
		||||
        mEngine->getLedger ()->getParentCloseTimeNC (),
 | 
			
		||||
        m_journal));
 | 
			
		||||
 | 
			
		||||
    core::Amounts const funds (
 | 
			
		||||
        view.accountFunds (mTxnAccountID, saTakerPays),
 | 
			
		||||
        view.accountFunds (mTxnAccountID, saTakerGets));
 | 
			
		||||
    
 | 
			
		||||
    if (m_journal.debug) m_journal.debug << " cross_flow: " <<
 | 
			
		||||
            cross_flow.in << ", " << cross_flow.out;
 | 
			
		||||
    
 | 
			
		||||
    if (m_journal.debug) m_journal.debug << "   balances: " <<
 | 
			
		||||
        funds.in << ", " << funds.out;
 | 
			
		||||
 | 
			
		||||
    saTakerPaid = cross_flow.in; 
 | 
			
		||||
    saTakerGot = cross_flow.out;
 | 
			
		||||
 | 
			
		||||
    if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
        "        result: " << transToken (result.first) <<
 | 
			
		||||
        (result.second ? " (consumed)" : "");
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TER DirectOfferCreateTransactor::doApply ()
 | 
			
		||||
{
 | 
			
		||||
    if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
        "OfferCreate> " << mTxn.getJson (0);
 | 
			
		||||
        
 | 
			
		||||
    std::uint32_t const uTxFlags = mTxn.getFlags ();
 | 
			
		||||
 | 
			
		||||
    bool const bPassive = is_bit_set (uTxFlags, tfPassive);
 | 
			
		||||
    bool const bImmediateOrCancel = is_bit_set (uTxFlags, tfImmediateOrCancel);
 | 
			
		||||
    bool const bFillOrKill = is_bit_set (uTxFlags, tfFillOrKill);
 | 
			
		||||
    bool const bSell = is_bit_set (uTxFlags, tfSell);
 | 
			
		||||
 | 
			
		||||
    STAmount saTakerPays = mTxn.getFieldAmount (sfTakerPays);
 | 
			
		||||
    STAmount saTakerGets = mTxn.getFieldAmount (sfTakerGets);
 | 
			
		||||
 | 
			
		||||
    if (!saTakerPays.isLegalNet () || !saTakerGets.isLegalNet ())
 | 
			
		||||
        return temBAD_AMOUNT;
 | 
			
		||||
 | 
			
		||||
    uint160 const uPaysIssuerID = saTakerPays.getIssuer ();
 | 
			
		||||
    uint160 const uGetsIssuerID = saTakerGets.getIssuer ();
 | 
			
		||||
 | 
			
		||||
    bool const bHaveExpiration (mTxn.isFieldPresent (sfExpiration));
 | 
			
		||||
    bool const bHaveCancel (mTxn.isFieldPresent (sfOfferSequence));
 | 
			
		||||
 | 
			
		||||
    std::uint32_t const uExpiration = mTxn.getFieldU32 (sfExpiration);
 | 
			
		||||
    std::uint32_t const uCancelSequence = mTxn.getFieldU32 (sfOfferSequence);
 | 
			
		||||
 | 
			
		||||
    // FIXME understand why we use SequenceNext instead of current transaction
 | 
			
		||||
    //       sequence to determine the transaction. Why is the offer seuqnce
 | 
			
		||||
    //       number insufficient?
 | 
			
		||||
 | 
			
		||||
    std::uint32_t const uAccountSequenceNext = mTxnAccount->getFieldU32 (sfSequence);
 | 
			
		||||
    std::uint32_t const uSequence = mTxn.getSequence ();
 | 
			
		||||
 | 
			
		||||
    const uint256 uLedgerIndex = Ledger::getOfferIndex (mTxnAccountID, uSequence);
 | 
			
		||||
 | 
			
		||||
    if (m_journal.debug)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.debug <<
 | 
			
		||||
            "Creating offer node: " << to_string (uLedgerIndex) <<
 | 
			
		||||
            " uSequence=" << uSequence;
 | 
			
		||||
 | 
			
		||||
        if (bImmediateOrCancel)
 | 
			
		||||
            m_journal.debug << "Transaction: IoC set.";
 | 
			
		||||
 | 
			
		||||
        if (bFillOrKill)
 | 
			
		||||
            m_journal.debug << "Transaction: FoK set.";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint160 const uPaysCurrency = saTakerPays.getCurrency ();
 | 
			
		||||
    uint160 const uGetsCurrency = saTakerGets.getCurrency ();
 | 
			
		||||
    std::uint64_t const uRate = STAmount::getRate (saTakerGets, saTakerPays);
 | 
			
		||||
 | 
			
		||||
    TER terResult (tesSUCCESS);
 | 
			
		||||
    uint256 uDirectory; // Delete hints.
 | 
			
		||||
    std::uint64_t uOwnerNode;
 | 
			
		||||
    std::uint64_t uBookNode;
 | 
			
		||||
 | 
			
		||||
    // This is the ledger view that we work against. Transactions are applied
 | 
			
		||||
    // as we go on processing transactions.
 | 
			
		||||
    core::LedgerView& view (mEngine->view ());
 | 
			
		||||
 | 
			
		||||
    // This is a checkpoint with just the fees paid. If something goes wrong
 | 
			
		||||
    // with this transaction, we roll back to this ledger.
 | 
			
		||||
    core::LedgerView view_checkpoint (view);
 | 
			
		||||
 | 
			
		||||
    view.bumpSeq (); // Begin ledger variance.
 | 
			
		||||
 | 
			
		||||
    SLE::pointer sleCreator = mEngine->entryCache (
 | 
			
		||||
        ltACCOUNT_ROOT, Ledger::getAccountRootIndex (mTxnAccountID));
 | 
			
		||||
 | 
			
		||||
    if (uTxFlags & tfOfferCreateMask)
 | 
			
		||||
    {
 | 
			
		||||
        if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
            "Malformed transaction: Invalid flags set.";
 | 
			
		||||
 | 
			
		||||
        return temINVALID_FLAG;
 | 
			
		||||
    }
 | 
			
		||||
    else if (bImmediateOrCancel && bFillOrKill)
 | 
			
		||||
    {
 | 
			
		||||
        if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
            "Malformed transaction: both IoC and FoK set.";
 | 
			
		||||
 | 
			
		||||
        return temINVALID_FLAG;
 | 
			
		||||
    }
 | 
			
		||||
    else if (bHaveExpiration && !uExpiration)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.warning <<
 | 
			
		||||
            "Malformed offer: bad expiration";
 | 
			
		||||
 | 
			
		||||
        terResult = temBAD_EXPIRATION;
 | 
			
		||||
    }
 | 
			
		||||
    else if (saTakerPays.isNative () && saTakerGets.isNative ())
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.warning <<
 | 
			
		||||
            "Malformed offer: XRP for XRP";
 | 
			
		||||
 | 
			
		||||
        terResult   = temBAD_OFFER;
 | 
			
		||||
    }
 | 
			
		||||
    else if (saTakerPays <= zero || saTakerGets <= zero)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.warning <<
 | 
			
		||||
            "Malformed offer: bad amount";
 | 
			
		||||
 | 
			
		||||
        terResult   = temBAD_OFFER;
 | 
			
		||||
    }
 | 
			
		||||
    else if (uPaysCurrency == uGetsCurrency && uPaysIssuerID == uGetsIssuerID)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.warning <<
 | 
			
		||||
            "Malformed offer: redundant offer";
 | 
			
		||||
 | 
			
		||||
        terResult = temREDUNDANT;
 | 
			
		||||
    }
 | 
			
		||||
    // We don't allow a non-native currency to use the currency code XRP.
 | 
			
		||||
    else if (CURRENCY_BAD == uPaysCurrency || CURRENCY_BAD == uGetsCurrency)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.warning <<
 | 
			
		||||
            "Malformed offer: Bad currency.";
 | 
			
		||||
 | 
			
		||||
        terResult = temBAD_CURRENCY;
 | 
			
		||||
    }
 | 
			
		||||
    else if (saTakerPays.isNative () != !uPaysIssuerID || saTakerGets.isNative () != !uGetsIssuerID)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.warning <<
 | 
			
		||||
            "Malformed offer: bad issuer";
 | 
			
		||||
 | 
			
		||||
        terResult = temBAD_ISSUER;
 | 
			
		||||
    }
 | 
			
		||||
    else if (view.accountFunds (mTxnAccountID, saTakerGets) <= zero)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.warning <<
 | 
			
		||||
            "delay: Offers must be at least partially funded.";
 | 
			
		||||
 | 
			
		||||
        terResult = tecUNFUNDED_OFFER;
 | 
			
		||||
    }
 | 
			
		||||
    // This can probably be simplified to make sure that you cancel sequences
 | 
			
		||||
    // before the transaction sequence number.
 | 
			
		||||
    else if (bHaveCancel && (!uCancelSequence || uAccountSequenceNext - 1 <= uCancelSequence))
 | 
			
		||||
    {
 | 
			
		||||
        if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
            "uAccountSequenceNext=" << uAccountSequenceNext <<
 | 
			
		||||
            " uOfferSequence=" << uCancelSequence;
 | 
			
		||||
 | 
			
		||||
        terResult = temBAD_SEQUENCE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (tesSUCCESS != terResult)
 | 
			
		||||
    {
 | 
			
		||||
        if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
            "final terResult=" << transToken (terResult);
 | 
			
		||||
 | 
			
		||||
        return terResult;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Process a cancellation request that's passed along with an offer.
 | 
			
		||||
    if ((tesSUCCESS == terResult) && bHaveCancel)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 const uCancelIndex (
 | 
			
		||||
            Ledger::getOfferIndex (mTxnAccountID, uCancelSequence));
 | 
			
		||||
        SLE::pointer sleCancel = mEngine->entryCache (ltOFFER, uCancelIndex);
 | 
			
		||||
 | 
			
		||||
        // It's not an error to not find the offer to cancel: it might have
 | 
			
		||||
        // been consumed or removed as we are processing. Additionally, it
 | 
			
		||||
        // might not even have been an offer - we don't care.
 | 
			
		||||
        if (sleCancel)
 | 
			
		||||
        {
 | 
			
		||||
            m_journal.warning <<
 | 
			
		||||
                "Cancelling order with sequence " << uCancelSequence;
 | 
			
		||||
 | 
			
		||||
            terResult = view.offerDelete (sleCancel);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Expiration is defined in terms of the close time of the parent ledger,
 | 
			
		||||
    // because we definitively know the time that it closed but we do not
 | 
			
		||||
    // know the closing time of the ledger that is under construction.
 | 
			
		||||
    if (bHaveExpiration &&
 | 
			
		||||
        (mEngine->getLedger ()->getParentCloseTimeNC () >= uExpiration))
 | 
			
		||||
    {
 | 
			
		||||
        return tesSUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If all is well and this isn't an offer to XRP, then we make sure we are
 | 
			
		||||
    // authorized to hold what the taker will pay.
 | 
			
		||||
    if (tesSUCCESS == terResult && !saTakerPays.isNative ())
 | 
			
		||||
    {
 | 
			
		||||
        SLE::pointer sleTakerPays = mEngine->entryCache (
 | 
			
		||||
            ltACCOUNT_ROOT, Ledger::getAccountRootIndex (uPaysIssuerID));
 | 
			
		||||
 | 
			
		||||
        if (!sleTakerPays)
 | 
			
		||||
        {
 | 
			
		||||
            m_journal.warning <<
 | 
			
		||||
                "delay: can't receive IOUs from non-existent issuer: " <<
 | 
			
		||||
                RippleAddress::createHumanAccountID (uPaysIssuerID);
 | 
			
		||||
 | 
			
		||||
            return is_bit_set (mParams, tapRETRY)
 | 
			
		||||
                ? terNO_ACCOUNT
 | 
			
		||||
                : tecNO_ISSUER;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if (is_bit_set (sleTakerPays->getFieldU32 (sfFlags), lsfRequireAuth))
 | 
			
		||||
        {
 | 
			
		||||
            SLE::pointer sleRippleState (mEngine->entryCache (
 | 
			
		||||
                ltRIPPLE_STATE,
 | 
			
		||||
                Ledger::getRippleStateIndex (
 | 
			
		||||
                    mTxnAccountID, uPaysIssuerID, uPaysCurrency)));
 | 
			
		||||
 | 
			
		||||
            if (!sleRippleState)
 | 
			
		||||
            {
 | 
			
		||||
                return is_bit_set (mParams, tapRETRY)
 | 
			
		||||
                    ? terNO_LINE
 | 
			
		||||
                    : tecNO_LINE;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Entries have a canonical representation, determined by a
 | 
			
		||||
            // lexicographical "greater than" comparison employing strict weak
 | 
			
		||||
            // ordering. Determine which entry we need to access.
 | 
			
		||||
            bool const canonical_gt (mTxnAccountID > uPaysIssuerID);
 | 
			
		||||
 | 
			
		||||
            bool const need_auth (is_bit_set (
 | 
			
		||||
                sleRippleState->getFieldU32 (sfFlags),
 | 
			
		||||
                (canonical_gt ? lsfLowAuth : lsfHighAuth)));
 | 
			
		||||
 | 
			
		||||
            if (need_auth)
 | 
			
		||||
            {
 | 
			
		||||
                if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
                    "delay: can't receive IOUs from issuer without auth.";
 | 
			
		||||
 | 
			
		||||
                return is_bit_set (mParams, tapRETRY)
 | 
			
		||||
                    ? terNO_AUTH
 | 
			
		||||
                    : tecNO_AUTH;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    STAmount saPaid;
 | 
			
		||||
    STAmount saGot;
 | 
			
		||||
    bool const bOpenLedger = is_bit_set (mParams, tapOPEN_LEDGER);
 | 
			
		||||
    bool const placeOffer = true;
 | 
			
		||||
 | 
			
		||||
    if (tesSUCCESS == terResult)
 | 
			
		||||
    {
 | 
			
		||||
        // Take using the parameters of the offer.
 | 
			
		||||
        if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
            "takeOffers: BEFORE saTakerGets=" << saTakerGets.getFullText ();
 | 
			
		||||
 | 
			
		||||
        auto ret = crossOffers (
 | 
			
		||||
            view,
 | 
			
		||||
            saTakerGets,  // Reverse as we are the taker for taking.
 | 
			
		||||
            saTakerPays,
 | 
			
		||||
            saPaid,       // Buy semantics: how much would have sold at full price. Sell semantics: how much was sold.
 | 
			
		||||
            saGot);       // How much was got.
 | 
			
		||||
 | 
			
		||||
        terResult = ret.first;
 | 
			
		||||
 | 
			
		||||
        if (terResult == tecFAILED_PROCESSING && bOpenLedger)
 | 
			
		||||
            terResult = telFAILED_PROCESSING;
 | 
			
		||||
 | 
			
		||||
        if (m_journal.debug)
 | 
			
		||||
        {
 | 
			
		||||
            m_journal.debug << "takeOffers=" << terResult;
 | 
			
		||||
            m_journal.debug << "takeOffers: saPaid=" << saPaid.getFullText ();
 | 
			
		||||
            m_journal.debug << "takeOffers:  saGot=" << saGot.getFullText ();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (tesSUCCESS == terResult)
 | 
			
		||||
        {
 | 
			
		||||
            // Reduce pay in from takers by what offer just got.
 | 
			
		||||
            saTakerPays -= saGot;
 | 
			
		||||
 | 
			
		||||
            // Reduce pay out to takers by what srcAccount just paid.
 | 
			
		||||
            saTakerGets -= saPaid;
 | 
			
		||||
 | 
			
		||||
            if (m_journal.debug)
 | 
			
		||||
            {
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: AFTER saTakerPays=" <<
 | 
			
		||||
                    saTakerPays.getFullText ();
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: AFTER saTakerGets=" <<
 | 
			
		||||
                    saTakerGets.getFullText ();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_journal.debug)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.debug <<
 | 
			
		||||
            "takeOffers: saTakerPays=" <<saTakerPays.getFullText ();
 | 
			
		||||
        m_journal.debug <<
 | 
			
		||||
            "takeOffers: saTakerGets=" << saTakerGets.getFullText ();
 | 
			
		||||
        m_journal.debug <<
 | 
			
		||||
            "takeOffers: mTxnAccountID=" <<
 | 
			
		||||
            RippleAddress::createHumanAccountID (mTxnAccountID);
 | 
			
		||||
        m_journal.debug <<
 | 
			
		||||
            "takeOffers:         FUNDS=" <<
 | 
			
		||||
            view.accountFunds (mTxnAccountID, saTakerGets).getFullText ();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (tesSUCCESS != terResult)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.debug <<
 | 
			
		||||
            "final terResult=" << transToken (terResult);
 | 
			
		||||
 | 
			
		||||
        return terResult;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (bFillOrKill && (saTakerPays || saTakerGets))
 | 
			
		||||
    {
 | 
			
		||||
        // Fill or kill and have leftovers.
 | 
			
		||||
        view.swapWith (view_checkpoint); // Restore with just fees paid.
 | 
			
		||||
        return tesSUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!placeOffer
 | 
			
		||||
        || saTakerPays <= zero                                          // Wants nothing more.
 | 
			
		||||
        || saTakerGets <= zero                                          // Offering nothing more.
 | 
			
		||||
        || bImmediateOrCancel                                           // Do not persist.
 | 
			
		||||
        || view.accountFunds (mTxnAccountID, saTakerGets) <= zero)      // Not funded.
 | 
			
		||||
    {
 | 
			
		||||
        // Complete as is.
 | 
			
		||||
        nothing ();
 | 
			
		||||
    }
 | 
			
		||||
    else if (mPriorBalance.getNValue () < mEngine->getLedger ()->getReserve (sleCreator->getFieldU32 (sfOwnerCount) + 1))
 | 
			
		||||
    {
 | 
			
		||||
        // If we are here, the signing account had an insufficient reserve
 | 
			
		||||
        // *prior* to our processing. We use the prior balance to simplify
 | 
			
		||||
        // client writing and make the user experience better.
 | 
			
		||||
 | 
			
		||||
        if (bOpenLedger) // Ledger is not final, can vote no.
 | 
			
		||||
        {
 | 
			
		||||
            // Hope for more reserve to come in or more offers to consume. If we
 | 
			
		||||
            // specified a local error this transaction will not be retried, so
 | 
			
		||||
            // specify a tec to distribute the transaction and allow it to be
 | 
			
		||||
            // retried. In particular, it may have been successful to a
 | 
			
		||||
            // degree (partially filled) and if it hasn't, it might succeed.
 | 
			
		||||
            terResult = tecINSUF_RESERVE_OFFER;
 | 
			
		||||
        }
 | 
			
		||||
        else if (!saPaid && !saGot)
 | 
			
		||||
        {
 | 
			
		||||
            // Ledger is final, insufficent reserve to create offer, processed
 | 
			
		||||
            // nothing.
 | 
			
		||||
 | 
			
		||||
            terResult = tecINSUF_RESERVE_OFFER;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // Ledger is final, insufficent reserve to create offer, processed
 | 
			
		||||
            // something.
 | 
			
		||||
 | 
			
		||||
            // Consider the offer unfunded. Treat as tesSUCCESS.
 | 
			
		||||
            nothing ();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        // We need to place the remainder of the offer into its order book.
 | 
			
		||||
        if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
            "offer not fully consumed:" <<
 | 
			
		||||
            " saTakerPays=" << saTakerPays.getFullText () <<
 | 
			
		||||
            " saTakerGets=" << saTakerGets.getFullText ();
 | 
			
		||||
 | 
			
		||||
        // Add offer to owner's directory.
 | 
			
		||||
        terResult   = view.dirAdd (uOwnerNode,
 | 
			
		||||
            Ledger::getOwnerDirIndex (mTxnAccountID), uLedgerIndex,
 | 
			
		||||
            BIND_TYPE (&Ledger::ownerDirDescriber, P_1, P_2, mTxnAccountID));
 | 
			
		||||
 | 
			
		||||
        if (tesSUCCESS == terResult)
 | 
			
		||||
        {
 | 
			
		||||
            // Update owner count.
 | 
			
		||||
            view.ownerCountAdjust (mTxnAccountID, 1, sleCreator);
 | 
			
		||||
 | 
			
		||||
            uint256 uBookBase   = Ledger::getBookBase (
 | 
			
		||||
                uPaysCurrency,
 | 
			
		||||
                uPaysIssuerID,
 | 
			
		||||
                uGetsCurrency,
 | 
			
		||||
                uGetsIssuerID);
 | 
			
		||||
 | 
			
		||||
            if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
                "adding to book: " << to_string (uBookBase) <<
 | 
			
		||||
                " : " << saTakerPays.getHumanCurrency () <<
 | 
			
		||||
                "/" << RippleAddress::createHumanAccountID (saTakerPays.getIssuer ()) <<
 | 
			
		||||
                " -> " << saTakerGets.getHumanCurrency () <<
 | 
			
		||||
                "/" << RippleAddress::createHumanAccountID (saTakerGets.getIssuer ());
 | 
			
		||||
 | 
			
		||||
            // We use the original rate to place the offer.
 | 
			
		||||
            uDirectory = Ledger::getQualityIndex (uBookBase, uRate);
 | 
			
		||||
 | 
			
		||||
            // Add offer to order book.
 | 
			
		||||
            terResult = view.dirAdd (uBookNode, uDirectory, uLedgerIndex,
 | 
			
		||||
                BIND_TYPE (&Ledger::qualityDirDescriber, P_1, P_2,
 | 
			
		||||
                    saTakerPays.getCurrency (), uPaysIssuerID,
 | 
			
		||||
                    saTakerGets.getCurrency (), uGetsIssuerID, uRate));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (tesSUCCESS == terResult)
 | 
			
		||||
        {
 | 
			
		||||
            if (m_journal.debug)
 | 
			
		||||
            {
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "sfAccount=" <<
 | 
			
		||||
                    RippleAddress::createHumanAccountID (mTxnAccountID);
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "uPaysIssuerID=" <<
 | 
			
		||||
                    RippleAddress::createHumanAccountID (uPaysIssuerID);
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "uGetsIssuerID=" <<
 | 
			
		||||
                    RippleAddress::createHumanAccountID (uGetsIssuerID);
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "saTakerPays.isNative()=" <<
 | 
			
		||||
                    saTakerPays.isNative ();
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "saTakerGets.isNative()=" <<
 | 
			
		||||
                    saTakerGets.isNative ();
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "uPaysCurrency=" <<
 | 
			
		||||
                    saTakerPays.getHumanCurrency ();
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "uGetsCurrency=" <<
 | 
			
		||||
                    saTakerGets.getHumanCurrency ();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SLE::pointer sleOffer (mEngine->entryCreate (ltOFFER, uLedgerIndex));
 | 
			
		||||
 | 
			
		||||
            sleOffer->setFieldAccount (sfAccount, mTxnAccountID);
 | 
			
		||||
            sleOffer->setFieldU32 (sfSequence, uSequence);
 | 
			
		||||
            sleOffer->setFieldH256 (sfBookDirectory, uDirectory);
 | 
			
		||||
            sleOffer->setFieldAmount (sfTakerPays, saTakerPays);
 | 
			
		||||
            sleOffer->setFieldAmount (sfTakerGets, saTakerGets);
 | 
			
		||||
            sleOffer->setFieldU64 (sfOwnerNode, uOwnerNode);
 | 
			
		||||
            sleOffer->setFieldU64 (sfBookNode, uBookNode);
 | 
			
		||||
 | 
			
		||||
            if (uExpiration)
 | 
			
		||||
                sleOffer->setFieldU32 (sfExpiration, uExpiration);
 | 
			
		||||
 | 
			
		||||
            if (bPassive)
 | 
			
		||||
                sleOffer->setFlag (lsfPassive);
 | 
			
		||||
 | 
			
		||||
            if (bSell)
 | 
			
		||||
                sleOffer->setFlag (lsfSell);
 | 
			
		||||
 | 
			
		||||
            if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
                "final terResult=" << transToken (terResult) <<
 | 
			
		||||
                " sleOffer=" << sleOffer->getJson (0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (tesSUCCESS != terResult)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.debug <<
 | 
			
		||||
            "final terResult=" << transToken (terResult);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return terResult;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										59
									
								
								src/ripple_app/transactors/CreateOfferDirect.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/ripple_app/transactors/CreateOfferDirect.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
    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_TX_DIRECT_OFFERCREATE_H_INCLUDED
 | 
			
		||||
#define RIPPLE_TX_DIRECT_OFFERCREATE_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include "../book/OfferStream.h"
 | 
			
		||||
#include "../book/Taker.h"
 | 
			
		||||
    
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
class DirectOfferCreateTransactor
 | 
			
		||||
    : public OfferCreateTransactor
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    DirectOfferCreateTransactor (
 | 
			
		||||
        SerializedTransaction const& txn,
 | 
			
		||||
        TransactionEngineParams params,
 | 
			
		||||
        TransactionEngine* engine)
 | 
			
		||||
        : OfferCreateTransactor (
 | 
			
		||||
            txn,
 | 
			
		||||
            params,
 | 
			
		||||
            engine)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    TER doApply () override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::pair<TER,bool> crossOffers (
 | 
			
		||||
        core::LedgerView& view,
 | 
			
		||||
        STAmount const&     saTakerPays,
 | 
			
		||||
        STAmount const&     saTakerGets,
 | 
			
		||||
        STAmount&           saTakerPaid,
 | 
			
		||||
        STAmount&           saTakerGot);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -22,7 +22,7 @@ namespace ripple {
 | 
			
		||||
/** Determine if an order is still valid
 | 
			
		||||
    If the order is not valid it will be marked as unfunded.
 | 
			
		||||
*/
 | 
			
		||||
bool OfferCreateTransactor::isValidOffer (
 | 
			
		||||
bool ClassicOfferCreateTransactor::isValidOffer (
 | 
			
		||||
    SLE::ref sleOffer,
 | 
			
		||||
    uint160 const& uOfferOwnerID,
 | 
			
		||||
    STAmount const& saOfferPays,
 | 
			
		||||
@@ -36,7 +36,7 @@ bool OfferCreateTransactor::isValidOffer (
 | 
			
		||||
        sleOffer->getFieldU32 (sfExpiration) <= mEngine->getLedger ()->getParentCloseTimeNC ())
 | 
			
		||||
    {
 | 
			
		||||
        // Offer is expired. Expired offers are considered unfunded. Delete it.
 | 
			
		||||
        m_journal.trace << "isValidOffer: encountered expired offer";
 | 
			
		||||
        m_journal.debug << "isValidOffer: encountered expired offer";
 | 
			
		||||
 | 
			
		||||
        usOfferUnfundedFound.insert (sleOffer->getIndex());
 | 
			
		||||
 | 
			
		||||
@@ -46,7 +46,7 @@ bool OfferCreateTransactor::isValidOffer (
 | 
			
		||||
    if (uOfferOwnerID == uTakerAccountID)
 | 
			
		||||
    {
 | 
			
		||||
        // Would take own offer. Consider old offer expired. Delete it.
 | 
			
		||||
        m_journal.trace << "isValidOffer: encountered taker's own old offer";
 | 
			
		||||
        m_journal.debug << "isValidOffer: encountered taker's own old offer";
 | 
			
		||||
 | 
			
		||||
        usOfferUnfundedFound.insert (sleOffer->getIndex());
 | 
			
		||||
 | 
			
		||||
@@ -65,7 +65,7 @@ bool OfferCreateTransactor::isValidOffer (
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_journal.trace <<
 | 
			
		||||
    m_journal.debug <<
 | 
			
		||||
        "isValidOffer: saOfferPays=" << saOfferPays.getFullText ();
 | 
			
		||||
 | 
			
		||||
    saOfferFunds = mEngine->view ().accountFunds (uOfferOwnerID, saOfferPays);
 | 
			
		||||
@@ -97,7 +97,7 @@ bool OfferCreateTransactor::isValidOffer (
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
*/
 | 
			
		||||
bool OfferCreateTransactor::canCross (
 | 
			
		||||
bool ClassicOfferCreateTransactor::canCross (
 | 
			
		||||
    STAmount const& saTakerFunds,
 | 
			
		||||
    STAmount const& saSubTakerPays,
 | 
			
		||||
    STAmount const& saSubTakerGets,
 | 
			
		||||
@@ -189,7 +189,7 @@ bool OfferCreateTransactor::canCross (
 | 
			
		||||
    books as: "give 0.57 BTC for 400 USD" which is what is left to sell at the
 | 
			
		||||
    original rate.
 | 
			
		||||
*/
 | 
			
		||||
bool OfferCreateTransactor::applyOffer (
 | 
			
		||||
bool ClassicOfferCreateTransactor::applyOffer (
 | 
			
		||||
    const bool bSell,
 | 
			
		||||
    const std::uint32_t uTakerPaysRate, const std::uint32_t uOfferPaysRate,
 | 
			
		||||
    const STAmount& saOfferRate,
 | 
			
		||||
@@ -210,17 +210,17 @@ bool OfferCreateTransactor::applyOffer (
 | 
			
		||||
                                          ? saOfferFunds          // As is.
 | 
			
		||||
                                          : STAmount::divide (saOfferFunds, STAmount (CURRENCY_ONE, ACCOUNT_ONE, uOfferPaysRate, -9)); // Reduce by offer fees.
 | 
			
		||||
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: uOfferPaysRate=" << uOfferPaysRate;
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: saOfferFundsAvailable=" << saOfferFundsAvailable.getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: uOfferPaysRate=" << uOfferPaysRate;
 | 
			
		||||
    m_journal.info << "applyOffer: saOfferFundsAvailable=" << saOfferFundsAvailable.getFullText ();
 | 
			
		||||
 | 
			
		||||
    // Limit taker funds available, by transfer fees.
 | 
			
		||||
    STAmount    saTakerFundsAvailable   = QUALITY_ONE == uTakerPaysRate
 | 
			
		||||
                                          ? saTakerFunds          // As is.
 | 
			
		||||
                                          : STAmount::divide (saTakerFunds, STAmount (CURRENCY_ONE, ACCOUNT_ONE, uTakerPaysRate, -9)); // Reduce by taker fees.
 | 
			
		||||
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: TAKER_FEES=" << STAmount (CURRENCY_ONE, ACCOUNT_ONE, uTakerPaysRate, -9).getFullText ();
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: uTakerPaysRate=" << uTakerPaysRate;
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: saTakerFundsAvailable=" << saTakerFundsAvailable.getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: TAKER_FEES=" << STAmount (CURRENCY_ONE, ACCOUNT_ONE, uTakerPaysRate, -9).getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: uTakerPaysRate=" << uTakerPaysRate;
 | 
			
		||||
    m_journal.info << "applyOffer: saTakerFundsAvailable=" << saTakerFundsAvailable.getFullText ();
 | 
			
		||||
 | 
			
		||||
    STAmount    saOfferPaysAvailable;   // Amount offer can pay out, limited by offer and offerer funds.
 | 
			
		||||
    STAmount    saOfferGetsAvailable;   // Amount offer would get, limited by offer funds.
 | 
			
		||||
@@ -240,24 +240,24 @@ bool OfferCreateTransactor::applyOffer (
 | 
			
		||||
        saOfferGetsAvailable    = std::min (saOfferGets, STAmount::mulRound (saOfferPaysAvailable, saOfferRate, saOfferGets, true));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable.getFullText ();
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: saOfferGetsAvailable=" << saOfferGetsAvailable.getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable.getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: saOfferGetsAvailable=" << saOfferGetsAvailable.getFullText ();
 | 
			
		||||
 | 
			
		||||
    STAmount    saTakerPaysAvailable    = std::min (saTakerPays, saTakerFundsAvailable);
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: saTakerPaysAvailable=" << saTakerPaysAvailable.getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: saTakerPaysAvailable=" << saTakerPaysAvailable.getFullText ();
 | 
			
		||||
 | 
			
		||||
    // Limited = limited by other sides raw numbers.
 | 
			
		||||
    // Taker can't pay more to offer than offer can get.
 | 
			
		||||
    STAmount    saTakerPaysLimited      = std::min (saTakerPaysAvailable, saOfferGetsAvailable);
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: saTakerPaysLimited=" << saTakerPaysLimited.getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: saTakerPaysLimited=" << saTakerPaysLimited.getFullText ();
 | 
			
		||||
 | 
			
		||||
    // Align saTakerGetsLimited with saTakerPaysLimited.
 | 
			
		||||
    STAmount    saTakerGetsLimited      = saTakerPaysLimited >= saOfferGetsAvailable              // Cannot actually be greater
 | 
			
		||||
                                          ? saOfferPaysAvailable                                  // Potentially take entire offer. Avoid math shenanigans.
 | 
			
		||||
                                          : std::min (saOfferPaysAvailable, STAmount::divRound (saTakerPaysLimited, saOfferRate, saTakerGets, true)); // Take a portion of offer.
 | 
			
		||||
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: saOfferRate=" << saOfferRate.getFullText ();
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: saTakerGetsLimited=" << saTakerGetsLimited.getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: saOfferRate=" << saOfferRate.getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: saTakerGetsLimited=" << saTakerGetsLimited.getFullText ();
 | 
			
		||||
 | 
			
		||||
    // Got & Paid = Calculated by price and transfered without fees.
 | 
			
		||||
    // Compute from got as when !bSell, we want got to be exact to finish off offer if possible.
 | 
			
		||||
@@ -269,8 +269,8 @@ bool OfferCreateTransactor::applyOffer (
 | 
			
		||||
                  ? saTakerPaysLimited
 | 
			
		||||
                  : std::min (saTakerPaysLimited, STAmount::mulRound (saTakerGot, saOfferRate, saTakerFunds, true));
 | 
			
		||||
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: saTakerGot=" << saTakerGot.getFullText ();
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: saTakerPaid=" << saTakerPaid.getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: saTakerGot=" << saTakerGot.getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: saTakerPaid=" << saTakerPaid.getFullText ();
 | 
			
		||||
 | 
			
		||||
    if (uTakerPaysRate == QUALITY_ONE)
 | 
			
		||||
    {
 | 
			
		||||
@@ -281,17 +281,17 @@ bool OfferCreateTransactor::applyOffer (
 | 
			
		||||
        // Compute fees in a rounding safe way.
 | 
			
		||||
 | 
			
		||||
        STAmount    saTransferRate  = STAmount (CURRENCY_ONE, ACCOUNT_ONE, uTakerPaysRate, -9);
 | 
			
		||||
        WriteLog (lsINFO, STAmount) << "applyOffer: saTransferRate=" << saTransferRate.getFullText ();
 | 
			
		||||
        m_journal.info << "applyOffer: saTransferRate=" << saTransferRate.getFullText ();
 | 
			
		||||
 | 
			
		||||
        // TakerCost includes transfer fees.
 | 
			
		||||
        STAmount    saTakerCost     = STAmount::mulRound (saTakerPaid, saTransferRate, true);
 | 
			
		||||
 | 
			
		||||
        WriteLog (lsINFO, STAmount) << "applyOffer: saTakerCost=" << saTakerCost.getFullText ();
 | 
			
		||||
        WriteLog (lsINFO, STAmount) << "applyOffer: saTakerFunds=" << saTakerFunds.getFullText ();
 | 
			
		||||
        m_journal.info << "applyOffer: saTakerCost=" << saTakerCost.getFullText ();
 | 
			
		||||
        m_journal.info << "applyOffer: saTakerFunds=" << saTakerFunds.getFullText ();
 | 
			
		||||
        saTakerIssuerFee    = saTakerCost > saTakerFunds
 | 
			
		||||
                              ? saTakerFunds - saTakerPaid // Not enough funds to cover fee, stiff issuer the rounding error.
 | 
			
		||||
                              : saTakerCost - saTakerPaid;
 | 
			
		||||
        WriteLog (lsINFO, STAmount) << "applyOffer: saTakerIssuerFee=" << saTakerIssuerFee.getFullText ();
 | 
			
		||||
        m_journal.info << "applyOffer: saTakerIssuerFee=" << saTakerIssuerFee.getFullText ();
 | 
			
		||||
        assert (saTakerIssuerFee >= zero);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -309,7 +309,7 @@ bool OfferCreateTransactor::applyOffer (
 | 
			
		||||
                              : saOfferCost - saTakerGot;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    WriteLog (lsINFO, STAmount) << "applyOffer: saTakerGot=" << saTakerGot.getFullText ();
 | 
			
		||||
    m_journal.info << "applyOffer: saTakerGot=" << saTakerGot.getFullText ();
 | 
			
		||||
 | 
			
		||||
    return saTakerGot >= saOfferPaysAvailable;              // True, if consumed offer.
 | 
			
		||||
}
 | 
			
		||||
@@ -327,7 +327,7 @@ bool OfferCreateTransactor::applyOffer (
 | 
			
		||||
    @return tesSUCCESS, terNO_ACCOUNT, telFAILED_PROCESSING, or
 | 
			
		||||
            tecFAILED_PROCESSING
 | 
			
		||||
*/
 | 
			
		||||
TER OfferCreateTransactor::takeOffers (
 | 
			
		||||
TER ClassicOfferCreateTransactor::takeOffers (
 | 
			
		||||
    const bool          bOpenLedger,
 | 
			
		||||
    const bool          bPassive,
 | 
			
		||||
    const bool          bSell,
 | 
			
		||||
@@ -376,38 +376,6 @@ TER OfferCreateTransactor::takeOffers (
 | 
			
		||||
        saTakerPays.getCurrency(), saTakerPays.getIssuer(),
 | 
			
		||||
        saTakerGets.getCurrency(), saTakerGets.getIssuer());
 | 
			
		||||
 | 
			
		||||
#ifdef RIPPLE_AUTOBRIDGE
 | 
			
		||||
    std::unique_ptr<OrderBookIterator> bridgeBookIn;
 | 
			
		||||
    std::unique_ptr<OrderBookIterator> bridgeBookOut;
 | 
			
		||||
 | 
			
		||||
    // If XRP isn't an already an endpoint, then we also create two additional
 | 
			
		||||
    // iterators:
 | 
			
		||||
    //  (1) source -> XPR
 | 
			
		||||
    //  (2) XRP -> target
 | 
			
		||||
    if (!saTakerPays.isNative () && !saTakerGets.isNative ())
 | 
			
		||||
    {
 | 
			
		||||
        if (m_journal.trace)
 | 
			
		||||
        {
 | 
			
		||||
            beast::Journal::ScopedStream ss (m_journal.trace);
 | 
			
		||||
 | 
			
		||||
            ss <<
 | 
			
		||||
                "Autobridging offer '" << saTakerPays.getFullText () <<
 | 
			
		||||
                "' to '" << saTakerGets.getFullText () << "'" << std::endl;
 | 
			
		||||
 | 
			
		||||
            ss <<
 | 
			
		||||
                "Selected bridge: '" <<
 | 
			
		||||
                    STAmount::createHumanCurrency(saTakerPays.getCurrency()) <<
 | 
			
		||||
                    "/" <<
 | 
			
		||||
                    RippleAddress::createHumanAccountID (saTakerPays.getIssuer()) <<
 | 
			
		||||
                "' - XRP - '" <<
 | 
			
		||||
                    STAmount::createHumanCurrency(saTakerGets.getCurrency ()) <<
 | 
			
		||||
                    "/" <<
 | 
			
		||||
                    RippleAddress::createHumanAccountID (saTakerGets.getIssuer()) <<
 | 
			
		||||
                "'";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    while ((temUNCERTAIN == terResult) && directBookIter.nextOffer())
 | 
			
		||||
    {
 | 
			
		||||
        STAmount saTakerFunds = lesActive.accountFunds (uTakerAccountID, saTakerPays);
 | 
			
		||||
@@ -415,28 +383,6 @@ TER OfferCreateTransactor::takeOffers (
 | 
			
		||||
        STAmount saSubTakerGets = saTakerGets - saTakerGot; // How much more is wanted.
 | 
			
		||||
        std::uint64_t uTipQuality = directBookIter.getCurrentQuality();
 | 
			
		||||
 | 
			
		||||
#ifdef RIPPLE_AUTOBRIDGE
 | 
			
		||||
        if (bridgeBookIn && bridgeBookIn->nextOffer() &&
 | 
			
		||||
            bridgeBookOut && bridgeBookOut->nextOffer())
 | 
			
		||||
        {
 | 
			
		||||
            STAmount bridgeIn = STAmount::setRate (bridgeBookIn->getCurrentQuality());
 | 
			
		||||
            STAmount bridgeOut = STAmount::setRate (bridgeBookOut->getCurrentQuality());
 | 
			
		||||
 | 
			
		||||
            m_journal.error <<
 | 
			
		||||
                "The direct quality is: " << STAmount::setRate (uTipQuality);
 | 
			
		||||
 | 
			
		||||
            m_journal.error <<
 | 
			
		||||
                "The bridge-to-XRP quality is: " << bridgeIn;
 | 
			
		||||
 | 
			
		||||
            m_journal.error <<
 | 
			
		||||
                "The bridge-from-XRP quality is: " << bridgeOut;
 | 
			
		||||
 | 
			
		||||
            m_journal.error <<
 | 
			
		||||
                "The bridge synthetic quality is: " <<
 | 
			
		||||
                STAmount::multiply (bridgeIn, bridgeOut, CURRENCY_ONE, ACCOUNT_ONE);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        if (!canCross(
 | 
			
		||||
                saTakerFunds,
 | 
			
		||||
                saSubTakerPays,
 | 
			
		||||
@@ -495,39 +441,39 @@ TER OfferCreateTransactor::takeOffers (
 | 
			
		||||
            STAmount    saOfferIssuerFee;
 | 
			
		||||
            STAmount    saOfferRate = STAmount::setRate (uTipQuality);
 | 
			
		||||
 | 
			
		||||
            if (m_journal.trace)
 | 
			
		||||
            if (m_journal.debug)
 | 
			
		||||
            {
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: applyOffer:    saTakerPays: " <<
 | 
			
		||||
                    saTakerPays.getFullText ();
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: applyOffer:    saTakerPaid: " <<
 | 
			
		||||
                    saTakerPaid.getFullText ();
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: applyOffer:   saTakerFunds: " <<
 | 
			
		||||
                    saTakerFunds.getFullText ();
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: applyOffer:   saOfferFunds: " <<
 | 
			
		||||
                    saOfferFunds.getFullText ();
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: applyOffer:    saOfferPays: " <<
 | 
			
		||||
                    saOfferPays.getFullText ();
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: applyOffer:    saOfferGets: " <<
 | 
			
		||||
                    saOfferGets.getFullText ();
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: applyOffer:    saOfferRate: " <<
 | 
			
		||||
                    saOfferRate.getFullText ();
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: applyOffer: saSubTakerPays: " <<
 | 
			
		||||
                    saSubTakerPays.getFullText ();
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: applyOffer: saSubTakerGets: " <<
 | 
			
		||||
                    saSubTakerGets.getFullText ();
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: applyOffer:    saTakerPays: " <<
 | 
			
		||||
                    saTakerPays.getFullText ();
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "takeOffers: applyOffer:    saTakerGets: " <<
 | 
			
		||||
                    saTakerGets.getFullText ();
 | 
			
		||||
            }
 | 
			
		||||
@@ -725,9 +671,9 @@ TER OfferCreateTransactor::takeOffers (
 | 
			
		||||
    return terResult;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TER OfferCreateTransactor::doApply ()
 | 
			
		||||
TER ClassicOfferCreateTransactor::doApply ()
 | 
			
		||||
{
 | 
			
		||||
    if (m_journal.trace) m_journal.trace <<
 | 
			
		||||
    if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
        "OfferCreate> " << mTxn.getJson (0);
 | 
			
		||||
 | 
			
		||||
    std::uint32_t const uTxFlags = mTxn.getFlags ();
 | 
			
		||||
@@ -741,7 +687,7 @@ TER OfferCreateTransactor::doApply ()
 | 
			
		||||
    if (!saTakerPays.isLegalNet () || !saTakerGets.isLegalNet ())
 | 
			
		||||
        return temBAD_AMOUNT;
 | 
			
		||||
 | 
			
		||||
    m_journal.trace <<
 | 
			
		||||
    m_journal.debug <<
 | 
			
		||||
        "saTakerPays=" << saTakerPays.getFullText () <<
 | 
			
		||||
        " saTakerGets=" << saTakerGets.getFullText ();
 | 
			
		||||
 | 
			
		||||
@@ -763,7 +709,7 @@ TER OfferCreateTransactor::doApply ()
 | 
			
		||||
 | 
			
		||||
    const uint256 uLedgerIndex = Ledger::getOfferIndex (mTxnAccountID, uSequence);
 | 
			
		||||
 | 
			
		||||
    m_journal.trace <<
 | 
			
		||||
    m_journal.debug <<
 | 
			
		||||
        "Creating offer node: " << to_string (uLedgerIndex) <<
 | 
			
		||||
        " uSequence=" << uSequence;
 | 
			
		||||
 | 
			
		||||
@@ -785,14 +731,14 @@ TER OfferCreateTransactor::doApply ()
 | 
			
		||||
 | 
			
		||||
    if (uTxFlags & tfOfferCreateMask)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.trace <<
 | 
			
		||||
        m_journal.debug <<
 | 
			
		||||
            "Malformed transaction: Invalid flags set.";
 | 
			
		||||
 | 
			
		||||
        return temINVALID_FLAG;
 | 
			
		||||
    }
 | 
			
		||||
    else if (bImmediateOrCancel && bFillOrKill)
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.trace <<
 | 
			
		||||
        m_journal.debug <<
 | 
			
		||||
            "Malformed transaction: both IoC and FoK set.";
 | 
			
		||||
 | 
			
		||||
        return temINVALID_FLAG;
 | 
			
		||||
@@ -851,7 +797,7 @@ TER OfferCreateTransactor::doApply ()
 | 
			
		||||
    // before the transaction sequence number.
 | 
			
		||||
    else if (bHaveCancel && (!uCancelSequence || uAccountSequenceNext - 1 <= uCancelSequence))
 | 
			
		||||
    {
 | 
			
		||||
        m_journal.trace <<
 | 
			
		||||
        m_journal.debug <<
 | 
			
		||||
            "uAccountSequenceNext=" << uAccountSequenceNext <<
 | 
			
		||||
            " uOfferSequence=" << uCancelSequence;
 | 
			
		||||
 | 
			
		||||
@@ -1076,7 +1022,7 @@ TER OfferCreateTransactor::doApply ()
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        // We need to place the remainder of the offer into its order book.
 | 
			
		||||
        if (m_journal.trace) m_journal.trace <<
 | 
			
		||||
        if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
            "offer not fully consumed:" <<
 | 
			
		||||
            " saTakerPays=" << saTakerPays.getFullText () <<
 | 
			
		||||
            " saTakerGets=" << saTakerGets.getFullText ();
 | 
			
		||||
@@ -1127,10 +1073,10 @@ TER OfferCreateTransactor::doApply ()
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "uGetsIssuerID=" <<
 | 
			
		||||
                    RippleAddress::createHumanAccountID (uGetsIssuerID);
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "saTakerPays.isNative()=" <<
 | 
			
		||||
                    saTakerPays.isNative ();
 | 
			
		||||
                m_journal.trace <<
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
                    "saTakerGets.isNative()=" <<
 | 
			
		||||
                    saTakerGets.isNative ();
 | 
			
		||||
                m_journal.debug <<
 | 
			
		||||
@@ -1160,7 +1106,7 @@ TER OfferCreateTransactor::doApply ()
 | 
			
		||||
            if (bSell)
 | 
			
		||||
                sleOffer->setFlag (lsfSell);
 | 
			
		||||
 | 
			
		||||
            if (m_journal.trace) m_journal.trace <<
 | 
			
		||||
            if (m_journal.debug) m_journal.debug <<
 | 
			
		||||
                "final terResult=" << transToken (terResult) <<
 | 
			
		||||
                " sleOffer=" << sleOffer->getJson (0);
 | 
			
		||||
        }
 | 
			
		||||
@@ -1176,7 +1122,6 @@ TER OfferCreateTransactor::doApply ()
 | 
			
		||||
        {
 | 
			
		||||
            m_journal.trace <<
 | 
			
		||||
                "takeOffers: found unfunded: " << to_string (uOfferIndex);
 | 
			
		||||
 | 
			
		||||
            lesActive.offerDelete (uOfferIndex);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1207,7 +1152,7 @@ TER OfferCreateTransactor::doApply ()
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    m_journal.trace <<
 | 
			
		||||
                    m_journal.debug <<
 | 
			
		||||
                        "takeOffers: offer " << indexes.first <<
 | 
			
		||||
                        " not found in directory " << indexes.second;
 | 
			
		||||
                }
 | 
			
		||||
@@ -1221,11 +1166,10 @@ TER OfferCreateTransactor::doApply ()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (tesSUCCESS != terResult) m_journal.trace <<
 | 
			
		||||
    if (tesSUCCESS != terResult) m_journal.debug <<
 | 
			
		||||
        "final terResult=" << transToken (terResult);
 | 
			
		||||
 | 
			
		||||
    return terResult;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -17,24 +17,15 @@
 | 
			
		||||
*/
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#ifndef RIPPLE_TX_OFFERCREATE_H_INCLUDED
 | 
			
		||||
#define RIPPLE_TX_OFFERCREATE_H_INCLUDED
 | 
			
		||||
#ifndef RIPPLE_TX_CLASSIC_OFFERCREATE_H_INCLUDED
 | 
			
		||||
#define RIPPLE_TX_CLASSIC_OFFERCREATE_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
class OfferCreateTransactorLog;
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
char const*
 | 
			
		||||
LogPartition::getPartitionName <OfferCreateTransactorLog> ()
 | 
			
		||||
{
 | 
			
		||||
    return "Tx/OfferCreate";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class OfferCreateTransactor
 | 
			
		||||
    : public Transactor
 | 
			
		||||
class ClassicOfferCreateTransactor
 | 
			
		||||
    : public OfferCreateTransactor
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    template <class T>
 | 
			
		||||
@@ -52,20 +43,19 @@ private:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    OfferCreateTransactor (
 | 
			
		||||
    ClassicOfferCreateTransactor (
 | 
			
		||||
        SerializedTransaction const& txn,
 | 
			
		||||
        TransactionEngineParams params,
 | 
			
		||||
        TransactionEngine* engine)
 | 
			
		||||
        : Transactor (
 | 
			
		||||
        : OfferCreateTransactor (
 | 
			
		||||
            txn,
 | 
			
		||||
            params,
 | 
			
		||||
            engine,
 | 
			
		||||
            LogPartition::getJournal <OfferCreateTransactorLog> ())
 | 
			
		||||
            engine)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    TER doApply ();
 | 
			
		||||
    TER doApply () override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool isValidOffer (
 | 
			
		||||
@@ -18,14 +18,14 @@
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#include "Transactor.h"
 | 
			
		||||
#include "ChangeTransactor.h"
 | 
			
		||||
#include "OfferCancelTransactor.h"
 | 
			
		||||
#include "OfferCreateTransactor.h"
 | 
			
		||||
#include "PaymentTransactor.h"
 | 
			
		||||
#include "RegularKeySetTransactor.h"
 | 
			
		||||
#include "AccountSetTransactor.h"
 | 
			
		||||
#include "TrustSetTransactor.h"
 | 
			
		||||
#include "WalletAddTransactor.h"
 | 
			
		||||
#include "AddWallet.h"
 | 
			
		||||
#include "CancelOffer.h"
 | 
			
		||||
#include "Change.h"
 | 
			
		||||
#include "CreateOffer.h"
 | 
			
		||||
#include "Payment.h"
 | 
			
		||||
#include "SetAccount.h"
 | 
			
		||||
#include "SetRegularKey.h"
 | 
			
		||||
#include "SetTrust.h"
 | 
			
		||||
 | 
			
		||||
namespace ripple {
 | 
			
		||||
 | 
			
		||||
@@ -53,8 +53,7 @@ std::unique_ptr<Transactor> Transactor::makeTransactor (
 | 
			
		||||
            new TrustSetTransactor (txn, params, engine));
 | 
			
		||||
 | 
			
		||||
    case ttOFFER_CREATE:
 | 
			
		||||
        return std::unique_ptr<Transactor> (
 | 
			
		||||
            new OfferCreateTransactor (txn, params, engine));
 | 
			
		||||
        return make_OfferCreateTransactor (txn, params, engine);
 | 
			
		||||
 | 
			
		||||
    case ttOFFER_CANCEL:
 | 
			
		||||
        return std::unique_ptr<Transactor> (
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user