refactor Transaction. compiling. still need to test

This commit is contained in:
jed
2012-11-14 13:05:59 -08:00
parent c1611f3b07
commit 5bbdd90a4c
23 changed files with 1515 additions and 1516 deletions

View File

@@ -95,6 +95,7 @@
<ClCompile Include="src\cpp\json\json_reader.cpp" /> <ClCompile Include="src\cpp\json\json_reader.cpp" />
<ClCompile Include="src\cpp\json\json_value.cpp" /> <ClCompile Include="src\cpp\json\json_value.cpp" />
<ClCompile Include="src\cpp\json\json_writer.cpp" /> <ClCompile Include="src\cpp\json\json_writer.cpp" />
<ClCompile Include="src\cpp\ripple\AccountSetTransactor.cpp" />
<ClCompile Include="src\cpp\ripple\AccountState.cpp" /> <ClCompile Include="src\cpp\ripple\AccountState.cpp" />
<ClCompile Include="src\cpp\ripple\Amount.cpp" /> <ClCompile Include="src\cpp\ripple\Amount.cpp" />
<ClCompile Include="src\cpp\ripple\Application.cpp" /> <ClCompile Include="src\cpp\ripple\Application.cpp" />
@@ -127,17 +128,21 @@
<ClCompile Include="src\cpp\ripple\main.cpp" /> <ClCompile Include="src\cpp\ripple\main.cpp" />
<ClCompile Include="src\cpp\ripple\NetworkOPs.cpp" /> <ClCompile Include="src\cpp\ripple\NetworkOPs.cpp" />
<ClCompile Include="src\cpp\ripple\NicknameState.cpp" /> <ClCompile Include="src\cpp\ripple\NicknameState.cpp" />
<ClCompile Include="src\cpp\ripple\OfferCancelTransactor.cpp" />
<ClCompile Include="src\cpp\ripple\OfferCreateTransactor.cpp" />
<ClCompile Include="src\cpp\ripple\Operation.cpp" /> <ClCompile Include="src\cpp\ripple\Operation.cpp" />
<ClCompile Include="src\cpp\ripple\OrderBook.cpp" /> <ClCompile Include="src\cpp\ripple\OrderBook.cpp" />
<ClCompile Include="src\cpp\ripple\OrderBookDB.cpp" /> <ClCompile Include="src\cpp\ripple\OrderBookDB.cpp" />
<ClCompile Include="src\cpp\ripple\PackedMessage.cpp" /> <ClCompile Include="src\cpp\ripple\PackedMessage.cpp" />
<ClCompile Include="src\cpp\ripple\ParseSection.cpp" /> <ClCompile Include="src\cpp\ripple\ParseSection.cpp" />
<ClCompile Include="src\cpp\ripple\Pathfinder.cpp" /> <ClCompile Include="src\cpp\ripple\Pathfinder.cpp" />
<ClCompile Include="src\cpp\ripple\PaymentTransactor.cpp" />
<ClCompile Include="src\cpp\ripple\Peer.cpp" /> <ClCompile Include="src\cpp\ripple\Peer.cpp" />
<ClCompile Include="src\cpp\ripple\PeerDoor.cpp" /> <ClCompile Include="src\cpp\ripple\PeerDoor.cpp" />
<ClCompile Include="src\cpp\ripple\PlatRand.cpp" /> <ClCompile Include="src\cpp\ripple\PlatRand.cpp" />
<ClCompile Include="src\cpp\ripple\PubKeyCache.cpp" /> <ClCompile Include="src\cpp\ripple\PubKeyCache.cpp" />
<ClCompile Include="src\cpp\ripple\RangeSet.cpp" /> <ClCompile Include="src\cpp\ripple\RangeSet.cpp" />
<ClCompile Include="src\cpp\ripple\RegularKeySetTransactor.cpp" />
<ClCompile Include="src\cpp\ripple\rfc1751.cpp" /> <ClCompile Include="src\cpp\ripple\rfc1751.cpp" />
<ClCompile Include="src\cpp\ripple\ripple.pb.cc" /> <ClCompile Include="src\cpp\ripple\ripple.pb.cc" />
<ClCompile Include="src\cpp\ripple\RippleAddress.cpp" /> <ClCompile Include="src\cpp\ripple\RippleAddress.cpp" />
@@ -163,16 +168,18 @@
<ClCompile Include="src\cpp\ripple\SNTPClient.cpp" /> <ClCompile Include="src\cpp\ripple\SNTPClient.cpp" />
<ClCompile Include="src\cpp\ripple\Suppression.cpp" /> <ClCompile Include="src\cpp\ripple\Suppression.cpp" />
<ClCompile Include="src\cpp\ripple\Transaction.cpp" /> <ClCompile Include="src\cpp\ripple\Transaction.cpp" />
<ClCompile Include="src\cpp\ripple\TransactionAction.cpp" />
<ClCompile Include="src\cpp\ripple\TransactionEngine.cpp" /> <ClCompile Include="src\cpp\ripple\TransactionEngine.cpp" />
<ClCompile Include="src\cpp\ripple\TransactionErr.cpp" /> <ClCompile Include="src\cpp\ripple\TransactionErr.cpp" />
<ClCompile Include="src\cpp\ripple\TransactionFormats.cpp" /> <ClCompile Include="src\cpp\ripple\TransactionFormats.cpp" />
<ClCompile Include="src\cpp\ripple\TransactionMaster.cpp" /> <ClCompile Include="src\cpp\ripple\TransactionMaster.cpp" />
<ClCompile Include="src\cpp\ripple\TransactionMeta.cpp" /> <ClCompile Include="src\cpp\ripple\TransactionMeta.cpp" />
<ClCompile Include="src\cpp\ripple\Transactor.cpp" />
<ClCompile Include="src\cpp\ripple\TrustSetTransactor.cpp" />
<ClCompile Include="src\cpp\ripple\UniqueNodeList.cpp" /> <ClCompile Include="src\cpp\ripple\UniqueNodeList.cpp" />
<ClCompile Include="src\cpp\ripple\utils.cpp" /> <ClCompile Include="src\cpp\ripple\utils.cpp" />
<ClCompile Include="src\cpp\ripple\ValidationCollection.cpp" /> <ClCompile Include="src\cpp\ripple\ValidationCollection.cpp" />
<ClCompile Include="src\cpp\ripple\Wallet.cpp" /> <ClCompile Include="src\cpp\ripple\Wallet.cpp" />
<ClCompile Include="src\cpp\ripple\WalletAddTransactor.cpp" />
<ClCompile Include="src\cpp\ripple\WSConnection.cpp" /> <ClCompile Include="src\cpp\ripple\WSConnection.cpp" />
<ClCompile Include="src\cpp\ripple\WSDoor.cpp" /> <ClCompile Include="src\cpp\ripple\WSDoor.cpp" />
<ClCompile Include="src\cpp\websocketpp\src\base64\base64.cpp" /> <ClCompile Include="src\cpp\websocketpp\src\base64\base64.cpp" />
@@ -192,6 +199,7 @@
<ClInclude Include="database\sqlite3.h" /> <ClInclude Include="database\sqlite3.h" />
<ClInclude Include="database\sqlite3ext.h" /> <ClInclude Include="database\sqlite3ext.h" />
<ClInclude Include="database\SqliteDatabase.h" /> <ClInclude Include="database\SqliteDatabase.h" />
<ClInclude Include="src\cpp\ripple\AccountSetTransactor.h" />
<ClInclude Include="src\cpp\ripple\AccountState.h" /> <ClInclude Include="src\cpp\ripple\AccountState.h" />
<ClInclude Include="src\cpp\ripple\Application.h" /> <ClInclude Include="src\cpp\ripple\Application.h" />
<ClInclude Include="src\cpp\ripple\base58.h" /> <ClInclude Include="src\cpp\ripple\base58.h" />
@@ -224,17 +232,21 @@
<ClInclude Include="src\cpp\ripple\NetworkOPs.h" /> <ClInclude Include="src\cpp\ripple\NetworkOPs.h" />
<ClInclude Include="src\cpp\ripple\NetworkStatus.h" /> <ClInclude Include="src\cpp\ripple\NetworkStatus.h" />
<ClInclude Include="src\cpp\ripple\NicknameState.h" /> <ClInclude Include="src\cpp\ripple\NicknameState.h" />
<ClInclude Include="src\cpp\ripple\OfferCancelTransactor.h" />
<ClInclude Include="src\cpp\ripple\OfferCreateTransactor.h" />
<ClInclude Include="src\cpp\ripple\Operation.h" /> <ClInclude Include="src\cpp\ripple\Operation.h" />
<ClInclude Include="src\cpp\ripple\OrderBook.h" /> <ClInclude Include="src\cpp\ripple\OrderBook.h" />
<ClInclude Include="src\cpp\ripple\OrderBookDB.h" /> <ClInclude Include="src\cpp\ripple\OrderBookDB.h" />
<ClInclude Include="src\cpp\ripple\PackedMessage.h" /> <ClInclude Include="src\cpp\ripple\PackedMessage.h" />
<ClInclude Include="src\cpp\ripple\ParseSection.h" /> <ClInclude Include="src\cpp\ripple\ParseSection.h" />
<ClInclude Include="src\cpp\ripple\Pathfinder.h" /> <ClInclude Include="src\cpp\ripple\Pathfinder.h" />
<ClInclude Include="src\cpp\ripple\PaymentTransactor.h" />
<ClInclude Include="src\cpp\ripple\Peer.h" /> <ClInclude Include="src\cpp\ripple\Peer.h" />
<ClInclude Include="src\cpp\ripple\PeerDoor.h" /> <ClInclude Include="src\cpp\ripple\PeerDoor.h" />
<ClInclude Include="src\cpp\ripple\ProofOfWork.h" /> <ClInclude Include="src\cpp\ripple\ProofOfWork.h" />
<ClInclude Include="src\cpp\ripple\PubKeyCache.h" /> <ClInclude Include="src\cpp\ripple\PubKeyCache.h" />
<ClInclude Include="src\cpp\ripple\RangeSet.h" /> <ClInclude Include="src\cpp\ripple\RangeSet.h" />
<ClInclude Include="src\cpp\ripple\RegularKeySetTransactor.h" />
<ClInclude Include="src\cpp\ripple\rfc1751.h" /> <ClInclude Include="src\cpp\ripple\rfc1751.h" />
<ClInclude Include="src\cpp\ripple\ripple.pb.h" /> <ClInclude Include="src\cpp\ripple\ripple.pb.h" />
<ClInclude Include="src\cpp\ripple\RippleAddress.h" /> <ClInclude Include="src\cpp\ripple\RippleAddress.h" />
@@ -267,6 +279,8 @@
<ClInclude Include="src\cpp\ripple\TransactionFormats.h" /> <ClInclude Include="src\cpp\ripple\TransactionFormats.h" />
<ClInclude Include="src\cpp\ripple\TransactionMaster.h" /> <ClInclude Include="src\cpp\ripple\TransactionMaster.h" />
<ClInclude Include="src\cpp\ripple\TransactionMeta.h" /> <ClInclude Include="src\cpp\ripple\TransactionMeta.h" />
<ClInclude Include="src\cpp\ripple\Transactor.h" />
<ClInclude Include="src\cpp\ripple\TrustSetTransactor.h" />
<ClInclude Include="src\cpp\ripple\types.h" /> <ClInclude Include="src\cpp\ripple\types.h" />
<ClInclude Include="src\cpp\ripple\uint256.h" /> <ClInclude Include="src\cpp\ripple\uint256.h" />
<ClInclude Include="src\cpp\ripple\UniqueNodeList.h" /> <ClInclude Include="src\cpp\ripple\UniqueNodeList.h" />
@@ -274,6 +288,7 @@
<ClInclude Include="src\cpp\ripple\ValidationCollection.h" /> <ClInclude Include="src\cpp\ripple\ValidationCollection.h" />
<ClInclude Include="src\cpp\ripple\Version.h" /> <ClInclude Include="src\cpp\ripple\Version.h" />
<ClInclude Include="src\cpp\ripple\Wallet.h" /> <ClInclude Include="src\cpp\ripple\Wallet.h" />
<ClInclude Include="src\cpp\ripple\WalletAddTransactor.h" />
<ClInclude Include="src\cpp\ripple\WSConnection.h" /> <ClInclude Include="src\cpp\ripple\WSConnection.h" />
<ClInclude Include="src\cpp\ripple\WSDoor.h" /> <ClInclude Include="src\cpp\ripple\WSDoor.h" />
<ClInclude Include="src\cpp\ripple\WSHandler.h" /> <ClInclude Include="src\cpp\ripple\WSHandler.h" />

View File

@@ -252,9 +252,6 @@
<ClCompile Include="src\cpp\ripple\Transaction.cpp"> <ClCompile Include="src\cpp\ripple\Transaction.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\cpp\ripple\TransactionAction.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\TransactionEngine.cpp"> <ClCompile Include="src\cpp\ripple\TransactionEngine.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@@ -324,6 +321,30 @@
<ClCompile Include="src\cpp\websocketpp\src\sha1\sha1.cpp"> <ClCompile Include="src\cpp\websocketpp\src\sha1\sha1.cpp">
<Filter>Source Files\websocketpp</Filter> <Filter>Source Files\websocketpp</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\cpp\ripple\Transactor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\PaymentTransactor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\WalletAddTransactor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\AccountSetTransactor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\OfferCancelTransactor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\OfferCreateTransactor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\RegularKeySetTransactor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\TrustSetTransactor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="util\pugiconfig.hpp"> <ClInclude Include="util\pugiconfig.hpp">
@@ -602,6 +623,30 @@
<ClInclude Include="src\cpp\ripple\WSHandler.h"> <ClInclude Include="src\cpp\ripple\WSHandler.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\cpp\ripple\Transactor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\PaymentTransactor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\TrustSetTransactor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\RegularKeySetTransactor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\OfferCreateTransactor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\OfferCancelTransactor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\AccountSetTransactor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\WalletAddTransactor.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="wallet.xml" /> <None Include="wallet.xml" />

View File

@@ -0,0 +1,119 @@
#include "AccountSetTransactor.h"
TER AccountSetTransactor::doApply()
{
Log(lsINFO) << "doAccountSet>";
//
// EmailHash
//
if (mTxn.isFieldPresent(sfEmailHash))
{
uint128 uHash = mTxn.getFieldH128(sfEmailHash);
if (!uHash)
{
Log(lsINFO) << "doAccountSet: unset email hash";
mTxnAccount->makeFieldAbsent(sfEmailHash);
}
else
{
Log(lsINFO) << "doAccountSet: set email hash";
mTxnAccount->setFieldH128(sfEmailHash, uHash);
}
}
//
// WalletLocator
//
if (mTxn.isFieldPresent(sfWalletLocator))
{
uint256 uHash = mTxn.getFieldH256(sfWalletLocator);
if (!uHash)
{
Log(lsINFO) << "doAccountSet: unset wallet locator";
mTxnAccount->makeFieldAbsent(sfEmailHash);
}
else
{
Log(lsINFO) << "doAccountSet: set wallet locator";
mTxnAccount->setFieldH256(sfWalletLocator, uHash);
}
}
//
// MessageKey
//
if (!mTxn.isFieldPresent(sfMessageKey))
{
nothing();
}
else
{
Log(lsINFO) << "doAccountSet: set message key";
mTxnAccount->setFieldVL(sfMessageKey, mTxn.getFieldVL(sfMessageKey));
}
//
// Domain
//
if (mTxn.isFieldPresent(sfDomain))
{
std::vector<unsigned char> vucDomain = mTxn.getFieldVL(sfDomain);
if (vucDomain.empty())
{
Log(lsINFO) << "doAccountSet: unset domain";
mTxnAccount->makeFieldAbsent(sfDomain);
}
else
{
Log(lsINFO) << "doAccountSet: set domain";
mTxnAccount->setFieldVL(sfDomain, vucDomain);
}
}
//
// TransferRate
//
if (mTxn.isFieldPresent(sfTransferRate))
{
uint32 uRate = mTxn.getFieldU32(sfTransferRate);
if (!uRate || uRate == QUALITY_ONE)
{
Log(lsINFO) << "doAccountSet: unset transfer rate";
mTxnAccount->makeFieldAbsent(sfTransferRate);
}
else if (uRate > QUALITY_ONE)
{
Log(lsINFO) << "doAccountSet: set transfer rate";
mTxnAccount->setFieldU32(sfTransferRate, uRate);
}
else
{
Log(lsINFO) << "doAccountSet: bad transfer rate";
return temBAD_TRANSFER_RATE;
}
}
Log(lsINFO) << "doAccountSet<";
return tesSUCCESS;
}

View File

@@ -0,0 +1,9 @@
#include "Transactor.h"
class AccountSetTransactor : public Transactor
{
public:
AccountSetTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine::pointer engine) : Transactor(txn,params,engine) {}
TER doApply();
};

View File

@@ -44,6 +44,7 @@ DEFINE_INSTANCE(Ledger);
class Ledger : public boost::enable_shared_from_this<Ledger>, public IS_INSTANCE(Ledger) class Ledger : public boost::enable_shared_from_this<Ledger>, public IS_INSTANCE(Ledger)
{ // The basic Ledger structure, can be opened, closed, or synching { // The basic Ledger structure, can be opened, closed, or synching
friend class TransactionEngine; friend class TransactionEngine;
friend class Transactor;
public: public:
typedef boost::shared_ptr<Ledger> pointer; typedef boost::shared_ptr<Ledger> pointer;
typedef const boost::shared_ptr<Ledger>& ref; typedef const boost::shared_ptr<Ledger>& ref;

View File

@@ -0,0 +1,41 @@
#include "OfferCancelTransactor.h"
#include "Log.h"
TER OfferCancelTransactor::doApply()
{
TER terResult;
const uint32 uOfferSequence = mTxn.getFieldU32(sfOfferSequence);
const uint32 uAccountSequenceNext = mTxnAccount->getFieldU32(sfSequence);
Log(lsDEBUG) << "doOfferCancel: uAccountSequenceNext=" << uAccountSequenceNext << " uOfferSequence=" << uOfferSequence;
if (!uOfferSequence || uAccountSequenceNext-1 <= uOfferSequence)
{
Log(lsINFO) << "doOfferCancel: uAccountSequenceNext=" << uAccountSequenceNext << " uOfferSequence=" << uOfferSequence;
terResult = temBAD_SEQUENCE;
}
else
{
const uint256 uOfferIndex = Ledger::getOfferIndex(mTxnAccountID, uOfferSequence);
SLE::pointer sleOffer = mEngine->entryCache(ltOFFER, uOfferIndex);
if (sleOffer)
{
Log(lsWARNING) << "doOfferCancel: uOfferSequence=" << uOfferSequence;
terResult = mEngine->getNodes().offerDelete(sleOffer, uOfferIndex, mTxnAccountID);
}
else
{
Log(lsWARNING) << "doOfferCancel: offer not found: "
<< RippleAddress::createHumanAccountID(mTxnAccountID)
<< " : " << uOfferSequence
<< " : " << uOfferIndex.ToString();
terResult = tesSUCCESS;
}
}
return terResult;
}

View File

@@ -0,0 +1,9 @@
#include "Transactor.h"
class OfferCancelTransactor : public Transactor
{
public:
OfferCancelTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine::pointer engine) : Transactor(txn,params,engine) {}
TER doApply();
};

View File

@@ -0,0 +1,440 @@
#include "OfferCreateTransactor.h"
#include <boost/foreach.hpp>
// Take as much as possible. Adjusts account balances. Charges fees on top to taker.
// --> uBookBase: The order book to take against.
// --> saTakerPays: What the taker offers (w/ issuer)
// --> saTakerGets: What the taker wanted (w/ issuer)
// <-- saTakerPaid: What taker paid not including fees. To reduce an offer.
// <-- saTakerGot: What taker got not including fees. To reduce an offer.
// <-- terResult: tesSUCCESS or terNO_ACCOUNT
// XXX: Fees should be paid by the source of the currency.
TER OfferCreateTransactor::takeOffers(
bool bPassive,
const uint256& uBookBase,
const uint160& uTakerAccountID,
const SLE::pointer& sleTakerAccount,
const STAmount& saTakerPays,
const STAmount& saTakerGets,
STAmount& saTakerPaid,
STAmount& saTakerGot)
{
assert(saTakerPays && saTakerGets);
Log(lsINFO) << "takeOffers: against book: " << uBookBase.ToString();
uint256 uTipIndex = uBookBase;
const uint256 uBookEnd = Ledger::getQualityNext(uBookBase);
const uint64 uTakeQuality = STAmount::getRate(saTakerGets, saTakerPays);
const uint160 uTakerPaysAccountID = saTakerPays.getIssuer();
const uint160 uTakerGetsAccountID = saTakerGets.getIssuer();
TER terResult = temUNCERTAIN;
boost::unordered_set<uint256> usOfferUnfundedFound; // Offers found unfunded.
boost::unordered_set<uint256> usOfferUnfundedBecame; // Offers that became unfunded.
boost::unordered_set<uint160> usAccountTouched; // Accounts touched.
saTakerPaid = STAmount(saTakerPays.getCurrency(), saTakerPays.getIssuer());
saTakerGot = STAmount(saTakerGets.getCurrency(), saTakerGets.getIssuer());
while (temUNCERTAIN == terResult)
{
SLE::pointer sleOfferDir;
uint64 uTipQuality;
// Figure out next offer to take, if needed.
if (saTakerGets != saTakerGot && saTakerPays != saTakerPaid)
{
// Taker, still, needs to get and pay.
sleOfferDir = mEngine->entryCache(ltDIR_NODE, mEngine->getLedger()->getNextLedgerIndex(uTipIndex, uBookEnd));
if (sleOfferDir)
{
Log(lsINFO) << "takeOffers: possible counter offer found";
uTipIndex = sleOfferDir->getIndex();
uTipQuality = Ledger::getQuality(uTipIndex);
}
else
{
Log(lsINFO) << "takeOffers: counter offer book is empty: "
<< uTipIndex.ToString()
<< " ... "
<< uBookEnd.ToString();
}
}
if (!sleOfferDir // No offer directory to take.
|| uTakeQuality < uTipQuality // No offers of sufficient quality available.
|| (bPassive && uTakeQuality == uTipQuality))
{
// Done.
Log(lsINFO) << "takeOffers: done";
terResult = tesSUCCESS;
}
else
{
// Have an offer directory to consider.
Log(lsINFO) << "takeOffers: considering dir: " << sleOfferDir->getJson(0);
SLE::pointer sleBookNode;
unsigned int uBookEntry;
uint256 uOfferIndex;
mEngine->getNodes().dirFirst(uTipIndex, sleBookNode, uBookEntry, uOfferIndex);
SLE::pointer sleOffer = mEngine->entryCache(ltOFFER, uOfferIndex);
Log(lsINFO) << "takeOffers: considering offer : " << sleOffer->getJson(0);
const uint160 uOfferOwnerID = sleOffer->getFieldAccount(sfAccount).getAccountID();
STAmount saOfferPays = sleOffer->getFieldAmount(sfTakerGets);
STAmount saOfferGets = sleOffer->getFieldAmount(sfTakerPays);
if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getFieldU32(sfExpiration) <= mEngine->getLedger()->getParentCloseTimeNC())
{
// Offer is expired. Expired offers are considered unfunded. Delete it.
Log(lsINFO) << "takeOffers: encountered expired offer";
usOfferUnfundedFound.insert(uOfferIndex);
}
else if (uOfferOwnerID == uTakerAccountID)
{
// Would take own offer. Consider old offer expired. Delete it.
Log(lsINFO) << "takeOffers: encountered taker's own old offer";
usOfferUnfundedFound.insert(uOfferIndex);
}
else
{
// Get offer funds available.
Log(lsINFO) << "takeOffers: saOfferPays=" << saOfferPays.getFullText();
STAmount saOfferFunds = mEngine->getNodes().accountFunds(uOfferOwnerID, saOfferPays);
STAmount saTakerFunds = mEngine->getNodes().accountFunds(uTakerAccountID, saTakerPays);
SLE::pointer sleOfferAccount; // Owner of offer.
if (!saOfferFunds.isPositive())
{
// Offer is unfunded, possibly due to previous balance action.
Log(lsINFO) << "takeOffers: offer unfunded: delete";
boost::unordered_set<uint160>::iterator account = usAccountTouched.find(uOfferOwnerID);
if (account != usAccountTouched.end())
{
// Previously touched account.
usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success.
}
else
{
// Never touched source account.
usOfferUnfundedFound.insert(uOfferIndex); // Delete found unfunded offer when possible.
}
}
else
{
STAmount saPay = saTakerPays - saTakerPaid;
if (saTakerFunds < saPay)
saPay = saTakerFunds;
STAmount saSubTakerPaid;
STAmount saSubTakerGot;
STAmount saTakerIssuerFee;
STAmount saOfferIssuerFee;
Log(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText();
Log(lsINFO) << "takeOffers: applyOffer: saTakerPaid: " << saTakerPaid.getFullText();
Log(lsINFO) << "takeOffers: applyOffer: saTakerFunds: " << saTakerFunds.getFullText();
Log(lsINFO) << "takeOffers: applyOffer: saOfferFunds: " << saOfferFunds.getFullText();
Log(lsINFO) << "takeOffers: applyOffer: saPay: " << saPay.getFullText();
Log(lsINFO) << "takeOffers: applyOffer: saOfferPays: " << saOfferPays.getFullText();
Log(lsINFO) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText();
Log(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText();
Log(lsINFO) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText();
bool bOfferDelete = STAmount::applyOffer(
mEngine->getNodes().rippleTransferRate(uTakerAccountID, uOfferOwnerID, uTakerPaysAccountID),
mEngine->getNodes().rippleTransferRate(uOfferOwnerID, uTakerAccountID, uTakerGetsAccountID),
saOfferFunds,
saPay, // Driver XXX need to account for fees.
saOfferPays,
saOfferGets,
saTakerPays,
saTakerGets,
saSubTakerPaid,
saSubTakerGot,
saTakerIssuerFee,
saOfferIssuerFee);
Log(lsINFO) << "takeOffers: applyOffer: saSubTakerPaid: " << saSubTakerPaid.getFullText();
Log(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText();
// Adjust offer
// Offer owner will pay less. Subtract what taker just got.
sleOffer->setFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot);
// Offer owner will get less. Subtract what owner just paid.
sleOffer->setFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid);
mEngine->entryModify(sleOffer);
if (bOfferDelete)
{
// Offer now fully claimed or now unfunded.
Log(lsINFO) << "takeOffers: offer claimed: delete";
usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success.
// Offer owner's account is no longer pristine.
usAccountTouched.insert(uOfferOwnerID);
}
else
{
Log(lsINFO) << "takeOffers: offer partial claim.";
}
// Offer owner pays taker.
// saSubTakerGot.setIssuer(uTakerGetsAccountID); // XXX Move this earlier?
assert(!!saSubTakerGot.getIssuer());
mEngine->getNodes().accountSend(uOfferOwnerID, uTakerAccountID, saSubTakerGot);
mEngine->getNodes().accountSend(uOfferOwnerID, uTakerGetsAccountID, saOfferIssuerFee);
saTakerGot += saSubTakerGot;
// Taker pays offer owner.
// saSubTakerPaid.setIssuer(uTakerPaysAccountID);
assert(!!saSubTakerPaid.getIssuer());
mEngine->getNodes().accountSend(uTakerAccountID, uOfferOwnerID, saSubTakerPaid);
mEngine->getNodes().accountSend(uTakerAccountID, uTakerPaysAccountID, saTakerIssuerFee);
saTakerPaid += saSubTakerPaid;
}
}
}
}
// On storing meta data, delete offers that were found unfunded to prevent encountering them in future.
if (tesSUCCESS == terResult)
{
BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedFound)
{
terResult = mEngine->getNodes().offerDelete(uOfferIndex);
if (tesSUCCESS != terResult)
break;
}
}
if (tesSUCCESS == terResult)
{
// On success, delete offers that became unfunded.
BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedBecame)
{
terResult = mEngine->getNodes().offerDelete(uOfferIndex);
if (tesSUCCESS != terResult)
break;
}
}
return terResult;
}
TER OfferCreateTransactor::doApply()
{
Log(lsWARNING) << "doOfferCreate> " << mTxn.getJson(0);
const uint32 txFlags = mTxn.getFlags();
const bool bPassive = isSetBit(txFlags, tfPassive);
STAmount saTakerPays = mTxn.getFieldAmount(sfTakerPays);
STAmount saTakerGets = mTxn.getFieldAmount(sfTakerGets);
Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGets=%s")
% saTakerPays.getFullText()
% saTakerGets.getFullText());
const uint160 uPaysIssuerID = saTakerPays.getIssuer();
const uint160 uGetsIssuerID = saTakerGets.getIssuer();
const uint32 uExpiration = mTxn.getFieldU32(sfExpiration);
const bool bHaveExpiration = mTxn.isFieldPresent(sfExpiration);
const uint32 uSequence = mTxn.getSequence();
const uint256 uLedgerIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence);
SLE::pointer sleOffer = mEngine->entryCreate(ltOFFER, uLedgerIndex);
Log(lsINFO) << "doOfferCreate: Creating offer node: " << uLedgerIndex.ToString() << " uSequence=" << uSequence;
const uint160 uPaysCurrency = saTakerPays.getCurrency();
const uint160 uGetsCurrency = saTakerGets.getCurrency();
const uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays);
TER terResult = tesSUCCESS;
uint256 uDirectory; // Delete hints.
uint64 uOwnerNode;
uint64 uBookNode;
if (bHaveExpiration && !uExpiration)
{
Log(lsWARNING) << "doOfferCreate: Malformed offer: bad expiration";
terResult = temBAD_EXPIRATION;
}
else if (bHaveExpiration && mEngine->getLedger()->getParentCloseTimeNC() >= uExpiration)
{
Log(lsWARNING) << "doOfferCreate: Expired transaction: offer expired";
// XXX CHARGE FEE ONLY.
terResult = tesSUCCESS;
}
else if (saTakerPays.isNative() && saTakerGets.isNative())
{
Log(lsWARNING) << "doOfferCreate: Malformed offer: XRP for XRP";
terResult = temBAD_OFFER;
}
else if (!saTakerPays.isPositive() || !saTakerGets.isPositive())
{
Log(lsWARNING) << "doOfferCreate: Malformed offer: bad amount";
terResult = temBAD_OFFER;
}
else if (uPaysCurrency == uGetsCurrency && uPaysIssuerID == uGetsIssuerID)
{
Log(lsWARNING) << "doOfferCreate: Malformed offer: redundant offer";
terResult = temREDUNDANT;
}
else if (saTakerPays.isNative() != !uPaysIssuerID || saTakerGets.isNative() != !uGetsIssuerID)
{
Log(lsWARNING) << "doOfferCreate: Malformed offer: bad issuer";
terResult = temBAD_ISSUER;
}
else if (!mEngine->getNodes().accountFunds(mTxnAccountID, saTakerGets).isPositive())
{
Log(lsWARNING) << "doOfferCreate: delay: Offers must be at least partially funded.";
terResult = terUNFUNDED;
}
if (tesSUCCESS == terResult && !saTakerPays.isNative())
{
SLE::pointer sleTakerPays = mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uPaysIssuerID));
if (!sleTakerPays)
{
Log(lsWARNING) << "doOfferCreate: delay: can't receive IOUs from non-existent issuer: " << RippleAddress::createHumanAccountID(uPaysIssuerID);
terResult = terNO_ACCOUNT;
}
}
if (tesSUCCESS == terResult)
{
STAmount saOfferPaid;
STAmount saOfferGot;
const uint256 uTakeBookBase = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID);
Log(lsINFO) << boost::str(boost::format("doOfferCreate: take against book: %s for %s -> %s")
% uTakeBookBase.ToString()
% saTakerGets.getFullText()
% saTakerPays.getFullText());
// Take using the parameters of the offer.
#if 1
Log(lsWARNING) << "doOfferCreate: takeOffers: BEFORE saTakerGets=" << saTakerGets.getFullText();
terResult = takeOffers(
bPassive,
uTakeBookBase,
mTxnAccountID,
mTxnAccount,
saTakerGets,
saTakerPays,
saOfferPaid, // How much was spent.
saOfferGot // How much was got.
);
#else
terResult = tesSUCCESS;
#endif
Log(lsWARNING) << "doOfferCreate: takeOffers=" << terResult;
Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferPaid=" << saOfferPaid.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferGot=" << saOfferGot.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: AFTER saTakerGets=" << saTakerGets.getFullText();
if (tesSUCCESS == terResult)
{
saTakerPays -= saOfferGot; // Reduce payin from takers by what offer just got.
saTakerGets -= saOfferPaid; // Reduce payout to takers by what srcAccount just paid.
}
}
Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText();
Log(lsWARNING) << "doOfferCreate: takeOffers: mTxnAccountID=" << RippleAddress::createHumanAccountID(mTxnAccountID);
Log(lsWARNING) << "doOfferCreate: takeOffers: FUNDS=" << mEngine->getNodes().accountFunds(mTxnAccountID, saTakerGets).getFullText();
// Log(lsWARNING) << "doOfferCreate: takeOffers: uPaysIssuerID=" << RippleAddress::createHumanAccountID(uPaysIssuerID);
// Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << RippleAddress::createHumanAccountID(uGetsIssuerID);
if (tesSUCCESS == terResult
&& saTakerPays // Still wanting something.
&& saTakerGets // Still offering something.
&& mEngine->getNodes().accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded.
{
// We need to place the remainder of the offer into its order book.
Log(lsINFO) << boost::str(boost::format("doOfferCreate: offer not fully consumed: saTakerPays=%s saTakerGets=%s")
% saTakerPays.getFullText()
% saTakerGets.getFullText());
// Add offer to owner's directory.
terResult = mEngine->getNodes().dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex);
if (tesSUCCESS == terResult)
{
uint256 uBookBase = Ledger::getBookBase(uPaysCurrency, uPaysIssuerID, uGetsCurrency, uGetsIssuerID);
Log(lsINFO) << boost::str(boost::format("doOfferCreate: adding to book: %s : %s/%s -> %s/%s")
% uBookBase.ToString()
% saTakerPays.getHumanCurrency()
% RippleAddress::createHumanAccountID(saTakerPays.getIssuer())
% saTakerGets.getHumanCurrency()
% RippleAddress::createHumanAccountID(saTakerGets.getIssuer()));
uDirectory = Ledger::getQualityIndex(uBookBase, uRate); // Use original rate.
// Add offer to order book.
terResult = mEngine->getNodes().dirAdd(uBookNode, uDirectory, uLedgerIndex);
}
if (tesSUCCESS == terResult)
{
Log(lsWARNING) << "doOfferCreate: sfAccount=" << RippleAddress::createHumanAccountID(mTxnAccountID);
Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << RippleAddress::createHumanAccountID(uPaysIssuerID);
Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << RippleAddress::createHumanAccountID(uGetsIssuerID);
Log(lsWARNING) << "doOfferCreate: saTakerPays.isNative()=" << saTakerPays.isNative();
Log(lsWARNING) << "doOfferCreate: saTakerGets.isNative()=" << saTakerGets.isNative();
Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency();
Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency();
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);
}
}
Log(lsINFO) << "doOfferCreate: final sleOffer=" << sleOffer->getJson(0);
return terResult;
}

View File

@@ -0,0 +1,22 @@
#include "Transactor.h"
class OfferCreateTransactor : public Transactor
{
TER takeOffers(
bool bPassive,
const uint256& uBookBase,
const uint160& uTakerAccountID,
const SLE::pointer& sleTakerAccount,
const STAmount& saTakerPays,
const STAmount& saTakerGets,
STAmount& saTakerPaid,
STAmount& saTakerGot);
public:
OfferCreateTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine::pointer engine) : Transactor(txn,params,engine) {}
TER doApply();
};

View File

@@ -0,0 +1,168 @@
#include "PaymentTransactor.h"
#include "Config.h"
#include "RippleCalc.h"
#define RIPPLE_PATHS_MAX 3
// TODO: only have the higher fee if the account doesn't in fact exist
void PaymentTransactor::calculateFee()
{
if (mTxn.getFlags() & tfCreateAccount)
{
mFeeDue = theConfig.FEE_ACCOUNT_CREATE;
}else Transactor::calculateFee();
}
TER PaymentTransactor::doApply()
{
// Ripple if source or destination is non-native or if there are paths.
const uint32 uTxFlags = mTxn.getFlags();
const bool bCreate = isSetBit(uTxFlags, tfCreateAccount);
const bool bPartialPayment = isSetBit(uTxFlags, tfPartialPayment);
const bool bLimitQuality = isSetBit(uTxFlags, tfLimitQuality);
const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect);
const bool bPaths = mTxn.isFieldPresent(sfPaths);
const bool bMax = mTxn.isFieldPresent(sfSendMax);
const uint160 uDstAccountID = mTxn.getFieldAccount160(sfDestination);
const STAmount saDstAmount = mTxn.getFieldAmount(sfAmount);
const STAmount saMaxAmount = bMax
? mTxn.getFieldAmount(sfSendMax)
: saDstAmount.isNative()
? saDstAmount
: STAmount(saDstAmount.getCurrency(), mTxnAccountID, saDstAmount.getMantissa(), saDstAmount.getExponent(), saDstAmount.isNegative());
const uint160 uSrcCurrency = saMaxAmount.getCurrency();
const uint160 uDstCurrency = saDstAmount.getCurrency();
Log(lsINFO) << boost::str(boost::format("doPayment> saMaxAmount=%s saDstAmount=%s")
% saMaxAmount.getFullText()
% saDstAmount.getFullText());
if (!uDstAccountID)
{
Log(lsINFO) << "doPayment: Invalid transaction: Payment destination account not specified.";
return temDST_NEEDED;
}
else if (bMax && !saMaxAmount.isPositive())
{
Log(lsINFO) << "doPayment: Invalid transaction: bad max amount: " << saMaxAmount.getFullText();
return temBAD_AMOUNT;
}
else if (!saDstAmount.isPositive())
{
Log(lsINFO) << "doPayment: Invalid transaction: bad dst amount: " << saDstAmount.getFullText();
return temBAD_AMOUNT;
}
else if (mTxnAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths)
{
Log(lsINFO) << boost::str(boost::format("doPayment: Invalid transaction: Redundant transaction: src=%s, dst=%s, src_cur=%s, dst_cur=%s")
% mTxnAccountID.ToString()
% uDstAccountID.ToString()
% uSrcCurrency.ToString()
% uDstCurrency.ToString());
return temREDUNDANT;
}
else if (bMax
&& ((saMaxAmount == saDstAmount && saMaxAmount.getCurrency() == saDstAmount.getCurrency())
|| (saDstAmount.isNative() && saMaxAmount.isNative())))
{
Log(lsINFO) << "doPayment: Invalid transaction: bad SendMax.";
return temINVALID;
}
SLE::pointer sleDst = mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID));
if (!sleDst)
{
// Destination account does not exist.
if (bCreate && !saDstAmount.isNative())
{
// This restriction could be relaxed.
Log(lsINFO) << "doPayment: Invalid transaction: Create account may only fund XRP.";
return temCREATEXRP;
}
else if (!bCreate)
{
Log(lsINFO) << "doPayment: Delay transaction: Destination account does not exist.";
return terNO_DST;
}
// Create the account.
sleDst = mEngine->entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID));
sleDst->setFieldAccount(sfAccount, uDstAccountID);
sleDst->setFieldU32(sfSequence, 1);
}
else
{
mEngine->entryModify(sleDst);
}
TER terResult;
// XXX Should bMax be sufficient to imply ripple?
const bool bRipple = bPaths || bMax || !saDstAmount.isNative();
if (bRipple)
{
// Ripple payment
STPathSet spsPaths = mTxn.getFieldPathSet(sfPaths);
STAmount saMaxAmountAct;
STAmount saDstAmountAct;
terResult = isSetBit(mParams, tapOPEN_LEDGER) && spsPaths.getPathCount() > RIPPLE_PATHS_MAX
? telBAD_PATH_COUNT
: RippleCalc::rippleCalc(
mEngine->getNodes(),
saMaxAmountAct,
saDstAmountAct,
saMaxAmount,
saDstAmount,
uDstAccountID,
mTxnAccountID,
spsPaths,
bPartialPayment,
bLimitQuality,
bNoRippleDirect);
}
else
{
// Direct XRP payment.
STAmount saSrcXRPBalance = mTxnAccount->getFieldAmount(sfBalance);
if (saSrcXRPBalance < saDstAmount)
{
// Transaction might succeed, if applied in a different order.
Log(lsINFO) << "doPayment: Delay transaction: Insufficient funds.";
terResult = terUNFUNDED;
}
else
{
mTxnAccount->setFieldAmount(sfBalance, saSrcXRPBalance - saDstAmount);
sleDst->setFieldAmount(sfBalance, sleDst->getFieldAmount(sfBalance) + saDstAmount);
terResult = tesSUCCESS;
}
}
std::string strToken;
std::string strHuman;
if (transResultInfo(terResult, strToken, strHuman))
{
Log(lsINFO) << boost::str(boost::format("doPayment: %s: %s") % strToken % strHuman);
}
else
{
assert(false);
}
return terResult;
}

View File

@@ -0,0 +1,11 @@
#include "Transactor.h"
class PaymentTransactor : public Transactor
{
void calculateFee();
public:
PaymentTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine::pointer engine) : Transactor(txn,params,engine) {}
TER doApply();
};

View File

@@ -0,0 +1,51 @@
#include "RegularKeySetTransactor.h"
#include "Log.h"
SETUP_LOG();
// TODO:
TER RegularKeySetTransactor::checkSig()
{
// Transaction's signing public key must be for the source account.
// To prove the master private key made this transaction.
if (mSigningPubKey.getAccountID() != mTxnAccountID)
{
// Signing Pub Key must be for Source Account ID.
cLog(lsWARNING) << "sourceAccountID: " << mSigningPubKey.humanAccountID();
cLog(lsWARNING) << "txn accountID: " << mTxn.getSourceAccount().humanAccountID();
return temBAD_SET_ID;
}
return tesSUCCESS;
}
// TODO: this should be default fee if flag isn't set
void RegularKeySetTransactor::calculateFee()
{
mFeeDue = 0;
}
// TODO: change to take a fee if there is one there
TER RegularKeySetTransactor::doApply()
{
std::cerr << "doRegularKeySet>" << std::endl;
if (mTxnAccount->getFlags() & lsfPasswordSpent)
{
std::cerr << "doRegularKeySet: Delay transaction: Funds already spent." << std::endl;
return terFUNDS_SPENT;
}
mTxnAccount->setFlag(lsfPasswordSpent);
uint160 uAuthKeyID=mTxn.getFieldAccount160(sfAuthorizedKey);
mTxnAccount->setFieldAccount(sfAuthorizedKey, uAuthKeyID);
std::cerr << "doRegularKeySet<" << std::endl;
return tesSUCCESS;
}

View File

@@ -0,0 +1,11 @@
#include "Transactor.h"
class RegularKeySetTransactor : public Transactor
{
void calculateFee();
public:
RegularKeySetTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine::pointer engine) : Transactor(txn,params,engine) {}
TER checkFee();
TER checkSig();
TER doApply();
};

View File

@@ -2,8 +2,7 @@
#define __TRANSACTION__ #define __TRANSACTION__
// //
// Notes: this code contains legacy constructored sharedXYZ and setXYZ. The intent is for these functions to go away. Transactions // Transactions should be constructed in JSON with. Use STObject::parseJson to obtain a binary version.
// should now be constructed in JSON with. Use STObject::parseJson to obtain a binary version.
// //
#include <vector> #include <vector>

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include "TransactionEngine.h" #include "TransactionEngine.h"
#include "Transactor.h"
#include "../json/writer.h" #include "../json/writer.h"
@@ -88,352 +89,18 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
} }
#endif #endif
TER terResult = tesSUCCESS; Transactor::pointer transactor=Transactor::makeTransactor(txn,params,shared_from_this());
if(transactor)
{
uint256 txID = txn.getTransactionID(); uint256 txID = txn.getTransactionID();
if (!txID) if (!txID)
{ {
cLog(lsWARNING) << "applyTransaction: invalid transaction id"; cLog(lsWARNING) << "applyTransaction: invalid transaction id";
terResult = temINVALID; return temINVALID;
}
//
// Verify transaction is signed properly.
//
// Extract signing key
// Transactions contain a signing key. This allows us to trivially verify a transaction has at least been properly signed
// without going to disk. Each transaction also notes a source account id. This is used to verify that the signing key is
// associated with the account.
// XXX This could be a lot cleaner to prevent unnecessary copying.
RippleAddress naSigningPubKey;
if (tesSUCCESS == terResult)
naSigningPubKey = RippleAddress::createAccountPublic(txn.getSigningPubKey());
// Consistency: really signed.
if ((tesSUCCESS == terResult) && !isSetBit(params, tapNO_CHECK_SIGN) && !txn.checkSign(naSigningPubKey))
{
cLog(lsWARNING) << "applyTransaction: Invalid transaction: bad signature";
terResult = temINVALID;
}
STAmount saCost = theConfig.FEE_DEFAULT;
// Customize behavior based on transaction type.
if (tesSUCCESS == terResult)
{
switch (txn.getTxnType())
{
case ttCLAIM:
case ttREGULAR_KEY_SET:
saCost = 0;
break;
case ttPAYMENT:
if (txn.getFlags() & tfCreateAccount)
{
saCost = theConfig.FEE_ACCOUNT_CREATE;
}
break;
case ttNICKNAME_SET:
{
SLE::pointer sleNickname = entryCache(ltNICKNAME, txn.getFieldH256(sfNickname));
if (!sleNickname)
saCost = theConfig.FEE_NICKNAME_CREATE;
}
break;
case ttACCOUNT_SET:
case ttTRUST_SET:
case ttOFFER_CREATE:
case ttOFFER_CANCEL:
case ttPASSWORD_FUND:
case ttWALLET_ADD:
nothing();
break;
case ttINVALID:
cLog(lsWARNING) << "applyTransaction: Invalid transaction: ttINVALID transaction type";
terResult = temINVALID;
break;
default:
cLog(lsWARNING) << "applyTransaction: Invalid transaction: unknown transaction type";
terResult = temUNKNOWN;
break;
}
}
STAmount saPaid = txn.getTransactionFee();
if (tesSUCCESS == terResult)
{
if (saCost)
{
// Only check fee is sufficient when the ledger is open.
if (isSetBit(params, tapOPEN_LEDGER) && saPaid < saCost)
{
cLog(lsINFO) << "applyTransaction: insufficient fee";
terResult = telINSUF_FEE_P;
}
}
else
{
if (saPaid)
{
// Transaction is malformed.
cLog(lsWARNING) << "applyTransaction: fee not allowed";
terResult = temINSUF_FEE_P;
}
}
}
// Get source account ID.
mTxnAccountID = txn.getSourceAccount().getAccountID();
if (tesSUCCESS == terResult && !mTxnAccountID)
{
cLog(lsWARNING) << "applyTransaction: bad source id";
terResult = temINVALID;
}
if (tesSUCCESS != terResult)
return terResult;
boost::recursive_mutex::scoped_lock sl(mLedger->mLock);
mTxnAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(mTxnAccountID));
// Find source account
// If are only forwarding, due to resource limitations, we might verifying only some transactions, this would be probablistic.
STAmount saSrcBalance;
uint32 t_seq = txn.getSequence();
bool bHaveAuthKey = false;
if (!mTxnAccount)
{
cLog(lsTRACE) << boost::str(boost::format("applyTransaction: Delay transaction: source account does not exist: %s") %
txn.getSourceAccount().humanAccountID());
terResult = terNO_ACCOUNT;
}
else
{
saSrcBalance = mTxnAccount->getFieldAmount(sfBalance);
bHaveAuthKey = mTxnAccount->isFieldPresent(sfAuthorizedKey);
}
// Check if account claimed.
if (tesSUCCESS == terResult)
{
switch (txn.getTxnType())
{
case ttCLAIM:
if (bHaveAuthKey)
{
cLog(lsWARNING) << "applyTransaction: Account already claimed.";
terResult = tefCLAIMED;
}
break;
default:
nothing();
break;
}
}
// Consistency: Check signature
if (tesSUCCESS == terResult)
{
switch (txn.getTxnType())
{
case ttCLAIM:
// Transaction's signing public key must be for the source account.
// To prove the master private key made this transaction.
if (naSigningPubKey.getAccountID() != mTxnAccountID)
{
// Signing Pub Key must be for Source Account ID.
cLog(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID();
cLog(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID();
terResult = tefBAD_CLAIM_ID;
}
break;
case ttREGULAR_KEY_SET:
// Transaction's signing public key must be for the source account.
// To prove the master private key made this transaction.
if (naSigningPubKey.getAccountID() != mTxnAccountID)
{
// Signing Pub Key must be for Source Account ID.
cLog(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID();
cLog(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID();
terResult = temBAD_SET_ID;
}
break;
default:
// Verify the transaction's signing public key is the key authorized for signing.
if (bHaveAuthKey && naSigningPubKey.getAccountID() == mTxnAccount->getFieldAccount(sfAuthorizedKey).getAccountID())
{
// Authorized to continue.
nothing();
}
else if (naSigningPubKey.getAccountID() == mTxnAccountID)
{
// Authorized to continue.
nothing();
}
else if (bHaveAuthKey)
{
cLog(lsINFO) << "applyTransaction: Delay: Not authorized to use account.";
terResult = tefBAD_AUTH;
}
else
{
cLog(lsINFO) << "applyTransaction: Invalid: Not authorized to use account.";
terResult = temBAD_AUTH_MASTER;
}
break;
}
}
// Deduct the fee, so it's not available during the transaction.
// Will only write the account back, if the transaction succeeds.
if (tesSUCCESS != terResult || !saCost)
{
nothing();
}
else if (saSrcBalance < saPaid)
{
cLog(lsINFO)
<< boost::str(boost::format("applyTransaction: Delay: insufficient balance: balance=%s paid=%s")
% saSrcBalance.getText()
% saPaid.getText());
terResult = terINSUF_FEE_B;
}
else
{
mTxnAccount->setFieldAmount(sfBalance, saSrcBalance - saPaid);
}
// Validate sequence
if (tesSUCCESS != terResult)
{
nothing();
}
else if (saCost)
{
uint32 a_seq = mTxnAccount->getFieldU32(sfSequence);
cLog(lsTRACE) << "Aseq=" << a_seq << ", Tseq=" << t_seq;
if (t_seq != a_seq)
{
if (a_seq < t_seq)
{
cLog(lsINFO) << "applyTransaction: future sequence number";
terResult = terPRE_SEQ;
}
else if (mLedger->hasTransaction(txID))
terResult = tefALREADY;
else
{
cLog(lsWARNING) << "applyTransaction: past sequence number";
terResult = tefPAST_SEQ;
}
}
else
{
mTxnAccount->setFieldU32(sfSequence, t_seq + 1);
}
}
else
{
cLog(lsINFO) << "applyTransaction: Zero cost transaction";
if (t_seq)
{
cLog(lsINFO) << "applyTransaction: bad sequence for pre-paid transaction";
terResult = tefPAST_SEQ;
}
}
if (tesSUCCESS == terResult)
{
entryModify(mTxnAccount);
switch (txn.getTxnType())
{
case ttACCOUNT_SET:
terResult = doAccountSet(txn);
break;
case ttCLAIM:
terResult = doClaim(txn);
break;
case ttTRUST_SET:
terResult = doTrustSet(txn);
break;
case ttINVALID:
cLog(lsINFO) << "applyTransaction: invalid type";
terResult = temINVALID;
break;
//case ttINVOICE:
// terResult = doInvoice(txn);
// break;
case ttOFFER_CREATE:
terResult = doOfferCreate(txn);
break;
case ttOFFER_CANCEL:
terResult = doOfferCancel(txn);
break;
case ttREGULAR_KEY_SET:
terResult = doRegularKeySet(txn);
break;
case ttPAYMENT:
terResult = doPayment(txn, params);
break;
case ttWALLET_ADD:
terResult = doWalletAdd(txn);
break;
case ttCONTRACT:
terResult = doContractAdd(txn);
break;
case ttCONTRACT_REMOVE:
terResult = doContractRemove(txn);
break;
default:
terResult = temUNKNOWN;
break;
}
} }
TER terResult= transactor->apply();
std::string strToken; std::string strToken;
std::string strHuman; std::string strHuman;
@@ -468,6 +135,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
if (!mLedger->addTransaction(txID, s, m)) if (!mLedger->addTransaction(txID, s, m))
assert(false); assert(false);
STAmount saPaid = txn.getTransactionFee();
// Charge whatever fee they specified. // Charge whatever fee they specified.
mLedger->destroyCoins(saPaid.getNValue()); mLedger->destroyCoins(saPaid.getNValue());
} }
@@ -483,6 +151,12 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
} }
return terResult; return terResult;
}else
{
cLog(lsWARNING) << "applyTransaction: Invalid transaction: unknown transaction type";
return temUNKNOWN;
}
} }
// vim:ts=4 // vim:ts=4

View File

@@ -11,6 +11,10 @@
#include "TransactionErr.h" #include "TransactionErr.h"
#include "InstanceCounter.h" #include "InstanceCounter.h"
#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
DEFINE_INSTANCE(TransactionEngine); DEFINE_INSTANCE(TransactionEngine);
// A TransactionEngine applies serialized transactions to a ledger // A TransactionEngine applies serialized transactions to a ledger
@@ -32,12 +36,13 @@ enum TransactionEngineParams
// One instance per ledger. // One instance per ledger.
// Only one transaction applied at a time. // Only one transaction applied at a time.
class TransactionEngine : private IS_INSTANCE(TransactionEngine) class TransactionEngine : public boost::enable_shared_from_this<TransactionEngine>, private IS_INSTANCE(TransactionEngine)
{ {
private: private:
LedgerEntrySet mNodes; LedgerEntrySet mNodes;
TER setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator); TER setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator);
TER checkSig(const SerializedTransaction& txn);
TER takeOffers( TER takeOffers(
bool bPassive, bool bPassive,
@@ -55,31 +60,26 @@ protected:
uint160 mTxnAccountID; uint160 mTxnAccountID;
SLE::pointer mTxnAccount; SLE::pointer mTxnAccount;
void txnWrite();
public:
typedef boost::shared_ptr<TransactionEngine> pointer;
TransactionEngine() { ; }
TransactionEngine(Ledger::ref ledger) : mLedger(ledger) { assert(mLedger); }
LedgerEntrySet& getNodes() { return mNodes; }
Ledger::pointer getLedger() { return mLedger; }
void setLedger(Ledger::ref ledger) { assert(ledger); mLedger = ledger; }
SLE::pointer entryCreate(LedgerEntryType type, const uint256& index) { return mNodes.entryCreate(type, index); } SLE::pointer entryCreate(LedgerEntryType type, const uint256& index) { return mNodes.entryCreate(type, index); }
SLE::pointer entryCache(LedgerEntryType type, const uint256& index) { return mNodes.entryCache(type, index); } SLE::pointer entryCache(LedgerEntryType type, const uint256& index) { return mNodes.entryCache(type, index); }
void entryDelete(SLE::ref sleEntry) { mNodes.entryDelete(sleEntry); } void entryDelete(SLE::ref sleEntry) { mNodes.entryDelete(sleEntry); }
void entryModify(SLE::ref sleEntry) { mNodes.entryModify(sleEntry); } void entryModify(SLE::ref sleEntry) { mNodes.entryModify(sleEntry); }
void txnWrite();
TER doAccountSet(const SerializedTransaction& txn);
TER doClaim(const SerializedTransaction& txn);
TER doTrustSet(const SerializedTransaction& txn);
TER doOfferCreate(const SerializedTransaction& txn);
TER doOfferCancel(const SerializedTransaction& txn);
TER doRegularKeySet(const SerializedTransaction& txn);
TER doPayment(const SerializedTransaction& txn, const TransactionEngineParams params);
TER doWalletAdd(const SerializedTransaction& txn);
TER doContractAdd(const SerializedTransaction& txn);
TER doContractRemove(const SerializedTransaction& txn);
public:
TransactionEngine() { ; }
TransactionEngine(Ledger::ref ledger) : mLedger(ledger) { assert(mLedger); }
Ledger::pointer getLedger() { return mLedger; }
void setLedger(Ledger::ref ledger) { assert(ledger); mLedger = ledger; }
TER applyTransaction(const SerializedTransaction&, TransactionEngineParams); TER applyTransaction(const SerializedTransaction&, TransactionEngineParams);
}; };

View File

@@ -0,0 +1,231 @@
#include "Transactor.h"
#include "Log.h"
#include "Config.h"
#include "PaymentTransactor.h"
#include "RegularKeySetTransactor.h"
#include "AccountSetTransactor.h"
#include "WalletAddTransactor.h"
#include "OfferCancelTransactor.h"
#include "OfferCreateTransactor.h"
#include "TrustSetTransactor.h"
SETUP_LOG();
Transactor::pointer Transactor::makeTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine::pointer engine)
{
switch(txn.getTxnType())
{
case ttPAYMENT:
return( Transactor::pointer(new PaymentTransactor(txn,params,engine)) );
case ttACCOUNT_SET:
return( Transactor::pointer(new AccountSetTransactor(txn,params,engine)) );
case ttREGULAR_KEY_SET:
return( Transactor::pointer(new RegularKeySetTransactor(txn,params,engine)) );
case ttTRUST_SET:
return( Transactor::pointer(new TrustSetTransactor(txn,params,engine)) );
case ttOFFER_CREATE:
return( Transactor::pointer(new OfferCreateTransactor(txn,params,engine)) );
case ttOFFER_CANCEL:
return( Transactor::pointer(new OfferCancelTransactor(txn,params,engine)) );
case ttWALLET_ADD:
return( Transactor::pointer(new WalletAddTransactor(txn,params,engine)) );
default:
return(Transactor::pointer());
}
}
Transactor::Transactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine::pointer engine) : mTxn(txn), mParams(params), mEngine(engine)
{
mHasAuthKey=false;
}
void Transactor::calculateFee()
{
mFeeDue = theConfig.FEE_DEFAULT;
}
TER Transactor::payFee()
{
STAmount saPaid = mTxn.getTransactionFee();
// Only check fee is sufficient when the ledger is open.
if (isSetBit(mParams, tapOPEN_LEDGER) && saPaid < mFeeDue)
{
cLog(lsINFO) << "applyTransaction: insufficient fee";
return telINSUF_FEE_P;
}
if( !saPaid ) return tesSUCCESS;
// Deduct the fee, so it's not available during the transaction.
// Will only write the account back, if the transaction succeeds.
if (mSourceBalance < saPaid)
{
cLog(lsINFO)
<< boost::str(boost::format("applyTransaction: Delay: insufficient balance: balance=%s paid=%s")
% mSourceBalance.getText()
% saPaid.getText());
return terINSUF_FEE_B;
}
mSourceBalance -= saPaid;
mTxnAccount->setFieldAmount(sfBalance, mSourceBalance);
return tesSUCCESS;
}
TER Transactor::checkSig()
{
// Consistency: Check signature
// Verify the transaction's signing public key is the key authorized for signing.
if (mHasAuthKey && mSigningPubKey.getAccountID() == mTxnAccount->getFieldAccount(sfAuthorizedKey).getAccountID())
{
// Authorized to continue.
nothing();
}
else if (mSigningPubKey.getAccountID() == mTxnAccountID)
{
// Authorized to continue.
nothing();
}
else if (mHasAuthKey)
{
cLog(lsINFO) << "applyTransaction: Delay: Not authorized to use account.";
return tefBAD_AUTH;
}
else
{
cLog(lsINFO) << "applyTransaction: Invalid: Not authorized to use account.";
return temBAD_AUTH_MASTER;
}
return tesSUCCESS;
}
TER Transactor::checkSeq()
{
uint32 t_seq = mTxn.getSequence();
uint32 a_seq = mTxnAccount->getFieldU32(sfSequence);
cLog(lsTRACE) << "Aseq=" << a_seq << ", Tseq=" << t_seq;
if (t_seq != a_seq)
{
if (a_seq < t_seq)
{
cLog(lsINFO) << "applyTransaction: future sequence number";
return terPRE_SEQ;
}
else
{
uint256 txID = mTxn.getTransactionID();
if (mEngine->getLedger()->hasTransaction(txID))
return tefALREADY;
}
cLog(lsWARNING) << "applyTransaction: past sequence number";
return tefPAST_SEQ;
}else
{
mTxnAccount->setFieldU32(sfSequence, t_seq + 1);
}
return tesSUCCESS;
}
// check stuff before you bother to lock the ledger
TER Transactor::preCheck()
{
mTxnAccountID = mTxn.getSourceAccount().getAccountID();
if (!mTxnAccountID)
{
cLog(lsWARNING) << "applyTransaction: bad source id";
return temINVALID;
}
// Extract signing key
// Transactions contain a signing key. This allows us to trivially verify a transaction has at least been properly signed
// without going to disk. Each transaction also notes a source account id. This is used to verify that the signing key is
// associated with the account.
// XXX This could be a lot cleaner to prevent unnecessary copying.
mSigningPubKey = RippleAddress::createAccountPublic(mTxn.getSigningPubKey());
// Consistency: really signed.
if ( !isSetBit(mParams, tapNO_CHECK_SIGN) && !mTxn.checkSign(mSigningPubKey))
{
cLog(lsWARNING) << "applyTransaction: Invalid transaction: bad signature";
return temINVALID;
}
return tesSUCCESS;
}
TER Transactor::apply()
{
TER terResult = tesSUCCESS;
terResult=preCheck();
if(terResult != tesSUCCESS) return(terResult);
calculateFee();
terResult=payFee();
if(terResult != tesSUCCESS) return(terResult);
boost::recursive_mutex::scoped_lock sl(mEngine->getLedger()->mLock);
mTxnAccount = mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(mTxnAccountID));
// Find source account
// If are only forwarding, due to resource limitations, we might verifying only some transactions, this would be probabilistic.
STAmount saSrcBalance;
if (!mTxnAccount)
{
cLog(lsTRACE) << boost::str(boost::format("applyTransaction: Delay transaction: source account does not exist: %s") %
mTxn.getSourceAccount().humanAccountID());
return terNO_ACCOUNT;
}
else
{
mSourceBalance = mTxnAccount->getFieldAmount(sfBalance);
mHasAuthKey = mTxnAccount->isFieldPresent(sfAuthorizedKey);
}
terResult=checkSig();
if(terResult != tesSUCCESS) return(terResult);
terResult=checkSeq();
if(terResult != tesSUCCESS) return(terResult);
mEngine->entryModify(mTxnAccount);
return doApply();
}

View File

@@ -0,0 +1,41 @@
#ifndef __TRANSACTOR__
#define __TRANSACTOR__
#include "SerializedTransaction.h"
#include "TransactionErr.h"
#include "TransactionEngine.h"
#include <boost/shared_ptr.hpp>
class Transactor
{
protected:
const SerializedTransaction& mTxn;
TransactionEngine::pointer mEngine;
TransactionEngineParams mParams;
uint160 mTxnAccountID;
STAmount mFeeDue;
STAmount mSourceBalance;
SLE::pointer mTxnAccount;
bool mHasAuthKey;
RippleAddress mSigningPubKey;
TER preCheck();
TER checkSeq();
TER payFee();
virtual void calculateFee();
virtual TER checkSig();
virtual TER doApply()=0;
Transactor(const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine::pointer engine);
public:
typedef boost::shared_ptr<Transactor> pointer;
static Transactor::pointer makeTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine::pointer engine);
TER apply();
};
#endif

View File

@@ -0,0 +1,147 @@
#include "TrustSetTransactor.h"
TER TrustSetTransactor::doApply()
{
TER terResult = tesSUCCESS;
Log(lsINFO) << "doTrustSet>";
const STAmount saLimitAmount = mTxn.getFieldAmount(sfLimitAmount);
const bool bQualityIn = mTxn.isFieldPresent(sfQualityIn);
const uint32 uQualityIn = bQualityIn ? mTxn.getFieldU32(sfQualityIn) : 0;
const bool bQualityOut = mTxn.isFieldPresent(sfQualityOut);
const uint32 uQualityOut = bQualityIn ? mTxn.getFieldU32(sfQualityOut) : 0;
const uint160 uCurrencyID = saLimitAmount.getCurrency();
uint160 uDstAccountID = saLimitAmount.getIssuer();
const bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest.
bool bDelIndex = false;
// Check if destination makes sense.
if (saLimitAmount.isNegative())
{
Log(lsINFO) << "doTrustSet: Malformed transaction: Negatived credit limit.";
return temBAD_AMOUNT;
}
else if (!uDstAccountID)
{
Log(lsINFO) << "doTrustSet: Malformed transaction: Destination account not specified.";
return temDST_NEEDED;
}
else if (mTxnAccountID == uDstAccountID)
{
Log(lsINFO) << "doTrustSet: Malformed transaction: Can not extend credit to self.";
return temDST_IS_SRC;
}
SLE::pointer sleDst = mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID));
if (!sleDst)
{
Log(lsINFO) << "doTrustSet: Delay transaction: Destination account does not exist.";
return terNO_DST;
}
STAmount saLimitAllow = saLimitAmount;
saLimitAllow.setIssuer(mTxnAccountID);
SLE::pointer sleRippleState = mEngine->entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID));
if (sleRippleState)
{
// A line exists in one or more directions.
#if 0
if (!saLimitAmount)
{
// Zeroing line.
uint160 uLowID = sleRippleState->getFieldAmount(sfLowLimit).getIssuer();
uint160 uHighID = sleRippleState->getFieldAmount(sfHighLimit).getIssuer();
bool bLow = uLowID == uSrcAccountID;
bool bHigh = uLowID == uDstAccountID;
bool bBalanceZero = !sleRippleState->getFieldAmount(sfBalance);
STAmount saDstLimit = sleRippleState->getFieldAmount(bSendLow ? sfLowLimit : sfHighLimit);
bool bDstLimitZero = !saDstLimit;
assert(bLow || bHigh);
if (bBalanceZero && bDstLimitZero)
{
// Zero balance and eliminating last limit.
bDelIndex = true;
terResult = dirDelete(false, uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex(), false);
}
}
#endif
if (!bDelIndex)
{
sleRippleState->setFieldAmount(bFlipped ? sfHighLimit: sfLowLimit, saLimitAllow);
if (!bQualityIn)
{
nothing();
}
else if (uQualityIn)
{
sleRippleState->setFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn);
}
else
{
sleRippleState->makeFieldAbsent(bFlipped ? sfLowQualityIn : sfHighQualityIn);
}
if (!bQualityOut)
{
nothing();
}
else if (uQualityOut)
{
sleRippleState->setFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut);
}
else
{
sleRippleState->makeFieldAbsent(bFlipped ? sfLowQualityOut : sfHighQualityOut);
}
mEngine->entryModify(sleRippleState);
}
Log(lsINFO) << "doTrustSet: Modifying ripple line: bDelIndex=" << bDelIndex;
}
// Line does not exist.
else if (!saLimitAmount)
{
Log(lsINFO) << "doTrustSet: Redundant: Setting non-existent ripple line to 0.";
return terNO_LINE_NO_ZERO;
}
else
{
// Create a new ripple line.
sleRippleState = mEngine->entryCreate(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID));
Log(lsINFO) << "doTrustSet: Creating ripple line: " << sleRippleState->getIndex().ToString();
sleRippleState->setFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency.
sleRippleState->setFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAllow);
sleRippleState->setFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uDstAccountID));
if (uQualityIn)
sleRippleState->setFieldU32(bFlipped ? sfHighQualityIn : sfLowQualityIn, uQualityIn);
if (uQualityOut)
sleRippleState->setFieldU32(bFlipped ? sfHighQualityOut : sfLowQualityOut, uQualityOut);
uint64 uSrcRef; // Ignored, dirs never delete.
terResult = mEngine->getNodes().dirAdd(uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex());
if (tesSUCCESS == terResult)
terResult = mEngine->getNodes().dirAdd(uSrcRef, Ledger::getOwnerDirIndex(uDstAccountID), sleRippleState->getIndex());
}
Log(lsINFO) << "doTrustSet<";
return terResult;
}

View File

@@ -0,0 +1,9 @@
#include "Transactor.h"
class TrustSetTransactor : public Transactor
{
public:
TrustSetTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine::pointer engine) : Transactor(txn,params,engine) {}
TER doApply();
};

View File

@@ -0,0 +1,58 @@
#include "WalletAddTransactor.h"
TER WalletAddTransactor::doApply()
{
std::cerr << "WalletAdd>" << std::endl;
const std::vector<unsigned char> vucPubKey = mTxn.getFieldVL(sfPublicKey);
const std::vector<unsigned char> vucSignature = mTxn.getFieldVL(sfSignature);
const uint160 uAuthKeyID = mTxn.getFieldAccount160(sfAuthorizedKey);
const RippleAddress naMasterPubKey = RippleAddress::createAccountPublic(vucPubKey);
const uint160 uDstAccountID = naMasterPubKey.getAccountID();
// FIXME: This should be moved to the transaction's signature check logic and cached
if (!naMasterPubKey.accountPublicVerify(Serializer::getSHA512Half(uAuthKeyID.begin(), uAuthKeyID.size()), vucSignature))
{
std::cerr << "WalletAdd: unauthorized: bad signature " << std::endl;
return tefBAD_ADD_AUTH;
}
SLE::pointer sleDst = mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID));
if (sleDst)
{
std::cerr << "WalletAdd: account already created" << std::endl;
return tefCREATED;
}
STAmount saAmount = mTxn.getFieldAmount(sfAmount);
STAmount saSrcBalance = mTxnAccount->getFieldAmount(sfBalance);
if (saSrcBalance < saAmount)
{
std::cerr
<< boost::str(boost::format("WalletAdd: Delay transaction: insufficient balance: balance=%s amount=%s")
% saSrcBalance.getText()
% saAmount.getText())
<< std::endl;
return terUNFUNDED;
}
// Deduct initial balance from source account.
mTxnAccount->setFieldAmount(sfBalance, saSrcBalance-saAmount);
// Create the account.
sleDst = mEngine->entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID));
sleDst->setFieldAccount(sfAccount, uDstAccountID);
sleDst->setFieldU32(sfSequence, 1);
sleDst->setFieldAmount(sfBalance, saAmount);
sleDst->setFieldAccount(sfAuthorizedKey, uAuthKeyID);
std::cerr << "WalletAdd<" << std::endl;
return tesSUCCESS;
}

View File

@@ -0,0 +1,10 @@
#include "Transactor.h"
class WalletAddTransactor : public Transactor
{
public:
WalletAddTransactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine::pointer engine) : Transactor(txn,params,engine) {}
TER doApply();
};