mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-25 05:25:55 +00:00
Improvements to protocol serialization:
A few serialization changes coming from m-of-n development: o Improve readability of SField.cpp. o Better initialization of STObject. o Trimming of STObject public methods. o Add STObject::getFieldObject and STObject::setFieldObject. o Make STObject::isEquivalent more robust. o Improvements to whitespace, overrides, and virtuals.
This commit is contained in:
committed by
Vinnie Falco
parent
2f3834359e
commit
92799187ed
@@ -81,7 +81,7 @@ bool ConsensusTransSetSF::haveNode (const SHAMapNodeID& id, uint256 const& nodeH
|
||||
WriteLog (lsTRACE, TransactionAcquire) << "Node in our acquiring TX set is TXN we have";
|
||||
Serializer s;
|
||||
s.add32 (HashPrefix::transactionID);
|
||||
txn->getSTransaction ()->add (s, true);
|
||||
txn->getSTransaction ()->add (s);
|
||||
assert (s.getSHA512Half () == nodeHash);
|
||||
nodeData = s.peekData ();
|
||||
return true;
|
||||
|
||||
@@ -52,8 +52,8 @@ enum LedgerStateParms
|
||||
class SqliteStatement;
|
||||
|
||||
// VFALCO TODO figure out exactly how this thing works.
|
||||
// It seems like some ledger database is stored as a global, static in the
|
||||
// class. But then what is the meaning of a Ledger object? Is this
|
||||
// It seems like some ledger database is stored as a global, static in
|
||||
// the class. But then what is the meaning of a Ledger object? Is this
|
||||
// really two classes in one? StoreOfAllLedgers + SingleLedgerObject?
|
||||
//
|
||||
/** Holds some or all of a ledger.
|
||||
|
||||
@@ -566,7 +566,7 @@ AmendmentTableImpl<AppApiFacade>::doVoting (Ledger::ref lastClosedLedger,
|
||||
|
||||
// Inject the transaction into our initial proposal
|
||||
Serializer s;
|
||||
trans.add (s, true);
|
||||
trans.add (s);
|
||||
#if RIPPLE_PROPOSE_AMENDMENTS
|
||||
auto tItem = std::make_shared<SHAMapItem> (txID, s.peekData ());
|
||||
if (!initialPosition->addGiveItem (tItem, true, false))
|
||||
|
||||
@@ -226,7 +226,7 @@ FeeVoteImpl::doVoting (Ledger::ref lastClosedLedger,
|
||||
journal_.warning << "Vote: " << txID;
|
||||
|
||||
Serializer s;
|
||||
trans.add (s, true);
|
||||
trans.add (s);
|
||||
|
||||
auto tItem = std::make_shared<SHAMapItem> (txID, s.peekData ());
|
||||
|
||||
|
||||
@@ -67,14 +67,14 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class NetworkOPsImp
|
||||
class NetworkOPsImp final
|
||||
: public NetworkOPs
|
||||
, public beast::DeadlineTimer::Listener
|
||||
{
|
||||
public:
|
||||
enum Fault
|
||||
{
|
||||
// exceptions these functions can throw
|
||||
// Exceptions these functions can throw.
|
||||
IO_ERROR = 1,
|
||||
NO_NETWORK = 2,
|
||||
};
|
||||
@@ -116,109 +116,111 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
~NetworkOPsImp()
|
||||
{
|
||||
}
|
||||
~NetworkOPsImp() override = default;
|
||||
|
||||
// network information
|
||||
// Our best estimate of wall time in seconds from 1/1/2000
|
||||
std::uint32_t getNetworkTimeNC () const;
|
||||
// Network information.
|
||||
// Our best estimate of wall time in seconds from 1/1/2000.
|
||||
std::uint32_t getNetworkTimeNC () const override;
|
||||
|
||||
// Our best estimate of current ledger close time
|
||||
std::uint32_t getCloseTimeNC () const;
|
||||
// Our best estimate of current ledger close time.
|
||||
std::uint32_t getCloseTimeNC () const override;
|
||||
private:
|
||||
std::uint32_t getCloseTimeNC (int& offset) const;
|
||||
|
||||
// Use *only* to timestamp our own validation
|
||||
std::uint32_t getValidationTimeNC ();
|
||||
void closeTimeOffset (int);
|
||||
public:
|
||||
// Use *only* to timestamp our own validation.
|
||||
std::uint32_t getValidationTimeNC () override;
|
||||
void closeTimeOffset (int) override;
|
||||
|
||||
/** On return the offset param holds the System time offset in seconds.
|
||||
*/
|
||||
boost::posix_time::ptime getNetworkTimePT(int& offset) const;
|
||||
std::uint32_t getLedgerID (uint256 const& hash);
|
||||
std::uint32_t getCurrentLedgerID ();
|
||||
OperatingMode getOperatingMode () const
|
||||
boost::posix_time::ptime getNetworkTimePT(int& offset) const override;
|
||||
std::uint32_t getLedgerID (uint256 const& hash) override;
|
||||
std::uint32_t getCurrentLedgerID () override;
|
||||
OperatingMode getOperatingMode () const override
|
||||
{
|
||||
return mMode;
|
||||
}
|
||||
std::string strOperatingMode () const;
|
||||
std::string strOperatingMode () const override;
|
||||
|
||||
Ledger::pointer getClosedLedger ()
|
||||
Ledger::pointer getClosedLedger () override
|
||||
{
|
||||
return m_ledgerMaster.getClosedLedger ();
|
||||
}
|
||||
Ledger::pointer getValidatedLedger ()
|
||||
Ledger::pointer getValidatedLedger () override
|
||||
{
|
||||
return m_ledgerMaster.getValidatedLedger ();
|
||||
}
|
||||
Ledger::pointer getPublishedLedger ()
|
||||
Ledger::pointer getPublishedLedger () override
|
||||
{
|
||||
return m_ledgerMaster.getPublishedLedger ();
|
||||
}
|
||||
Ledger::pointer getCurrentLedger ()
|
||||
Ledger::pointer getCurrentLedger () override
|
||||
{
|
||||
return m_ledgerMaster.getCurrentLedger ();
|
||||
}
|
||||
Ledger::pointer getLedgerByHash (uint256 const& hash)
|
||||
Ledger::pointer getLedgerByHash (uint256 const& hash) override
|
||||
{
|
||||
return m_ledgerMaster.getLedgerByHash (hash);
|
||||
}
|
||||
Ledger::pointer getLedgerBySeq (const std::uint32_t seq);
|
||||
void missingNodeInLedger (const std::uint32_t seq);
|
||||
Ledger::pointer getLedgerBySeq (const std::uint32_t seq) override;
|
||||
void missingNodeInLedger (const std::uint32_t seq) override;
|
||||
|
||||
uint256 getClosedLedgerHash ()
|
||||
uint256 getClosedLedgerHash () override
|
||||
{
|
||||
return m_ledgerMaster.getClosedLedger ()->getHash ();
|
||||
}
|
||||
|
||||
// Do we have this inclusive range of ledgers in our database
|
||||
bool haveLedgerRange (std::uint32_t from, std::uint32_t to);
|
||||
bool haveLedger (std::uint32_t seq);
|
||||
std::uint32_t getValidatedSeq ();
|
||||
bool isValidated (std::uint32_t seq);
|
||||
bool isValidated (std::uint32_t seq, uint256 const& hash);
|
||||
bool isValidated (Ledger::ref l)
|
||||
bool haveLedgerRange (std::uint32_t from, std::uint32_t to) override;
|
||||
bool haveLedger (std::uint32_t seq) override;
|
||||
std::uint32_t getValidatedSeq () override;
|
||||
bool isValidated (std::uint32_t seq) override;
|
||||
bool isValidated (std::uint32_t seq, uint256 const& hash) override;
|
||||
bool isValidated (Ledger::ref l) override
|
||||
{
|
||||
return isValidated (l->getLedgerSeq (), l->getHash ());
|
||||
}
|
||||
bool getValidatedRange (std::uint32_t& minVal, std::uint32_t& maxVal)
|
||||
bool getValidatedRange (
|
||||
std::uint32_t& minVal, std::uint32_t& maxVal) override
|
||||
{
|
||||
return m_ledgerMaster.getValidatedRange (minVal, maxVal);
|
||||
}
|
||||
bool getFullValidatedRange (std::uint32_t& minVal, std::uint32_t& maxVal)
|
||||
bool getFullValidatedRange (
|
||||
std::uint32_t& minVal, std::uint32_t& maxVal) override
|
||||
{
|
||||
return m_ledgerMaster.getFullValidatedRange (minVal, maxVal);
|
||||
}
|
||||
|
||||
STValidation::ref getLastValidation ()
|
||||
STValidation::ref getLastValidation () override
|
||||
{
|
||||
return mLastValidation;
|
||||
}
|
||||
void setLastValidation (STValidation::ref v)
|
||||
void setLastValidation (STValidation::ref v) override
|
||||
{
|
||||
mLastValidation = v;
|
||||
}
|
||||
|
||||
//
|
||||
// Transaction operations
|
||||
// Transaction operations.
|
||||
//
|
||||
|
||||
// must complete immediately
|
||||
// Must complete immediately.
|
||||
typedef std::function<void (Transaction::pointer, TER)> stCallback;
|
||||
void submitTransaction (
|
||||
Job&, STTx::pointer,
|
||||
stCallback callback = stCallback ());
|
||||
stCallback callback = stCallback ()) override;
|
||||
|
||||
Transaction::pointer submitTransactionSync (
|
||||
Transaction::ref tpTrans,
|
||||
bool bAdmin, bool bLocal, bool bFailHard, bool bSubmit);
|
||||
bool bAdmin, bool bLocal, bool bFailHard, bool bSubmit) override;
|
||||
|
||||
Transaction::pointer processTransactionCb (
|
||||
Transaction::pointer,
|
||||
bool bAdmin, bool bLocal, bool bFailHard, stCallback);
|
||||
bool bAdmin, bool bLocal, bool bFailHard, stCallback) override;
|
||||
Transaction::pointer processTransaction (
|
||||
Transaction::pointer transaction,
|
||||
bool bAdmin, bool bLocal, bool bFailHard)
|
||||
bool bAdmin, bool bLocal, bool bFailHard) override
|
||||
{
|
||||
return processTransactionCb (
|
||||
transaction, bAdmin, bLocal, bFailHard, stCallback ());
|
||||
@@ -227,6 +229,7 @@ public:
|
||||
// VFALCO Workaround for MSVC std::function which doesn't swallow return
|
||||
// types.
|
||||
//
|
||||
private:
|
||||
void processTransactionCbVoid (
|
||||
Transaction::pointer p,
|
||||
bool bAdmin, bool bLocal, bool bFailHard, stCallback cb)
|
||||
@@ -234,77 +237,82 @@ public:
|
||||
processTransactionCb (p, bAdmin, bLocal, bFailHard, cb);
|
||||
}
|
||||
|
||||
Transaction::pointer findTransactionByID (uint256 const& transactionID);
|
||||
public:
|
||||
Transaction::pointer findTransactionByID (
|
||||
uint256 const& transactionID) override;
|
||||
|
||||
int findTransactionsByDestination (
|
||||
std::list<Transaction::pointer>&,
|
||||
RippleAddress const& destinationAccount,
|
||||
std::uint32_t startLedgerSeq, std::uint32_t endLedgerSeq,
|
||||
int maxTransactions);
|
||||
int maxTransactions) override;
|
||||
|
||||
//
|
||||
// Account functions
|
||||
// Account functions.
|
||||
//
|
||||
|
||||
AccountState::pointer getAccountState (
|
||||
Ledger::ref lrLedger, RippleAddress const& accountID);
|
||||
Ledger::ref lrLedger, RippleAddress const& accountID) override;
|
||||
|
||||
//
|
||||
// Directory functions
|
||||
// Directory functions.
|
||||
//
|
||||
|
||||
STVector256 getDirNodeInfo (
|
||||
Ledger::ref lrLedger, uint256 const& uRootIndex,
|
||||
std::uint64_t& uNodePrevious, std::uint64_t& uNodeNext);
|
||||
std::uint64_t& uNodePrevious, std::uint64_t& uNodeNext) override;
|
||||
|
||||
//
|
||||
// Owner functions
|
||||
// Owner functions.
|
||||
//
|
||||
|
||||
Json::Value getOwnerInfo (
|
||||
Ledger::pointer lpLedger, RippleAddress const& naAccount);
|
||||
Ledger::pointer lpLedger, RippleAddress const& naAccount) override;
|
||||
|
||||
//
|
||||
// Book functions
|
||||
// Book functions.
|
||||
//
|
||||
|
||||
void getBookPage (bool bAdmin, Ledger::pointer lpLedger, Book const&,
|
||||
Account const& uTakerID, const bool bProof, const unsigned int iLimit,
|
||||
Json::Value const& jvMarker, Json::Value& jvResult);
|
||||
Json::Value const& jvMarker, Json::Value& jvResult) override;
|
||||
|
||||
// ledger proposal/close functions
|
||||
// Ledger proposal/close functions.
|
||||
void processTrustedProposal (
|
||||
LedgerProposal::pointer proposal,
|
||||
std::shared_ptr<protocol::TMProposeSet> set,
|
||||
RippleAddress nodePublic, uint256 checkLedger, bool sigGood);
|
||||
RippleAddress nodePublic, uint256 checkLedger, bool sigGood) override;
|
||||
|
||||
bool recvValidation (
|
||||
STValidation::ref val, std::string const& source);
|
||||
void takePosition (int seq, std::shared_ptr<SHAMap> const& position);
|
||||
STValidation::ref val, std::string const& source) override;
|
||||
void takePosition (
|
||||
int seq, std::shared_ptr<SHAMap> const& position) override;
|
||||
std::shared_ptr<SHAMap> getTXMap (uint256 const& hash);
|
||||
bool hasTXSet (
|
||||
const std::shared_ptr<Peer>& peer, uint256 const& set,
|
||||
protocol::TxSetStatus status);
|
||||
|
||||
void mapComplete (uint256 const& hash, std::shared_ptr<SHAMap> const& map);
|
||||
void mapComplete (uint256 const& hash, std::shared_ptr<SHAMap> const& map) override;
|
||||
void makeFetchPack (
|
||||
Job&, std::weak_ptr<Peer> peer,
|
||||
std::shared_ptr<protocol::TMGetObjectByHash> request,
|
||||
uint256 haveLedger, std::uint32_t uUptime);
|
||||
uint256 haveLedger, std::uint32_t uUptime) override;
|
||||
|
||||
bool shouldFetchPack (std::uint32_t seq);
|
||||
void gotFetchPack (bool progress, std::uint32_t seq);
|
||||
void addFetchPack (uint256 const& hash, std::shared_ptr< Blob >& data);
|
||||
bool getFetchPack (uint256 const& hash, Blob& data);
|
||||
int getFetchSize ();
|
||||
void sweepFetchPack ();
|
||||
bool shouldFetchPack (std::uint32_t seq) override;
|
||||
void gotFetchPack (bool progress, std::uint32_t seq) override;
|
||||
void addFetchPack (
|
||||
uint256 const& hash, std::shared_ptr< Blob >& data) override;
|
||||
bool getFetchPack (uint256 const& hash, Blob& data) override;
|
||||
int getFetchSize () override;
|
||||
void sweepFetchPack () override;
|
||||
|
||||
// network state machine
|
||||
// Network state machine.
|
||||
|
||||
// VFALCO TODO Try to make all these private since they seem to be...private
|
||||
//
|
||||
|
||||
// Used for the "jump" case
|
||||
// Used for the "jump" case.
|
||||
private:
|
||||
void switchLastClosedLedger (
|
||||
Ledger::pointer newLedger, bool duringConsensus);
|
||||
bool checkLastClosedLedger (
|
||||
@@ -312,8 +320,10 @@ public:
|
||||
int beginConsensus (
|
||||
uint256 const& networkClosed, Ledger::pointer closingLedger);
|
||||
void tryStartConsensus ();
|
||||
void endConsensus (bool correctLCL);
|
||||
void setStandAlone ()
|
||||
|
||||
public:
|
||||
void endConsensus (bool correctLCL) override;
|
||||
void setStandAlone () override
|
||||
{
|
||||
setMode (omFULL);
|
||||
}
|
||||
@@ -321,73 +331,74 @@ public:
|
||||
/** Called to initially start our timers.
|
||||
Not called for stand-alone mode.
|
||||
*/
|
||||
void setStateTimer ();
|
||||
void setStateTimer () override;
|
||||
|
||||
void newLCL (int proposers, int convergeTime, uint256 const& ledgerHash);
|
||||
void needNetworkLedger ()
|
||||
void newLCL (
|
||||
int proposers, int convergeTime, uint256 const& ledgerHash) override;
|
||||
void needNetworkLedger () override
|
||||
{
|
||||
mNeedNetworkLedger = true;
|
||||
}
|
||||
void clearNeedNetworkLedger ()
|
||||
void clearNeedNetworkLedger () override
|
||||
{
|
||||
mNeedNetworkLedger = false;
|
||||
}
|
||||
bool isNeedNetworkLedger ()
|
||||
bool isNeedNetworkLedger () override
|
||||
{
|
||||
return mNeedNetworkLedger;
|
||||
}
|
||||
bool isFull ()
|
||||
bool isFull () override
|
||||
{
|
||||
return !mNeedNetworkLedger && (mMode == omFULL);
|
||||
}
|
||||
void setProposing (bool p, bool v)
|
||||
void setProposing (bool p, bool v) override
|
||||
{
|
||||
mProposing = p;
|
||||
mValidating = v;
|
||||
}
|
||||
bool isProposing ()
|
||||
bool isProposing () override
|
||||
{
|
||||
return mProposing;
|
||||
}
|
||||
bool isValidating ()
|
||||
bool isValidating () override
|
||||
{
|
||||
return mValidating;
|
||||
}
|
||||
bool isAmendmentBlocked ()
|
||||
bool isAmendmentBlocked () override
|
||||
{
|
||||
return m_amendmentBlocked;
|
||||
}
|
||||
void setAmendmentBlocked ();
|
||||
void consensusViewChange ();
|
||||
int getPreviousProposers ()
|
||||
void setAmendmentBlocked () override;
|
||||
void consensusViewChange () override;
|
||||
int getPreviousProposers () override
|
||||
{
|
||||
return mLastCloseProposers;
|
||||
}
|
||||
int getPreviousConvergeTime ()
|
||||
int getPreviousConvergeTime () override
|
||||
{
|
||||
return mLastCloseConvergeTime;
|
||||
}
|
||||
std::uint32_t getLastCloseTime ()
|
||||
std::uint32_t getLastCloseTime () override
|
||||
{
|
||||
return mLastCloseTime;
|
||||
}
|
||||
void setLastCloseTime (std::uint32_t t)
|
||||
void setLastCloseTime (std::uint32_t t) override
|
||||
{
|
||||
mLastCloseTime = t;
|
||||
}
|
||||
Json::Value getConsensusInfo ();
|
||||
Json::Value getServerInfo (bool human, bool admin);
|
||||
void clearLedgerFetch ();
|
||||
Json::Value getLedgerFetchInfo ();
|
||||
std::uint32_t acceptLedger ();
|
||||
Proposals & peekStoredProposals ()
|
||||
Json::Value getConsensusInfo () override;
|
||||
Json::Value getServerInfo (bool human, bool admin) override;
|
||||
void clearLedgerFetch () override;
|
||||
Json::Value getLedgerFetchInfo () override;
|
||||
std::uint32_t acceptLedger () override;
|
||||
Proposals & peekStoredProposals () override
|
||||
{
|
||||
return mStoredProposals;
|
||||
}
|
||||
void storeProposal (
|
||||
LedgerProposal::ref proposal, RippleAddress const& peerPublic);
|
||||
uint256 getConsensusLCL ();
|
||||
void reportFeeChange ();
|
||||
LedgerProposal::ref proposal, RippleAddress const& peerPublic) override;
|
||||
uint256 getConsensusLCL () override;
|
||||
void reportFeeChange () override;
|
||||
|
||||
void updateLocalTx (Ledger::ref newValidLedger) override
|
||||
{
|
||||
@@ -403,24 +414,24 @@ public:
|
||||
return m_localTX->size ();
|
||||
}
|
||||
|
||||
//Helper function to generate SQL query to get transactions
|
||||
//Helper function to generate SQL query to get transactions.
|
||||
std::string transactionsSQL (
|
||||
std::string selection, RippleAddress const& account,
|
||||
std::int32_t minLedger, std::int32_t maxLedger,
|
||||
bool descending, std::uint32_t offset, int limit,
|
||||
bool binary, bool count, bool bAdmin);
|
||||
bool binary, bool count, bool bAdmin) override;
|
||||
|
||||
// client information retrieval functions
|
||||
// Client information retrieval functions.
|
||||
using NetworkOPs::AccountTxs;
|
||||
AccountTxs getAccountTxs (
|
||||
RippleAddress const& account,
|
||||
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
|
||||
std::uint32_t offset, int limit, bool bAdmin);
|
||||
std::uint32_t offset, int limit, bool bAdmin) override;
|
||||
|
||||
AccountTxs getTxsAccount (
|
||||
RippleAddress const& account, std::int32_t minLedger,
|
||||
std::int32_t maxLedger, bool forward, Json::Value& token, int limit,
|
||||
bool bAdmin);
|
||||
bool bAdmin) override;
|
||||
|
||||
using NetworkOPs::txnMetaLedgerType;
|
||||
using NetworkOPs::MetaTxsList;
|
||||
@@ -429,31 +440,31 @@ public:
|
||||
getAccountTxsB (
|
||||
RippleAddress const& account, std::int32_t minLedger,
|
||||
std::int32_t maxLedger, bool descending, std::uint32_t offset,
|
||||
int limit, bool bAdmin);
|
||||
int limit, bool bAdmin) override;
|
||||
|
||||
MetaTxsList
|
||||
getTxsAccountB (
|
||||
RippleAddress const& account, std::int32_t minLedger,
|
||||
std::int32_t maxLedger, bool forward, Json::Value& token,
|
||||
int limit, bool bAdmin);
|
||||
int limit, bool bAdmin) override;
|
||||
|
||||
std::vector<RippleAddress> getLedgerAffectedAccounts (
|
||||
std::uint32_t ledgerSeq);
|
||||
std::uint32_t ledgerSeq) override;
|
||||
|
||||
//
|
||||
// Monitoring: publisher side
|
||||
// Monitoring: publisher side.
|
||||
//
|
||||
void pubLedger (Ledger::ref lpAccepted);
|
||||
void pubLedger (Ledger::ref lpAccepted) override;
|
||||
void pubProposedTransaction (
|
||||
Ledger::ref lpCurrent, STTx::ref stTxn, TER terResult);
|
||||
Ledger::ref lpCurrent, STTx::ref stTxn, TER terResult) override;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// InfoSub::Source
|
||||
// InfoSub::Source.
|
||||
//
|
||||
void subAccount (
|
||||
InfoSub::ref ispListener,
|
||||
const hash_set<RippleAddress>& vnaAccountIDs, bool rt);
|
||||
const hash_set<RippleAddress>& vnaAccountIDs, bool rt) override;
|
||||
void unsubAccount (
|
||||
InfoSub::ref ispListener,
|
||||
const hash_set<RippleAddress>& vnaAccountIDs,
|
||||
@@ -466,29 +477,31 @@ public:
|
||||
const hash_set<RippleAddress>& vnaAccountIDs,
|
||||
bool rt);
|
||||
|
||||
bool subLedger (InfoSub::ref ispListener, Json::Value& jvResult);
|
||||
bool unsubLedger (std::uint64_t uListener);
|
||||
bool subLedger (InfoSub::ref ispListener, Json::Value& jvResult) override;
|
||||
bool unsubLedger (std::uint64_t uListener) override;
|
||||
|
||||
bool subServer (InfoSub::ref ispListener, Json::Value& jvResult, bool admin);
|
||||
bool unsubServer (std::uint64_t uListener);
|
||||
bool subServer (
|
||||
InfoSub::ref ispListener, Json::Value& jvResult, bool admin) override;
|
||||
bool unsubServer (std::uint64_t uListener) override;
|
||||
|
||||
bool subBook (InfoSub::ref ispListener, Book const&) override;
|
||||
bool unsubBook (std::uint64_t uListener, Book const&) override;
|
||||
|
||||
bool subTransactions (InfoSub::ref ispListener);
|
||||
bool unsubTransactions (std::uint64_t uListener);
|
||||
bool subTransactions (InfoSub::ref ispListener) override;
|
||||
bool unsubTransactions (std::uint64_t uListener) override;
|
||||
|
||||
bool subRTTransactions (InfoSub::ref ispListener);
|
||||
bool unsubRTTransactions (std::uint64_t uListener);
|
||||
bool subRTTransactions (InfoSub::ref ispListener) override;
|
||||
bool unsubRTTransactions (std::uint64_t uListener) override;
|
||||
|
||||
InfoSub::pointer findRpcSub (std::string const& strUrl);
|
||||
InfoSub::pointer addRpcSub (std::string const& strUrl, InfoSub::ref);
|
||||
InfoSub::pointer findRpcSub (std::string const& strUrl) override;
|
||||
InfoSub::pointer addRpcSub (
|
||||
std::string const& strUrl, InfoSub::ref) override;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Stoppable
|
||||
// Stoppable.
|
||||
|
||||
void onStop ()
|
||||
void onStop () override
|
||||
{
|
||||
mAcquiringLedger.reset();
|
||||
m_heartbeatTimer.cancel();
|
||||
@@ -500,7 +513,7 @@ public:
|
||||
private:
|
||||
void setHeartbeatTimer ();
|
||||
void setClusterTimer ();
|
||||
void onDeadlineTimer (beast::DeadlineTimer& timer);
|
||||
void onDeadlineTimer (beast::DeadlineTimer& timer) override;
|
||||
void processHeartbeatTimer ();
|
||||
void processClusterTimer ();
|
||||
|
||||
@@ -578,10 +591,10 @@ private:
|
||||
|
||||
subRpcMapType mRpcSubMap;
|
||||
|
||||
SubMapType mSubLedger; // accepted ledgers
|
||||
SubMapType mSubServer; // when server changes connectivity state
|
||||
SubMapType mSubTransactions; // all accepted transactions
|
||||
SubMapType mSubRTTransactions; // all proposed and accepted transactions
|
||||
SubMapType mSubLedger; // Accepted ledgers.
|
||||
SubMapType mSubServer; // When server changes connectivity state.
|
||||
SubMapType mSubTransactions; // All accepted transactions.
|
||||
SubMapType mSubRTTransactions; // All proposed and accepted transactions.
|
||||
|
||||
TaggedCache<uint256, Blob> mFetchPack;
|
||||
std::uint32_t mFetchSeq;
|
||||
@@ -591,10 +604,10 @@ private:
|
||||
|
||||
JobQueue& m_job_queue;
|
||||
|
||||
// Whether we are in standalone mode
|
||||
// Whether we are in standalone mode.
|
||||
bool const m_standalone;
|
||||
|
||||
// The number of nodes that we need to consider ourselves connected
|
||||
// The number of nodes that we need to consider ourselves connected.
|
||||
std::size_t const m_network_quorum;
|
||||
};
|
||||
|
||||
|
||||
90
src/ripple/app/transactors/README.md
Normal file
90
src/ripple/app/transactors/README.md
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
# Transactors #
|
||||
|
||||
## Introduction ##
|
||||
|
||||
Each separate kind of transaction is handled by it's own Transactor.
|
||||
The Transactor base class provides functionality that is common to
|
||||
all derived Transactors. The Transactor base class also gives derived
|
||||
classes the ability to replace portions of the default implementation.
|
||||
|
||||
|
||||
# Details on Specific Transactors #
|
||||
|
||||
## AddWallet ##
|
||||
|
||||
## Change ##
|
||||
|
||||
## Offers ##
|
||||
|
||||
### CreateOffer ###
|
||||
|
||||
### CancelOffer ###
|
||||
|
||||
## Payment ##
|
||||
|
||||
## SetAccount ##
|
||||
|
||||
## SetRegularKey ##
|
||||
|
||||
## SetTrust ##
|
||||
|
||||
## Tickets ##
|
||||
|
||||
**Associated JIRA task is [RIPD-368](https://ripplelabs.atlassian.net/browse/RIPD-368)**
|
||||
|
||||
Currently transactions on the Ripple network require the use of sequence
|
||||
numbers and sequence numbers must monotonically increase. Since the sequence
|
||||
number is part of the transaction, it is "covered" by the signature that
|
||||
authorizes the transaction, which means that the sequence number would have
|
||||
to be decided at the time of transaction issuance. This would mean that
|
||||
multi-signature transactions could only be processed in strict "first-in,
|
||||
first-out" order which is not practical.
|
||||
|
||||
Tickets can be used in lieu of sequence number. A ticket is a special token
|
||||
which, through a transaction, can be issued by any account and can be
|
||||
configured with an optional expiry date and an optional associated account.
|
||||
|
||||
### Specifics ###
|
||||
|
||||
The expiry date can be used to constrain the validity of the ticket. If
|
||||
specified, the ticket will be considered invalid and unusable if the closing
|
||||
time of the last *validated* ledger is greater than or equal to the expiration
|
||||
time of the ticket.
|
||||
|
||||
The associated account can be used to specify an account, other than the
|
||||
issuing account, that is allowed to "consume" the ticket. Consuming a ticket
|
||||
means to use the ticket in a transaction that is accepted by the network and
|
||||
makes its way into a validated ledger. If not present, the ticket can only be
|
||||
consumed by the issuing account.
|
||||
|
||||
*Corner Case:* It is possible that two or more transactions reference the same
|
||||
ticket and that both go into the same consensus set. During final application
|
||||
of transactions from the consensus set at most one of these transactions may
|
||||
succeed; others must fail with the indication that the ticket has been consumed.
|
||||
|
||||
*Reserve:* While a ticket is outstanding, it should count against the reserve
|
||||
of the *issuer*.
|
||||
|
||||
##### Issuance
|
||||
We should decide whether, in the case of multi-signature accounts, any single
|
||||
authorized signer can issue a ticket on the multi-signature accounts' behalf.
|
||||
This approach has both advantages and disadvantages.
|
||||
|
||||
Advantages include:
|
||||
|
||||
+ Simpler logic for tickets and reduced data - no need to store or consider an associated account.
|
||||
+ Owner reserves for issued tickets count against the multi-signature account instead of the account of the signer proposing a transaction.
|
||||
+ Cleaner meta-data: easier to follow who issued a ticket and how many tickets are outstanding and associated with a particular account.
|
||||
|
||||
Disadvantages are:
|
||||
|
||||
+ Any single authorized signer can issue multiple tickets, each counting against the account's reserve.
|
||||
+ Special-case logic for authorizing tickets on multi-sign accounts.
|
||||
|
||||
I believe that the disadvantages outweigh the advantages, but debate is welcome.
|
||||
|
||||
|
||||
### CreateTicket ###
|
||||
|
||||
### CancelTicket ###
|
||||
@@ -187,7 +187,8 @@ TER Transactor::checkSeq ()
|
||||
{
|
||||
if (a_seq < t_seq)
|
||||
{
|
||||
m_journal.trace << "Transaction has future sequence number " <<
|
||||
m_journal.trace <<
|
||||
"applyTransaction: has future sequence number " <<
|
||||
"a_seq=" << a_seq << " t_seq=" << t_seq;
|
||||
return terPRE_SEQ;
|
||||
}
|
||||
@@ -195,7 +196,7 @@ TER Transactor::checkSeq ()
|
||||
if (mEngine->getLedger ()->hasTransaction (mTxn.getTransactionID ()))
|
||||
return tefALREADY;
|
||||
|
||||
m_journal.trace << "Transaction has past sequence number " <<
|
||||
m_journal.trace << "applyTransaction: has past sequence number " <<
|
||||
"a_seq=" << a_seq << " t_seq=" << t_seq;
|
||||
return tefPAST_SEQ;
|
||||
}
|
||||
@@ -223,7 +224,7 @@ TER Transactor::preCheck ()
|
||||
|
||||
if (!mTxnAccountID)
|
||||
{
|
||||
m_journal.warning << "apply: bad transaction source id";
|
||||
m_journal.warning << "applyTransaction: bad transaction source id";
|
||||
return temBAD_SRC_ACCOUNT;
|
||||
}
|
||||
|
||||
@@ -272,7 +273,7 @@ TER Transactor::apply ()
|
||||
if (mustHaveValidAccount ())
|
||||
{
|
||||
m_journal.trace <<
|
||||
"apply: delay transaction: source account does not exist " <<
|
||||
"applyTransaction: delay: source account does not exist " <<
|
||||
mTxn.getSourceAccount ().humanAccountID ();
|
||||
return terNO_ACCOUNT;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ inline bool operator!= (StaticString x, std::string const& y)
|
||||
|
||||
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
|
||||
*
|
||||
* This class is a discriminated union wrapper that can represents a:
|
||||
* This class is a discriminated union wrapper that can represent a:
|
||||
* - signed integer [range: Value::minInt - Value::maxInt]
|
||||
* - unsigned integer (range: 0 - Value::maxUInt)
|
||||
* - double
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
|
||||
# M-of-N / Multi-Signature Support on Ripple
|
||||
|
||||
In order to enhance the flexibility of Ripple and provide support for enhanced security of accounts, native support for "multi-signature" or "multisign" accounts is required.
|
||||
|
||||
Transactions on an account which is designated as multisign can be authorized either by using the master or regular keys (unless those are disabled) or by being signed by a certain number (a quorum) of preauthorized accounts.
|
||||
|
||||
Some technical details, including tables indicating some of the Ripple commands and ledger entries to be used for implementing multi-signature, are currently listed on the [wiki](https://ripple.com/wiki/Multisign) but will eventually be migrated into this document as well.
|
||||
|
||||
## Steps to MultiSign
|
||||
|
||||
The implementation of multisign is a protocol breaking change which will require the coordinated rollout and deployment of the feature on the Ripple network.
|
||||
|
||||
Critical components for MultiSign are:
|
||||
|
||||
* Ticket Support
|
||||
* Authorized Signer List Management
|
||||
* Verification of Multiple Signatures during TX processing.
|
||||
|
||||
### Ticket Support
|
||||
|
||||
**Associated JIRA task is [RIPD-368](https://ripplelabs.atlassian.net/browse/RIPD-368)**
|
||||
|
||||
Currently transactions on the Ripple network require the use of sequence numbers and sequence numbers must monotonically increase. Since the sequence number is part of the transaction, it is "covered" by the signature that authorizes the transaction, which means that the sequence number would have to be decided at the time of transaction issuance. This would mean that multi-signature transactions could only be processed in strict "first-in, first-out" order which is not practical.
|
||||
|
||||
Tickets can be used in lieu of sequence number. A ticket is a special token which, through a transaction, can be issued by any account and can be configured with an optional expiry date and an optional associated account.
|
||||
|
||||
#### Specifics
|
||||
|
||||
The expiry date can be used to constrain the validity of the ticket. If specified, the ticket will be considered invalid and unusable if the closing time of the last *validated* ledger is greater than or equal to the expiration time of the ticket.
|
||||
|
||||
The associated account can be used to specify an account, other than the issuing account, that is allowed to "consume" the ticket. Consuming a ticket means to use the ticket in a transaction that is accepted by the network and makes its way into a validated ledger. If not present, the ticket can only be consumed by the issuing account.
|
||||
|
||||
*Corner Case:* It is possible that two or more transactions reference the same ticket and that both go into the same consensus set. During final application of transactions from the consensus set at most one of these transactions may succeed; others must fail with the indication that the ticket has been consumed.
|
||||
|
||||
*Reserve:* While a ticket is outstanding, it should count against the reserve of the *issuer*.
|
||||
|
||||
##### Issuance
|
||||
We should decide whether, in the case of multi-signature accounts, any single authorized signer can issue a ticket on the multisignature accounts' behalf. This approach has both advantages and disadvantages.
|
||||
|
||||
Advantages include:
|
||||
|
||||
+ Simpler logic for tickets and reduced data - no need to store or consider an associated account.
|
||||
+ Owner reserves for issued tickets count against the multi-signature account instead of the account of the signer proposing a transaction.
|
||||
+ Cleaner meta-data: easier to follow who issued a ticket and how many tickets are outstanding and associated with a particular account.
|
||||
|
||||
Disadvantages are:
|
||||
|
||||
+ Any single authorized signer can issue multiple tickets, each counting against the account's reserve.
|
||||
+ Special-case logic for authorizing tickets on multi-sign accounts.
|
||||
|
||||
I believe that the disadvantages outweigh the advantages, but debate is welcome.
|
||||
|
||||
##### Proposed Transaction Cancelation
|
||||
A transaction that has been proposed against a multi-sign account using a ticket can be positively cancelled if a quorum of authorized signers sign and issue a transaction that consumes that ticket.
|
||||
|
||||
### Authorized Signer List Management
|
||||
|
||||
For accounts which are designated as multi-sign, there must be a list which specifies which accounts are authorized to sign and the quorum threshold.
|
||||
|
||||
The quorum threshold indicates the minimum required weight that the sum of the weights of all signatures must have before a transaction can be authorized. It is an unsigned integer that is at least 2.
|
||||
|
||||
Each authorized account can be given a weight, from 1 to 32 inclusive. The weight is used when to determine whether a given number of signatures are sufficient for a quorum.
|
||||
|
||||
### Verification of Multiple Signatures during TX processing
|
||||
The current approach to adding multi-signature support is to require that a transaction is to be signed outside the Ripple network and only submitted after the quorum has been reached.
|
||||
|
||||
This reduces the implementation footprint and the load imposed on the network, and mirrors the way transaction signing is currently handled. It will require some messaging mechanism outside the Ripple network to disseminate the proposed transaction to the authorized signers and to allow them apply signatures.
|
||||
|
||||
Supporting in-ledger voting should be considered, but it has both advantages and disadvantages.
|
||||
|
||||
One of the advantages is increased transparency - transactions are visible as are the "votes" (the authorized accounts signing the transaction) on the ledger. However, transactions may also languish for a long time in the ledger, never reaching a quorum and consuming network resources.
|
||||
|
||||
### Signature Format
|
||||
We should not develop a new format for multi-sign signatures. Instead each signer should extract and sign the transaction as he normally would if this were a regular transaction. The resulting signature will be stored as a pair of { signing-account, signature } in an array of signatures associated with this transaction.
|
||||
|
||||
The advantage of this is that we can reuse the existing signing and verification code, and leverage the work that will go towards implementing support for the Ed25519 elliptic curve.
|
||||
|
||||
|
||||
### Fees
|
||||
Multi-signature transactions impose a heavier load on the network and should claim higher fees.
|
||||
|
||||
The fee structure is not yet decided, but an escalating fee structure is laid out and discussed on the [wiki](https://ripple.com/wiki/Multisign). This might need to be revisited and designed in light of discussions about changing how fees are handled.
|
||||
@@ -115,13 +115,20 @@ public:
|
||||
sMD_Default = sMD_ChangeOrig | sMD_ChangeNew | sMD_DeleteFinal | sMD_Create
|
||||
};
|
||||
|
||||
const int fieldCode; // (type<<16)|index
|
||||
const SerializedTypeID fieldType; // STI_*
|
||||
const int fieldValue; // Code number for protocol
|
||||
enum class IsSigning : unsigned char
|
||||
{
|
||||
no,
|
||||
yes
|
||||
};
|
||||
static IsSigning const notSigning = IsSigning::no;
|
||||
|
||||
int const fieldCode; // (type<<16)|index
|
||||
SerializedTypeID const fieldType; // STI_*
|
||||
int const fieldValue; // Code number for protocol
|
||||
std::string fieldName;
|
||||
int fieldMeta;
|
||||
int fieldNum;
|
||||
bool signingField;
|
||||
IsSigning const signingField;
|
||||
std::string rawJsonName;
|
||||
Json::StaticString jsonName;
|
||||
|
||||
@@ -146,7 +153,7 @@ public:
|
||||
protected:
|
||||
// These constructors can only be called from FieldNames.cpp
|
||||
SField (SerializedTypeID tid, int fv, const char* fn,
|
||||
int meta = sMD_Default, bool signing = true);
|
||||
int meta = sMD_Default, IsSigning signing = IsSigning::yes);
|
||||
explicit SField (int fc);
|
||||
SField (SerializedTypeID id, int val);
|
||||
|
||||
@@ -219,11 +226,7 @@ public:
|
||||
|
||||
bool isSigningField () const
|
||||
{
|
||||
return signingField;
|
||||
}
|
||||
void notSigningField ()
|
||||
{
|
||||
signingField = false;
|
||||
return signingField == IsSigning::yes;
|
||||
}
|
||||
bool shouldMeta (int c) const
|
||||
{
|
||||
@@ -236,7 +239,8 @@ public:
|
||||
|
||||
bool shouldInclude (bool withSigningField) const
|
||||
{
|
||||
return (fieldValue < 256) && (withSigningField || signingField);
|
||||
return (fieldValue < 256) &&
|
||||
(withSigningField || (signingField == IsSigning::yes));
|
||||
}
|
||||
|
||||
bool operator== (const SField& f) const
|
||||
|
||||
@@ -159,7 +159,10 @@ public:
|
||||
add (s, true); // just inner elements
|
||||
}
|
||||
|
||||
void add (Serializer & s, bool withSignature) const;
|
||||
void addWithoutSigningFields (Serializer & s) const
|
||||
{
|
||||
add (s, false);
|
||||
}
|
||||
|
||||
// VFALCO NOTE does this return an expensive copy of an object with a
|
||||
// dynamic buffer?
|
||||
@@ -167,7 +170,7 @@ public:
|
||||
Serializer getSerializer () const
|
||||
{
|
||||
Serializer s;
|
||||
add (s);
|
||||
add (s, true);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -242,6 +245,7 @@ public:
|
||||
STPathSet const& getFieldPathSet (SField const& field) const;
|
||||
const STVector256& getFieldV256 (SField const& field) const;
|
||||
const STArray& getFieldArray (SField const& field) const;
|
||||
const STObject& getFieldObject (SField const& field) const;
|
||||
|
||||
/** Set a field.
|
||||
if the field already exists, it is replaced.
|
||||
@@ -265,6 +269,7 @@ public:
|
||||
void setFieldPathSet (SField const& field, STPathSet const&);
|
||||
void setFieldV256 (SField const& field, STVector256 const& v);
|
||||
void setFieldArray (SField const& field, STArray const& v);
|
||||
void setFieldObject (SField const& field, STObject const& v);
|
||||
|
||||
template <class Tag>
|
||||
void setFieldH160 (SField const& field, base_uint<160, Tag> const& v)
|
||||
@@ -285,6 +290,7 @@ public:
|
||||
}
|
||||
|
||||
STObject& peekFieldObject (SField const& field);
|
||||
STArray& peekFieldArray (SField const& field);
|
||||
|
||||
bool isFieldPresent (SField const& field) const;
|
||||
STBase* makeFieldPresent (SField const& field);
|
||||
@@ -301,6 +307,24 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void add (Serializer & s, bool withSigningFields) const;
|
||||
|
||||
// Sort the entries in an STObject into the order that they will be
|
||||
// serialized. Note: they are not sorted into pointer value order, they
|
||||
// are sorted by SField::fieldCode.
|
||||
static std::vector<STBase const*>
|
||||
getSortedFields (STObject const& objToSort);
|
||||
|
||||
// Two different ways to compare STObjects.
|
||||
//
|
||||
// This one works only if the SOTemplates are the same. Presumably it
|
||||
// runs faster since there's no sorting.
|
||||
static bool equivalentSTObjectSameTemplate (
|
||||
STObject const& obj1, STObject const& obj2);
|
||||
|
||||
// This way of comparing STObjects always works, but is slower.
|
||||
static bool equivalentSTObject (STObject const& obj1, STObject const& obj2);
|
||||
|
||||
// Implementation for getting (most) fields that return by value.
|
||||
//
|
||||
// The remove_cv and remove_reference are necessitated by the STBitString
|
||||
@@ -396,6 +420,26 @@ private:
|
||||
|
||||
(*cf) = value;
|
||||
}
|
||||
|
||||
// Implementation for peeking STObjects and STArrays
|
||||
template <typename T>
|
||||
T& peekField (SField const& field)
|
||||
{
|
||||
STBase* rf = getPField (field, true);
|
||||
|
||||
if (!rf)
|
||||
throw std::runtime_error ("Field not found");
|
||||
|
||||
if (rf->getSType () == STI_NOTPRESENT)
|
||||
rf = makeFieldPresent (field);
|
||||
|
||||
T* cf = dynamic_cast<T*> (rf);
|
||||
|
||||
if (!cf)
|
||||
throw std::runtime_error ("Wrong field type");
|
||||
|
||||
return *cf;
|
||||
}
|
||||
};
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -67,14 +67,14 @@ public:
|
||||
return emplace(n, buf, std::move(*this));
|
||||
}
|
||||
|
||||
// STObject functions
|
||||
// STObject functions.
|
||||
SerializedTypeID getSType () const override
|
||||
{
|
||||
return STI_TRANSACTION;
|
||||
}
|
||||
std::string getFullText () const override;
|
||||
|
||||
// outer transaction functions / signature functions
|
||||
// Outer transaction functions / signature functions.
|
||||
Blob getSignature () const;
|
||||
|
||||
uint256 getSigningHash () const;
|
||||
@@ -116,8 +116,8 @@ public:
|
||||
|
||||
uint256 getTransactionID () const;
|
||||
|
||||
virtual Json::Value getJson (int options) const override;
|
||||
virtual Json::Value getJson (int options, bool binary) const;
|
||||
Json::Value getJson (int options) const override;
|
||||
Json::Value getJson (int options, bool binary) const;
|
||||
|
||||
void sign (RippleAddress const& private_key);
|
||||
|
||||
@@ -140,7 +140,7 @@ public:
|
||||
sig_state_ = false;
|
||||
}
|
||||
|
||||
// SQL Functions with metadata
|
||||
// SQL Functions with metadata.
|
||||
static
|
||||
std::string const&
|
||||
getMetaSQLInsertReplaceHeader ();
|
||||
|
||||
@@ -88,7 +88,7 @@ LedgerFormats::LedgerFormats ()
|
||||
;
|
||||
|
||||
add ("EnabledAmendments", ltAMENDMENTS)
|
||||
<< SOElement (sfAmendments, SOE_REQUIRED)
|
||||
<< SOElement (sfAmendments, SOE_REQUIRED)
|
||||
;
|
||||
|
||||
add ("FeeSettings", ltFEE_SETTINGS)
|
||||
|
||||
@@ -34,6 +34,9 @@ static std::mutex SField_mutex;
|
||||
static std::map<int, SField const*> knownCodeToField;
|
||||
static std::map<int, std::unique_ptr<SField const>> unknownCodeToField;
|
||||
|
||||
// Storage for static const member.
|
||||
SField::IsSigning const SField::notSigning;
|
||||
|
||||
int SField::num = 0;
|
||||
|
||||
typedef std::lock_guard <std::mutex> StaticScopedLockType;
|
||||
@@ -173,9 +176,9 @@ SField const sfDeliveredAmount = make::one(&sfDeliveredAmount, STI_AMOUNT, 18, "
|
||||
// variable length
|
||||
TypedField<STBlob> const sfPublicKey = make::one<STBlob>(&sfPublicKey, STI_VL, 1, "PublicKey");
|
||||
TypedField<STBlob> const sfSigningPubKey = make::one<STBlob>(&sfSigningPubKey, STI_VL, 3, "SigningPubKey");
|
||||
TypedField<STBlob> const sfSignature = make::one<STBlob>(&sfSignature, STI_VL, 6, "Signature", SField::sMD_Default, false);
|
||||
TypedField<STBlob> const sfSignature = make::one<STBlob>(&sfSignature, STI_VL, 6, "Signature", SField::sMD_Default, SField::notSigning);
|
||||
SField const sfMessageKey = make::one(&sfMessageKey, STI_VL, 2, "MessageKey");
|
||||
SField const sfTxnSignature = make::one(&sfTxnSignature, STI_VL, 4, "TxnSignature", SField::sMD_Default, false);
|
||||
SField const sfTxnSignature = make::one(&sfTxnSignature, STI_VL, 4, "TxnSignature", SField::sMD_Default, SField::notSigning);
|
||||
SField const sfDomain = make::one(&sfDomain, STI_VL, 7, "Domain");
|
||||
SField const sfFundCode = make::one(&sfFundCode, STI_VL, 8, "FundCode");
|
||||
SField const sfRemoveCode = make::one(&sfRemoveCode, STI_VL, 9, "RemoveCode");
|
||||
@@ -216,7 +219,7 @@ SField const sfMemo = make::one(&sfMemo, STI_OBJEC
|
||||
// array of objects
|
||||
// ARRAY/1 is reserved for end of array
|
||||
SField const sfSigningAccounts = make::one(&sfSigningAccounts, STI_ARRAY, 2, "SigningAccounts");
|
||||
SField const sfTxnSignatures = make::one(&sfTxnSignatures, STI_ARRAY, 3, "TxnSignatures", SField::sMD_Default, false);
|
||||
SField const sfTxnSignatures = make::one(&sfTxnSignatures, STI_ARRAY, 3, "TxnSignatures", SField::sMD_Default, SField::notSigning);
|
||||
SField const sfSignatures = make::one(&sfSignatures, STI_ARRAY, 4, "Signatures");
|
||||
SField const sfTemplate = make::one(&sfTemplate, STI_ARRAY, 5, "Template");
|
||||
SField const sfNecessary = make::one(&sfNecessary, STI_ARRAY, 6, "Necessary");
|
||||
@@ -225,7 +228,7 @@ SField const sfAffectedNodes = make::one(&sfAffectedNodes, STI_ARRAY, 8, "Af
|
||||
SField const sfMemos = make::one(&sfMemos, STI_ARRAY, 9, "Memos");
|
||||
|
||||
SField::SField (SerializedTypeID tid, int fv, const char* fn,
|
||||
int meta, bool signing)
|
||||
int meta, IsSigning signing)
|
||||
: fieldCode (field_code (tid, fv))
|
||||
, fieldType (tid)
|
||||
, fieldValue (fv)
|
||||
@@ -244,7 +247,7 @@ SField::SField (int fc)
|
||||
, fieldValue (0)
|
||||
, fieldMeta (sMD_Never)
|
||||
, fieldNum (++num)
|
||||
, signingField (true)
|
||||
, signingField (IsSigning::yes)
|
||||
, rawJsonName (getName ())
|
||||
, jsonName (rawJsonName.c_str ())
|
||||
{
|
||||
@@ -257,7 +260,7 @@ SField::SField (SerializedTypeID tid, int fv)
|
||||
: fieldCode (field_code (tid, fv)), fieldType (tid), fieldValue (fv),
|
||||
fieldMeta (sMD_Default),
|
||||
fieldNum (++num),
|
||||
signingField (true),
|
||||
signingField (IsSigning::yes),
|
||||
jsonName (nullptr)
|
||||
{
|
||||
fieldName = std::to_string (tid) + '/' + std::to_string (fv);
|
||||
|
||||
@@ -264,39 +264,6 @@ std::string STObject::getFullText () const
|
||||
return ret;
|
||||
}
|
||||
|
||||
void STObject::add (Serializer& s, bool withSigningFields) const
|
||||
{
|
||||
std::map<int, STBase const*> fields;
|
||||
for (auto const& e : v_)
|
||||
{
|
||||
// pick out the fields and sort them
|
||||
if ((e->getSType() != STI_NOTPRESENT) &&
|
||||
e->getFName().shouldInclude (withSigningFields))
|
||||
{
|
||||
fields.insert (std::make_pair (
|
||||
e->getFName().fieldCode, &e.get()));
|
||||
}
|
||||
}
|
||||
|
||||
// insert sorted
|
||||
for (auto const& e : fields)
|
||||
{
|
||||
auto const field = e.second;
|
||||
|
||||
// When we serialize an object inside another object,
|
||||
// the type associated by rule with this field name
|
||||
// must be OBJECT, or the object cannot be deserialized
|
||||
assert ((field->getSType() != STI_OBJECT) ||
|
||||
(field->getFName().fieldType == STI_OBJECT));
|
||||
field->addFieldID (s);
|
||||
field->add (s);
|
||||
if (dynamic_cast<const STArray*> (field) != nullptr)
|
||||
s.addFieldID (STI_ARRAY, 1);
|
||||
else if (dynamic_cast<const STObject*> (field) != nullptr)
|
||||
s.addFieldID (STI_OBJECT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::string STObject::getText () const
|
||||
{
|
||||
std::string ret = "{";
|
||||
@@ -326,32 +293,10 @@ bool STObject::isEquivalent (const STBase& t) const
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it1 = v_.begin (), end1 = v_.end ();
|
||||
auto it2 = v->v_.begin (), end2 = v->v_.end ();
|
||||
if (mType != nullptr && (v->mType == mType))
|
||||
return equivalentSTObjectSameTemplate (*this, *v);
|
||||
|
||||
while ((it1 != end1) && (it2 != end2))
|
||||
{
|
||||
if ((it1->get().getSType () != it2->get().getSType ()) ||
|
||||
!it1->get().isEquivalent (it2->get()))
|
||||
{
|
||||
if (it1->get().getSType () != it2->get().getSType ())
|
||||
{
|
||||
WriteLog (lsDEBUG, STObject) << "notEquiv type " <<
|
||||
it1->get().getFullText() << " != " << it2->get().getFullText();
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLog (lsDEBUG, STObject) << "notEquiv " <<
|
||||
it1->get().getFullText() << " != " << it2->get().getFullText();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
++it1;
|
||||
++it2;
|
||||
}
|
||||
|
||||
return (it1 == end1) && (it2 == end2);
|
||||
return equivalentSTObject (*this, *v);
|
||||
}
|
||||
|
||||
uint256 STObject::getHash (std::uint32_t prefix) const
|
||||
@@ -448,20 +393,12 @@ bool STObject::isFieldPresent (SField const& field) const
|
||||
|
||||
STObject& STObject::peekFieldObject (SField const& field)
|
||||
{
|
||||
STBase* rf = getPField (field, true);
|
||||
return peekField<STObject> (field);
|
||||
}
|
||||
|
||||
if (!rf)
|
||||
throw std::runtime_error ("Field not found");
|
||||
|
||||
if (rf->getSType () == STI_NOTPRESENT)
|
||||
rf = makeFieldPresent (field);
|
||||
|
||||
STObject* cf = dynamic_cast<STObject*> (rf);
|
||||
|
||||
if (!cf)
|
||||
throw std::runtime_error ("Wrong field type");
|
||||
|
||||
return *cf;
|
||||
STArray& STObject::peekFieldArray (SField const& field)
|
||||
{
|
||||
return peekField<STArray> (field);
|
||||
}
|
||||
|
||||
bool STObject::setFlag (std::uint32_t f)
|
||||
@@ -650,12 +587,6 @@ STAmount const& STObject::getFieldAmount (SField const& field) const
|
||||
return getFieldByConstRef <STAmount> (field, empty);
|
||||
}
|
||||
|
||||
const STArray& STObject::getFieldArray (SField const& field) const
|
||||
{
|
||||
static STArray const empty{};
|
||||
return getFieldByConstRef <STArray> (field, empty);
|
||||
}
|
||||
|
||||
STPathSet const& STObject::getFieldPathSet (SField const& field) const
|
||||
{
|
||||
static STPathSet const empty{};
|
||||
@@ -668,6 +599,18 @@ const STVector256& STObject::getFieldV256 (SField const& field) const
|
||||
return getFieldByConstRef <STVector256> (field, empty);
|
||||
}
|
||||
|
||||
const STArray& STObject::getFieldArray (SField const& field) const
|
||||
{
|
||||
static STArray const empty{};
|
||||
return getFieldByConstRef <STArray> (field, empty);
|
||||
}
|
||||
|
||||
const STObject& STObject::getFieldObject (SField const& field) const
|
||||
{
|
||||
static STObject const empty{sfInvalid};
|
||||
return getFieldByConstRef <STObject> (field, empty);
|
||||
}
|
||||
|
||||
void
|
||||
STObject::set (std::unique_ptr<STBase> v)
|
||||
{
|
||||
@@ -760,6 +703,11 @@ void STObject::setFieldArray (SField const& field, STArray const& v)
|
||||
setFieldUsingAssignment (field, v);
|
||||
}
|
||||
|
||||
void STObject::setFieldObject (SField const& field, STObject const& v)
|
||||
{
|
||||
setFieldUsingAssignment (field, v);
|
||||
}
|
||||
|
||||
Json::Value STObject::getJson (int options) const
|
||||
{
|
||||
Json::Value ret (Json::objectValue);
|
||||
@@ -830,4 +778,96 @@ bool STObject::operator== (const STObject& obj) const
|
||||
return true;
|
||||
}
|
||||
|
||||
void STObject::add (Serializer& s, bool withSigningFields) const
|
||||
{
|
||||
std::map<int, STBase const*> fields;
|
||||
for (auto const& e : v_)
|
||||
{
|
||||
// pick out the fields and sort them
|
||||
if ((e->getSType() != STI_NOTPRESENT) &&
|
||||
e->getFName().shouldInclude (withSigningFields))
|
||||
{
|
||||
fields.insert (std::make_pair (
|
||||
e->getFName().fieldCode, &e.get()));
|
||||
}
|
||||
}
|
||||
|
||||
// insert sorted
|
||||
for (auto const& e : fields)
|
||||
{
|
||||
auto const field = e.second;
|
||||
|
||||
// When we serialize an object inside another object,
|
||||
// the type associated by rule with this field name
|
||||
// must be OBJECT, or the object cannot be deserialized
|
||||
assert ((field->getSType() != STI_OBJECT) ||
|
||||
(field->getFName().fieldType == STI_OBJECT));
|
||||
field->addFieldID (s);
|
||||
field->add (s);
|
||||
if (dynamic_cast<const STArray*> (field) != nullptr)
|
||||
s.addFieldID (STI_ARRAY, 1);
|
||||
else if (dynamic_cast<const STObject*> (field) != nullptr)
|
||||
s.addFieldID (STI_OBJECT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<STBase const*>
|
||||
STObject::getSortedFields (STObject const& objToSort)
|
||||
{
|
||||
std::vector<STBase const*> sf;
|
||||
sf.reserve (objToSort.getCount ());
|
||||
|
||||
// Choose the fields that we need to sort.
|
||||
for (detail::STVar const& elem : objToSort.v_)
|
||||
{
|
||||
// Pick out the fields and sort them.
|
||||
STBase const& base = elem.get();
|
||||
if ((base.getSType () != STI_NOTPRESENT) &&
|
||||
base.getFName ().shouldInclude (true))
|
||||
{
|
||||
sf.push_back (&base);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the fields by fieldCode.
|
||||
std::sort (sf.begin (), sf.end (),
|
||||
[] (STBase const* a, STBase const* b) -> bool
|
||||
{
|
||||
return a->getFName ().fieldCode < b->getFName ().fieldCode;
|
||||
});
|
||||
|
||||
// There should never be duplicate fields in an STObject. Verify that
|
||||
// in debug mode.
|
||||
assert (std::adjacent_find (sf.cbegin (), sf.cend ()) == sf.cend ());
|
||||
|
||||
return sf;
|
||||
}
|
||||
|
||||
bool STObject::equivalentSTObjectSameTemplate (
|
||||
STObject const& obj1, STObject const& obj2)
|
||||
{
|
||||
assert (obj1.mType != nullptr);
|
||||
assert (obj1.mType == obj2.mType);
|
||||
|
||||
return std::equal (obj1.begin (), obj1.end (), obj2.begin (), obj2.end (),
|
||||
[] (STBase const& st1, STBase const& st2)
|
||||
{
|
||||
return (st1.getSType() == st2.getSType()) &&
|
||||
st1.isEquivalent (st2);
|
||||
});
|
||||
}
|
||||
|
||||
bool STObject::equivalentSTObject (STObject const& obj1, STObject const& obj2)
|
||||
{
|
||||
auto sf1 = getSortedFields (obj1);
|
||||
auto sf2 = getSortedFields (obj2);
|
||||
|
||||
return std::equal (sf1.begin (), sf1.end (), sf2.begin (), sf2.end (),
|
||||
[] (STBase const* st1, STBase const* st2)
|
||||
{
|
||||
return (st1->getSType() == st2->getSType()) &&
|
||||
st1->isEquivalent (*st2);
|
||||
});
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -155,7 +155,7 @@ static Blob getSigningData (STTx const& that)
|
||||
{
|
||||
Serializer s;
|
||||
s.add32 (HashPrefix::txSign);
|
||||
that.add (s, false);
|
||||
that.addWithoutSigningFields (s);
|
||||
return s.getData();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ sign (STObject& st, HashPrefix const& prefix,
|
||||
{
|
||||
Serializer ss;
|
||||
ss.add32(prefix);
|
||||
st.add(ss, false);
|
||||
st.addWithoutSigningFields(ss);
|
||||
set(st, sfSignature,
|
||||
sk.sign(ss.data(), ss.size()));
|
||||
}
|
||||
@@ -42,7 +42,7 @@ verify (STObject const& st,
|
||||
return false;
|
||||
Serializer ss;
|
||||
ss.add32(prefix);
|
||||
st.add(ss, false);
|
||||
st.addWithoutSigningFields(ss);
|
||||
return pk.verify(
|
||||
ss.data(), ss.size(),
|
||||
sig->data(), sig->size());
|
||||
|
||||
@@ -57,7 +57,7 @@ Json::Value doSubmit (RPC::Context& context)
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
jvResult[jss::error] = "invalidTransaction";
|
||||
jvResult[jss::error] = "invalidTransaction";
|
||||
jvResult[jss::error_exception] = e.what ();
|
||||
|
||||
return jvResult;
|
||||
|
||||
Reference in New Issue
Block a user