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