Reorganize source file hierarchy:

* Rename unity files
* Move some modules to new subdirectories
* Remove obsolete Visual Studio project files
* Remove obsolete coding style and TODO list
This commit is contained in:
Vinnie Falco
2014-06-03 14:48:34 -07:00
parent 39a387b54c
commit 4f1d1d2a8a
774 changed files with 6924 additions and 10355 deletions

View File

@@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
AccountItem::AccountItem (SerializedLedgerEntry::ref ledger)
: mLedgerEntry (ledger)
{
}
} // ripple

View File

@@ -0,0 +1,91 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_ACCOUNTITEM_H
#define RIPPLE_ACCOUNTITEM_H
namespace ripple {
//
// Fetch ledger entries from an account's owner dir.
//
/** Base class representing account items.
Account items include:
- Offers
- Trust Lines
NOTE these are deprecated and will go away, to be replaced with
simple visitor patterns.
*/
class AccountItem
{
public:
typedef boost::shared_ptr <AccountItem> pointer;
typedef const pointer& ref;
public:
AccountItem ()
{ }
/** Construct from a flat ledger entry.
*/
explicit AccountItem (SerializedLedgerEntry::ref ledger);
virtual ~AccountItem ()
{
;
}
virtual AccountItem::pointer makeItem (const uint160& accountID, SerializedLedgerEntry::ref ledgerEntry) = 0;
// VFALCO TODO Make this const and change derived classes
virtual LedgerEntryType getType () = 0;
// VFALCO TODO Document the int parameter
virtual Json::Value getJson (int) = 0;
SerializedLedgerEntry::pointer getSLE ()
{
return mLedgerEntry;
}
const SerializedLedgerEntry& peekSLE () const
{
return *mLedgerEntry;
}
SerializedLedgerEntry& peekSLE ()
{
return *mLedgerEntry;
}
Blob getRaw () const;
// VFALCO TODO Make this private and use the existing accessors
//
protected:
// VFALCO TODO Research making the object pointed to const
SerializedLedgerEntry::pointer mLedgerEntry;
};
} // ripple
#endif

View File

@@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
AccountItems::AccountItems (uint160 const& accountID,
Ledger::ref ledger,
AccountItem::pointer ofType)
{
mOfType = ofType;
fillItems (accountID, ledger);
}
void AccountItems::fillItems (const uint160& accountID, Ledger::ref ledger)
{
uint256 const rootIndex = Ledger::getOwnerDirIndex (accountID);
uint256 currentIndex = rootIndex;
// VFALCO TODO Rewrite all infinite loops to have clear terminating
// conditions defined in one location.
//
while (1)
{
SLE::pointer ownerDir = ledger->getDirNode (currentIndex);
// VFALCO TODO Rewrite to not return from the middle of the function
if (!ownerDir)
return;
BOOST_FOREACH (uint256 const & uNode, ownerDir->getFieldV256 (sfIndexes).peekValue ())
{
// VFALCO TODO rename getSLEi() to something legible.
SLE::pointer sleCur = ledger->getSLEi (uNode);
if (!sleCur)
{
// item in directory not in ledger
}
else
{
AccountItem::pointer item = mOfType->makeItem (accountID, sleCur);
// VFALCO NOTE Under what conditions would makeItem() return nullptr?
// DJS NOTE If the item wasn't one this particular AccountItems was interested in
// (For example, if the owner is only interested in ripple lines and this is an offer)
if (item)
{
mItems.push_back (item);
}
}
}
std::uint64_t uNodeNext = ownerDir->getFieldU64 (sfIndexNext);
// VFALCO TODO Rewrite to not return from the middle of the function
if (!uNodeNext)
return;
currentIndex = Ledger::getDirNodeIndex (rootIndex, uNodeNext);
}
}
Json::Value AccountItems::getJson (int v)
{
Json::Value ret (Json::arrayValue);
BOOST_FOREACH (AccountItem::ref ai, mItems)
{
ret.append (ai->getJson (v));
}
return ret;
}
} // ripple

View File

@@ -0,0 +1,61 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_ACCOUNTITEMS_H
#define RIPPLE_ACCOUNTITEMS_H
namespace ripple {
/** A set of AccountItem objects. */
class AccountItems : beast::LeakChecked <AccountItems>
{
public:
typedef boost::shared_ptr <AccountItems> pointer;
typedef std::vector <AccountItem::pointer> Container;
// VFALCO TODO Create a typedef uint160 AccountID and replace
AccountItems (uint160 const& accountID,
Ledger::ref ledger,
AccountItem::pointer ofType);
// VFALCO TODO rename to getContainer and make this change in every interface
// that exposes the caller to the type of container.
//
Container& getItems ()
{
return mItems;
}
// VFALCO TODO What is the int for?
Json::Value getJson (int);
private:
void fillItems (const uint160& accountID, Ledger::ref ledger);
private:
// VFALCO TODO This looks like its used as an exemplar, rename appropriately
AccountItem::pointer mOfType;
Container mItems;
};
} // ripple
#endif

View File

@@ -0,0 +1,84 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
AccountState::AccountState (RippleAddress const& naAccountID)
: mAccountID (naAccountID)
, mValid (false)
{
if (naAccountID.isValid ())
{
mValid = true;
mLedgerEntry = boost::make_shared <SerializedLedgerEntry> (
ltACCOUNT_ROOT, Ledger::getAccountRootIndex (naAccountID));
mLedgerEntry->setFieldAccount (sfAccount, naAccountID.getAccountID ());
}
}
AccountState::AccountState (SLE::ref ledgerEntry, const RippleAddress& naAccountID) :
mAccountID (naAccountID), mLedgerEntry (ledgerEntry), mValid (false)
{
if (!mLedgerEntry)
return;
if (mLedgerEntry->getType () != ltACCOUNT_ROOT)
return;
mValid = true;
}
// VFALCO TODO Make this a generic utility function of some container class
//
std::string AccountState::createGravatarUrl (uint128 uEmailHash)
{
Blob vucMD5 (uEmailHash.begin (), uEmailHash.end ());
std::string strMD5Lower = strHex (vucMD5);
boost::to_lower (strMD5Lower);
// VFALCO TODO Give a name and move this constant to a more visible location.
// Also shouldn't this be https?
return str (boost::format ("http://www.gravatar.com/avatar/%s") % strMD5Lower);
}
void AccountState::addJson (Json::Value& val)
{
val = mLedgerEntry->getJson (0);
if (mValid)
{
if (mLedgerEntry->isFieldPresent (sfEmailHash))
val["urlgravatar"] = createGravatarUrl (mLedgerEntry->getFieldH128 (sfEmailHash));
}
else
{
val["Invalid"] = true;
}
}
void AccountState::dump ()
{
Json::Value j (Json::objectValue);
addJson (j);
Log (lsINFO) << j;
}
} // ripple

View File

@@ -0,0 +1,94 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_ACCOUNTSTATE_H
#define RIPPLE_ACCOUNTSTATE_H
namespace ripple {
//
// Provide abstract access to an account's state, such that access to the serialized format is hidden.
//
class AccountState : beast::LeakChecked <AccountState>
{
public:
typedef boost::shared_ptr<AccountState> pointer;
public:
// For new accounts
explicit AccountState (RippleAddress const& naAccountID);
// For accounts in a ledger
AccountState (SLE::ref ledgerEntry, RippleAddress const& naAccountI);
bool haveAuthorizedKey ()
{
return mLedgerEntry->isFieldPresent (sfRegularKey);
}
RippleAddress getAuthorizedKey ()
{
return mLedgerEntry->getFieldAccount (sfRegularKey);
}
STAmount getBalance () const
{
return mLedgerEntry->getFieldAmount (sfBalance);
}
std::uint32_t getSeq () const
{
return mLedgerEntry->getFieldU32 (sfSequence);
}
SerializedLedgerEntry::pointer getSLE ()
{
return mLedgerEntry;
}
SerializedLedgerEntry const& peekSLE () const
{
return *mLedgerEntry;
}
SerializedLedgerEntry& peekSLE ()
{
return *mLedgerEntry;
}
Blob getRaw () const;
void addJson (Json::Value& value);
void dump ();
static std::string createGravatarUrl (uint128 uEmailHash);
private:
RippleAddress const mAccountID;
RippleAddress mAuthorizedKey;
SerializedLedgerEntry::pointer mLedgerEntry;
bool mValid;
};
} // ripple
#endif

View File

@@ -0,0 +1,161 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_AMENDMENT_TABLE_H
#define RIPPLE_AMENDMENT_TABLE_H
#include <ripple/module/app/book/Types.h>
namespace ripple {
/** The status of all amendments requested in a given window. */
class AmendmentSet
{
public:
std::uint32_t mCloseTime;
int mTrustedValidations; // number of trusted validations
ripple::unordered_map<uint256, int> mVotes; // yes votes by amendment
AmendmentSet (std::uint32_t ct) : mCloseTime (ct), mTrustedValidations (0)
{
;
}
void addVoter ()
{
++mTrustedValidations;
}
void addVote (uint256 const& amendment)
{
++mVotes[amendment];
}
};
/** Current state of an amendment.
Tells if a amendment is supported, enabled or vetoed. A vetoed amendment
means the node will never announce its support.
*/
class AmendmentState
{
public:
bool mVetoed; // We don't want this amendment enabled
bool mEnabled;
bool mSupported;
bool mDefault; // Include in genesis ledger
core::Clock::time_point m_firstMajority; // First time we saw a majority (close time)
core::Clock::time_point m_lastMajority; // Most recent time we saw a majority (close time)
std::string mFriendlyName;
AmendmentState ()
: mVetoed (false), mEnabled (false), mSupported (false), mDefault (false),
m_firstMajority (0), m_lastMajority (0)
{
;
}
void setVeto ()
{
mVetoed = true;
}
void setDefault ()
{
mDefault = true;
}
bool isDefault ()
{
return mDefault;
}
bool isSupported ()
{
return mSupported;
}
bool isVetoed ()
{
return mVetoed;
}
bool isEnabled ()
{
return mEnabled;
}
const std::string& getFiendlyName ()
{
return mFriendlyName;
}
void setFriendlyName (const std::string& n)
{
mFriendlyName = n;
}
};
/** The amendment table stores the list of enabled and potential amendments.
Individuals amendments are voted on by validators during the consensus
process.
*/
class AmendmentTable
{
public:
/** Create a new AmendmentTable.
@param majorityTime the number of seconds an amendment must hold a majority
before we're willing to vote yes on it.
@param majorityFraction ratio, out of 256, of servers that must say
they want an amendment before we consider it to
have a majority.
@param journal
*/
virtual ~AmendmentTable() { }
virtual void addInitial () = 0;
virtual AmendmentState* addKnown (const char* amendmentID,
const char* friendlyName, bool veto) = 0;
virtual uint256 get (const std::string& name) = 0;
virtual bool veto (uint256 const& amendment) = 0;
virtual bool unVeto (uint256 const& amendment) = 0;
virtual bool enable (uint256 const& amendment) = 0;
virtual bool disable (uint256 const& amendment) = 0;
virtual bool isEnabled (uint256 const& amendment) = 0;
virtual bool isSupported (uint256 const& amendment) = 0;
virtual void setEnabled (const std::vector<uint256>& amendments) = 0;
virtual void setSupported (const std::vector<uint256>& amendments) = 0;
virtual void reportValidations (const AmendmentSet&) = 0;
virtual Json::Value getJson (int) = 0;
virtual Json::Value getJson (uint256 const& ) = 0;
virtual void
doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation) = 0;
virtual void
doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) = 0;
};
std::unique_ptr<AmendmentTable>
make_AmendmentTable (std::chrono::seconds majorityTime, int majorityFraction,
beast::Journal journal);
} // ripple
#endif

View File

@@ -0,0 +1,584 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
/** Track the list of "amendments"
An "amendment" is an option that can affect transaction processing
rules that is identified by a 256-bit amendment identifier
and adopted, or rejected, by the network.
*/
class AmendmentTableImpl : public AmendmentTable
{
protected:
typedef ripple::unordered_map<uint256, AmendmentState> amendmentMap_t;
typedef std::pair<const uint256, AmendmentState> amendmentIt_t;
typedef boost::unordered_set<uint256> amendmentList_t;
typedef RippleMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
LockType mLock;
amendmentMap_t m_amendmentMap;
std::chrono::seconds m_majorityTime; // Seconds an amendment must hold a majority
int mMajorityFraction; // 256 = 100%
core::Clock::time_point m_firstReport; // close time of first majority report
core::Clock::time_point m_lastReport; // close time of most recent majority report
beast::Journal m_journal;
AmendmentState* getCreate (uint256 const& amendment, bool create);
bool shouldEnable (std::uint32_t closeTime, const AmendmentState& fs);
void setJson (Json::Value& v, const AmendmentState&);
public:
AmendmentTableImpl (std::chrono::seconds majorityTime, int majorityFraction,
beast::Journal journal)
: m_majorityTime (majorityTime)
, mMajorityFraction (majorityFraction)
, m_firstReport (0)
, m_lastReport (0)
, m_journal (journal)
{
}
void addInitial () override;
AmendmentState* addKnown (const char* amendmentID, const char* friendlyName,
bool veto) override;
uint256 get (const std::string& name) override;
bool veto (uint256 const& amendment) override;
bool unVeto (uint256 const& amendment) override;
bool enable (uint256 const& amendment) override;
bool disable (uint256 const& amendment) override;
bool isEnabled (uint256 const& amendment) override;
bool isSupported (uint256 const& amendment) override;
void setEnabled (const std::vector<uint256>& amendments) override;
void setSupported (const std::vector<uint256>& amendments) override;
void reportValidations (const AmendmentSet&) override;
Json::Value getJson (int) override;
Json::Value getJson (uint256 const&) override;
void doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation) override;
void doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) override;
amendmentList_t getVetoed();
amendmentList_t getEnabled();
amendmentList_t getToEnable(core::Clock::time_point closeTime); // gets amendments we would vote to enable
amendmentList_t getDesired(); // amendments we support, do not veto, are not enabled
};
void
AmendmentTableImpl::addInitial ()
{
// For each amendment this version supports, construct the AmendmentState object by calling
// addKnown. Set any vetoes or defaults. A pointer to the AmendmentState can be stashed
}
AmendmentState*
AmendmentTableImpl::getCreate (uint256 const& amendmentHash, bool create)
{
// call with the mutex held
auto iter (m_amendmentMap.find (amendmentHash));
if (iter == m_amendmentMap.end())
{
if (!create)
return nullptr;
AmendmentState* amendment = & (m_amendmentMap[amendmentHash]);
{
std::string query = "SELECT FirstMajority,LastMajority FROM Features WHERE hash='";
query.append (to_string (amendmentHash));
query.append ("';");
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
Database* db = getApp().getWalletDB ()->getDB ();
if (db->executeSQL (query) && db->startIterRows ())
{
amendment->m_firstMajority = db->getBigInt("FirstMajority");
amendment->m_lastMajority = db->getBigInt("LastMajority");
db->endIterRows ();
}
}
return amendment;
}
return & (iter->second);
}
uint256
AmendmentTableImpl::get (const std::string& name)
{
for (auto const& e : m_amendmentMap)
{
if (name == e.second.mFriendlyName)
return e.first;
}
return uint256 ();
}
AmendmentState*
AmendmentTableImpl::addKnown (const char* amendmentID, const char* friendlyName,
bool veto)
{
uint256 hash;
hash.SetHex (amendmentID);
if (hash.isZero ())
{
assert (false);
return nullptr;
}
AmendmentState* f = getCreate (hash, true);
if (friendlyName != nullptr)
f->setFriendlyName (friendlyName);
f->mVetoed = veto;
f->mSupported = true;
return f;
}
bool
AmendmentTableImpl::veto (uint256 const& amendment)
{
ScopedLockType sl (mLock);
AmendmentState* s = getCreate (amendment, true);
if (s->mVetoed)
return false;
s->mVetoed = true;
return true;
}
bool
AmendmentTableImpl::unVeto (uint256 const& amendment)
{
ScopedLockType sl (mLock);
AmendmentState* s = getCreate (amendment, false);
if (!s || !s->mVetoed)
return false;
s->mVetoed = false;
return true;
}
bool
AmendmentTableImpl::enable (uint256 const& amendment)
{
ScopedLockType sl (mLock);
AmendmentState* s = getCreate (amendment, true);
if (s->mEnabled)
return false;
s->mEnabled = true;
return true;
}
bool
AmendmentTableImpl::disable (uint256 const& amendment)
{
ScopedLockType sl (mLock);
AmendmentState* s = getCreate (amendment, false);
if (!s || !s->mEnabled)
return false;
s->mEnabled = false;
return true;
}
bool
AmendmentTableImpl::isEnabled (uint256 const& amendment)
{
ScopedLockType sl (mLock);
AmendmentState* s = getCreate (amendment, false);
return s && s->mEnabled;
}
bool
AmendmentTableImpl::isSupported (uint256 const& amendment)
{
ScopedLockType sl (mLock);
AmendmentState* s = getCreate (amendment, false);
return s && s->mSupported;
}
AmendmentTableImpl::amendmentList_t
AmendmentTableImpl::getVetoed ()
{
amendmentList_t ret;
ScopedLockType sl (mLock);
for (auto const& e : m_amendmentMap)
{
if (e.second.mVetoed)
ret.insert (e.first);
}
return ret;
}
AmendmentTableImpl::amendmentList_t
AmendmentTableImpl::getEnabled ()
{
amendmentList_t ret;
ScopedLockType sl (mLock);
for (auto const& e : m_amendmentMap)
{
if (e.second.mEnabled)
ret.insert (e.first);
}
return ret;
}
bool
AmendmentTableImpl::shouldEnable (std::uint32_t closeTime,
const AmendmentState& fs)
{
if (fs.mVetoed || fs.mEnabled || !fs.mSupported || (fs.m_lastMajority != m_lastReport))
return false;
if (fs.m_firstMajority == m_firstReport)
{
// had a majority when we first started the server, relaxed check
// WRITEME
}
// didn't have a majority when we first started the server, normal check
return (fs.m_lastMajority - fs.m_firstMajority) > m_majorityTime.count();
}
AmendmentTableImpl::amendmentList_t
AmendmentTableImpl::getToEnable (core::Clock::time_point closeTime)
{
amendmentList_t ret;
ScopedLockType sl (mLock);
if (m_lastReport != 0)
{
for (auto const& e : m_amendmentMap)
{
if (shouldEnable (closeTime, e.second))
ret.insert (e.first);
}
}
return ret;
}
AmendmentTableImpl::amendmentList_t
AmendmentTableImpl::getDesired ()
{
amendmentList_t ret;
ScopedLockType sl (mLock);
for (auto const& e : m_amendmentMap)
{
if (e.second.mSupported && !e.second.mEnabled && !e.second.mVetoed)
ret.insert (e.first);
}
return ret;
}
void
AmendmentTableImpl::reportValidations (const AmendmentSet& set)
{
if (set.mTrustedValidations == 0)
return;
int threshold = (set.mTrustedValidations * mMajorityFraction) / 256;
typedef std::map<uint256, int>::value_type u256_int_pair;
ScopedLockType sl (mLock);
if (m_firstReport == 0)
m_firstReport = set.mCloseTime;
std::vector<uint256> changedAmendments;
changedAmendments.resize(set.mVotes.size());
for (auto const& e : set.mVotes)
{
AmendmentState& state = m_amendmentMap[e.first];
if (m_journal.debug) m_journal.debug <<
"Amendment " << to_string (e.first) <<
" has " << e.second <<
" votes, needs " << threshold;
if (e.second >= threshold)
{
// we have a majority
state.m_lastMajority = set.mCloseTime;
if (state.m_firstMajority == 0)
{
if (m_journal.warning) m_journal.warning <<
"Amendment " << to_string (e.first) <<
" attains a majority vote";
state.m_firstMajority = set.mCloseTime;
changedAmendments.push_back(e.first);
}
}
else // we have no majority
{
if (state.m_firstMajority != 0)
{
if (m_journal.warning) m_journal.warning <<
"Amendment " << to_string (e.first) <<
" loses majority vote";
state.m_firstMajority = 0;
state.m_lastMajority = 0;
changedAmendments.push_back(e.first);
}
}
}
m_lastReport = set.mCloseTime;
if (!changedAmendments.empty())
{
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
Database* db = getApp().getWalletDB ()->getDB ();
db->executeSQL ("BEGIN TRANSACTION;");
for (auto const& hash : changedAmendments)
{
AmendmentState& fState = m_amendmentMap[hash];
db->executeSQL (boost::str (boost::format (
"UPDATE Features SET FirstMajority = %d WHERE Hash = '%s';") %
fState.m_firstMajority % to_string (hash)));
db->executeSQL (boost::str (boost::format (
"UPDATE Features SET LastMajority = %d WHERE Hash = '%s';") %
fState.m_lastMajority % to_string(hash)));
}
db->executeSQL ("END TRANSACTION;");
changedAmendments.clear();
}
}
void
AmendmentTableImpl::setEnabled (const std::vector<uint256>& amendments)
{
ScopedLockType sl (mLock);
for (auto& e : m_amendmentMap)
{
e.second.mEnabled = false;
}
for (auto const& e : amendments)
{
m_amendmentMap[e].mEnabled = true;
}
}
void
AmendmentTableImpl::setSupported (const std::vector<uint256>& amendments)
{
ScopedLockType sl (mLock);
for (auto &e : m_amendmentMap)
{
e.second.mSupported = false;
}
for (auto const& e : amendments)
{
m_amendmentMap[e].mSupported = true;
}
}
void
AmendmentTableImpl::doValidation (Ledger::ref lastClosedLedger,
STObject& baseValidation)
{
amendmentList_t lAmendments = getDesired();
if (lAmendments.empty())
return;
STVector256 vAmendments (sfAmendments);
for (auto const& uAmendment : lAmendments)
{
vAmendments.addValue (uAmendment);
}
vAmendments.sort ();
baseValidation.setFieldV256 (sfAmendments, vAmendments);
}
void
AmendmentTableImpl::doVoting (Ledger::ref lastClosedLedger,
SHAMap::ref initialPosition)
{
// LCL must be flag ledger
assert((lastClosedLedger->getLedgerSeq () % 256) == 0);
AmendmentSet amendmentSet (lastClosedLedger->getParentCloseTimeNC ());
// get validations for ledger before flag ledger
ValidationSet valSet = getApp().getValidations ().getValidations (lastClosedLedger->getParentHash ());
for (auto const& entry : valSet)
{
auto const& val = *entry.second;
if (val.isTrusted ())
{
amendmentSet.addVoter ();
if (val.isFieldPresent (sfAmendments))
{
for (auto const& amendment : val.getFieldV256 (sfAmendments))
{
amendmentSet.addVote (amendment);
}
}
}
}
reportValidations (amendmentSet);
amendmentList_t lAmendments = getToEnable (lastClosedLedger->getCloseTimeNC ());
for (auto const& uAmendment : lAmendments)
{
if (m_journal.warning) m_journal.warning <<
"Voting for amendment: " << uAmendment;
// Create the transaction to enable the amendment
SerializedTransaction trans (ttAMENDMENT);
trans.setFieldAccount (sfAccount, uint160 ());
trans.setFieldH256 (sfAmendment, uAmendment);
uint256 txID = trans.getTransactionID ();
if (m_journal.warning) m_journal.warning <<
"Vote ID: " << txID;
// Inject the transaction into our initial proposal
Serializer s;
trans.add (s, true);
#if RIPPLE_PROPOSE_AMENDMENTS
SHAMapItem::pointer tItem = boost::make_shared<SHAMapItem> (txID, s.peekData ());
if (!initialPosition->addGiveItem (tItem, true, false))
{
if (m_journal.warning) m_journal.warning <<
"Ledger already had amendment transaction";
}
#endif
}
}
Json::Value
AmendmentTableImpl::getJson (int)
{
Json::Value ret(Json::objectValue);
{
ScopedLockType sl(mLock);
for (auto const& e : m_amendmentMap)
{
setJson (ret[to_string (e.first)] = Json::objectValue, e.second);
}
}
return ret;
}
void
AmendmentTableImpl::setJson (Json::Value& v, const AmendmentState& fs)
{
if (!fs.mFriendlyName.empty())
v["name"] = fs.mFriendlyName;
v["supported"] = fs.mSupported;
v["vetoed"] = fs.mVetoed;
if (fs.mEnabled)
v["enabled"] = true;
else
{
v["enabled"] = false;
if (m_lastReport != 0)
{
if (fs.m_lastMajority == 0)
{
v["majority"] = false;
}
else
{
if (fs.m_firstMajority != 0)
{
if (fs.m_firstMajority == m_firstReport)
v["majority_start"] = "start";
else
v["majority_start"] = fs.m_firstMajority;
}
if (fs.m_lastMajority != 0)
{
if (fs.m_lastMajority == m_lastReport)
v["majority_until"] = "now";
else
v["majority_until"] = fs.m_lastMajority;
}
}
}
}
if (fs.mVetoed)
v["veto"] = true;
}
Json::Value
AmendmentTableImpl::getJson (uint256 const& amendmentID)
{
Json::Value ret = Json::objectValue;
Json::Value& jAmendment = (ret[to_string (amendmentID)] = Json::objectValue);
{
ScopedLockType sl(mLock);
AmendmentState *amendmentState = getCreate (amendmentID, true);
setJson (jAmendment, *amendmentState);
}
return ret;
}
std::unique_ptr<AmendmentTable>
make_AmendmentTable (std::chrono::seconds majorityTime, int majorityFraction,
beast::Journal journal)
{
return std::make_unique<AmendmentTableImpl> (majorityTime, majorityFraction,
journal);
}
} // ripple

View File

@@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
bool CanonicalTXSet::Key::operator< (Key const& rhs) const
{
if (mAccount < rhs.mAccount) return true;
if (mAccount > rhs.mAccount) return false;
if (mSeq < rhs.mSeq) return true;
if (mSeq > rhs.mSeq) return false;
return mTXid < rhs.mTXid;
}
bool CanonicalTXSet::Key::operator> (Key const& rhs) const
{
if (mAccount > rhs.mAccount) return true;
if (mAccount < rhs.mAccount) return false;
if (mSeq > rhs.mSeq) return true;
if (mSeq < rhs.mSeq) return false;
return mTXid > rhs.mTXid;
}
bool CanonicalTXSet::Key::operator<= (Key const& rhs) const
{
if (mAccount < rhs.mAccount) return true;
if (mAccount > rhs.mAccount) return false;
if (mSeq < rhs.mSeq) return true;
if (mSeq > rhs.mSeq) return false;
return mTXid <= rhs.mTXid;
}
bool CanonicalTXSet::Key::operator>= (Key const& rhs)const
{
if (mAccount > rhs.mAccount) return true;
if (mAccount < rhs.mAccount) return false;
if (mSeq > rhs.mSeq) return true;
if (mSeq < rhs.mSeq) return false;
return mTXid >= rhs.mTXid;
}
void CanonicalTXSet::push_back (SerializedTransaction::ref txn)
{
uint256 effectiveAccount = mSetHash;
effectiveAccount ^= to256 (txn->getSourceAccount ().getAccountID ());
mMap.insert (std::make_pair (
Key (effectiveAccount, txn->getSequence (), txn->getTransactionID ()),
txn));
}
CanonicalTXSet::iterator CanonicalTXSet::erase (iterator const& it)
{
iterator tmp = it;
++tmp;
mMap.erase (it);
return tmp;
}
} // ripple

View File

@@ -0,0 +1,126 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_CANONICALTXSET_H
#define RIPPLE_CANONICALTXSET_H
namespace ripple {
/** Holds transactions which were deferred to the next pass of consensus.
"Canonical" refers to the order in which transactions are applied.
- Puts transactions from the same account in sequence order
*/
// VFALCO TODO rename to SortedTxSet
class CanonicalTXSet : beast::LeakChecked <CanonicalTXSet>
{
public:
class Key
{
public:
Key (uint256 const& account, std::uint32_t seq, uint256 const& id)
: mAccount (account)
, mTXid (id)
, mSeq (seq)
{
}
bool operator< (Key const& rhs) const;
bool operator> (Key const& rhs) const;
bool operator<= (Key const& rhs) const;
bool operator>= (Key const& rhs) const;
bool operator== (Key const& rhs) const
{
return mTXid == rhs.mTXid;
}
bool operator!= (Key const& rhs) const
{
return mTXid != rhs.mTXid;
}
uint256 const& getTXID () const
{
return mTXid;
}
private:
uint256 mAccount;
uint256 mTXid;
std::uint32_t mSeq;
};
typedef std::map <Key, SerializedTransaction::pointer>::iterator iterator;
typedef std::map <Key, SerializedTransaction::pointer>::const_iterator const_iterator;
public:
explicit CanonicalTXSet (LedgerHash const& lastClosedLedgerHash)
: mSetHash (lastClosedLedgerHash)
{
}
void push_back (SerializedTransaction::ref txn);
// VFALCO TODO remove this function
void reset (LedgerHash const& newLastClosedLedgerHash)
{
mSetHash = newLastClosedLedgerHash;
mMap.clear ();
}
iterator erase (iterator const& it);
iterator begin ()
{
return mMap.begin ();
}
iterator end ()
{
return mMap.end ();
}
const_iterator begin () const
{
return mMap.begin ();
}
const_iterator end () const
{
return mMap.end ();
}
size_t size () const
{
return mMap.size ();
}
bool empty () const
{
return mMap.empty ();
}
private:
// Used to salt the accounts so people can't mine for low account numbers
uint256 mSetHash;
std::map <Key, SerializedTransaction::pointer> mMap;
};
} // ripple
#endif

View File

@@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_IFEEVOTE_H
#define RIPPLE_IFEEVOTE_H
namespace ripple {
/** Manager to process fee votes. */
class FeeVote
{
public:
/** Create a new fee vote manager.
@param targetBaseFee
@param targetReserveBase
@param targetReserveIncrement
@param journal
*/
virtual ~FeeVote () { }
/** Add local fee preference to validation.
@param lastClosedLedger
@param baseValidation
*/
virtual void doValidation (Ledger::ref lastClosedLedger,
STObject& baseValidation) = 0;
/** Cast our local vote on the fee.
@param lastClosedLedger
@param initialPosition
*/
virtual void doVoting (Ledger::ref lastClosedLedger,
SHAMap::ref initialPosition) = 0;
};
std::unique_ptr<FeeVote>
make_FeeVote (std::uint64_t targetBaseFee, std::uint32_t targetReserveBase,
std::uint32_t targetReserveIncrement, beast::Journal journal);
} // ripple
#endif

View File

@@ -0,0 +1,233 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
class FeaturesImpl;
class FeeVoteImpl : public FeeVote
{
private:
template <typename Integer>
class VotableInteger
{
public:
VotableInteger (Integer current, Integer target)
: mCurrent (current)
, mTarget (target)
{
// Add our vote
++mVoteMap[mTarget];
}
bool
mayVote () const
{
// If we love the current setting, we will not vote
return mCurrent != mTarget;
}
void
addVote (Integer vote)
{
++mVoteMap[vote];
}
void
noVote ()
{
addVote (mCurrent);
}
Integer
getVotes ()
{
Integer ourVote = mCurrent;
int weight = 0;
typedef typename std::map<Integer, int>::value_type mapVType;
for (auto const& e : mVoteMap)
{
// Take most voted value between current and target, inclusive
if ((e.first <= std::max (mTarget, mCurrent)) &&
(e.first >= std::min (mTarget, mCurrent)) &&
(e.second > weight))
{
ourVote = e.first;
weight = e.second;
}
}
return ourVote;
}
private:
Integer mCurrent; // The current setting
Integer mTarget; // The setting we want
std::map<Integer, int> mVoteMap;
};
public:
FeeVoteImpl (std::uint64_t targetBaseFee, std::uint32_t targetReserveBase,
std::uint32_t targetReserveIncrement, beast::Journal journal)
: mTargetBaseFee (targetBaseFee)
, mTargetReserveBase (targetReserveBase)
, mTargetReserveIncrement (targetReserveIncrement)
, m_journal (journal)
{
}
//--------------------------------------------------------------------------
void
doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation) override
{
if (lastClosedLedger->getBaseFee () != mTargetBaseFee)
{
if (m_journal.info) m_journal.info <<
"Voting for base fee of " << mTargetBaseFee;
baseValidation.setFieldU64 (sfBaseFee, mTargetBaseFee);
}
if (lastClosedLedger->getReserve (0) != mTargetReserveBase)
{
if (m_journal.info) m_journal.info <<
"Voting for base resrve of " << mTargetReserveBase;
baseValidation.setFieldU32(sfReserveBase, mTargetReserveBase);
}
if (lastClosedLedger->getReserveInc () != mTargetReserveIncrement)
{
if (m_journal.info) m_journal.info <<
"Voting for reserve increment of " << mTargetReserveIncrement;
baseValidation.setFieldU32 (sfReserveIncrement, mTargetReserveIncrement);
}
}
//--------------------------------------------------------------------------
void
doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) override
{
// LCL must be flag ledger
assert ((lastClosedLedger->getLedgerSeq () % 256) == 0);
VotableInteger<std::uint64_t> baseFeeVote (lastClosedLedger->getBaseFee (), mTargetBaseFee);
VotableInteger<std::uint32_t> baseReserveVote (lastClosedLedger->getReserve (0), mTargetReserveBase);
VotableInteger<std::uint32_t> incReserveVote (lastClosedLedger->getReserveInc (), mTargetReserveIncrement);
// get validations for ledger before flag
ValidationSet set = getApp().getValidations ().getValidations (lastClosedLedger->getParentHash ());
for (auto const& e : set)
{
SerializedValidation const& val = *e.second;
if (val.isTrusted ())
{
if (val.isFieldPresent (sfBaseFee))
{
baseFeeVote.addVote (val.getFieldU64 (sfBaseFee));
}
else
{
baseFeeVote.noVote ();
}
if (val.isFieldPresent (sfReserveBase))
{
baseReserveVote.addVote (val.getFieldU32 (sfReserveBase));
}
else
{
baseReserveVote.noVote ();
}
if (val.isFieldPresent (sfReserveIncrement))
{
incReserveVote.addVote (val.getFieldU32 (sfReserveIncrement));
}
else
{
incReserveVote.noVote ();
}
}
}
// choose our positions
std::uint64_t baseFee = baseFeeVote.getVotes ();
std::uint32_t baseReserve = baseReserveVote.getVotes ();
std::uint32_t incReserve = incReserveVote.getVotes ();
// add transactions to our position
if ((baseFee != lastClosedLedger->getBaseFee ()) ||
(baseReserve != lastClosedLedger->getReserve (0)) ||
(incReserve != lastClosedLedger->getReserveInc ()))
{
if (m_journal.warning) m_journal.warning <<
"We are voting for a fee change: " << baseFee <<
"/" << baseReserve <<
"/" << incReserve;
SerializedTransaction trans (ttFEE);
trans.setFieldAccount (sfAccount, uint160 ());
trans.setFieldU64 (sfBaseFee, baseFee);
trans.setFieldU32 (sfReferenceFeeUnits, 10);
trans.setFieldU32 (sfReserveBase, baseReserve);
trans.setFieldU32 (sfReserveIncrement, incReserve);
uint256 txID = trans.getTransactionID ();
if (m_journal.warning) m_journal.warning <<
"Vote: " << txID;
Serializer s;
trans.add (s, true);
SHAMapItem::pointer tItem = boost::make_shared<SHAMapItem> (txID, s.peekData ());
if (!initialPosition->addGiveItem (tItem, true, false))
{
if (m_journal.warning) m_journal.warning <<
"Ledger already had fee change";
}
}
}
private:
std::uint64_t mTargetBaseFee;
std::uint32_t mTargetReserveBase;
std::uint32_t mTargetReserveIncrement;
beast::Journal m_journal;
};
//------------------------------------------------------------------------------
std::unique_ptr<FeeVote>
make_FeeVote (std::uint64_t targetBaseFee, std::uint32_t targetReserveBase,
std::uint32_t targetReserveIncrement, beast::Journal journal)
{
return std::make_unique<FeeVoteImpl> (targetBaseFee, targetReserveBase,
targetReserveIncrement, journal);
}
} // ripple

View File

@@ -0,0 +1,246 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
// VFALCO TODO Inline the function definitions
class HashRouter : public IHashRouter
{
private:
/** An entry in the routing table.
*/
class Entry : public CountedObject <Entry>
{
public:
static char const* getCountedObjectName () { return "HashRouterEntry"; }
Entry ()
: mFlags (0)
{
}
std::set <PeerShortID> const& peekPeers () const
{
return mPeers;
}
void addPeer (PeerShortID peer)
{
if (peer != 0)
mPeers.insert (peer);
}
bool hasPeer (PeerShortID peer) const
{
return mPeers.count (peer) > 0;
}
int getFlags (void) const
{
return mFlags;
}
bool hasFlag (int mask) const
{
return (mFlags & mask) != 0;
}
void setFlag (int flagsToSet)
{
mFlags |= flagsToSet;
}
void clearFlag (int flagsToClear)
{
mFlags &= ~flagsToClear;
}
void swapSet (std::set <PeerShortID>& other)
{
mPeers.swap (other);
}
private:
int mFlags;
std::set <PeerShortID> mPeers;
};
public:
explicit HashRouter (int holdTime)
: mHoldTime (holdTime)
{
}
bool addSuppression (uint256 const& index);
bool addSuppressionPeer (uint256 const& index, PeerShortID peer);
bool addSuppressionPeer (uint256 const& index, PeerShortID peer, int& flags);
bool addSuppressionFlags (uint256 const& index, int flag);
bool setFlag (uint256 const& index, int flag);
int getFlags (uint256 const& index);
bool swapSet (uint256 const& index, std::set<PeerShortID>& peers, int flag);
private:
Entry getEntry (uint256 const& );
Entry& findCreateEntry (uint256 const& , bool& created);
typedef RippleMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
LockType mLock;
// Stores all suppressed hashes and their expiration time
ripple::unordered_map <uint256, Entry> mSuppressionMap;
// Stores all expiration times and the hashes indexed for them
std::map< int, std::list<uint256> > mSuppressionTimes;
int mHoldTime;
};
//------------------------------------------------------------------------------
HashRouter::Entry& HashRouter::findCreateEntry (uint256 const& index, bool& created)
{
ripple::unordered_map<uint256, Entry>::iterator fit = mSuppressionMap.find (index);
if (fit != mSuppressionMap.end ())
{
created = false;
return fit->second;
}
created = true;
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
int expireTime = now - mHoldTime;
// See if any supressions need to be expired
std::map< int, std::list<uint256> >::iterator it = mSuppressionTimes.begin ();
if ((it != mSuppressionTimes.end ()) && (it->first <= expireTime))
{
BOOST_FOREACH (uint256 const & lit, it->second)
mSuppressionMap.erase (lit);
mSuppressionTimes.erase (it);
}
mSuppressionTimes[now].push_back (index);
return mSuppressionMap.emplace (index, Entry ()).first->second;
}
bool HashRouter::addSuppression (uint256 const& index)
{
ScopedLockType sl (mLock);
bool created;
findCreateEntry (index, created);
return created;
}
HashRouter::Entry HashRouter::getEntry (uint256 const& index)
{
ScopedLockType sl (mLock);
bool created;
return findCreateEntry (index, created);
}
bool HashRouter::addSuppressionPeer (uint256 const& index, PeerShortID peer)
{
ScopedLockType sl (mLock);
bool created;
findCreateEntry (index, created).addPeer (peer);
return created;
}
bool HashRouter::addSuppressionPeer (uint256 const& index, PeerShortID peer, int& flags)
{
ScopedLockType sl (mLock);
bool created;
Entry& s = findCreateEntry (index, created);
s.addPeer (peer);
flags = s.getFlags ();
return created;
}
int HashRouter::getFlags (uint256 const& index)
{
ScopedLockType sl (mLock);
bool created;
return findCreateEntry (index, created).getFlags ();
}
bool HashRouter::addSuppressionFlags (uint256 const& index, int flag)
{
ScopedLockType sl (mLock);
bool created;
findCreateEntry (index, created).setFlag (flag);
return created;
}
bool HashRouter::setFlag (uint256 const& index, int flag)
{
// VFALCO NOTE Comments like this belong in the HEADER file,
// and more importantly in a Javadoc comment so
// they appear in the generated documentation.
//
// return: true = changed, false = unchanged
assert (flag != 0);
ScopedLockType sl (mLock);
bool created;
Entry& s = findCreateEntry (index, created);
if ((s.getFlags () & flag) == flag)
return false;
s.setFlag (flag);
return true;
}
bool HashRouter::swapSet (uint256 const& index, std::set<PeerShortID>& peers, int flag)
{
ScopedLockType sl (mLock);
bool created;
Entry& s = findCreateEntry (index, created);
if ((s.getFlags () & flag) == flag)
return false;
s.swapSet (peers);
s.setFlag (flag);
return true;
}
IHashRouter* IHashRouter::New (int holdTime)
{
return new HashRouter (holdTime);
}
} // ripple

View File

@@ -0,0 +1,87 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_HASHROUTER_H_INCLUDED
#define RIPPLE_HASHROUTER_H_INCLUDED
namespace ripple {
// VFALCO NOTE Are these the flags?? Why aren't we using a packed struct?
// VFALCO TODO convert these macros to int constants
#define SF_RELAYED 0x01 // Has already been relayed to other nodes
// VFALCO NOTE How can both bad and good be set on a hash?
#define SF_BAD 0x02 // Signature/format is bad
#define SF_SIGGOOD 0x04 // Signature is good
#define SF_SAVED 0x08
#define SF_RETRY 0x10 // Transaction can be retried
#define SF_TRUSTED 0x20 // comes from trusted source
/** Routing table for objects identified by hash.
This table keeps track of which hashes have been received by which peers.
It is used to manage the routing and broadcasting of messages in the peer
to peer overlay.
*/
class IHashRouter
{
public:
// The type here *MUST* match the type of Peer::ShortId
typedef std::uint32_t PeerShortID;
// VFALCO NOTE this preferred alternative to default parameters makes
// behavior clear.
//
static inline int getDefaultHoldTime ()
{
return 300;
}
// VFALCO TODO rename the parameter to entryHoldTimeInSeconds
static IHashRouter* New (int holdTime);
virtual ~IHashRouter () { }
// VFALCO TODO Replace "Supression" terminology with something more semantically meaningful.
virtual bool addSuppression (uint256 const& index) = 0;
virtual bool addSuppressionPeer (uint256 const& index, PeerShortID peer) = 0;
virtual bool addSuppressionPeer (uint256 const& index, PeerShortID peer, int& flags) = 0;
virtual bool addSuppressionFlags (uint256 const& index, int flag) = 0;
/** Set the flags on a hash.
@return `true` if the flags were changed.
*/
// VFALCO TODO Rename to setFlags since it works with multiple flags.
virtual bool setFlag (uint256 const& index, int mask) = 0;
virtual int getFlags (uint256 const& index) = 0;
virtual bool swapSet (uint256 const& index, std::set<PeerShortID>& peers, int flag) = 0;
// VFALCO TODO This appears to be unused!
//
// virtual Entry getEntry (uint256 const&) = 0;
};
} // ripple
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,322 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_NETWORKOPS_H
#define RIPPLE_NETWORKOPS_H
#include <tuple>
namespace ripple {
// Operations that clients may wish to perform against the network
// Master operational handler, server sequencer, network tracker
class Peer;
class LedgerConsensus;
// This is the primary interface into the "client" portion of the program.
// Code that wants to do normal operations on the network such as
// creating and monitoring accounts, creating transactions, and so on
// should use this interface. The RPC code will primarily be a light wrapper
// over this code.
//
// Eventually, it will check the node's operating mode (synched, unsynched,
// etectera) and defer to the correct means of processing. The current
// code assumes this node is synched (and will continue to do so until
// there's a functional network.
//
/** Provides server functionality for clients.
Clients include backend applications, local commands, and connected
clients. This class acts as a proxy, fulfilling the command with local
data if possible, or asking the network and returning the results if
needed.
A backend application or local client can trust a local instance of
rippled / NetworkOPs. However, client software connecting to non-local
instances of rippled will need to be hardened to protect against hostile
or unreliable servers.
*/
class NetworkOPs
: public InfoSub::Source
{
protected:
explicit NetworkOPs (Stoppable& parent);
public:
typedef beast::abstract_clock <std::chrono::seconds> clock_type;
enum Fault
{
// exceptions these functions can throw
IO_ERROR = 1,
NO_NETWORK = 2,
};
enum OperatingMode
{
// how we process transactions or account balance requests
omDISCONNECTED = 0, // not ready to process requests
omCONNECTED = 1, // convinced we are talking to the network
omSYNCING = 2, // fallen slightly behind
omTRACKING = 3, // convinced we agree with the network
omFULL = 4 // we have the ledger and can even validate
};
// VFALCO TODO Fix OrderBookDB to not need this unrelated type.
//
typedef ripple::unordered_map <std::uint64_t, InfoSub::wptr> SubMapType;
public:
// VFALCO TODO Make LedgerMaster a SharedPtr or a reference.
//
static NetworkOPs* New (clock_type& clock, LedgerMaster& ledgerMaster,
Stoppable& parent, beast::Journal journal);
virtual ~NetworkOPs () = 0;
//--------------------------------------------------------------------------
//
// Network information
//
// Our best estimate of wall time in seconds from 1/1/2000
virtual std::uint32_t getNetworkTimeNC () = 0;
// Our best estimate of current ledger close time
virtual std::uint32_t getCloseTimeNC () = 0;
// Use *only* to timestamp our own validation
virtual std::uint32_t getValidationTimeNC () = 0;
virtual void closeTimeOffset (int) = 0;
virtual boost::posix_time::ptime getNetworkTimePT () = 0;
virtual std::uint32_t getLedgerID (uint256 const& hash) = 0;
virtual std::uint32_t getCurrentLedgerID () = 0;
virtual OperatingMode getOperatingMode () = 0;
virtual std::string strOperatingMode () = 0;
virtual Ledger::pointer getClosedLedger () = 0;
virtual Ledger::pointer getValidatedLedger () = 0;
virtual Ledger::pointer getPublishedLedger () = 0;
virtual Ledger::pointer getCurrentLedger () = 0;
virtual Ledger::pointer getLedgerByHash (uint256 const& hash) = 0;
virtual Ledger::pointer getLedgerBySeq (const std::uint32_t seq) = 0;
virtual void missingNodeInLedger (const std::uint32_t seq) = 0;
virtual uint256 getClosedLedgerHash () = 0;
// Do we have this inclusive range of ledgers in our database
virtual bool haveLedgerRange (std::uint32_t from, std::uint32_t to) = 0;
virtual bool haveLedger (std::uint32_t seq) = 0;
virtual std::uint32_t getValidatedSeq () = 0;
virtual bool isValidated (std::uint32_t seq) = 0;
virtual bool isValidated (std::uint32_t seq, uint256 const& hash) = 0;
virtual bool isValidated (Ledger::ref l) = 0;
virtual bool getValidatedRange (std::uint32_t& minVal, std::uint32_t& maxVal) = 0;
virtual bool getFullValidatedRange (std::uint32_t& minVal, std::uint32_t& maxVal) = 0;
virtual SerializedValidation::ref getLastValidation () = 0;
virtual void setLastValidation (SerializedValidation::ref v) = 0;
virtual SLE::pointer getSLE (Ledger::pointer lpLedger, uint256 const& uHash) = 0;
virtual SLE::pointer getSLEi (Ledger::pointer lpLedger, uint256 const& uHash) = 0;
//--------------------------------------------------------------------------
//
// Transaction processing
//
// must complete immediately
// VFALCO TODO Make this a TxCallback structure
typedef std::function<void (Transaction::pointer, TER)> stCallback;
virtual void submitTransaction (Job&, SerializedTransaction::pointer,
stCallback callback = stCallback ()) = 0;
virtual Transaction::pointer submitTransactionSync (Transaction::ref tpTrans,
bool bAdmin, bool bLocal, bool bFailHard, bool bSubmit) = 0;
virtual void runTransactionQueue () = 0;
virtual Transaction::pointer processTransactionCb (Transaction::pointer,
bool bAdmin, bool bLocal, bool bFailHard, stCallback) = 0;
virtual Transaction::pointer processTransaction (Transaction::pointer transaction,
bool bAdmin, bool bLocal, bool bFailHard) = 0;
virtual Transaction::pointer findTransactionByID (uint256 const& transactionID) = 0;
virtual int findTransactionsByDestination (std::list<Transaction::pointer>&,
const RippleAddress& destinationAccount, std::uint32_t startLedgerSeq,
std::uint32_t endLedgerSeq, int maxTransactions) = 0;
//--------------------------------------------------------------------------
//
// Account functions
//
virtual AccountState::pointer getAccountState (Ledger::ref lrLedger,
const RippleAddress& accountID) = 0;
virtual SLE::pointer getGenerator (Ledger::ref lrLedger,
uint160 const& uGeneratorID) = 0;
//--------------------------------------------------------------------------
//
// Directory functions
//
virtual STVector256 getDirNodeInfo (Ledger::ref lrLedger,
uint256 const& uRootIndex, std::uint64_t& uNodePrevious,
std::uint64_t& uNodeNext) = 0;
//--------------------------------------------------------------------------
//
// Owner functions
//
virtual Json::Value getOwnerInfo (Ledger::pointer lpLedger,
const RippleAddress& naAccount) = 0;
//--------------------------------------------------------------------------
//
// Book functions
//
virtual void getBookPage (
Ledger::pointer lpLedger,
const uint160& uTakerPaysCurrencyID,
const uint160& uTakerPaysIssuerID,
const uint160& uTakerGetsCurrencyID,
const uint160& uTakerGetsIssuerID,
const uint160& uTakerID,
const bool bProof,
const unsigned int iLimit,
const Json::Value& jvMarker,
Json::Value& jvResult) = 0;
//--------------------------------------------------------------------------
// ledger proposal/close functions
virtual void processTrustedProposal (LedgerProposal::pointer proposal,
boost::shared_ptr<protocol::TMProposeSet> set, RippleAddress nodePublic,
uint256 checkLedger, bool sigGood) = 0;
virtual SHAMapAddNode gotTXData (const boost::shared_ptr<Peer>& peer,
uint256 const& hash, const std::list<SHAMapNode>& nodeIDs,
const std::list< Blob >& nodeData) = 0;
virtual bool recvValidation (SerializedValidation::ref val,
const std::string& source) = 0;
virtual void takePosition (int seq, SHAMap::ref position) = 0;
virtual SHAMap::pointer getTXMap (uint256 const& hash) = 0;
virtual bool hasTXSet (const boost::shared_ptr<Peer>& peer,
uint256 const& set, protocol::TxSetStatus status) = 0;
virtual void mapComplete (uint256 const& hash, SHAMap::ref map) = 0;
virtual bool stillNeedTXSet (uint256 const& hash) = 0;
// Fetch packs
virtual void makeFetchPack (Job&, boost::weak_ptr<Peer> peer,
boost::shared_ptr<protocol::TMGetObjectByHash> request,
uint256 wantLedger, std::uint32_t uUptime) = 0;
virtual bool shouldFetchPack (std::uint32_t seq) = 0;
virtual void gotFetchPack (bool progress, std::uint32_t seq) = 0;
virtual void addFetchPack (uint256 const& hash, boost::shared_ptr< Blob >& data) = 0;
virtual bool getFetchPack (uint256 const& hash, Blob& data) = 0;
virtual int getFetchSize () = 0;
virtual void sweepFetchPack () = 0;
// network state machine
virtual void endConsensus (bool correctLCL) = 0;
virtual void setStandAlone () = 0;
virtual void setStateTimer () = 0;
virtual void newLCL (int proposers, int convergeTime, uint256 const& ledgerHash) = 0;
// VFALCO TODO rename to setNeedNetworkLedger
virtual void needNetworkLedger () = 0;
virtual void clearNeedNetworkLedger () = 0;
virtual bool isNeedNetworkLedger () = 0;
virtual bool isFull () = 0;
virtual void setProposing (bool isProposing, bool isValidating) = 0;
virtual bool isProposing () = 0;
virtual bool isValidating () = 0;
virtual bool isAmendmentBlocked () = 0;
virtual void setAmendmentBlocked () = 0;
virtual void consensusViewChange () = 0;
virtual int getPreviousProposers () = 0;
virtual int getPreviousConvergeTime () = 0;
virtual std::uint32_t getLastCloseTime () = 0;
virtual void setLastCloseTime (std::uint32_t t) = 0;
virtual Json::Value getConsensusInfo () = 0;
virtual Json::Value getServerInfo (bool human, bool admin) = 0;
virtual void clearLedgerFetch () = 0;
virtual Json::Value getLedgerFetchInfo () = 0;
virtual std::uint32_t acceptLedger () = 0;
typedef ripple::unordered_map <uint160, std::list<LedgerProposal::pointer> > Proposals;
virtual Proposals& peekStoredProposals () = 0;
virtual void storeProposal (LedgerProposal::ref proposal,
const RippleAddress& peerPublic) = 0;
virtual uint256 getConsensusLCL () = 0;
virtual void reportFeeChange () = 0;
virtual void updateLocalTx (Ledger::ref newValidLedger) = 0;
virtual void addLocalTx (Ledger::ref openLedger, SerializedTransaction::ref txn) = 0;
virtual std::size_t getLocalTxCount () = 0;
//Helper function to generate SQL query to get transactions
virtual std::string transactionsSQL (std::string selection,
const RippleAddress& account, std::int32_t minLedger, std::int32_t maxLedger,
bool descending, std::uint32_t offset, int limit, bool binary,
bool count, bool bAdmin) = 0;
// client information retrieval functions
typedef std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > AccountTxs;
virtual AccountTxs getAccountTxs (const RippleAddress& account,
std::int32_t minLedger, std::int32_t maxLedger, bool descending, std::uint32_t offset,
int limit, bool bAdmin) = 0;
typedef std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > TxsAccount;
virtual TxsAccount getTxsAccount (const RippleAddress& account,
std::int32_t minLedger, std::int32_t maxLedger, bool forward, Json::Value& token,
int limit, bool bAdmin) = 0;
typedef std::tuple<std::string, std::string, std::uint32_t> txnMetaLedgerType;
typedef std::vector<txnMetaLedgerType> MetaTxsList;
virtual MetaTxsList getAccountTxsB (const RippleAddress& account,
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
std::uint32_t offset, int limit, bool bAdmin) = 0;
virtual MetaTxsList getTxsAccountB (const RippleAddress& account,
std::int32_t minLedger, std::int32_t maxLedger, bool forward,
Json::Value& token, int limit, bool bAdmin) = 0;
virtual std::vector<RippleAddress> getLedgerAffectedAccounts (std::uint32_t ledgerSeq) = 0;
//--------------------------------------------------------------------------
//
// Monitoring: publisher side
//
virtual void pubLedger (Ledger::ref lpAccepted) = 0;
virtual void pubProposedTransaction (Ledger::ref lpCurrent,
SerializedTransaction::ref stTxn, TER terResult) = 0;
};
} // ripple
#endif

View File

@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
NicknameState::NicknameState (SerializedLedgerEntry::pointer ledgerEntry) :
mLedgerEntry (ledgerEntry)
{
if (!mLedgerEntry || mLedgerEntry->getType () != ltNICKNAME) return;
}
bool NicknameState::haveMinimumOffer () const
{
return mLedgerEntry->isFieldPresent (sfMinimumOffer);
}
STAmount NicknameState::getMinimumOffer () const
{
return mLedgerEntry->isFieldPresent (sfMinimumOffer)
? mLedgerEntry->getFieldAmount (sfMinimumOffer)
: STAmount ();
}
RippleAddress NicknameState::getAccountID () const
{
return mLedgerEntry->getFieldAccount (sfAccount);
}
void NicknameState::addJson (Json::Value& val)
{
val = mLedgerEntry->getJson (0);
}
} // ripple

View File

@@ -0,0 +1,64 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_NICKNAMESTATE_H
#define RIPPLE_NICKNAMESTATE_H
namespace ripple {
//
// State of a nickname node.
// - Isolate ledger entry format.
//
class NicknameState
{
public:
typedef boost::shared_ptr <NicknameState> pointer;
public:
explicit NicknameState (SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger
bool haveMinimumOffer () const;
STAmount getMinimumOffer () const;
RippleAddress getAccountID () const;
SerializedLedgerEntry::pointer getSLE ()
{
return mLedgerEntry;
}
const SerializedLedgerEntry& peekSLE () const
{
return *mLedgerEntry;
}
SerializedLedgerEntry& peekSLE ()
{
return *mLedgerEntry;
}
Blob getRaw () const;
void addJson (Json::Value& value);
private:
SerializedLedgerEntry::pointer mLedgerEntry;
};
} // ripple
#endif

View File

@@ -0,0 +1,48 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
AccountItem::pointer Offer::makeItem (const uint160& , SerializedLedgerEntry::ref ledgerEntry)
{
if (!ledgerEntry || ledgerEntry->getType () != ltOFFER) return (AccountItem::pointer ());
Offer* offer = new Offer (ledgerEntry);
return (AccountItem::pointer (offer));
}
Offer::Offer (SerializedLedgerEntry::pointer ledgerEntry) : AccountItem (ledgerEntry),
mAccount (mLedgerEntry->getFieldAccount (sfAccount)),
mTakerGets (mLedgerEntry->getFieldAmount (sfTakerGets)),
mTakerPays (mLedgerEntry->getFieldAmount (sfTakerPays)),
mSeq (mLedgerEntry->getFieldU32 (sfSequence))
{
;
}
Json::Value Offer::getJson (int)
{
Json::Value ret (Json::objectValue);
ret["account"] = mAccount.humanAccountID ();
ret["taker_gets"] = getTakerGets ().getFullText ();
ret["taker_pays"] = getTakerPays ().getFullText ();
return ret;
}
} // ripple

View File

@@ -0,0 +1,70 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_OFFER_H
#define RIPPLE_OFFER_H
namespace ripple {
class Offer : public AccountItem
{
public:
Offer () {}
virtual ~Offer () {}
AccountItem::pointer makeItem (const uint160&, SerializedLedgerEntry::ref ledgerEntry);
LedgerEntryType getType ()
{
return (ltOFFER);
}
const STAmount& getTakerPays ()
{
return (mTakerPays);
}
const STAmount& getTakerGets ()
{
return (mTakerGets);
}
const RippleAddress& getAccount ()
{
return (mAccount);
}
int getSeq ()
{
return (mSeq);
}
Json::Value getJson (int);
private:
// For accounts in a ledger
explicit Offer (SerializedLedgerEntry::pointer ledgerEntry);
private:
RippleAddress mAccount;
STAmount mTakerGets;
STAmount mTakerPays;
int mSeq;
};
} // ripple
#endif

View File

@@ -0,0 +1,35 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
OrderBook::OrderBook (uint256 const& index,
uint160 const& currencyIn,
uint160 const& currencyOut,
uint160 const& issuerIn,
uint160 const& issuerOut)
: mBookBase (index)
, mCurrencyIn (currencyIn)
, mCurrencyOut (currencyOut)
, mIssuerIn (issuerIn)
, mIssuerOut (issuerOut)
{
}
} // ripple

View File

@@ -0,0 +1,87 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_ORDERBOOK_H
#define RIPPLE_ORDERBOOK_H
namespace ripple {
/** Describes a serialized ledger entry for an order book. */
class OrderBook : beast::LeakChecked <OrderBook>
{
public:
typedef boost::shared_ptr <OrderBook> pointer;
typedef boost::shared_ptr <OrderBook> const& ref;
public:
/** Construct from a currency specification.
@param index ???
@param currencyIn The base currency.
@param currencyOut The destination currency.
@param issuerIn The base issuer.
@param issuerOut The destination issuer.
*/
// VFALCO NOTE what is the meaning of the index parameter?
// VFALCO TODO Replace with RippleAsset
OrderBook (uint256 const& index,
uint160 const& currencyIn,
uint160 const& currencyOut,
uint160 const& issuerIn,
uint160 const& issuerOut);
uint256 const& getBookBase () const
{
return mBookBase;
}
uint160 const& getCurrencyIn () const
{
return mCurrencyIn;
}
uint160 const& getCurrencyOut () const
{
return mCurrencyOut;
}
uint160 const& getIssuerIn () const
{
return mIssuerIn;
}
uint160 const& getIssuerOut () const
{
return mIssuerOut;
}
private:
// VFALCO TODO Replace these with RippleAsset
uint256 const mBookBase;
uint160 const mCurrencyIn;
uint160 const mCurrencyOut;
uint160 const mIssuerIn;
uint160 const mIssuerOut;
};
} // ripple
#endif

View File

@@ -0,0 +1,37 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_POWRESULT_H_INCLUDED
#define RIPPLE_POWRESULT_H_INCLUDED
namespace ripple {
enum PowResult
{
powOK = 0,
powREUSED = 1, // already submitted
powBADNONCE = 2, // you didn't solve it
powEXPIRED = 3, // time is up
powCORRUPT = 4,
powTOOEASY = 5, // the difficulty increased too much while you solved it
};
}
#endif

View File

@@ -0,0 +1,198 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
namespace ripple {
SETUP_LOG (ProofOfWork)
// VFALCO TODO Move these to a header
const uint256 ProofOfWork::sMinTarget ("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
ProofOfWork::ProofOfWork (const std::string& token,
int iterations,
uint256 const& challenge,
uint256 const& target)
: mToken (token)
, mChallenge (challenge)
, mTarget (target)
, mIterations (iterations)
{
}
ProofOfWork::ProofOfWork (const std::string& token)
{
std::vector<std::string> fields;
boost::split (fields, token, boost::algorithm::is_any_of ("-"));
if (fields.size () != 5)
throw std::runtime_error ("invalid token");
mToken = token;
mChallenge.SetHex (fields[0]);
mTarget.SetHex (fields[1]);
mIterations = beast::lexicalCast <int> (fields[2]);
}
bool ProofOfWork::isValid () const
{
if ((mIterations <= kMaxIterations) && (mTarget >= sMinTarget))
return true;
WriteLog (lsWARNING, ProofOfWork) << "Invalid PoW: " << mIterations << ", " << mTarget;
return false;
}
std::uint64_t ProofOfWork::getDifficulty (uint256 const& target, int iterations)
{
// calculate the approximate number of hashes required to solve this proof of work
if ((iterations > kMaxIterations) || (target < sMinTarget))
{
WriteLog (lsINFO, ProofOfWork) << "Iterations:" << iterations;
WriteLog (lsINFO, ProofOfWork) << "MaxIterat: " << kMaxIterations;
WriteLog (lsINFO, ProofOfWork) << "Target: " << target;
WriteLog (lsINFO, ProofOfWork) << "MinTarget: " << sMinTarget;
throw std::runtime_error ("invalid proof of work target/iteration");
}
// more iterations means more hashes per iteration but also a larger final hash
std::uint64_t difficulty = iterations + (iterations / 8);
// Multiply the number of hashes needed by 256 for each leading zero byte in the difficulty
const unsigned char* ptr = target.begin ();
while (*ptr == 0)
{
difficulty *= 256;
++ptr;
}
difficulty = (difficulty * 256) / (*ptr + 1);
return difficulty;
}
static uint256 getSHA512Half (const std::vector<uint256>& vec)
{
return Serializer::getSHA512Half (vec.front ().begin (), vec.size () * (256 / 8));
}
uint256 ProofOfWork::solve (int maxIterations) const
{
if (!isValid ())
throw std::runtime_error ("invalid proof of work target/iteration");
uint256 nonce;
RandomNumbers::getInstance ().fill (&nonce);
std::vector<uint256> buf2;
buf2.resize (mIterations);
std::vector<uint256> buf1;
buf1.resize (3);
buf1[0] = mChallenge;
while (maxIterations > 0)
{
buf1[1] = nonce;
buf1[2].zero ();
for (int i = (mIterations - 1); i >= 0; --i)
{
buf1[2] = getSHA512Half (buf1);
buf2[i] = buf1[2];
}
if (getSHA512Half (buf2) <= mTarget)
return nonce;
++nonce;
--maxIterations;
}
return uint256 ();
}
bool ProofOfWork::checkSolution (uint256 const& solution) const
{
if (mIterations > kMaxIterations)
return false;
std::vector<uint256> buf1;
buf1.push_back (mChallenge);
buf1.push_back (solution);
buf1.push_back (uint256 ());
std::vector<uint256> buf2;
buf2.resize (mIterations);
for (int i = (mIterations - 1); i >= 0; --i)
{
buf1[2] = getSHA512Half (buf1);
buf2[i] = buf1[2];
}
return getSHA512Half (buf2) <= mTarget;
}
bool ProofOfWork::validateToken (const std::string& strToken)
{
static boost::regex reToken ("[[:xdigit:]]{64}-[[:xdigit:]]{64}-[[:digit:]]+-[[:digit:]]+-[[:xdigit:]]{64}");
boost::smatch smMatch;
return boost::regex_match (strToken, smMatch, reToken);
}
//------------------------------------------------------------------------------
bool ProofOfWork::calcResultInfo (PowResult powCode, std::string& strToken, std::string& strHuman)
{
static struct
{
PowResult powCode;
const char* cpToken;
const char* cpHuman;
} powResultInfoA[] =
{
{ powREUSED, "powREUSED", "Proof-of-work has already been used." },
{ powBADNONCE, "powBADNONCE", "The solution does not meet the required difficulty." },
{ powEXPIRED, "powEXPIRED", "Token is expired." },
{ powCORRUPT, "powCORRUPT", "Invalid token." },
{ powTOOEASY, "powTOOEASY", "Difficulty has increased since token was issued." },
{ powOK, "powOK", "Valid proof-of-work." },
};
int iIndex = RIPPLE_ARRAYSIZE (powResultInfoA);
while (iIndex-- && powResultInfoA[iIndex].powCode != powCode)
;
if (iIndex >= 0)
{
strToken = powResultInfoA[iIndex].cpToken;
strHuman = powResultInfoA[iIndex].cpHuman;
}
return iIndex >= 0;
}
} // ripple

View File

@@ -0,0 +1,83 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_PROOFOFWORK_H
#define RIPPLE_PROOFOFWORK_H
#include <ripple/module/app/misc/PowResult.h>
namespace ripple {
class ProofOfWork : beast::LeakChecked <ProofOfWork>
{
public:
enum
{
kMaxIterations = (1 << 23)
};
typedef boost::shared_ptr <ProofOfWork> pointer;
ProofOfWork (const std::string& token,
int iterations,
uint256 const& challenge,
uint256 const& target);
explicit ProofOfWork (const std::string& token);
bool isValid () const;
uint256 solve (int maxIterations = 2 * kMaxIterations) const;
bool checkSolution (uint256 const& solution) const;
const std::string& getToken () const
{
return mToken;
}
uint256 const& getChallenge () const
{
return mChallenge;
}
std::uint64_t getDifficulty () const
{
return getDifficulty (mTarget, mIterations);
}
// approximate number of hashes needed to solve
static std::uint64_t getDifficulty (uint256 const& target, int iterations);
static bool validateToken (const std::string& strToken);
static bool calcResultInfo (PowResult powCode, std::string& strToken, std::string& strHuman);
private:
std::string mToken;
uint256 mChallenge;
uint256 mTarget;
int mIterations;
static const uint256 sMinTarget;
static const int maxIterations;
};
}
#endif

View File

@@ -0,0 +1,427 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
#include <boost/algorithm/string.hpp>
namespace ripple {
class ProofOfWorkFactoryImp
: public ProofOfWorkFactory
, public beast::LeakChecked <ProofOfWorkFactoryImp>
{
public:
typedef boost::bimap< boost::bimaps::multiset_of<time_t>,
boost::bimaps::unordered_set_of<uint256> > powMap_t;
typedef powMap_t::value_type powMap_vt;
//--------------------------------------------------------------------------
ProofOfWorkFactoryImp ()
: mValidTime (180)
{
setDifficulty (1);
RandomNumbers::getInstance ().fillBytes (mSecret.begin (), mSecret.size ());
}
//--------------------------------------------------------------------------
enum
{
numPowEntries = kMaxDifficulty + 1
};
struct PowEntry
{
const char* target;
int iterations;
};
typedef std::vector <PowEntry> PowEntries;
static PowEntries const& getPowEntries ()
{
struct StaticPowEntries
{
StaticPowEntries ()
{
// VFALCO TODO Make this array know its own size.
//
PowEntry entries [numPowEntries] =
{
// target iterations hashes memory
{ "0CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 65536 }, // 1451874, 2 MB
{ "0CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 98304 }, // 2177811, 3 MB
{ "07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 98304 }, // 3538944, 3 MB
{ "0CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 196608}, // 4355623, 6 MB
{ "07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 131072}, // 4718592, 4 MB
{ "0CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 5807497, 8 MB
{ "07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 196608}, // 7077888, 6 MB
{ "07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 9437184, 8 MB
{ "07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 14155776, 12MB
{ "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 28311552, 12MB
{ "00CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 92919965, 8 MB
{ "00CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 139379948, 12MB
{ "007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 150994944, 8 MB
{ "007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 226492416, 12MB
{ "000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 49152 }, // 278759896, 1.5MB
{ "003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 301989888, 8 MB
{ "003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 452984832, 12MB
{ "0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 98304 }, // 905969664, 3 MB
{ "000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 196608}, // 1115039586, 6 MB
{ "000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 1486719448 8 MB
{ "000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 2230079172 12MB
{ "0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 2415919104, 8 MB
{ "0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 3623878656, 12MB
{ "0003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 7247757312, 12MB
{ "0000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 23787511177, 8 MB
{ "0000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 35681266766, 12MB
{ "00003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 131072}, // 38654705664, 4 MB
{ "00007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 38654705664, 8 MB
{ "00003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 196608}, // 57982058496, 6 MB
{ "00007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 57982058496, 12MB
{ "00003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 77309411328, 8 MB
};
data.reserve (numPowEntries);
for (int i = 0; i < numPowEntries; ++i)
data.push_back (entries [i]);
}
std::vector <PowEntry> data;
};
static StaticPowEntries list;
return list.data;
}
//--------------------------------------------------------------------------
static int getPowEntry (uint256 const& target, int iterations)
{
PowEntries const& entries (getPowEntries ());
for (int i = 0; i < numPowEntries; ++i)
{
if (entries [i].iterations == iterations)
{
uint256 t;
t.SetHex (entries [i].target);
if (t == target)
return i;
}
}
return -1;
}
//--------------------------------------------------------------------------
ProofOfWork getProof ()
{
// challenge - target - iterations - time - validator
static boost::format f ("%s-%s-%d-%d");
int now = static_cast<int> (time (nullptr) / 4);
uint256 challenge;
RandomNumbers::getInstance ().fillBytes (challenge.begin (), challenge.size ());
ScopedLockType sl (mLock);
std::string s = boost::str (boost::format (f) % to_string (challenge) %
to_string (mTarget) % mIterations % now);
std::string c = to_string (mSecret) + s;
s += "-" + to_string (Serializer::getSHA512Half (c));
return ProofOfWork (s, mIterations, challenge, mTarget);
}
//--------------------------------------------------------------------------
PowResult checkProof (const std::string& token, uint256 const& solution)
{
// VFALCO COmmented this out because Dave said it wasn't used
// and also we dont have the lexicalCast from a vector of strings to a time_t
// challenge - target - iterations - time - validator
std::vector<std::string> fields;
boost::split (fields, token, boost::algorithm::is_any_of ("-"));
if (fields.size () != 5)
{
WriteLog (lsDEBUG, ProofOfWork) << "PoW " << token << " is corrupt";
return powCORRUPT;
}
std::string v = to_string (mSecret) + fields[0] + "-" +
fields[1] + "-" + fields[2] + "-" + fields[3];
if (fields[4] != to_string (Serializer::getSHA512Half (v)))
{
WriteLog (lsDEBUG, ProofOfWork) << "PoW " << token << " has a bad token";
return powCORRUPT;
}
uint256 challenge, target;
challenge.SetHex (fields[0]);
target.SetHex (fields[1]);
time_t t;
#if 0
// Broken with lexicalCast<> changes
t = beast::lexicalCast <time_t> (fields[3]);
#else
t = static_cast <time_t> (beast::lexicalCast <std::uint64_t> (fields [3]));
#endif
time_t now = time (nullptr);
int iterations = beast::lexicalCast <int> (fields[2]);
{
ScopedLockType sl (mLock);
if ((t * 4) > (now + mValidTime))
{
WriteLog (lsDEBUG, ProofOfWork) << "PoW " << token << " has expired";
return powEXPIRED;
}
if (((iterations != mIterations) || (target != mTarget)) && getPowEntry (target, iterations) < (mPowEntry - 2))
{
// difficulty has increased more than two times since PoW requested
WriteLog (lsINFO, ProofOfWork) << "Difficulty has increased since PoW requested";
return powTOOEASY;
}
}
ProofOfWork pow (token, iterations, challenge, target);
if (!pow.checkSolution (solution))
{
WriteLog (lsDEBUG, ProofOfWork) << "PoW " << token << " has a bad nonce";
return powBADNONCE;
}
{
ScopedLockType sl (mLock);
if (!mSolvedChallenges.insert (powMap_vt (now, challenge)).second)
{
WriteLog (lsDEBUG, ProofOfWork) << "PoW " << token << " has been reused";
return powREUSED;
}
}
return powOK;
}
//--------------------------------------------------------------------------
void sweep ()
{
time_t expire = time (nullptr) - mValidTime;
ScopedLockType sl (mLock);
do
{
powMap_t::left_map::iterator it = mSolvedChallenges.left.begin ();
if (it == mSolvedChallenges.left.end ())
return;
if (it->first >= expire)
return;
mSolvedChallenges.left.erase (it);
}
while (1);
}
//--------------------------------------------------------------------------
void loadHigh ()
{
time_t now = time (nullptr);
ScopedLockType sl (mLock);
if (mLastDifficultyChange == now)
return;
if (mPowEntry == 30)
return;
++mPowEntry;
mLastDifficultyChange = now;
}
//--------------------------------------------------------------------------
void loadLow ()
{
time_t now = time (nullptr);
ScopedLockType sl (mLock);
if (mLastDifficultyChange == now)
return;
if (mPowEntry == 0)
return;
--mPowEntry;
mLastDifficultyChange = now;
}
//--------------------------------------------------------------------------
void setDifficulty (int i)
{
assert ((i >= 0) && (i <= kMaxDifficulty));
time_t now = time (nullptr);
ScopedLockType sl (mLock);
mPowEntry = i;
PowEntries const& entries (getPowEntries ());
mIterations = entries [i].iterations;
mTarget.SetHex (entries [i].target);
mLastDifficultyChange = now;
}
//--------------------------------------------------------------------------
std::uint64_t getDifficulty ()
{
return ProofOfWork::getDifficulty (mTarget, mIterations);
}
uint256 const& getSecret () const
{
return mSecret;
}
void setSecret (uint256 const& secret)
{
mSecret = secret;
}
private:
typedef RippleMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
LockType mLock;
uint256 mSecret;
int mIterations;
uint256 mTarget;
time_t mLastDifficultyChange;
int mValidTime;
int mPowEntry;
powMap_t mSolvedChallenges;
};
//------------------------------------------------------------------------------
ProofOfWorkFactory* ProofOfWorkFactory::New ()
{
return new ProofOfWorkFactoryImp;
}
//------------------------------------------------------------------------------
class ProofOfWork_test : public beast::unit_test::suite
{
public:
void run ()
{
using namespace ripple;
ProofOfWorkFactoryImp gen;
ProofOfWork pow = gen.getProof ();
beast::String s;
s << "solve difficulty " << beast::String (pow.getDifficulty ());
uint256 solution = pow.solve (16777216);
expect (! solution.isZero (), "Should be solved");
expect (pow.checkSolution (solution), "Should be checked");
// Why is this emitted?
//WriteLog (lsDEBUG, ProofOfWork) << "A bad nonce error is expected";
PowResult r = gen.checkProof (pow.getToken (), uint256 ());
expect (r == powBADNONCE, "Should show bad nonce for empty solution");
expect (gen.checkProof (pow.getToken (), solution) == powOK, "Solution should check with issuer");
//WriteLog (lsDEBUG, ProofOfWork) << "A reused nonce error is expected";
expect (gen.checkProof (pow.getToken (), solution) == powREUSED, "Reuse solution should be detected");
#ifdef SOLVE_POWS
for (int i = 0; i < 12; ++i)
{
gen.setDifficulty (i);
ProofOfWork pow = gen.getProof ();
WriteLog (lsINFO, ProofOfWork) << "Level: " << i << ", Estimated difficulty: " << pow.getDifficulty ();
uint256 solution = pow.solve (131072);
if (solution.isZero ())
{
//WriteLog (lsINFO, ProofOfWork) << "Giving up";
}
else
{
//WriteLog (lsINFO, ProofOfWork) << "Solution found";
if (gen.checkProof (pow.getToken (), solution) != powOK)
{
//WriteLog (lsFATAL, ProofOfWork) << "Solution fails";
}
}
}
#endif
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(ProofOfWork,ripple_app,ripple);
} // ripple

View File

@@ -0,0 +1,61 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_PROOFOFWORKFACTORY_H_INCLUDED
#define RIPPLE_PROOFOFWORKFACTORY_H_INCLUDED
#include <ripple/module/app/misc/PowResult.h>
#include <ripple/module/app/misc/ProofOfWork.h>
namespace ripple {
class ProofOfWorkFactory
{
public:
enum
{
kMaxDifficulty = 30,
};
static ProofOfWorkFactory* New ();
virtual ~ProofOfWorkFactory () { }
virtual ProofOfWork getProof () = 0;
virtual PowResult checkProof (const std::string& token, uint256 const& solution) = 0;
virtual std::uint64_t getDifficulty () = 0;
virtual void setDifficulty (int i) = 0;
virtual void loadHigh () = 0;
virtual void loadLow () = 0;
virtual void sweep () = 0;
virtual uint256 const& getSecret () const = 0;
virtual void setSecret (uint256 const& secret) = 0;
};
}
#endif

View File

@@ -0,0 +1,30 @@
# Amendment
An Amendment is a new or proposed change to a ledger rule. Ledger rules affect
transaction processing and consensus; peers must use the same set of rules for
consensus to succeed, otherwise different instances of rippled will get
different results. Amendments can be almost anything but they must be accepted
by a network majority through a consensus process before they are utilized. An
Amendment must receive at least an 80% approval rate from validating nodes for
a period of two weeks before being accepted. The following example outlines the
process of an Amendment from its conception to approval and usage.
* A community member makes proposes to change transaction processing in some
way. The proposal is discussed amongst the community and receives its support
creating a community or human consensus.
* Some members contribute their time and work to develop the Amendment.
* A pull request is created and the new code is folded into a rippled build
and made available for use.
* The consensus process begins with the validating nodes.
* If the Amendment holds an 80% majority for a two week period, nodes will begin
including the transaction to enable it in their initial sets.
Nodes may veto Amendments they consider undesirable by never announcing their
support for those Amendments. Just a few nodes vetoing an Amendment will normally
keep it from being accepted. Nodes could also vote yes on an Amendments even
before it obtains a super-majority. This might make sense for a critical bug fix.

View File

@@ -0,0 +1,221 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
struct SerializedLedgerLog; // for Log
SETUP_LOGN (SerializedLedgerLog,"SerializedLedger")
SerializedLedgerEntry::SerializedLedgerEntry (
SerializerIterator& sit, uint256 const& index)
: STObject (sfLedgerEntry), mIndex (index), mMutable (true)
{
set (sit);
setSLEType ();
}
SerializedLedgerEntry::SerializedLedgerEntry (
const Serializer& s, uint256 const& index)
: STObject (sfLedgerEntry), mIndex (index), mMutable (true)
{
// we know 's' isn't going away
SerializerIterator sit (const_cast<Serializer&> (s));
set (sit);
setSLEType ();
}
SerializedLedgerEntry::SerializedLedgerEntry (
const STObject & object, uint256 const& index)
: STObject (object), mIndex(index), mMutable (true)
{
setSLEType ();
}
void SerializedLedgerEntry::setSLEType ()
{
auto type = static_cast <LedgerEntryType> (getFieldU16 (sfLedgerEntryType));
auto const item = LedgerFormats::getInstance()->findByType (type);
if (item == nullptr)
throw std::runtime_error ("invalid ledger entry type");
mType = item->getType ();
if (!setType (item->elements))
{
WriteLog (lsWARNING, SerializedLedgerLog)
<< "Ledger entry not valid for type " << mFormat->getName ();
WriteLog (lsWARNING, SerializedLedgerLog) << getJson (0);
throw std::runtime_error ("ledger entry not valid for type");
}
}
SerializedLedgerEntry::SerializedLedgerEntry (LedgerEntryType type, uint256 const& index) :
STObject (sfLedgerEntry), mIndex (index), mType (type), mMutable (true)
{
LedgerFormats::Item const* const item =
LedgerFormats::getInstance()->findByType (type);
if (item != nullptr)
{
set (item->elements);
setFieldU16 (sfLedgerEntryType, static_cast <std::uint16_t> (item->getType ()));
}
else
{
throw std::runtime_error ("invalid ledger entry type");
}
}
SerializedLedgerEntry::pointer SerializedLedgerEntry::getMutable () const
{
SerializedLedgerEntry::pointer ret = boost::make_shared<SerializedLedgerEntry> (boost::cref (*this));
ret->mMutable = true;
return ret;
}
std::string SerializedLedgerEntry::getFullText () const
{
std::string ret = "\"";
ret += to_string (mIndex);
ret += "\" = { ";
ret += mFormat->getName ();
ret += ", ";
ret += STObject::getFullText ();
ret += "}";
return ret;
}
std::string SerializedLedgerEntry::getText () const
{
return str (boost::format ("{ %s, %s }")
% to_string (mIndex)
% STObject::getText ());
}
Json::Value SerializedLedgerEntry::getJson (int options) const
{
Json::Value ret (STObject::getJson (options));
ret["index"] = to_string (mIndex);
return ret;
}
bool SerializedLedgerEntry::isThreadedType ()
{
return getFieldIndex (sfPreviousTxnID) != -1;
}
bool SerializedLedgerEntry::isThreaded ()
{
return isFieldPresent (sfPreviousTxnID);
}
uint256 SerializedLedgerEntry::getThreadedTransaction ()
{
return getFieldH256 (sfPreviousTxnID);
}
std::uint32_t SerializedLedgerEntry::getThreadedLedger ()
{
return getFieldU32 (sfPreviousTxnLgrSeq);
}
bool SerializedLedgerEntry::thread (uint256 const& txID, std::uint32_t ledgerSeq,
uint256& prevTxID, std::uint32_t& prevLedgerID)
{
uint256 oldPrevTxID = getFieldH256 (sfPreviousTxnID);
WriteLog (lsTRACE, SerializedLedgerLog) << "Thread Tx:" << txID << " prev:" << oldPrevTxID;
if (oldPrevTxID == txID)
{
// this transaction is already threaded
assert (getFieldU32 (sfPreviousTxnLgrSeq) == ledgerSeq);
return false;
}
prevTxID = oldPrevTxID;
prevLedgerID = getFieldU32 (sfPreviousTxnLgrSeq);
setFieldH256 (sfPreviousTxnID, txID);
setFieldU32 (sfPreviousTxnLgrSeq, ledgerSeq);
return true;
}
bool SerializedLedgerEntry::hasOneOwner ()
{
return (mType != ltACCOUNT_ROOT) && (getFieldIndex (sfAccount) != -1);
}
bool SerializedLedgerEntry::hasTwoOwners ()
{
return mType == ltRIPPLE_STATE;
}
RippleAddress SerializedLedgerEntry::getOwner ()
{
return getFieldAccount (sfAccount);
}
RippleAddress SerializedLedgerEntry::getFirstOwner ()
{
return RippleAddress::createAccountID (getFieldAmount (sfLowLimit).getIssuer ());
}
RippleAddress SerializedLedgerEntry::getSecondOwner ()
{
return RippleAddress::createAccountID (getFieldAmount (sfHighLimit).getIssuer ());
}
std::vector<uint256> SerializedLedgerEntry::getOwners ()
{
std::vector<uint256> owners;
uint160 account;
for (int i = 0, fields = getCount (); i < fields; ++i)
{
SField::ref fc = getFieldSType (i);
if ((fc == sfAccount) || (fc == sfOwner))
{
const STAccount* entry = dynamic_cast<const STAccount*> (peekAtPIndex (i));
if ((entry != nullptr) && entry->getValueH160 (account))
owners.push_back (Ledger::getAccountRootIndex (account));
}
if ((fc == sfLowLimit) || (fc == sfHighLimit))
{
const STAmount* entry = dynamic_cast<const STAmount*> (peekAtPIndex (i));
if ((entry != nullptr))
{
uint160 issuer = entry->getIssuer ();
if (issuer.isNonZero ())
owners.push_back (Ledger::getAccountRootIndex (issuer));
}
}
}
return owners;
}
} // ripple

View File

@@ -0,0 +1,132 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_SERIALIZEDLEDGER_H
#define RIPPLE_SERIALIZEDLEDGER_H
namespace ripple {
// VFALCO NOTE
//
// This looks like a central class for Ripple. Almost everything that
// does anything of interest deals with SLE objects. Any documentation
// effort should start with a complete description of this object and
// all of its operations.
//
// It is derived from STObject so it inherits a lot of behavior from that.
//
// VFALCO TODO Rename the source file to match the class
//
// VFALCO TODO Can we rename this class to something shorter and more concise?
//
// Can we just call this LedgerEntry?
//
class SerializedLedgerEntry
: public STObject
, public CountedObject <SerializedLedgerEntry>
{
public:
static char const* getCountedObjectName () { return "SerializedLedgerEntry"; }
typedef boost::shared_ptr<SerializedLedgerEntry> pointer;
typedef const boost::shared_ptr<SerializedLedgerEntry>& ref;
public:
SerializedLedgerEntry (const Serializer & s, uint256 const & index);
SerializedLedgerEntry (SerializerIterator & sit, uint256 const & index);
SerializedLedgerEntry (LedgerEntryType type, uint256 const & index);
SerializedLedgerEntry (const STObject & object, uint256 const & index);
SerializedTypeID getSType () const
{
return STI_LEDGERENTRY;
}
std::string getFullText () const;
std::string getText () const;
Json::Value getJson (int options) const;
uint256 const& getIndex () const
{
return mIndex;
}
void setIndex (uint256 const & i)
{
mIndex = i;
}
void setImmutable ()
{
mMutable = false;
}
bool isMutable ()
{
return mMutable;
}
SerializedLedgerEntry::pointer getMutable () const;
LedgerEntryType getType () const
{
return mType;
}
std::uint16_t getVersion () const
{
return getFieldU16 (sfLedgerEntryType);
}
LedgerFormats::Item const* getFormat ()
{
return mFormat;
}
bool isThreadedType (); // is this a ledger entry that can be threaded
bool isThreaded (); // is this ledger entry actually threaded
bool hasOneOwner (); // This node has one other node that owns it (like nickname)
bool hasTwoOwners (); // This node has two nodes that own it (like ripple balance)
RippleAddress getOwner ();
RippleAddress getFirstOwner ();
RippleAddress getSecondOwner ();
uint256 getThreadedTransaction ();
std::uint32_t getThreadedLedger ();
bool thread (uint256 const & txID, std::uint32_t ledgerSeq, uint256 & prevTxID,
std::uint32_t & prevLedgerID);
std::vector<uint256> getOwners (); // nodes notified if this node is deleted
private:
SerializedLedgerEntry* duplicate () const
{
return new SerializedLedgerEntry (*this);
}
/** Make STObject comply with the template for this SLE type
Can throw
*/
void setSLEType ();
private:
uint256 mIndex;
LedgerEntryType mType;
LedgerFormats::Item const* mFormat;
bool mMutable;
};
typedef SerializedLedgerEntry SLE;
} // ripple
#endif

View File

@@ -0,0 +1,427 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace ripple {
SETUP_LOG (SerializedTransaction)
SerializedTransaction::SerializedTransaction (TxType type)
: STObject (sfTransaction)
, mType (type)
, mSigGood (false)
, mSigBad (false)
{
mFormat = TxFormats::getInstance()->findByType (type);
if (mFormat == nullptr)
{
WriteLog (lsWARNING, SerializedTransaction) << "Transaction type: " << type;
throw std::runtime_error ("invalid transaction type");
}
set (mFormat->elements);
setFieldU16 (sfTransactionType, mFormat->getType ());
}
SerializedTransaction::SerializedTransaction (STObject const& object)
: STObject (object)
, mSigGood (false)
, mSigBad (false)
{
mType = static_cast <TxType> (getFieldU16 (sfTransactionType));
mFormat = TxFormats::getInstance()->findByType (mType);
if (!mFormat)
{
WriteLog (lsWARNING, SerializedTransaction) << "Transaction type: " << mType;
throw std::runtime_error ("invalid transaction type");
}
if (!setType (mFormat->elements))
{
throw std::runtime_error ("transaction not valid");
}
}
SerializedTransaction::SerializedTransaction (SerializerIterator& sit) : STObject (sfTransaction),
mSigGood (false), mSigBad (false)
{
int length = sit.getBytesLeft ();
if ((length < Protocol::txMinSizeBytes) || (length > Protocol::txMaxSizeBytes))
{
Log (lsERROR) << "Transaction has invalid length: " << length;
throw std::runtime_error ("Transaction length invalid");
}
set (sit);
mType = static_cast<TxType> (getFieldU16 (sfTransactionType));
mFormat = TxFormats::getInstance()->findByType (mType);
if (!mFormat)
{
WriteLog (lsWARNING, SerializedTransaction) << "Transaction type: " << mType;
throw std::runtime_error ("invalid transaction type");
}
if (!setType (mFormat->elements))
{
WriteLog (lsWARNING, SerializedTransaction) << "Transaction not legal for format";
throw std::runtime_error ("transaction not valid");
}
}
std::string SerializedTransaction::getFullText () const
{
std::string ret = "\"";
ret += to_string (getTransactionID ());
ret += "\" = {";
ret += STObject::getFullText ();
ret += "}";
return ret;
}
std::string SerializedTransaction::getText () const
{
return STObject::getText ();
}
std::vector<RippleAddress> SerializedTransaction::getMentionedAccounts () const
{
std::vector<RippleAddress> accounts;
BOOST_FOREACH (const SerializedType & it, peekData ())
{
const STAccount* sa = dynamic_cast<const STAccount*> (&it);
if (sa != nullptr)
{
bool found = false;
RippleAddress na = sa->getValueNCA ();
BOOST_FOREACH (const RippleAddress & it, accounts)
{
if (it == na)
{
found = true;
break;
}
}
if (!found)
accounts.push_back (na);
}
const STAmount* sam = dynamic_cast<const STAmount*> (&it);
if (sam)
{
uint160 issuer = sam->getIssuer ();
if (issuer.isNonZero ())
{
RippleAddress na;
na.setAccountID (issuer);
bool found = false;
BOOST_FOREACH (const RippleAddress & it, accounts)
{
if (it == na)
{
found = true;
break;
}
}
if (!found)
accounts.push_back (na);
}
}
}
return accounts;
}
uint256 SerializedTransaction::getSigningHash () const
{
return STObject::getSigningHash (getConfig ().SIGN_TRANSACTION);
}
uint256 SerializedTransaction::getTransactionID () const
{
// perhaps we should cache this
return getHash (HashPrefix::transactionID);
}
Blob SerializedTransaction::getSignature () const
{
try
{
return getFieldVL (sfTxnSignature);
}
catch (...)
{
return Blob ();
}
}
void SerializedTransaction::sign (const RippleAddress& naAccountPrivate)
{
Blob signature;
naAccountPrivate.accountPrivateSign (getSigningHash (), signature);
setFieldVL (sfTxnSignature, signature);
}
bool SerializedTransaction::checkSign () const
{
if (mSigGood)
return true;
if (mSigBad)
return false;
try
{
RippleAddress n;
n.setAccountPublic (getFieldVL (sfSigningPubKey));
if (checkSign (n))
{
mSigGood = true;
return true;
}
}
catch (...)
{
;
}
mSigBad = true;
return false;
}
bool SerializedTransaction::checkSign (const RippleAddress& naAccountPublic) const
{
try
{
const ECDSA fullyCanonical = (getFlags() & tfFullyCanonicalSig) ?
ECDSA::strict : ECDSA::not_strict;
return naAccountPublic.accountPublicVerify (getSigningHash (), getFieldVL (sfTxnSignature), fullyCanonical);
}
catch (...)
{
return false;
}
}
void SerializedTransaction::setSigningPubKey (const RippleAddress& naSignPubKey)
{
setFieldVL (sfSigningPubKey, naSignPubKey.getAccountPublic ());
}
void SerializedTransaction::setSourceAccount (const RippleAddress& naSource)
{
setFieldAccount (sfAccount, naSource);
}
Json::Value SerializedTransaction::getJson (int) const
{
Json::Value ret = STObject::getJson (0);
ret["hash"] = to_string (getTransactionID ());
return ret;
}
Json::Value SerializedTransaction::getJson (int options, bool binary) const
{
if (binary)
{
Json::Value ret;
Serializer s = STObject::getSerializer ();
ret["tx"] = strHex (s.peekData ());
ret["hash"] = to_string (getTransactionID ());
return ret;
}
return getJson(options);
}
std::string SerializedTransaction::getSQLValueHeader ()
{
return "(TransID, TransType, FromAcct, FromSeq, LedgerSeq, Status, RawTxn)";
}
std::string SerializedTransaction::getMetaSQLValueHeader ()
{
return "(TransID, TransType, FromAcct, FromSeq, LedgerSeq, Status, RawTxn, TxnMeta)";
}
std::string SerializedTransaction::getMetaSQLInsertReplaceHeader ()
{
return "INSERT OR REPLACE INTO Transactions " + getMetaSQLValueHeader () + " VALUES ";
}
std::string SerializedTransaction::getSQL (std::uint32_t inLedger, char status) const
{
Serializer s;
add (s);
return getSQL (s, inLedger, status);
}
std::string SerializedTransaction::getMetaSQL (std::uint32_t inLedger,
const std::string& escapedMetaData) const
{
Serializer s;
add (s);
return getMetaSQL (s, inLedger, TXN_SQL_VALIDATED, escapedMetaData);
}
std::string SerializedTransaction::getSQL (Serializer rawTxn, std::uint32_t inLedger, char status) const
{
static boost::format bfTrans ("('%s', '%s', '%s', '%d', '%d', '%c', %s)");
std::string rTxn = sqlEscape (rawTxn.peekData ());
return str (boost::format (bfTrans)
% to_string (getTransactionID ()) % getTransactionType ()
% getSourceAccount ().humanAccountID ()
% getSequence () % inLedger % status % rTxn);
}
std::string SerializedTransaction::getMetaSQL (Serializer rawTxn, std::uint32_t inLedger, char status,
const std::string& escapedMetaData) const
{
static boost::format bfTrans ("('%s', '%s', '%s', '%d', '%d', '%c', %s, %s)");
std::string rTxn = sqlEscape (rawTxn.peekData ());
return str (boost::format (bfTrans)
% to_string (getTransactionID ()) % getTransactionType ()
% getSourceAccount ().humanAccountID ()
% getSequence () % inLedger % status % rTxn % escapedMetaData);
}
//------------------------------------------------------------------------------
bool isMemoOkay (STObject const& st)
{
if (!st.isFieldPresent (sfMemos))
return true;
// The number 2048 is a preallocation hint, not a hard limit
// to avoid allocate/copy/free's
Serializer s (2048);
st.getFieldArray (sfMemos).add (s);
// FIXME move the memo limit into a config tunable
if (s.getDataLength () > 1024)
return false;
return true;
}
// Ensure all account fields are 160-bits
bool isAccountFieldOkay (STObject const& st)
{
for (int i = 0; i < st.getCount(); ++i)
{
const STAccount* t = dynamic_cast<STAccount const*>(st.peekAtPIndex (i));
if (t&& !t->isValueH160 ())
return false;
}
return true;
}
bool passesLocalChecks (STObject const& st, std::string& reason)
{
if (!isMemoOkay (st))
{
reason = "The memo exceeds the maximum allowed size.";
return false;
}
if (!isAccountFieldOkay (st))
{
reason = "An account field is invalid.";
return false;
}
return true;
}
bool passesLocalChecks (STObject const& st)
{
std::string reason;
return passesLocalChecks (st, reason);
}
//------------------------------------------------------------------------------
class SerializedTransaction_test : public beast::unit_test::suite
{
public:
void run()
{
RippleAddress seed;
seed.setSeedRandom ();
RippleAddress generator = RippleAddress::createGeneratorPublic (seed);
RippleAddress publicAcct = RippleAddress::createAccountPublic (generator, 1);
RippleAddress privateAcct = RippleAddress::createAccountPrivate (generator, seed, 1);
SerializedTransaction j (ttACCOUNT_SET);
j.setSourceAccount (publicAcct);
j.setSigningPubKey (publicAcct);
j.setFieldVL (sfMessageKey, publicAcct.getAccountPublic ());
j.sign (privateAcct);
unexpected (!j.checkSign (), "Transaction fails signature test");
Serializer rawTxn;
j.add (rawTxn);
SerializerIterator sit (rawTxn);
SerializedTransaction copy (sit);
if (copy != j)
{
log << j.getJson (0);
log << copy.getJson (0);
fail ("Transaction fails serialize/deserialize test");
}
else
{
pass ();
}
STParsedJSON parsed ("test", j.getJson (0));
std::unique_ptr <STObject> new_obj (std::move (parsed.object));
if (new_obj.get () == nullptr)
fail ("Unable to build object from json");
if (STObject (j) != *new_obj)
{
log << "ORIG: " << j.getJson (0);
log << "BUILT " << new_obj->getJson (0);
fail ("Built a different transaction");
}
else
{
pass ();
}
}
};
BEAST_DEFINE_TESTSUITE(SerializedTransaction,ripple_app,ripple);
} // ripple

View File

@@ -0,0 +1,161 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_SERIALIZEDTRANSACTION_H
#define RIPPLE_SERIALIZEDTRANSACTION_H
namespace ripple {
// VFALCO TODO replace these macros with language constants
#define TXN_SQL_NEW 'N'
#define TXN_SQL_CONFLICT 'C'
#define TXN_SQL_HELD 'H'
#define TXN_SQL_VALIDATED 'V'
#define TXN_SQL_INCLUDED 'I'
#define TXN_SQL_UNKNOWN 'U'
class SerializedTransaction
: public STObject
, public CountedObject <SerializedTransaction>
{
public:
static char const* getCountedObjectName () { return "SerializedTransaction"; }
typedef boost::shared_ptr<SerializedTransaction> pointer;
typedef const boost::shared_ptr<SerializedTransaction>& ref;
public:
SerializedTransaction (SerializerIterator & sit);
SerializedTransaction (TxType type);
SerializedTransaction (const STObject & object);
// STObject functions
SerializedTypeID getSType () const
{
return STI_TRANSACTION;
}
std::string getFullText () const;
std::string getText () const;
// outer transaction functions / signature functions
Blob getSignature () const;
void setSignature (Blob const & s)
{
setFieldVL (sfTxnSignature, s);
}
uint256 getSigningHash () const;
TxType getTxnType () const
{
return mType;
}
STAmount getTransactionFee () const
{
return getFieldAmount (sfFee);
}
void setTransactionFee (const STAmount & fee)
{
setFieldAmount (sfFee, fee);
}
RippleAddress getSourceAccount () const
{
return getFieldAccount (sfAccount);
}
Blob getSigningPubKey () const
{
return getFieldVL (sfSigningPubKey);
}
void setSigningPubKey (const RippleAddress & naSignPubKey);
void setSourceAccount (const RippleAddress & naSource);
std::string getTransactionType () const
{
return mFormat->getName ();
}
std::uint32_t getSequence () const
{
return getFieldU32 (sfSequence);
}
void setSequence (std::uint32_t seq)
{
return setFieldU32 (sfSequence, seq);
}
std::vector<RippleAddress> getMentionedAccounts () const;
uint256 getTransactionID () const;
virtual Json::Value getJson (int options) const;
virtual Json::Value getJson (int options, bool binary) const;
void sign (const RippleAddress & naAccountPrivate);
bool checkSign (const RippleAddress & naAccountPublic) const;
bool checkSign () const;
bool isKnownGood () const
{
return mSigGood;
}
bool isKnownBad () const
{
return mSigBad;
}
void setGood () const
{
mSigGood = true;
}
void setBad () const
{
mSigBad = true;
}
// SQL Functions
static std::string getSQLValueHeader ();
static std::string getSQLInsertHeader ();
static std::string getSQLInsertIgnoreHeader ();
std::string getSQL (std::string & sql, std::uint32_t inLedger, char status) const;
std::string getSQL (std::uint32_t inLedger, char status) const;
std::string getSQL (Serializer rawTxn, std::uint32_t inLedger, char status) const;
// SQL Functions with metadata
static std::string getMetaSQLValueHeader ();
static std::string getMetaSQLInsertReplaceHeader ();
std::string getMetaSQL (std::uint32_t inLedger, const std::string & escapedMetaData) const;
std::string getMetaSQL (Serializer rawTxn, std::uint32_t inLedger, char status, const std::string & escapedMetaData) const;
private:
TxType mType;
TxFormats::Item const* mFormat;
SerializedTransaction* duplicate () const
{
return new SerializedTransaction (*this);
}
mutable bool mSigGood;
mutable bool mSigBad;
};
bool passesLocalChecks (STObject const& st, std::string&);
bool passesLocalChecks (STObject const& st);
} // ripple
#endif

View File

@@ -0,0 +1,478 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace ripple {
class ValidationsImp;
SETUP_LOG (Validations)
typedef std::map<uint160, SerializedValidation::pointer>::value_type u160_val_pair;
typedef boost::shared_ptr<ValidationSet> VSpointer;
class ValidationsImp : public Validations
{
private:
typedef RippleMutex LockType;
typedef std::lock_guard <LockType> ScopedLockType;
typedef beast::GenericScopedUnlock <LockType> ScopedUnlockType;
LockType mLock;
TaggedCache<uint256, ValidationSet> mValidations;
ripple::unordered_map<uint160, SerializedValidation::pointer> mCurrentValidations;
std::vector<SerializedValidation::pointer> mStaleValidations;
bool mWriting;
private:
boost::shared_ptr<ValidationSet> findCreateSet (uint256 const& ledgerHash)
{
VSpointer j = mValidations.fetch (ledgerHash);
if (!j)
{
j = boost::make_shared<ValidationSet> ();
mValidations.canonicalize (ledgerHash, j);
}
return j;
}
boost::shared_ptr<ValidationSet> findSet (uint256 const& ledgerHash)
{
return mValidations.fetch (ledgerHash);
}
public:
ValidationsImp ()
: mValidations ("Validations", 128, 600, get_seconds_clock (),
LogPartition::getJournal <TaggedCacheLog> ())
, mWriting (false)
{
mStaleValidations.reserve (512);
}
private:
bool addValidation (SerializedValidation::ref val, const std::string& source)
{
RippleAddress signer = val->getSignerPublic ();
bool isCurrent = false;
if (!val->isTrusted() && getApp().getUNL().nodeInUNL (signer))
val->setTrusted();
std::uint32_t now = getApp().getOPs().getCloseTimeNC();
std::uint32_t valClose = val->getSignTime();
if ((now > (valClose - LEDGER_EARLY_INTERVAL)) && (now < (valClose + LEDGER_VAL_INTERVAL)))
isCurrent = true;
else
WriteLog (lsWARNING, Validations) << "Received stale validation now=" << now << ", close=" << valClose;
if (!val->isTrusted ())
{
WriteLog (lsDEBUG, Validations) << "Node " << signer.humanNodePublic () << " not in UNL st=" << val->getSignTime () <<
", hash=" << val->getLedgerHash () << ", shash=" << val->getSigningHash () << " src=" << source;
}
uint256 hash = val->getLedgerHash ();
uint160 node = signer.getNodeID ();
if (val->isTrusted () && isCurrent)
{
ScopedLockType sl (mLock);
if (!findCreateSet (hash)->insert (std::make_pair (node, val)).second)
return false;
auto it = mCurrentValidations.find (node);
if (it == mCurrentValidations.end ())
{
// No previous validation from this validator
mCurrentValidations.emplace (node, val);
}
else if (!it->second)
{
// Previous validation has expired
it->second = val;
}
else if (val->getSignTime () > it->second->getSignTime ())
{
// This is a newer validation
val->setPreviousHash (it->second->getLedgerHash ());
mStaleValidations.push_back (it->second);
it->second = val;
condWrite ();
}
else
{
// We already have a newer validation from this source
isCurrent = false;
}
}
WriteLog (lsDEBUG, Validations) << "Val for " << hash << " from " << signer.humanNodePublic ()
<< " added " << (val->isTrusted () ? "trusted/" : "UNtrusted/") << (isCurrent ? "current" : "stale");
if (val->isTrusted () && isCurrent)
{
getApp().getLedgerMaster ().checkAccept (hash, val->getFieldU32 (sfLedgerSequence));
return true;
}
// FIXME: This never forwards untrusted validations
return false;
}
void tune (int size, int age)
{
mValidations.setTargetSize (size);
mValidations.setTargetAge (age);
}
ValidationSet getValidations (uint256 const& ledger)
{
{
ScopedLockType sl (mLock);
VSpointer set = findSet (ledger);
if (set)
return *set;
}
return ValidationSet ();
}
void getValidationCount (uint256 const& ledger, bool currentOnly, int& trusted, int& untrusted)
{
trusted = untrusted = 0;
ScopedLockType sl (mLock);
VSpointer set = findSet (ledger);
if (set)
{
std::uint32_t now = getApp().getOPs ().getNetworkTimeNC ();
BOOST_FOREACH (u160_val_pair & it, *set)
{
bool isTrusted = it.second->isTrusted ();
if (isTrusted && currentOnly)
{
std::uint32_t closeTime = it.second->getSignTime ();
if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_VAL_INTERVAL)))
isTrusted = false;
else
{
WriteLog (lsTRACE, Validations) << "VC: Untrusted due to time " << ledger;
}
}
if (isTrusted)
++trusted;
else
++untrusted;
}
}
WriteLog (lsTRACE, Validations) << "VC: " << ledger << "t:" << trusted << " u:" << untrusted;
}
void getValidationTypes (uint256 const& ledger, int& full, int& partial)
{
full = partial = 0;
ScopedLockType sl (mLock);
VSpointer set = findSet (ledger);
if (set)
{
BOOST_FOREACH (u160_val_pair & it, *set)
{
if (it.second->isTrusted ())
{
if (it.second->isFull ())
++full;
else
++partial;
}
}
}
WriteLog (lsTRACE, Validations) << "VC: " << ledger << "f:" << full << " p:" << partial;
}
int getTrustedValidationCount (uint256 const& ledger)
{
int trusted = 0;
ScopedLockType sl (mLock);
VSpointer set = findSet (ledger);
if (set)
{
BOOST_FOREACH (u160_val_pair & it, *set)
{
if (it.second->isTrusted ())
++trusted;
}
}
return trusted;
}
int getFeeAverage (uint256 const& ledger, std::uint64_t ref, std::uint64_t& fee)
{
int trusted = 0;
fee = 0;
ScopedLockType sl (mLock);
VSpointer set = findSet (ledger);
if (set)
{
BOOST_FOREACH (u160_val_pair & it, *set)
{
if (it.second->isTrusted ())
{
++trusted;
if (it.second->isFieldPresent(sfLoadFee))
fee += it.second->getFieldU32(sfLoadFee);
else
fee += ref;
}
}
}
if (trusted == 0)
fee = ref;
else
fee /= trusted;
return trusted;
}
int getNodesAfter (uint256 const& ledger)
{
// Number of trusted nodes that have moved past this ledger
int count = 0;
ScopedLockType sl (mLock);
BOOST_FOREACH (u160_val_pair & it, mCurrentValidations)
{
if (it.second->isTrusted () && it.second->isPreviousHash (ledger))
++count;
}
return count;
}
int getLoadRatio (bool overLoaded)
{
// how many trusted nodes are able to keep up, higher is better
int goodNodes = overLoaded ? 1 : 0;
int badNodes = overLoaded ? 0 : 1;
{
ScopedLockType sl (mLock);
BOOST_FOREACH (u160_val_pair & it, mCurrentValidations)
{
if (it.second->isTrusted ())
{
if (it.second->isFull ())
++goodNodes;
else
++badNodes;
}
}
}
return (goodNodes * 100) / (goodNodes + badNodes);
}
std::list<SerializedValidation::pointer> getCurrentTrustedValidations ()
{
std::uint32_t cutoff = getApp().getOPs ().getNetworkTimeNC () - LEDGER_VAL_INTERVAL;
std::list<SerializedValidation::pointer> ret;
ScopedLockType sl (mLock);
ripple::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin ();
while (it != mCurrentValidations.end ())
{
if (!it->second) // contains no record
it = mCurrentValidations.erase (it);
else if (it->second->getSignTime () < cutoff)
{
// contains a stale record
mStaleValidations.push_back (it->second);
it->second.reset ();
condWrite ();
it = mCurrentValidations.erase (it);
}
else
{
// contains a live record
if (it->second->isTrusted ())
ret.push_back (it->second);
++it;
}
}
return ret;
}
ripple::unordered_map<uint256, currentValidationCount>
getCurrentValidations (uint256 currentLedger, uint256 priorLedger)
{
std::uint32_t cutoff = getApp().getOPs ().getNetworkTimeNC () - LEDGER_VAL_INTERVAL;
bool valCurrentLedger = currentLedger.isNonZero ();
bool valPriorLedger = priorLedger.isNonZero ();
ripple::unordered_map<uint256, currentValidationCount> ret;
ScopedLockType sl (mLock);
ripple::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin ();
while (it != mCurrentValidations.end ())
{
if (!it->second) // contains no record
it = mCurrentValidations.erase (it);
else if (it->second->getSignTime () < cutoff)
{
// contains a stale record
mStaleValidations.push_back (it->second);
it->second.reset ();
condWrite ();
it = mCurrentValidations.erase (it);
}
else
{
// contains a live record
bool countPreferred = valCurrentLedger && (it->second->getLedgerHash () == currentLedger);
if (!countPreferred && // allow up to one ledger slip in either direction
((valCurrentLedger && it->second->isPreviousHash (currentLedger)) ||
(valPriorLedger && (it->second->getLedgerHash () == priorLedger))))
{
countPreferred = true;
WriteLog (lsTRACE, Validations) << "Counting for " << currentLedger << " not " << it->second->getLedgerHash ();
}
currentValidationCount& p = countPreferred ? ret[currentLedger] : ret[it->second->getLedgerHash ()];
++ (p.first);
uint160 ni = it->second->getNodeID ();
if (ni > p.second)
p.second = ni;
++it;
}
}
return ret;
}
void flush ()
{
bool anyNew = false;
WriteLog (lsINFO, Validations) << "Flushing validations";
ScopedLockType sl (mLock);
BOOST_FOREACH (u160_val_pair & it, mCurrentValidations)
{
if (it.second)
mStaleValidations.push_back (it.second);
anyNew = true;
}
mCurrentValidations.clear ();
if (anyNew)
condWrite ();
while (mWriting)
{
ScopedUnlockType sul (mLock);
boost::this_thread::sleep (boost::posix_time::milliseconds (100));
}
WriteLog (lsDEBUG, Validations) << "Validations flushed";
}
void condWrite ()
{
if (mWriting)
return;
mWriting = true;
getApp().getJobQueue ().addJob (jtWRITE, "Validations::doWrite",
std::bind (&ValidationsImp::doWrite,
this, std::placeholders::_1));
}
void doWrite (Job&)
{
LoadEvent::autoptr event (getApp().getJobQueue ().getLoadEventAP (jtDISK, "ValidationWrite"));
boost::format insVal ("INSERT INTO Validations "
"(LedgerHash,NodePubKey,SignTime,RawData) VALUES ('%s','%s','%u',%s);");
ScopedLockType sl (mLock);
assert (mWriting);
while (!mStaleValidations.empty ())
{
std::vector<SerializedValidation::pointer> vector;
vector.reserve (512);
mStaleValidations.swap (vector);
{
ScopedUnlockType sul (mLock);
{
Database* db = getApp().getLedgerDB ()->getDB ();
DeprecatedScopedLock dbl (getApp().getLedgerDB ()->getDBLock ());
Serializer s (1024);
db->executeSQL ("BEGIN TRANSACTION;");
BOOST_FOREACH (SerializedValidation::ref it, vector)
{
s.erase ();
it->add (s);
db->executeSQL (boost::str (
insVal % to_string (it->getLedgerHash ()) %
it->getSignerPublic ().humanNodePublic () %
it->getSignTime () % sqlEscape (s.peekData ())));
}
db->executeSQL ("END TRANSACTION;");
}
}
}
mWriting = false;
}
void sweep ()
{
ScopedLockType sl (mLock);
mValidations.sweep ();
}
};
Validations* Validations::New ()
{
return new ValidationsImp;
}
} // ripple

View File

@@ -0,0 +1,65 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_VALIDATIONS_H_INCLUDED
#define RIPPLE_VALIDATIONS_H_INCLUDED
namespace ripple {
// VFALCO TODO rename and move these typedefs into the Validations interface
typedef ripple::unordered_map<uint160, SerializedValidation::pointer> ValidationSet;
typedef std::pair<int, uint160> currentValidationCount; // nodes validating and highest node ID validating
class Validations : beast::LeakChecked <Validations>
{
public:
static Validations* New ();
virtual ~Validations () { }
virtual bool addValidation (SerializedValidation::ref, const std::string& source) = 0;
virtual ValidationSet getValidations (uint256 const& ledger) = 0;
virtual void getValidationCount (uint256 const& ledger, bool currentOnly, int& trusted, int& untrusted) = 0;
virtual void getValidationTypes (uint256 const& ledger, int& full, int& partial) = 0;
virtual int getTrustedValidationCount (uint256 const& ledger) = 0;
virtual int getFeeAverage(uint256 const& ledger, std::uint64_t ref, std::uint64_t& fee) = 0;
virtual int getNodesAfter (uint256 const& ledger) = 0;
virtual int getLoadRatio (bool overLoaded) = 0;
// VFALCO TODO make a typedef for this ugly return value!
virtual ripple::unordered_map<uint256, currentValidationCount> getCurrentValidations (
uint256 currentLedger, uint256 previousLedger) = 0;
virtual std::list <SerializedValidation::pointer> getCurrentTrustedValidations () = 0;
virtual void tune (int size, int age) = 0;
virtual void flush () = 0;
virtual void sweep () = 0;
};
} // ripple
#endif