Move files to ripple_app

This commit is contained in:
Vinnie Falco
2013-07-10 15:41:44 -07:00
parent 740115b65a
commit 169bac3640
45 changed files with 136 additions and 299 deletions

View File

@@ -1,33 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
Contract::Contract ()
{
}
void Contract::executeCreate ()
{
}
void Contract::executeRemove ()
{
}
void Contract::executeFund ()
{
}
void Contract::executeAccept ()
{
//std::vector<char> code;
//Interpreter interpreter;
//interpreter.interpret(this,code);
}
// vim:ts=4

View File

@@ -1,35 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef CONTRACT_H
#define CONTRACT_H
/*
Encapsulates the SLE for a Contract
*/
class Contract
{
public:
Contract ();
uint160& getIssuer ();
uint160& getOwner ();
STAmount& getRippleEscrow ();
uint32 getEscrow ();
uint32 getBond ();
Script::Data getData (int index);
void executeCreate ();
void executeRemove ();
void executeFund ();
void executeAccept ();
};
#endif
// vim:ts=4

View File

@@ -1,214 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
/*
We also need to charge for each op
*/
namespace Script
{
Interpreter::Interpreter ()
{
mContract = NULL;
mCode = NULL;
mInstructionPointer = 0;
mTotalFee = 0;
mInBlock = false;
mBlockSuccess = true;
mBlockJump = 0;
mFunctionTable.resize (NUM_OF_OPS);
mFunctionTable[INT_OP] = new IntOp ();
mFunctionTable[FLOAT_OP] = new FloatOp ();
mFunctionTable[UINT160_OP] = new Uint160Op ();
mFunctionTable[BOOL_OP] = new Uint160Op ();
mFunctionTable[PATH_OP] = new Uint160Op ();
mFunctionTable[ADD_OP] = new AddOp ();
mFunctionTable[SUB_OP] = new SubOp ();
mFunctionTable[MUL_OP] = new MulOp ();
mFunctionTable[DIV_OP] = new DivOp ();
mFunctionTable[MOD_OP] = new ModOp ();
mFunctionTable[GTR_OP] = new GtrOp ();
mFunctionTable[LESS_OP] = new LessOp ();
mFunctionTable[EQUAL_OP] = new SubOp ();
mFunctionTable[NOT_EQUAL_OP] = new SubOp ();
mFunctionTable[AND_OP] = new SubOp ();
mFunctionTable[OR_OP] = new SubOp ();
mFunctionTable[NOT_OP] = new SubOp ();
mFunctionTable[JUMP_OP] = new SubOp ();
mFunctionTable[JUMPIF_OP] = new SubOp ();
mFunctionTable[STOP_OP] = new SubOp ();
mFunctionTable[CANCEL_OP] = new SubOp ();
mFunctionTable[BLOCK_OP] = new SubOp ();
mFunctionTable[BLOCK_END_OP] = new SubOp ();
mFunctionTable[SEND_XRP_OP] = new SendXRPOp ();
/*
mFunctionTable[SEND_OP]=new SendOp();
mFunctionTable[REMOVE_CONTRACT_OP]=new SubOp();
mFunctionTable[FEE_OP]=new SubOp();
mFunctionTable[CHANGE_CONTRACT_OWNER_OP]=new SubOp();
mFunctionTable[STOP_REMOVE_OP]=new SubOp();
mFunctionTable[SET_DATA_OP]=new SubOp();
mFunctionTable[GET_DATA_OP]=new SubOp();
mFunctionTable[GET_NUM_DATA_OP]=new SubOp();
mFunctionTable[SET_REGISTER_OP]=new SubOp();
mFunctionTable[GET_REGISTER_OP]=new SubOp();
mFunctionTable[GET_ISSUER_ID_OP]=new SubOp();
mFunctionTable[GET_OWNER_ID_OP]=new SubOp();
mFunctionTable[GET_LEDGER_TIME_OP]=new SubOp();
mFunctionTable[GET_LEDGER_NUM_OP]=new SubOp();
mFunctionTable[GET_RAND_FLOAT_OP]=new SubOp();
mFunctionTable[GET_XRP_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_CURRENCY_OP]=new SubOp();
mFunctionTable[GET_RIPPLE_ESCROWED_ISSUER]=new GetRippleEscrowedIssuerOp();
mFunctionTable[GET_ACCEPT_DATA_OP]=new AcceptDataOp();
mFunctionTable[GET_ACCEPTOR_ID_OP]=new GetAcceptorIDOp();
mFunctionTable[GET_CONTRACT_ID_OP]=new GetContractIDOp();
*/
}
Data::pointer Interpreter::popStack ()
{
if (mStack.size ())
{
Data::pointer item = mStack[mStack.size () - 1];
mStack.pop_back ();
return (item);
}
else
{
return (Data::pointer (new ErrorData ()));
}
}
void Interpreter::pushStack (Data::pointer data)
{
mStack.push_back (data);
}
// offset is where to jump to if the block fails
bool Interpreter::startBlock (int offset)
{
if (mInBlock) return (false); // can't nest blocks
mBlockSuccess = true;
mInBlock = true;
mBlockJump = offset + mInstructionPointer;
return (true);
}
bool Interpreter::endBlock ()
{
if (!mInBlock) return (false);
mInBlock = false;
mBlockJump = 0;
pushStack (Data::pointer (new BoolData (mBlockSuccess)));
return (true);
}
TER Interpreter::interpret (Contract* contract, const SerializedTransaction& txn, Blob& code)
{
mContract = contract;
mCode = &code;
mTotalFee = 0;
mInstructionPointer = 0;
while (mInstructionPointer < code.size ())
{
unsigned int fun = (*mCode)[mInstructionPointer];
mInstructionPointer++;
if (fun >= mFunctionTable.size ())
{
// TODO: log
return (temMALFORMED); // TODO: is this actually what we want to do?
}
mTotalFee += mFunctionTable[ fun ]->getFee (); // FIXME: You can't use fees this way, there's no consensus
if (mTotalFee > txn.getTransactionFee ().getNValue ())
{
// TODO: log
return (telINSUF_FEE_P);
}
else
{
if (!mFunctionTable[ fun ]->work (this))
{
// TODO: log
return (temMALFORMED); // TODO: is this actually what we want to do?
}
}
}
return (tesSUCCESS);
}
Data::pointer Interpreter::getIntData ()
{
int value = 0; // TODO
mInstructionPointer += 4;
return (Data::pointer (new IntData (value)));
}
Data::pointer Interpreter::getFloatData ()
{
float value = 0; // TODO
mInstructionPointer += 4;
return (Data::pointer (new FloatData (value)));
}
Data::pointer Interpreter::getUint160Data ()
{
uint160 value; // TODO
mInstructionPointer += 20;
return (Data::pointer (new Uint160Data (value)));
}
bool Interpreter::jumpTo (int offset)
{
mInstructionPointer += offset;
if ( (mInstructionPointer < 0) || (mInstructionPointer > mCode->size ()) )
{
mInstructionPointer -= offset;
return (false);
}
return (true);
}
void Interpreter::stop ()
{
mInstructionPointer = mCode->size ();
}
Data::pointer Interpreter::getContractData (int index)
{
return (Data::pointer (new ErrorData ()));
}
bool Interpreter::canSign (const uint160& signer)
{
return (true);
}
} // end namespace

View File

@@ -1,86 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef INTERPRETER_H
#define INTERPRETER_H
namespace Script
{
class Operation;
// Contracts are non typed have variable data types
class Interpreter
{
std::vector<Operation*> mFunctionTable;
std::vector<Data::pointer> mStack;
Contract* mContract;
Blob* mCode;
unsigned int mInstructionPointer;
int mTotalFee;
bool mInBlock;
int mBlockJump;
bool mBlockSuccess;
public:
enum { INT_OP = 1, FLOAT_OP, UINT160_OP, BOOL_OP, PATH_OP,
ADD_OP, SUB_OP, MUL_OP, DIV_OP, MOD_OP,
GTR_OP, LESS_OP, EQUAL_OP, NOT_EQUAL_OP,
AND_OP, OR_OP, NOT_OP,
JUMP_OP, JUMPIF_OP,
STOP_OP, CANCEL_OP,
BLOCK_OP, BLOCK_END_OP,
SEND_XRP_OP, SEND_OP, REMOVE_CONTRACT_OP, FEE_OP, CHANGE_CONTRACT_OWNER_OP,
STOP_REMOVE_OP,
SET_DATA_OP, GET_DATA_OP, GET_NUM_DATA_OP,
SET_REGISTER_OP, GET_REGISTER_OP,
GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, GET_LEDGER_NUM_OP, GET_RAND_FLOAT_OP,
GET_XRP_ESCROWED_OP, GET_RIPPLE_ESCROWED_OP, GET_RIPPLE_ESCROWED_CURRENCY_OP, GET_RIPPLE_ESCROWED_ISSUER,
GET_ACCEPT_DATA_OP, GET_ACCEPTOR_ID_OP, GET_CONTRACT_ID_OP,
NUM_OF_OPS
};
Interpreter ();
// returns a TransactionEngineResult
TER interpret (Contract* contract, const SerializedTransaction& txn, Blob& code);
void stop ();
bool canSign (const uint160& signer);
int getInstructionPointer ()
{
return (mInstructionPointer);
}
void setInstructionPointer (int n)
{
mInstructionPointer = n;
}
Data::pointer popStack ();
void pushStack (Data::pointer data);
bool jumpTo (int offset);
bool startBlock (int offset);
bool endBlock ();
Data::pointer getIntData ();
Data::pointer getFloatData ();
Data::pointer getUint160Data ();
Data::pointer getAcceptData (int index);
Data::pointer getContractData (int index);
};
} // end namespace
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,475 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LEDGER_H
#define RIPPLE_LEDGER_H
class Job;
enum LedgerStateParms
{
lepNONE = 0, // no special flags
// input flags
lepCREATE = 1, // Create if not present
// output flags
lepOKAY = 2, // success
lepMISSING = 4, // No node in that slot
lepWRONGTYPE = 8, // Node of different type there
lepCREATED = 16, // Node was created
lepERROR = 32, // error
};
#define LEDGER_JSON_DUMP_TXRP 0x10000000
#define LEDGER_JSON_DUMP_STATE 0x20000000
#define LEDGER_JSON_EXPAND 0x40000000
#define LEDGER_JSON_FULL 0x80000000
class SqliteStatement;
// VFALCO TODO figure out exactly how this thing works.
// It seems like some ledger database is stored as a global, static in the
// class. But then what is the meaning of a Ledger object? Is this
// really two classes in one? StoreOfAllLedgers + SingleLedgerObject?
//
class Ledger
: public boost::enable_shared_from_this <Ledger>
, public CountedObject <Ledger>
, Uncopyable
{
public:
static char const* getCountedObjectName () { return "Ledger"; }
typedef boost::shared_ptr<Ledger> pointer;
typedef const boost::shared_ptr<Ledger>& ref;
enum TransResult
{
TR_ERROR = -1,
TR_SUCCESS = 0,
TR_NOTFOUND = 1,
TR_ALREADY = 2,
TR_BADTRANS = 3, // the transaction itself is corrupt
TR_BADACCT = 4, // one of the accounts is invalid
TR_INSUFF = 5, // the sending(apply)/receiving(remove) account is broke
TR_PASTASEQ = 6, // account is past this transaction
TR_PREASEQ = 7, // account is missing transactions before this
TR_BADLSEQ = 8, // ledger too early
TR_TOOSMALL = 9, // amount is less than Tx fee
};
// ledger close flags
static const uint32 sLCF_NoConsensusTime = 1;
public:
Ledger (const RippleAddress & masterID, uint64 startAmount); // used for the starting bootstrap ledger
Ledger (uint256 const & parentHash, uint256 const & transHash, uint256 const & accountHash,
uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution,
uint32 ledgerSeq, bool & loaded); // used for database ledgers
Ledger (Blob const & rawLedger, bool hasPrefix);
Ledger (const std::string & rawLedger, bool hasPrefix);
Ledger (bool dummy, Ledger & previous); // ledger after this one
Ledger (Ledger & target, bool isMutable); // snapshot
static Ledger::pointer getSQL (const std::string & sqlStatement);
static Ledger::pointer getSQL1 (SqliteStatement*);
static void getSQL2 (Ledger::ref);
static Ledger::pointer getLastFullLedger ();
static uint32 roundCloseTime (uint32 closeTime, uint32 closeResolution);
void updateHash ();
void setClosed ()
{
mClosed = true;
}
void setAccepted (uint32 closeTime, int closeResolution, bool correctCloseTime);
void setAccepted ();
void setImmutable ();
bool isClosed ()
{
return mClosed;
}
bool isAccepted ()
{
return mAccepted;
}
bool isImmutable ()
{
return mImmutable;
}
bool isFixed ()
{
return mClosed || mImmutable;
}
void setFull ()
{
mTransactionMap->setLedgerSeq (mLedgerSeq);
mAccountStateMap->setLedgerSeq (mLedgerSeq);
}
// ledger signature operations
void addRaw (Serializer & s) const;
void setRaw (Serializer & s, bool hasPrefix);
uint256 getHash ();
uint256 const& getParentHash () const
{
return mParentHash;
}
uint256 const& getTransHash () const
{
return mTransHash;
}
uint256 const& getAccountHash () const
{
return mAccountHash;
}
uint64 getTotalCoins () const
{
return mTotCoins;
}
void destroyCoins (uint64 fee)
{
mTotCoins -= fee;
}
uint32 getCloseTimeNC () const
{
return mCloseTime;
}
uint32 getParentCloseTimeNC () const
{
return mParentCloseTime;
}
uint32 getLedgerSeq () const
{
return mLedgerSeq;
}
int getCloseResolution () const
{
return mCloseResolution;
}
bool getCloseAgree () const
{
return (mCloseFlags & sLCF_NoConsensusTime) == 0;
}
// close time functions
void setCloseTime (uint32 ct)
{
assert (!mImmutable);
mCloseTime = ct;
}
void setCloseTime (boost::posix_time::ptime);
boost::posix_time::ptime getCloseTime () const;
// low level functions
SHAMap::ref peekTransactionMap ()
{
return mTransactionMap;
}
SHAMap::ref peekAccountStateMap ()
{
return mAccountStateMap;
}
void dropCache ()
{
assert (isImmutable ());
if (mTransactionMap)
mTransactionMap->dropCache ();
if (mAccountStateMap)
mAccountStateMap->dropCache ();
}
// ledger sync functions
void setAcquiring (void);
bool isAcquiring (void);
bool isAcquiringTx (void);
bool isAcquiringAS (void);
// Transaction Functions
bool addTransaction (uint256 const & id, const Serializer & txn);
bool addTransaction (uint256 const & id, const Serializer & txn, const Serializer & metaData);
bool hasTransaction (uint256 const & TransID) const
{
return mTransactionMap->hasItem (TransID);
}
Transaction::pointer getTransaction (uint256 const & transID) const;
bool getTransaction (uint256 const & transID, Transaction::pointer & txn, TransactionMetaSet::pointer & txMeta);
bool getTransactionMeta (uint256 const & transID, TransactionMetaSet::pointer & txMeta);
bool getMetaHex (uint256 const & transID, std::string & hex);
static SerializedTransaction::pointer getSTransaction (SHAMapItem::ref, SHAMapTreeNode::TNType);
SerializedTransaction::pointer getSMTransaction (SHAMapItem::ref, SHAMapTreeNode::TNType,
TransactionMetaSet::pointer & txMeta);
// high-level functions
bool hasAccount (const RippleAddress & acctID);
AccountState::pointer getAccountState (const RippleAddress & acctID);
LedgerStateParms writeBack (LedgerStateParms parms, SLE::ref);
SLE::pointer getAccountRoot (const uint160 & accountID);
SLE::pointer getAccountRoot (const RippleAddress & naAccountID);
void updateSkipList ();
void visitAccountItems (const uint160 & acctID, FUNCTION_TYPE<void (SLE::ref)>);
// database functions (low-level)
static Ledger::pointer loadByIndex (uint32 ledgerIndex);
static Ledger::pointer loadByHash (uint256 const & ledgerHash);
static uint256 getHashByIndex (uint32 index);
static bool getHashesByIndex (uint32 index, uint256 & ledgerHash, uint256 & parentHash);
static std::map< uint32, std::pair<uint256, uint256> > getHashesByIndex (uint32 minSeq, uint32 maxSeq);
void pendSave (bool fromConsensus);
// next/prev function
SLE::pointer getSLE (uint256 const & uHash); // SLE is mutable
SLE::pointer getSLEi (uint256 const & uHash); // SLE is immutable
// VFALCO NOTE These seem to let you walk the list of ledgers
//
uint256 getFirstLedgerIndex ();
uint256 getLastLedgerIndex ();
uint256 getNextLedgerIndex (uint256 const & uHash); // first node >hash
uint256 getNextLedgerIndex (uint256 const & uHash, uint256 const & uEnd); // first node >hash, <end
uint256 getPrevLedgerIndex (uint256 const & uHash); // last node <hash
uint256 getPrevLedgerIndex (uint256 const & uHash, uint256 const & uBegin); // last node <hash, >begin
// Ledger hash table function
static uint256 getLedgerHashIndex ();
static uint256 getLedgerHashIndex (uint32 desiredLedgerIndex);
static int getLedgerHashOffset (uint32 desiredLedgerIndex);
static int getLedgerHashOffset (uint32 desiredLedgerIndex, uint32 currentLedgerIndex);
uint256 getLedgerHash (uint32 ledgerIndex);
std::vector< std::pair<uint32, uint256> > getLedgerHashes ();
static uint256 getLedgerFeatureIndex ();
static uint256 getLedgerFeeIndex ();
std::vector<uint256> getLedgerFeatures ();
std::vector<uint256> getNeededTransactionHashes (int max, SHAMapSyncFilter * filter);
std::vector<uint256> getNeededAccountStateHashes (int max, SHAMapSyncFilter * filter);
// index calculation functions
static uint256 getAccountRootIndex (const uint160 & uAccountID);
static uint256 getAccountRootIndex (const RippleAddress & account)
{
return getAccountRootIndex (account.getAccountID ());
}
//
// Generator Map functions
//
SLE::pointer getGenerator (const uint160 & uGeneratorID);
static uint256 getGeneratorIndex (const uint160 & uGeneratorID);
//
// Nickname functions
//
static uint256 getNicknameHash (const std::string & strNickname)
{
Serializer s (strNickname);
return s.getSHA256 ();
}
NicknameState::pointer getNicknameState (uint256 const & uNickname);
NicknameState::pointer getNicknameState (const std::string & strNickname)
{
return getNicknameState (getNicknameHash (strNickname));
}
SLE::pointer getNickname (uint256 const & uNickname);
SLE::pointer getNickname (const std::string & strNickname)
{
return getNickname (getNicknameHash (strNickname));
}
static uint256 getNicknameIndex (uint256 const & uNickname);
//
// Order book functions
//
// Order book dirs have a base so we can use next to step through them in quality order.
static bool isValidBook (const uint160 & uTakerPaysCurrency, const uint160 & uTakerPaysIssuerID,
const uint160 & uTakerGetsCurrency, const uint160 & uTakerGetsIssuerID);
static uint256 getBookBase (const uint160 & uTakerPaysCurrency, const uint160 & uTakerPaysIssuerID,
const uint160 & uTakerGetsCurrency, const uint160 & uTakerGetsIssuerID);
//
// Offer functions
//
SLE::pointer getOffer (uint256 const & uIndex);
SLE::pointer getOffer (const uint160 & uAccountID, uint32 uSequence)
{
return getOffer (getOfferIndex (uAccountID, uSequence));
}
// The index of an offer.
static uint256 getOfferIndex (const uint160 & uAccountID, uint32 uSequence);
//
// Owner functions
//
// VFALCO NOTE This is a simple math operation that converts the account ID
// into a 256 bit object (I think....need to research this)
//
// All items controlled by an account are here: offers
static uint256 getOwnerDirIndex (const uint160 & uAccountID);
//
// Directory functions
// Directories are doubly linked lists of nodes.
// Given a directory root and and index compute the index of a node.
static uint256 getDirNodeIndex (uint256 const & uDirRoot, const uint64 uNodeIndex = 0);
static void ownerDirDescriber (SLE::ref, const uint160 & owner);
// Return a node: root or normal
SLE::pointer getDirNode (uint256 const & uNodeIndex);
//
// Quality
//
static uint256 getQualityIndex (uint256 const & uBase, const uint64 uNodeDir = 0);
static uint256 getQualityNext (uint256 const & uBase);
static uint64 getQuality (uint256 const & uBase);
static void qualityDirDescriber (SLE::ref,
const uint160 & uTakerPaysCurrency, const uint160 & uTakerPaysIssuer,
const uint160 & uTakerGetsCurrency, const uint160 & uTakerGetsIssuer,
const uint64 & uRate);
//
// Ripple functions : credit lines
//
// Index of node which is the ripple state between two accounts for a currency.
// VFALCO NOTE Rename these to make it clear they are simple functions that
// don't access global variables. e.g. "calculateKeyFromRippleStateAndAddress"
//
static uint256 getRippleStateIndex (const RippleAddress & naA, const RippleAddress & naB, const uint160 & uCurrency);
static uint256 getRippleStateIndex (const uint160 & uiA, const uint160 & uiB, const uint160 & uCurrency)
{
return getRippleStateIndex (RippleAddress::createAccountID (uiA), RippleAddress::createAccountID (uiB), uCurrency);
}
SLE::pointer getRippleState (uint256 const & uNode);
SLE::pointer getRippleState (const RippleAddress & naA, const RippleAddress & naB, const uint160 & uCurrency)
{
return getRippleState (getRippleStateIndex (naA, naB, uCurrency));
}
SLE::pointer getRippleState (const uint160 & uiA, const uint160 & uiB, const uint160 & uCurrency)
{
return getRippleState (getRippleStateIndex (RippleAddress::createAccountID (uiA), RippleAddress::createAccountID (uiB), uCurrency));
}
uint32 getReferenceFeeUnits ()
{
if (!mBaseFee) updateFees ();
return mReferenceFeeUnits;
}
uint64 getBaseFee ()
{
if (!mBaseFee) updateFees ();
return mBaseFee;
}
uint64 getReserve (int increments)
{
if (!mBaseFee) updateFees ();
return scaleFeeBase (static_cast<uint64> (increments) * mReserveIncrement + mReserveBase);
}
uint64 getReserveInc ()
{
if (!mBaseFee) updateFees ();
return mReserveIncrement;
}
uint64 scaleFeeBase (uint64 fee);
uint64 scaleFeeLoad (uint64 fee, bool bAdmin);
Json::Value getJson (int options);
void addJson (Json::Value&, int options);
bool walkLedger ();
bool assertSane ();
protected:
SLE::pointer getASNode (LedgerStateParms & parms, uint256 const & nodeID, LedgerEntryType let);
// returned SLE is immutable
SLE::pointer getASNodeI (uint256 const & nodeID, LedgerEntryType let);
void saveAcceptedLedger (Job&, bool fromConsensus);
void updateFees ();
private:
// The basic Ledger structure, can be opened, closed, or synching
// VFALCO TODO eliminate the need for friends
friend class TransactionEngine;
friend class Transactor;
void initializeFees ();
private:
uint256 mHash;
uint256 mParentHash;
uint256 mTransHash;
uint256 mAccountHash;
uint64 mTotCoins;
uint32 mLedgerSeq;
uint32 mCloseTime; // when this ledger closed
uint32 mParentCloseTime; // when the previous ledger closed
int mCloseResolution; // the resolution for this ledger close time (2-120 seconds)
uint32 mCloseFlags; // flags indicating how this ledger close took place
bool mClosed, mValidHash, mAccepted, mImmutable;
uint32 mReferenceFeeUnits; // Fee units for the reference transaction
uint32 mReserveBase, mReserveIncrement; // Reserve basse and increment in fee units
uint64 mBaseFee; // Ripple cost of the reference transaction
SHAMap::pointer mTransactionMap;
SHAMap::pointer mAccountStateMap;
mutable boost::recursive_mutex mLock;
};
inline LedgerStateParms operator| (const LedgerStateParms& l1, const LedgerStateParms& l2)
{
return static_cast<LedgerStateParms> (static_cast<int> (l1) | static_cast<int> (l2));
}
inline LedgerStateParms operator& (const LedgerStateParms& l1, const LedgerStateParms& l2)
{
return static_cast<LedgerStateParms> (static_cast<int> (l1) & static_cast<int> (l2));
}
#endif
// vim:ts=4

View File

@@ -1,878 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#define MIN_VALIDATION_RATIO 150 // 150/256ths of validations of previous ledger
#define MAX_LEDGER_GAP 100 // Don't catch up more than 100 ledgers (cannot exceed 256)
SETUP_LOG (LedgerMaster)
uint32 LedgerMaster::getCurrentLedgerIndex ()
{
return mCurrentLedger->getLedgerSeq ();
}
Ledger::ref LedgerMaster::getCurrentSnapshot ()
{
if (!mCurrentSnapshot || (mCurrentSnapshot->getHash () != mCurrentLedger->getHash ()))
mCurrentSnapshot = boost::make_shared<Ledger> (boost::ref (*mCurrentLedger), false);
assert (mCurrentSnapshot->isImmutable ());
return mCurrentSnapshot;
}
int LedgerMaster::getPublishedLedgerAge ()
{
boost::recursive_mutex::scoped_lock ml (mLock);
if (!mPubLedger)
{
WriteLog (lsDEBUG, LedgerMaster) << "No published ledger";
return 999999;
}
int64 ret = getApp().getOPs ().getCloseTimeNC ();
ret -= static_cast<int64> (mPubLedger->getCloseTimeNC ());
ret = std::max (0LL, ret);
WriteLog (lsTRACE, LedgerMaster) << "Published ledger age is " << ret;
return static_cast<int> (ret);
}
int LedgerMaster::getValidatedLedgerAge ()
{
boost::recursive_mutex::scoped_lock ml (mLock);
if (!mValidLedger)
{
WriteLog (lsDEBUG, LedgerMaster) << "No validated ledger";
return 999999;
}
int64 ret = getApp().getOPs ().getCloseTimeNC ();
ret -= static_cast<int64> (mValidLedger->getCloseTimeNC ());
ret = std::max (0LL, ret);
WriteLog (lsTRACE, LedgerMaster) << "Validated ledger age is " << ret;
return static_cast<int> (ret);
}
bool LedgerMaster::isCaughtUp(std::string& reason)
{
if (getPublishedLedgerAge() > 180)
{
reason = "No recently-validated ledger";
return false;
}
boost::recursive_mutex::scoped_lock ml (mLock);
if (!mValidLedger || !mPubLedger)
{
reason = "No published ledger";
return false;
}
if (mValidLedger->getLedgerSeq() > (mPubLedger->getLedgerSeq() + 3))
{
reason = "Published ledger lags validated ledger";
return false;
}
return true;
}
void LedgerMaster::addHeldTransaction (Transaction::ref transaction)
{
// returns true if transaction was added
boost::recursive_mutex::scoped_lock ml (mLock);
mHeldTransactions.push_back (transaction->getSTransaction ());
}
void LedgerMaster::pushLedger (Ledger::pointer newLedger)
{
// Caller should already have properly assembled this ledger into "ready-to-close" form --
// all candidate transactions must already be applied
WriteLog (lsINFO, LedgerMaster) << "PushLedger: " << newLedger->getHash ();
boost::recursive_mutex::scoped_lock ml (mLock);
if (!mPubLedger)
mPubLedger = newLedger;
if (!!mFinalizedLedger)
{
mFinalizedLedger->setClosed ();
WriteLog (lsTRACE, LedgerMaster) << "Finalizes: " << mFinalizedLedger->getHash ();
}
mFinalizedLedger = mCurrentLedger;
mCurrentLedger = newLedger;
mEngine.setLedger (newLedger);
}
void LedgerMaster::pushLedger (Ledger::pointer newLCL, Ledger::pointer newOL, bool fromConsensus)
{
assert (newLCL->isClosed () && newLCL->isAccepted ());
assert (!newOL->isClosed () && !newOL->isAccepted ());
boost::recursive_mutex::scoped_lock ml (mLock);
if (newLCL->isAccepted ())
{
assert (newLCL->isClosed ());
assert (newLCL->isImmutable ());
mLedgerHistory.addAcceptedLedger (newLCL, fromConsensus);
WriteLog (lsINFO, LedgerMaster) << "StashAccepted: " << newLCL->getHash ();
}
{
boost::recursive_mutex::scoped_lock ml (mLock);
mFinalizedLedger = newLCL;
mCurrentLedger = newOL;
mEngine.setLedger (newOL);
}
checkAccept (newLCL->getHash (), newLCL->getLedgerSeq ());
}
void LedgerMaster::switchLedgers (Ledger::pointer lastClosed, Ledger::pointer current)
{
assert (lastClosed && current);
{
boost::recursive_mutex::scoped_lock ml (mLock);
mFinalizedLedger = lastClosed;
mFinalizedLedger->setClosed ();
mFinalizedLedger->setAccepted ();
mCurrentLedger = current;
assert (!mCurrentLedger->isClosed ());
mEngine.setLedger (mCurrentLedger);
}
checkAccept (lastClosed->getHash (), lastClosed->getLedgerSeq ());
}
void LedgerMaster::storeLedger (Ledger::pointer ledger)
{
mLedgerHistory.addLedger (ledger);
if (ledger->isAccepted ())
mLedgerHistory.addAcceptedLedger (ledger, false);
}
Ledger::pointer LedgerMaster::closeLedger (bool recover)
{
boost::recursive_mutex::scoped_lock sl (mLock);
Ledger::pointer closingLedger = mCurrentLedger;
if (recover)
{
int recovers = 0;
for (CanonicalTXSet::iterator it = mHeldTransactions.begin (), end = mHeldTransactions.end (); it != end; ++it)
{
try
{
TransactionEngineParams tepFlags = tapOPEN_LEDGER;
if (getApp().getHashRouter ().addSuppressionPeer (it->first.getTXID (), SF_SIGGOOD))
tepFlags = static_cast<TransactionEngineParams> (tepFlags | tapNO_CHECK_SIGN);
bool didApply;
mEngine.applyTransaction (*it->second, tepFlags, didApply);
if (didApply)
++recovers;
}
catch (...)
{
// CHECKME: We got a few of these
WriteLog (lsWARNING, LedgerMaster) << "Held transaction throws";
}
}
CondLog (recovers != 0, lsINFO, LedgerMaster) << "Recovered " << recovers << " held transactions";
// VFALCO TODO recreate the CanonicalTxSet object instead of resetting it
mHeldTransactions.reset (closingLedger->getHash ());
}
mCurrentLedger = boost::make_shared<Ledger> (boost::ref (*closingLedger), true);
mEngine.setLedger (mCurrentLedger);
return Ledger::pointer (new Ledger (*closingLedger, true));
}
TER LedgerMaster::doTransaction (SerializedTransaction::ref txn, TransactionEngineParams params, bool& didApply)
{
Ledger::pointer ledger;
TER result;
{
boost::recursive_mutex::scoped_lock sl (mLock);
result = mEngine.applyTransaction (*txn, params, didApply);
ledger = mEngine.getLedger ();
}
if (didApply)
getApp().getOPs ().pubProposedTransaction (ledger, txn, result);
return result;
}
bool LedgerMaster::haveLedgerRange (uint32 from, uint32 to)
{
boost::recursive_mutex::scoped_lock sl (mLock);
uint32 prevMissing = mCompleteLedgers.prevMissing (to + 1);
return (prevMissing == RangeSet::absent) || (prevMissing < from);
}
bool LedgerMaster::haveLedger (uint32 seq)
{
boost::recursive_mutex::scoped_lock sl (mLock);
return mCompleteLedgers.hasValue (seq);
}
bool LedgerMaster::getValidatedRange (uint32& minVal, uint32& maxVal)
{
boost::recursive_mutex::scoped_lock sl (mLock);
if (!mValidLedger)
return false;
maxVal = mValidLedger->getLedgerSeq ();
if (maxVal == 0)
return false;
minVal = mCompleteLedgers.prevMissing (maxVal);
if (minVal == RangeSet::absent)
minVal = 0;
else
++minVal;
return true;
}
void LedgerMaster::asyncAccept (Ledger::pointer ledger)
{
uint32 seq = ledger->getLedgerSeq ();
uint256 prevHash = ledger->getParentHash ();
std::map< uint32, std::pair<uint256, uint256> > ledgerHashes;
uint32 minHas = ledger->getLedgerSeq ();
uint32 maxHas = ledger->getLedgerSeq ();
while (seq > 0)
{
{
boost::recursive_mutex::scoped_lock ml (mLock);
minHas = seq;
--seq;
if (mCompleteLedgers.hasValue (seq))
break;
}
std::map< uint32, std::pair<uint256, uint256> >::iterator it = ledgerHashes.find (seq);
if (it == ledgerHashes.end ())
{
if (getApp().isShutdown ())
return;
{
boost::recursive_mutex::scoped_lock ml (mLock);
mCompleteLedgers.setRange (minHas, maxHas);
}
maxHas = minHas;
ledgerHashes = Ledger::getHashesByIndex ((seq < 500) ? 0 : (seq - 499), seq);
it = ledgerHashes.find (seq);
if (it == ledgerHashes.end ())
break;
}
if (it->second.first != prevHash)
break;
prevHash = it->second.second;
}
{
boost::recursive_mutex::scoped_lock ml (mLock);
mCompleteLedgers.setRange (minHas, maxHas);
}
resumeAcquiring ();
}
bool LedgerMaster::acquireMissingLedger (Ledger::ref origLedger, uint256 const& ledgerHash, uint32 ledgerSeq)
{
// return: false = already gave up recently
Ledger::pointer ledger = mLedgerHistory.getLedgerBySeq (ledgerSeq);
if (ledger && (Ledger::getHashByIndex (ledgerSeq) == ledgerHash))
{
WriteLog (lsTRACE, LedgerMaster) << "Ledger hash found in database";
getApp().getJobQueue ().addJob (jtPUBOLDLEDGER, "LedgerMaster::asyncAccept",
BIND_TYPE (&LedgerMaster::asyncAccept, this, ledger));
return true;
}
if (getApp().getInboundLedgers ().isFailure (ledgerHash))
{
WriteLog (lsTRACE, LedgerMaster) << "Already failed to acquire " << ledgerSeq;
return false;
}
mMissingLedger = getApp().getInboundLedgers ().findCreate (ledgerHash, ledgerSeq);
if (mMissingLedger->isComplete ())
{
Ledger::pointer lgr = mMissingLedger->getLedger ();
if (lgr && (lgr->getLedgerSeq () == ledgerSeq))
missingAcquireComplete (mMissingLedger);
mMissingLedger.reset ();
return true;
}
else if (mMissingLedger->isDone ())
{
mMissingLedger.reset ();
return false;
}
mMissingSeq = ledgerSeq;
if (mMissingLedger->setAccept ())
{
if (!mMissingLedger->addOnComplete (BIND_TYPE (&LedgerMaster::missingAcquireComplete, this, P_1)))
getApp().getIOService ().post (BIND_TYPE (&LedgerMaster::missingAcquireComplete, this, mMissingLedger));
}
int fetchMax = theConfig.getSize (siLedgerFetch);
int timeoutCount;
int fetchCount = getApp().getInboundLedgers ().getFetchCount (timeoutCount);
if ((fetchCount < fetchMax) && getApp().getOPs ().isFull ())
{
if (timeoutCount > 2)
{
WriteLog (lsDEBUG, LedgerMaster) << "Not acquiring due to timeouts";
}
else
{
typedef std::pair<uint32, uint256> u_pair;
std::vector<u_pair> vec = origLedger->getLedgerHashes ();
BOOST_REVERSE_FOREACH (const u_pair & it, vec)
{
if ((fetchCount < fetchMax) && (it.first < ledgerSeq) &&
!mCompleteLedgers.hasValue (it.first) && !getApp().getInboundLedgers ().find (it.second))
{
InboundLedger::pointer acq = getApp().getInboundLedgers ().findCreate (it.second, it.first);
if (acq && acq->isComplete ())
{
acq->getLedger ()->setAccepted ();
setFullLedger (acq->getLedger ());
mLedgerHistory.addAcceptedLedger (acq->getLedger (), false);
}
else
++fetchCount;
}
}
}
}
if (getApp().getOPs ().shouldFetchPack (ledgerSeq) && (ledgerSeq > 40000))
{
// refill our fetch pack
Ledger::pointer nextLedger = mLedgerHistory.getLedgerBySeq (ledgerSeq + 1);
if (nextLedger)
{
protocol::TMGetObjectByHash tmBH;
tmBH.set_type (protocol::TMGetObjectByHash::otFETCH_PACK);
tmBH.set_query (true);
tmBH.set_seq (ledgerSeq);
tmBH.set_ledgerhash (ledgerHash.begin (), 32);
std::vector<Peer::pointer> peerList = getApp().getPeers ().getPeerVector ();
Peer::pointer target;
int count = 0;
BOOST_FOREACH (const Peer::pointer & peer, peerList)
{
if (peer->hasRange (ledgerSeq, ledgerSeq + 1))
{
if (count++ == 0)
target = peer;
else if ((rand () % ++count) == 0)
target = peer;
}
}
if (target)
{
PackedMessage::pointer packet = boost::make_shared<PackedMessage> (tmBH, protocol::mtGET_OBJECTS);
target->sendPacket (packet, false);
}
else
WriteLog (lsTRACE, LedgerMaster) << "No peer for fetch pack";
}
}
return true;
}
void LedgerMaster::missingAcquireComplete (InboundLedger::pointer acq)
{
boost::recursive_mutex::scoped_lock ml (mLock);
if (acq->isFailed () && (mMissingSeq != 0))
{
WriteLog (lsWARNING, LedgerMaster) << "Acquire failed for " << mMissingSeq;
}
mMissingLedger.reset ();
mMissingSeq = 0;
if (acq->isComplete ())
{
acq->getLedger ()->setAccepted ();
setFullLedger (acq->getLedger ());
mLedgerHistory.addAcceptedLedger (acq->getLedger (), false);
}
}
bool LedgerMaster::shouldAcquire (uint32 currentLedger, uint32 ledgerHistory, uint32 candidateLedger)
{
bool ret;
if (candidateLedger >= currentLedger)
ret = true;
else ret = (currentLedger - candidateLedger) <= ledgerHistory;
WriteLog (lsTRACE, LedgerMaster) << "Missing ledger " << candidateLedger << (ret ? " should" : " should NOT") << " be acquired";
return ret;
}
void LedgerMaster::resumeAcquiring ()
{
// VFALCO NOTE These returns from the middle are troubling. You might think
// that calling a function called "resumeAcquiring" would
// actually resume acquiring. But it doesn't always resume acquiring,
// based on a myriad of conditions which short circuit the function
// in ways that the caller cannot expect or predict.
//
if (!getApp().getOPs ().isFull ())
return;
boost::recursive_mutex::scoped_lock ml (mLock);
if (mMissingLedger && mMissingLedger->isDone ())
mMissingLedger.reset ();
if (mMissingLedger || !theConfig.LEDGER_HISTORY)
{
CondLog (mMissingLedger, lsDEBUG, LedgerMaster) << "Fetch already in progress, not resuming";
return;
}
uint32 prevMissing = mCompleteLedgers.prevMissing (mFinalizedLedger->getLedgerSeq ());
if (prevMissing == RangeSet::absent)
{
WriteLog (lsDEBUG, LedgerMaster) << "no prior missing ledger, not resuming";
return;
}
if (shouldAcquire (mCurrentLedger->getLedgerSeq (), theConfig.LEDGER_HISTORY, prevMissing))
{
WriteLog (lsTRACE, LedgerMaster) << "Resuming at " << prevMissing;
assert (!mCompleteLedgers.hasValue (prevMissing));
Ledger::pointer nextLedger = getLedgerBySeq (prevMissing + 1);
if (nextLedger)
acquireMissingLedger (nextLedger, nextLedger->getParentHash (), nextLedger->getLedgerSeq () - 1);
else
{
mCompleteLedgers.clearValue (prevMissing);
WriteLog (lsINFO, LedgerMaster) << "We have a gap at: " << prevMissing + 1;
}
}
}
void LedgerMaster::fixMismatch (Ledger::ref ledger)
{
int invalidate = 0;
mMissingLedger.reset ();
mMissingSeq = 0;
for (uint32 lSeq = ledger->getLedgerSeq () - 1; lSeq > 0; --lSeq)
if (mCompleteLedgers.hasValue (lSeq))
{
uint256 hash = ledger->getLedgerHash (lSeq);
if (hash.isNonZero ())
{
// try to close the seam
Ledger::pointer otherLedger = getLedgerBySeq (lSeq);
if (otherLedger && (otherLedger->getHash () == hash))
{
// we closed the seam
CondLog (invalidate != 0, lsWARNING, LedgerMaster) << "Match at " << lSeq << ", " <<
invalidate << " prior ledgers invalidated";
return;
}
}
mCompleteLedgers.clearValue (lSeq);
++invalidate;
}
// all prior ledgers invalidated
CondLog (invalidate != 0, lsWARNING, LedgerMaster) << "All " << invalidate << " prior ledgers invalidated";
}
void LedgerMaster::setFullLedger (Ledger::pointer ledger)
{
// A new ledger has been accepted as part of the trusted chain
WriteLog (lsDEBUG, LedgerMaster) << "Ledger " << ledger->getLedgerSeq () << " accepted :" << ledger->getHash ();
assert (ledger->peekAccountStateMap ()->getHash ().isNonZero ());
if (getApp().getOPs ().isNeedNetworkLedger ())
return;
boost::recursive_mutex::scoped_lock ml (mLock);
mCompleteLedgers.setValue (ledger->getLedgerSeq ());
if (Ledger::getHashByIndex (ledger->getLedgerSeq ()) != ledger->getHash ())
{
ledger->pendSave (false);
return;
}
if ((ledger->getLedgerSeq () != 0) && mCompleteLedgers.hasValue (ledger->getLedgerSeq () - 1))
{
// we think we have the previous ledger, double check
Ledger::pointer prevLedger = getLedgerBySeq (ledger->getLedgerSeq () - 1);
if (!prevLedger || (prevLedger->getHash () != ledger->getParentHash ()))
{
WriteLog (lsWARNING, LedgerMaster) << "Acquired ledger invalidates previous ledger: " <<
(prevLedger ? "hashMismatch" : "missingLedger");
fixMismatch (ledger);
}
}
if (mMissingLedger && mMissingLedger->isDone ())
{
if (mMissingLedger->isFailed ())
getApp().getInboundLedgers ().dropLedger (mMissingLedger->getHash ());
mMissingLedger.reset ();
}
if (mMissingLedger || !theConfig.LEDGER_HISTORY)
{
CondLog (mMissingLedger, lsDEBUG, LedgerMaster) << "Fetch already in progress, " << mMissingLedger->getTimeouts () << " timeouts";
return;
}
if (getApp().getJobQueue ().getJobCountTotal (jtPUBOLDLEDGER) > 1)
{
WriteLog (lsDEBUG, LedgerMaster) << "Too many pending ledger saves";
return;
}
// see if there's a ledger gap we need to fill
if (!mCompleteLedgers.hasValue (ledger->getLedgerSeq () - 1))
{
if (!shouldAcquire (mCurrentLedger->getLedgerSeq (), theConfig.LEDGER_HISTORY, ledger->getLedgerSeq () - 1))
{
WriteLog (lsTRACE, LedgerMaster) << "Don't need any ledgers";
return;
}
WriteLog (lsDEBUG, LedgerMaster) << "We need the ledger before the ledger we just accepted: " << ledger->getLedgerSeq () - 1;
acquireMissingLedger (ledger, ledger->getParentHash (), ledger->getLedgerSeq () - 1);
}
else
{
uint32 prevMissing = mCompleteLedgers.prevMissing (ledger->getLedgerSeq ());
if (prevMissing == RangeSet::absent)
{
WriteLog (lsDEBUG, LedgerMaster) << "no prior missing ledger";
return;
}
if (shouldAcquire (mCurrentLedger->getLedgerSeq (), theConfig.LEDGER_HISTORY, prevMissing))
{
WriteLog (lsDEBUG, LedgerMaster) << "Ledger " << prevMissing << " is needed";
assert (!mCompleteLedgers.hasValue (prevMissing));
Ledger::pointer nextLedger = getLedgerBySeq (prevMissing + 1);
if (nextLedger)
acquireMissingLedger (ledger, nextLedger->getParentHash (), nextLedger->getLedgerSeq () - 1);
else
{
mCompleteLedgers.clearValue (prevMissing);
WriteLog (lsWARNING, LedgerMaster) << "We have a gap we can't fix: " << prevMissing + 1;
}
}
else
WriteLog (lsTRACE, LedgerMaster) << "Shouldn't acquire";
}
}
void LedgerMaster::checkAccept (uint256 const& hash)
{
Ledger::pointer ledger = mLedgerHistory.getLedgerByHash (hash);
if (ledger)
checkAccept (hash, ledger->getLedgerSeq ());
}
void LedgerMaster::checkAccept (uint256 const& hash, uint32 seq)
{
// Can we advance the last fully accepted ledger? If so, can we publish?
boost::recursive_mutex::scoped_lock ml (mLock);
if (mValidLedger && (seq <= mValidLedger->getLedgerSeq ()))
return;
int minVal = mMinValidations;
if (mLastValidateHash.isNonZero ())
{
int val = getApp().getValidations ().getTrustedValidationCount (mLastValidateHash);
val *= MIN_VALIDATION_RATIO;
val /= 256;
if (val > minVal)
minVal = val;
}
if (theConfig.RUN_STANDALONE)
minVal = 0;
else if (getApp().getOPs ().isNeedNetworkLedger ())
minVal = 1;
if (getApp().getValidations ().getTrustedValidationCount (hash) < minVal) // nothing we can do
return;
WriteLog (lsINFO, LedgerMaster) << "Advancing accepted ledger to " << seq << " with >= " << minVal << " validations";
mLastValidateHash = hash;
mLastValidateSeq = seq;
Ledger::pointer ledger = mLedgerHistory.getLedgerByHash (hash);
if (!ledger)
{
getApp().getInboundLedgers ().findCreate (hash, seq);
return;
}
mValidLedger = ledger;
uint64 fee, fee2, ref;
ref = getApp().getFeeTrack().getLoadBase();
int count = getApp().getValidations().getFeeAverage(ledger->getHash(), ref, fee);
int count2 = getApp().getValidations().getFeeAverage(ledger->getParentHash(), ref, fee2);
if ((count + count2) == 0)
getApp().getFeeTrack().setRemoteFee(ref);
else
getApp().getFeeTrack().setRemoteFee(((fee * count) + (fee2 * count2)) / (count + count2));
tryPublish ();
}
void LedgerMaster::tryPublish ()
{
boost::recursive_mutex::scoped_lock ml (mLock);
assert (mValidLedger);
if (!mPubLedger)
{
mPubLedger = mValidLedger;
mPubLedgers.push_back (mValidLedger);
}
else if (mValidLedger->getLedgerSeq () > (mPubLedger->getLedgerSeq () + MAX_LEDGER_GAP))
{
WriteLog (lsWARNING, LedgerMaster) << "Gap in validated ledger stream " << mPubLedger->getLedgerSeq () << " - " <<
mValidLedger->getLedgerSeq () - 1;
mPubLedger = mValidLedger;
mPubLedgers.push_back (mValidLedger);
}
else if (mValidLedger->getLedgerSeq () > mPubLedger->getLedgerSeq ())
{
int acq = 0;
for (uint32 seq = mPubLedger->getLedgerSeq () + 1; seq <= mValidLedger->getLedgerSeq (); ++seq)
{
WriteLog (lsTRACE, LedgerMaster) << "Trying to publish ledger " << seq;
Ledger::pointer ledger;
uint256 hash;
if (seq == mValidLedger->getLedgerSeq ())
{ // We need to publish the ledger we just fully validated
ledger = mValidLedger;
hash = ledger->getHash ();
}
else
{
hash = mValidLedger->getLedgerHash (seq);
if (hash.isZero ())
{
WriteLog (lsFATAL, LedgerMaster) << "Ledger: " << mValidLedger->getLedgerSeq () << " does not have hash for " <<
seq;
assert (false);
}
ledger = mLedgerHistory.getLedgerByHash (hash);
}
if (!ledger && (++acq < 4))
{ // We can try to acquire the ledger we need
InboundLedger::pointer acq = getApp().getInboundLedgers ().findCreate (hash, seq);
if (!acq->isDone ())
{
acq->setAccept ();
}
else if (acq->isComplete () && !acq->isFailed ())
{
ledger = acq->getLedger();
}
else
{
WriteLog (lsWARNING, LedgerMaster) << "Failed to acquire a published ledger";
getApp().getInboundLedgers().dropLedger(hash);
acq = getApp().getInboundLedgers().findCreate(hash, seq);
acq->setAccept();
if (acq->isDone())
ledger = acq->getLedger();
}
}
if (ledger && (ledger->getLedgerSeq() == (mPubLedger->getLedgerSeq() + 1)))
{ // We acquired the next ledger we need to publish
mPubLedger = ledger;
mPubLedgers.push_back (mPubLedger);
}
}
}
if (!mPubLedgers.empty () && !mPubThread)
{
getApp().getOPs ().clearNeedNetworkLedger ();
mPubThread = true;
getApp().getJobQueue ().addJob (jtPUBLEDGER, "Ledger::pubThread",
BIND_TYPE (&LedgerMaster::pubThread, this));
mPathFindNewLedger = true;
if (!mPathFindThread)
{
mPathFindThread = true;
getApp().getJobQueue ().addJob (jtUPDATE_PF, "updatePaths",
BIND_TYPE (&LedgerMaster::updatePaths, this));
}
}
}
void LedgerMaster::pubThread ()
{
std::list<Ledger::pointer> ledgers;
bool published = false;
while (1)
{
ledgers.clear ();
{
boost::recursive_mutex::scoped_lock ml (mLock);
mPubLedgers.swap (ledgers);
if (ledgers.empty ())
{
mPubThread = false;
if (published && !mPathFindThread)
{
mPathFindThread = true;
getApp().getJobQueue ().addJob (jtUPDATE_PF, "updatePaths",
BIND_TYPE (&LedgerMaster::updatePaths, this));
}
return;
}
}
BOOST_FOREACH (Ledger::ref l, ledgers)
{
WriteLog (lsDEBUG, LedgerMaster) << "Publishing ledger " << l->getLedgerSeq ();
setFullLedger (l); // OPTIMIZEME: This is actually more work than we need to do
getApp().getOPs ().pubLedger (l);
published = true;
}
}
}
void LedgerMaster::updatePaths ()
{
Ledger::pointer lastLedger;
do
{
bool newOnly = false;
{
boost::recursive_mutex::scoped_lock ml (mLock);
if (mPathFindNewLedger || (lastLedger && (lastLedger.get () != mPubLedger.get ())))
lastLedger = mPubLedger;
else if (mPathFindNewRequest)
{
newOnly = true;
lastLedger = boost::make_shared<Ledger> (boost::ref (*mCurrentLedger), false);
}
else
{
mPathFindThread = false;
return;
}
lastLedger = mPubLedger;
mPathFindNewLedger = false;
mPathFindNewRequest = false;
}
// VFALCO TODO Fix this global variable
PathRequest::updateAll (lastLedger, newOnly);
}
while (1);
}
void LedgerMaster::newPathRequest ()
{
boost::recursive_mutex::scoped_lock ml (mLock);
mPathFindNewRequest = true;
if (!mPathFindThread)
{
mPathFindThread = true;
getApp().getJobQueue ().addJob (jtUPDATE_PF, "updatePaths",
BIND_TYPE (&LedgerMaster::updatePaths, this));
}
}
// vim:ts=4

View File

@@ -1,230 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LEDGERMASTER_H
#define RIPPLE_LEDGERMASTER_H
// Tracks the current ledger and any ledgers in the process of closing
// Tracks ledger history
// Tracks held transactions
// VFALCO TODO Rename to Ledgers
// It sounds like this holds all the ledgers...
//
class LedgerMaster : LeakChecked <LedgerMaster>
{
public:
typedef FUNCTION_TYPE <void (Ledger::ref)> callback;
public:
LedgerMaster ()
: mHeldTransactions (uint256 ())
, mMissingSeq (0)
, mMinValidations (0)
, mLastValidateSeq (0)
, mPubThread (false)
, mPathFindThread (false)
, mPathFindNewLedger (false)
, mPathFindNewRequest (false)
{
}
~LedgerMaster ()
{
}
uint32 getCurrentLedgerIndex ();
ScopedLock getLock ()
{
return ScopedLock (mLock);
}
// The current ledger is the ledger we believe new transactions should go in
Ledger::ref getCurrentLedger ()
{
return mCurrentLedger;
}
// An immutable snapshot of the current ledger
Ledger::ref getCurrentSnapshot ();
// The finalized ledger is the last closed/accepted ledger
Ledger::ref getClosedLedger ()
{
return mFinalizedLedger;
}
// The validated ledger is the last fully validated ledger
Ledger::ref getValidatedLedger ()
{
return mValidLedger;
}
// This is the last ledger we published to clients and can lag the validated ledger
Ledger::ref getPublishedLedger ()
{
return mPubLedger;
}
int getPublishedLedgerAge ();
int getValidatedLedgerAge ();
bool isCaughtUp(std::string& reason);
TER doTransaction (SerializedTransaction::ref txn, TransactionEngineParams params, bool& didApply);
int getMinValidations ()
{
return mMinValidations;
}
void setMinValidations (int v)
{
mMinValidations = v;
}
void pushLedger (Ledger::pointer newLedger);
void pushLedger (Ledger::pointer newLCL, Ledger::pointer newOL, bool fromConsensus);
void storeLedger (Ledger::pointer);
void setFullLedger (Ledger::pointer ledger);
void switchLedgers (Ledger::pointer lastClosed, Ledger::pointer newCurrent);
std::string getCompleteLedgers ()
{
boost::recursive_mutex::scoped_lock sl (mLock);
return mCompleteLedgers.toString ();
}
Ledger::pointer closeLedger (bool recoverHeldTransactions);
uint256 getHashBySeq (uint32 index)
{
uint256 hash = mLedgerHistory.getLedgerHash (index);
if (hash.isNonZero ())
return hash;
return Ledger::getHashByIndex (index);
}
Ledger::pointer getLedgerBySeq (uint32 index)
{
if (mCurrentLedger && (mCurrentLedger->getLedgerSeq () == index))
return mCurrentLedger;
if (mFinalizedLedger && (mFinalizedLedger->getLedgerSeq () == index))
return mFinalizedLedger;
Ledger::pointer ret = mLedgerHistory.getLedgerBySeq (index);
if (ret)
return ret;
boost::recursive_mutex::scoped_lock ml (mLock);
mCompleteLedgers.clearValue (index);
return ret;
}
Ledger::pointer getLedgerByHash (uint256 const& hash)
{
if (hash.isZero ())
return boost::make_shared<Ledger> (boost::ref (*mCurrentLedger), false);
if (mCurrentLedger && (mCurrentLedger->getHash () == hash))
return boost::make_shared<Ledger> (boost::ref (*mCurrentLedger), false);
if (mFinalizedLedger && (mFinalizedLedger->getHash () == hash))
return mFinalizedLedger;
return mLedgerHistory.getLedgerByHash (hash);
}
void setLedgerRangePresent (uint32 minV, uint32 maxV)
{
boost::recursive_mutex::scoped_lock sl (mLock);
mCompleteLedgers.setRange (minV, maxV);
}
void addHeldTransaction (Transaction::ref trans);
void fixMismatch (Ledger::ref ledger);
bool haveLedgerRange (uint32 from, uint32 to);
bool haveLedger (uint32 seq);
bool getValidatedRange (uint32& minVal, uint32& maxVal);
void resumeAcquiring ();
void tune (int size, int age)
{
mLedgerHistory.tune (size, age);
}
void sweep ()
{
mLedgerHistory.sweep ();
}
float getCacheHitRate ()
{
return mLedgerHistory.getCacheHitRate ();
}
void addValidateCallback (callback& c)
{
mOnValidate.push_back (c);
}
void checkAccept (uint256 const& hash);
void checkAccept (uint256 const& hash, uint32 seq);
void tryPublish ();
void newPathRequest ();
static bool shouldAcquire (uint32 currentLedgerID, uint32 ledgerHistory, uint32 targetLedger);
private:
void applyFutureTransactions (uint32 ledgerIndex);
bool isValidTransaction (Transaction::ref trans);
bool isTransactionOnFutureList (Transaction::ref trans);
bool acquireMissingLedger (Ledger::ref from, uint256 const& ledgerHash, uint32 ledgerSeq);
void asyncAccept (Ledger::pointer);
void missingAcquireComplete (InboundLedger::pointer);
void pubThread ();
void updatePaths ();
private:
boost::recursive_mutex mLock;
TransactionEngine mEngine;
Ledger::pointer mCurrentLedger; // The ledger we are currently processiong
Ledger::pointer mCurrentSnapshot; // Snapshot of the current ledger
Ledger::pointer mFinalizedLedger; // The ledger that most recently closed
Ledger::pointer mValidLedger; // The highest-sequence ledger we have fully accepted
Ledger::pointer mPubLedger; // The last ledger we have published
LedgerHistory mLedgerHistory;
CanonicalTXSet mHeldTransactions;
RangeSet mCompleteLedgers;
InboundLedger::pointer mMissingLedger;
uint32 mMissingSeq;
int mMinValidations; // The minimum validations to publish a ledger
uint256 mLastValidateHash;
uint32 mLastValidateSeq;
std::list<callback> mOnValidate; // Called when a ledger has enough validations
std::list<Ledger::pointer> mPubLedgers; // List of ledgers to publish
bool mPubThread; // Publish thread is running
bool mPathFindThread; // Pathfind thread is running
bool mPathFindNewLedger;
bool mPathFindNewRequest;
};
#endif
// vim:ts=4

View File

@@ -1,103 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
LedgerProposal::LedgerProposal (uint256 const& pLgr, uint32 seq, uint256 const& tx, uint32 closeTime,
const RippleAddress& naPeerPublic, uint256 const& suppression) :
mPreviousLedger (pLgr), mCurrentHash (tx), mSuppression (suppression), mCloseTime (closeTime),
mProposeSeq (seq), mPublicKey (naPeerPublic)
{
// XXX Validate key.
// if (!mKey->SetPubKey(pubKey))
// throw std::runtime_error("Invalid public key in proposal");
mPeerID = mPublicKey.getNodeID ();
mTime = boost::posix_time::second_clock::universal_time ();
}
LedgerProposal::LedgerProposal (const RippleAddress& naPub, const RippleAddress& naPriv,
uint256 const& prevLgr, uint256 const& position, uint32 closeTime) :
mPreviousLedger (prevLgr), mCurrentHash (position), mCloseTime (closeTime), mProposeSeq (0),
mPublicKey (naPub), mPrivateKey (naPriv)
{
mPeerID = mPublicKey.getNodeID ();
mTime = boost::posix_time::second_clock::universal_time ();
}
LedgerProposal::LedgerProposal (uint256 const& prevLgr, uint256 const& position, uint32 closeTime) :
mPreviousLedger (prevLgr), mCurrentHash (position), mCloseTime (closeTime), mProposeSeq (0)
{
mTime = boost::posix_time::second_clock::universal_time ();
}
uint256 LedgerProposal::getSigningHash () const
{
Serializer s ((32 + 32 + 32 + 256 + 256) / 8);
s.add32 (theConfig.SIGN_PROPOSAL);
s.add32 (mProposeSeq);
s.add32 (mCloseTime);
s.add256 (mPreviousLedger);
s.add256 (mCurrentHash);
return s.getSHA512Half ();
}
bool LedgerProposal::checkSign (const std::string& signature, uint256 const& signingHash)
{
return mPublicKey.verifyNodePublic (signingHash, signature);
}
bool LedgerProposal::changePosition (uint256 const& newPosition, uint32 closeTime)
{
if (mProposeSeq == seqLeave)
return false;
mCurrentHash = newPosition;
mCloseTime = closeTime;
mTime = boost::posix_time::second_clock::universal_time ();
++mProposeSeq;
return true;
}
void LedgerProposal::bowOut ()
{
mTime = boost::posix_time::second_clock::universal_time ();
mProposeSeq = seqLeave;
}
Blob LedgerProposal::sign (void)
{
Blob ret;
mPrivateKey.signNodePrivate (getSigningHash (), ret);
// XXX If this can fail, find out sooner.
// if (!mPrivateKey.signNodePrivate(getSigningHash(), ret))
// throw std::runtime_error("unable to sign proposal");
return ret;
}
Json::Value LedgerProposal::getJson () const
{
Json::Value ret = Json::objectValue;
ret["previous_ledger"] = mPreviousLedger.GetHex ();
if (mProposeSeq != seqLeave)
{
ret["transaction_hash"] = mCurrentHash.GetHex ();
ret["propose_seq"] = mProposeSeq;
}
ret["close_time"] = mCloseTime;
if (mPublicKey.isValid ())
ret["peer_id"] = mPublicKey.humanNodePublic ();
return ret;
}
// vim:ts=4

View File

@@ -1,125 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef __PROPOSELEDGER__
#define __PROPOSELEDGER__
class LedgerProposal
: public CountedObject <LedgerProposal>
{
public:
static char const* getCountedObjectName () { return "LedgerProposal"; }
static const uint32 seqLeave = 0xffffffff; // leaving the consensus process
typedef boost::shared_ptr<LedgerProposal> pointer;
typedef const pointer& ref;
// proposal from peer
LedgerProposal (uint256 const & prevLgr, uint32 proposeSeq, uint256 const & propose,
uint32 closeTime, const RippleAddress & naPeerPublic, uint256 const & suppress);
// our first proposal
LedgerProposal (const RippleAddress & pubKey, const RippleAddress & privKey,
uint256 const & prevLedger, uint256 const & position, uint32 closeTime);
// an unsigned "dummy" proposal for nodes not validating
LedgerProposal (uint256 const & prevLedger, uint256 const & position, uint32 closeTime);
uint256 getSigningHash () const;
bool checkSign (const std::string & signature, uint256 const & signingHash);
bool checkSign (const std::string & signature)
{
return checkSign (signature, getSigningHash ());
}
bool checkSign ()
{
return checkSign (mSignature, getSigningHash ());
}
const uint160& getPeerID () const
{
return mPeerID;
}
uint256 const& getCurrentHash () const
{
return mCurrentHash;
}
uint256 const& getPrevLedger () const
{
return mPreviousLedger;
}
uint256 const& getHashRouter () const
{
return mSuppression;
}
uint32 getProposeSeq () const
{
return mProposeSeq;
}
uint32 getCloseTime () const
{
return mCloseTime;
}
const RippleAddress& peekPublic () const
{
return mPublicKey;
}
Blob getPubKey () const
{
return mPublicKey.getNodePublic ();
}
Blob sign ();
void setPrevLedger (uint256 const & prevLedger)
{
mPreviousLedger = prevLedger;
}
void setSignature (const std::string & signature)
{
mSignature = signature;
}
bool hasSignature ()
{
return !mSignature.empty ();
}
bool isPrevLedger (uint256 const & pl)
{
return mPreviousLedger == pl;
}
bool isBowOut ()
{
return mProposeSeq == seqLeave;
}
const boost::posix_time::ptime getCreateTime ()
{
return mTime;
}
bool isStale (boost::posix_time::ptime cutoff)
{
return mTime <= cutoff;
}
bool changePosition (uint256 const & newPosition, uint32 newCloseTime);
void bowOut ();
Json::Value getJson () const;
private:
uint256 mPreviousLedger, mCurrentHash, mSuppression;
uint32 mCloseTime, mProposeSeq;
uint160 mPeerID;
RippleAddress mPublicKey;
RippleAddress mPrivateKey; // If ours
std::string mSignature; // set only if needed
boost::posix_time::ptime mTime;
};
#endif
// vim:ts=4

View File

@@ -1,156 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// VFALCO Should rename ContinuousLedgerTiming to LedgerTiming
struct LedgerTiming; // for Log
SETUP_LOG (LedgerTiming)
// NOTE: First and last times must be repeated
int ContinuousLedgerTiming::LedgerTimeResolution[] = { 10, 10, 20, 30, 60, 90, 120, 120 };
// Called when a ledger is open and no close is in progress -- when a transaction is received and no close
// is in process, or when a close completes. Returns the number of seconds the ledger should be be open.
bool ContinuousLedgerTiming::shouldClose (
bool anyTransactions,
int previousProposers, // proposers in the last closing
int proposersClosed, // proposers who have currently closed this ledgers
int proposersValidated, // proposers who have validated the last closed ledger
int previousMSeconds, // milliseconds the previous ledger took to reach consensus
int currentMSeconds, // milliseconds since the previous ledger closed
int openMSeconds, // milliseconds since the previous LCL was computed
int idleInterval) // network's desired idle interval
{
if ((previousMSeconds < -1000) || (previousMSeconds > 600000) ||
(currentMSeconds < -1000) || (currentMSeconds > 600000))
{
WriteLog (lsWARNING, LedgerTiming) <<
boost::str (boost::format ("CLC::shouldClose range Trans=%s, Prop: %d/%d, Secs: %d (last:%d)")
% (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed
% currentMSeconds % previousMSeconds);
return true;
}
if (!anyTransactions)
{
// no transactions so far this interval
if (proposersClosed > (previousProposers / 4)) // did we miss a transaction?
{
WriteLog (lsTRACE, LedgerTiming) << "no transactions, many proposers: now (" << proposersClosed << " closed, "
<< previousProposers << " before)";
return true;
}
#if 0 // This false triggers on the genesis ledger
if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close
{
WriteLog (lsTRACE, LedgerTiming) << "was slow to converge (p=" << (previousMSeconds) << ")";
if (previousMSeconds < 2000)
return previousMSeconds;
return previousMSeconds - 1000;
}
#endif
return currentMSeconds >= (idleInterval * 1000); // normal idle
}
if ((openMSeconds < LEDGER_MIN_CLOSE) && ((proposersClosed + proposersValidated) < (previousProposers / 2 )))
{
WriteLog (lsDEBUG, LedgerTiming) << "Must wait minimum time before closing";
return false;
}
if ((currentMSeconds < previousMSeconds) && ((proposersClosed + proposersValidated) < previousProposers))
{
WriteLog (lsDEBUG, LedgerTiming) << "We are waiting for more closes/validations";
return false;
}
return true; // this ledger should close now
}
// Returns whether we have a consensus or not. If so, we expect all honest nodes
// to already have everything they need to accept a consensus. Our vote is 'locked in'.
bool ContinuousLedgerTiming::haveConsensus (
int previousProposers, // proposers in the last closing (not including us)
int currentProposers, // proposers in this closing so far (not including us)
int currentAgree, // proposers who agree with us
int currentFinished, // proposers who have validated a ledger after this one
int previousAgreeTime, // how long it took to agree on the last ledger
int currentAgreeTime, // how long we've been trying to agree
bool forReal, // deciding whether to stop consensus process
bool& failed) // we can't reach a consensus
{
WriteLog (lsTRACE, LedgerTiming) << boost::str (boost::format ("CLC::haveConsensus: prop=%d/%d agree=%d validated=%d time=%d/%d%s") %
currentProposers % previousProposers % currentAgree % currentFinished % currentAgreeTime % previousAgreeTime %
(forReal ? "" : "X"));
if (currentAgreeTime <= LEDGER_MIN_CONSENSUS)
return false;
if (currentProposers < (previousProposers * 3 / 4))
{
// Less than 3/4 of the last ledger's proposers are present, we may need more time
if (currentAgreeTime < (previousAgreeTime + LEDGER_MIN_CONSENSUS))
{
CondLog (forReal, lsTRACE, LedgerTiming) << "too fast, not enough proposers";
return false;
}
}
// If 80% of current proposers (plus us) agree on a set, we have consensus
if (((currentAgree * 100 + 100) / (currentProposers + 1)) > 80)
{
CondLog (forReal, lsINFO, LedgerTiming) << "normal consensus";
failed = false;
return true;
}
// If 80% of the nodes on your UNL have moved on, you should declare consensus
if (((currentFinished * 100) / (currentProposers + 1)) > 80)
{
CondLog (forReal, lsWARNING, LedgerTiming) << "We see no consensus, but 80% of nodes have moved on";
failed = true;
return true;
}
// no consensus yet
CondLog (forReal, lsTRACE, LedgerTiming) << "no consensus";
return false;
}
int ContinuousLedgerTiming::getNextLedgerTimeResolution (int previousResolution, bool previousAgree, int ledgerSeq)
{
assert (ledgerSeq);
if ((!previousAgree) && ((ledgerSeq % LEDGER_RES_DECREASE) == 0))
{
// reduce resolution
int i = 1;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i + 1];
}
if ((previousAgree) && ((ledgerSeq % LEDGER_RES_INCREASE) == 0))
{
// increase resolution
int i = 1;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i - 1];
}
return previousResolution;
}

View File

@@ -1,87 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef __LEDGERTIMING__
#define __LEDGERTIMING__
// The number of seconds a ledger may remain idle before closing
# define LEDGER_IDLE_INTERVAL 15
// The number of seconds a validation remains current after its ledger's close time
// This is a safety to protect against very old validations and the time it takes to adjust
// the close time accuracy window
# define LEDGER_VAL_INTERVAL 300
// The number of seconds before a close time that we consider a validation acceptable
// This protects against extreme clock errors
# define LEDGER_EARLY_INTERVAL 180
// The number of milliseconds we wait minimum to ensure participation
# define LEDGER_MIN_CONSENSUS 2000
// The number of milliseconds we wait minimum to ensure others have computed the LCL
# define LEDGER_MIN_CLOSE 2000
// Initial resolution of ledger close time
# define LEDGER_TIME_ACCURACY 30
// How often to increase resolution
# define LEDGER_RES_INCREASE 8
// How often to decrease resolution
# define LEDGER_RES_DECREASE 1
// How often we check state or change positions (in milliseconds)
# define LEDGER_GRANULARITY 1000
// The percentage of active trusted validators that must be able to
// keep up with the network or we consider the network overloaded
# define LEDGER_NET_RATIO 70
// How long we consider a proposal fresh
# define PROPOSE_FRESHNESS 20
// How often we force generating a new proposal to keep ours fresh
# define PROPOSE_INTERVAL 12
// Avalanche tuning
# define AV_INIT_CONSENSUS_PCT 50 // percentage of nodes on our UNL that must vote yes
# define AV_MID_CONSENSUS_TIME 50 // percentage of previous close time before we advance
# define AV_MID_CONSENSUS_PCT 65 // percentage of nodes that most vote yes after advancing
# define AV_LATE_CONSENSUS_TIME 85 // percentage of previous close time before we advance
# define AV_LATE_CONSENSUS_PCT 70 // percentage of nodes that most vote yes after advancing
# define AV_STUCK_CONSENSUS_TIME 200
# define AV_STUCK_CONSENSUS_PCT 95
# define AV_CT_CONSENSUS_PCT 75
class ContinuousLedgerTiming
{
public:
static int LedgerTimeResolution[];
// Returns the number of seconds the ledger was or should be open
// Call when a consensus is reached and when any transaction is relayed to be added
static bool shouldClose (
bool anyTransactions,
int previousProposers, int proposersClosed, int proposerersValidated,
int previousMSeconds, int currentMSeconds, int openMSeconds,
int idleInterval);
static bool haveConsensus (
int previousProposers, int currentProposers,
int currentAgree, int currentClosed,
int previousAgreeTime, int currentAgreeTime,
bool forReal, bool& failed);
static int getNextLedgerTimeResolution (int previousResolution, bool previousAgree, int ledgerSeq);
};
#endif

View File

@@ -1,19 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
BOOST_AUTO_TEST_SUITE (quality)
BOOST_AUTO_TEST_CASE ( getquality )
{
using namespace ripple;
uint256 uBig ("D2DC44E5DC189318DB36EF87D2104CDF0A0FE3A4B698BEEE55038D7EA4C68000");
if (6125895493223874560 != Ledger::getQuality (uBig))
BOOST_FAIL ("Ledger::getQuality fails.");
}
BOOST_AUTO_TEST_SUITE_END ()

View File

@@ -1,21 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
/*
We also need to charge for each op
*/
namespace Script
{
int Operation::getFee ()
{
return (theConfig.FEE_CONTRACT_OPERATION);
}
}

View File

@@ -1,367 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef OPERATION_H
#define OPERATION_H
namespace Script
{
// Contracts are non typed have variable data types
class Operation
{
public:
// returns false if there was an error
virtual bool work (Interpreter* interpreter) = 0;
virtual int getFee ();
virtual ~Operation ()
{
;
}
};
// this is just an Int in the code
class IntOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->getIntData ();
if (data->isInt32 ())
{
interpreter->pushStack ( data );
return (true);
}
return (false);
}
};
class FloatOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->getFloatData ();
if (data->isFloat ())
{
interpreter->pushStack ( data );
return (true);
}
return (false);
}
};
class Uint160Op : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->getUint160Data ();
if (data->isUint160 ())
{
interpreter->pushStack ( data );
return (true);
}
return (false);
}
};
class AddOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () + data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt () + data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class SubOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () - data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt () - data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class MulOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat ()*data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt ()*data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class DivOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
if (data1->isFloat () || data2->isFloat ()) interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () / data2->getFloat ())));
else interpreter->pushStack (Data::pointer (new IntData (data1->getInt () / data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class GtrOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
interpreter->pushStack (Data::pointer (new BoolData (data1->getFloat () > data2->getFloat ())));
return (true);
}
else
{
return (false);
}
}
};
class LessOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( (data1->isInt32 () || data1->isFloat ()) &&
(data2->isInt32 () || data2->isFloat ()) )
{
interpreter->pushStack (Data::pointer (new FloatData (data1->getFloat () < data2->getFloat ())));
return (true);
}
else
{
return (false);
}
}
};
class ModOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data1 = interpreter->popStack ();
Data::pointer data2 = interpreter->popStack ();
if ( data1->isInt32 () && data2->isInt32 () )
{
interpreter->pushStack (Data::pointer (new IntData (data1->getInt () % data2->getInt ())));
return (true);
}
else
{
return (false);
}
}
};
class StartBlockOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer offset = interpreter->getIntData ();
return (interpreter->startBlock (offset->getInt ()));
}
};
class EndBlockOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
return (interpreter->endBlock ());
}
};
class StopOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
interpreter->stop ();
return (true);
}
};
class AcceptDataOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer data = interpreter->popStack ();
if (data->isInt32 ())
{
interpreter->pushStack ( interpreter->getAcceptData (data->getInt ()) );
return (true);
}
return (false);
}
};
class JumpIfOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer offset = interpreter->getIntData ();
Data::pointer cond = interpreter->popStack ();
if (cond->isBool () && offset->isInt32 ())
{
if (cond->isTrue ())
{
return (interpreter->jumpTo (offset->getInt ()));
}
return (true);
}
return (false);
}
};
class JumpOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer offset = interpreter->getIntData ();
if (offset->isInt32 ())
{
return (interpreter->jumpTo (offset->getInt ()));
}
return (false);
}
};
class SendXRPOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer sourceID = interpreter->popStack ();
Data::pointer destID = interpreter->popStack ();
Data::pointer amount = interpreter->popStack ();
if (sourceID->isUint160 () && destID->isUint160 () && amount->isInt32 () && interpreter->canSign (sourceID->getUint160 ()))
{
// make sure:
// source is either, this contract, issuer, or acceptor
// TODO do the send
//interpreter->pushStack( send result);
return (true);
}
return (false);
}
};
class GetDataOp : public Operation
{
public:
bool work (Interpreter* interpreter)
{
Data::pointer index = interpreter->popStack ();
if (index->isInt32 ())
{
interpreter->pushStack ( interpreter->getContractData (index->getInt ()));
return (true);
}
return (false);
}
};
}
#endif
// vim:ts=4

View File

@@ -1,243 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
SETUP_LOG (OrderBookDB)
OrderBookDB::OrderBookDB () : mSeq (0)
{
}
void OrderBookDB::invalidate ()
{
boost::recursive_mutex::scoped_lock sl (mLock);
mSeq = 0;
}
void OrderBookDB::setup (Ledger::ref ledger)
{
boost::unordered_set<uint256> mSeen;
boost::recursive_mutex::scoped_lock sl (mLock);
if (ledger->getLedgerSeq () == mSeq)
return;
mSeq = ledger->getLedgerSeq ();
LoadEvent::autoptr ev = getApp().getJobQueue ().getLoadEventAP (jtOB_SETUP, "OrderBookDB::setup");
mDestMap.clear ();
mSourceMap.clear ();
WriteLog (lsDEBUG, OrderBookDB) << "OrderBookDB>";
// walk through the entire ledger looking for orderbook entries
uint256 currentIndex = ledger->getFirstLedgerIndex ();
while (currentIndex.isNonZero ())
{
SLE::pointer entry = ledger->getSLEi (currentIndex);
if ((entry->getType () == ltDIR_NODE) && (entry->isFieldPresent (sfExchangeRate)) &&
(entry->getFieldH256 (sfRootIndex) == currentIndex))
{
const uint160& ci = entry->getFieldH160 (sfTakerPaysCurrency);
const uint160& co = entry->getFieldH160 (sfTakerGetsCurrency);
const uint160& ii = entry->getFieldH160 (sfTakerPaysIssuer);
const uint160& io = entry->getFieldH160 (sfTakerGetsIssuer);
uint256 index = Ledger::getBookBase (ci, ii, co, io);
if (mSeen.insert (index).second)
{
// VFALCO TODO Reduce the clunkiness of these parameter wrappers
OrderBook::pointer book = boost::make_shared<OrderBook> (boost::cref (index),
boost::cref (ci), boost::cref (co), boost::cref (ii), boost::cref (io));
mSourceMap[currencyIssuer_ct (ci, ii)].push_back (book);
mDestMap[currencyIssuer_ct (co, io)].push_back (book);
}
}
currentIndex = ledger->getNextLedgerIndex (currentIndex);
}
WriteLog (lsDEBUG, OrderBookDB) << "OrderBookDB<";
}
// return list of all orderbooks that want this issuerID and currencyID
void OrderBookDB::getBooksByTakerPays (const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet)
{
boost::recursive_mutex::scoped_lock sl (mLock);
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> >::const_iterator
it = mSourceMap.find (currencyIssuer_ct (currencyID, issuerID));
if (it != mSourceMap.end ())
bookRet = it->second;
else
bookRet.clear ();
}
// return list of all orderbooks that give this issuerID and currencyID
void OrderBookDB::getBooksByTakerGets (const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet)
{
boost::recursive_mutex::scoped_lock sl (mLock);
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> >::const_iterator
it = mDestMap.find (currencyIssuer_ct (currencyID, issuerID));
if (it != mDestMap.end ())
bookRet = it->second;
else
bookRet.clear ();
}
BookListeners::pointer OrderBookDB::makeBookListeners (const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets)
{
boost::recursive_mutex::scoped_lock sl (mLock);
BookListeners::pointer ret = getBookListeners (currencyPays, currencyGets, issuerPays, issuerGets);
if (!ret)
{
ret = boost::make_shared<BookListeners> ();
mListeners[issuerPays][issuerGets][currencyPays][currencyGets] = ret;
}
return ret;
}
BookListeners::pointer OrderBookDB::getBookListeners (const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets)
{
BookListeners::pointer ret;
boost::recursive_mutex::scoped_lock sl (mLock);
std::map<uint160, std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > > >::iterator
it0 = mListeners.find (issuerPays);
if (it0 == mListeners.end ())
return ret;
std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > >::iterator
it1 = (*it0).second.find (issuerGets);
if (it1 == (*it0).second.end ())
return ret;
std::map<uint160, std::map<uint160, BookListeners::pointer> >::iterator it2 = (*it1).second.find (currencyPays);
if (it2 == (*it1).second.end ())
return ret;
std::map<uint160, BookListeners::pointer>::iterator it3 = (*it2).second.find (currencyGets);
if (it3 == (*it2).second.end ())
return ret;
return (*it3).second;
}
// Based on the meta, send the meta to the streams that are listening
// We need to determine which streams a given meta effects
void OrderBookDB::processTxn (Ledger::ref ledger, const AcceptedLedgerTx& alTx, Json::Value& jvObj)
{
boost::recursive_mutex::scoped_lock sl (mLock);
if (alTx.getResult () == tesSUCCESS)
{
// check if this is an offer or an offer cancel or a payment that consumes an offer
//check to see what the meta looks like
BOOST_FOREACH (STObject & node, alTx.getMeta ()->getNodes ())
{
try
{
if (node.getFieldU16 (sfLedgerEntryType) == ltOFFER)
{
SField* field = NULL;
if (node.getFName () == sfModifiedNode)
{
field = &sfPreviousFields;
}
else if (node.getFName () == sfCreatedNode)
{
field = &sfNewFields;
}
else if (node.getFName () == sfDeletedNode)
{
field = &sfFinalFields;
}
if (field)
{
const STObject* data = dynamic_cast<const STObject*> (node.peekAtPField (*field));
if (data)
{
const STAmount& takerGets = data->getFieldAmount (sfTakerGets);
const uint160& currencyGets = takerGets.getCurrency ();
const uint160& issuerGets = takerGets.getIssuer ();
const STAmount& takerPays = data->getFieldAmount (sfTakerPays);
const uint160& currencyPays = takerPays.getCurrency ();
const uint160& issuerPays = takerPays.getIssuer ();
// determine the OrderBook
BookListeners::pointer book =
getBookListeners (currencyPays, currencyGets, issuerPays, issuerGets);
if (book)
book->publish (jvObj);
}
}
}
}
catch (...)
{
WriteLog (lsINFO, OrderBookDB) << "Fields not found in OrderBookDB::processTxn";
}
}
}
}
void BookListeners::addSubscriber (InfoSub::ref sub)
{
boost::recursive_mutex::scoped_lock sl (mLock);
mListeners[sub->getSeq ()] = sub;
}
void BookListeners::removeSubscriber (uint64 seq)
{
boost::recursive_mutex::scoped_lock sl (mLock);
mListeners.erase (seq);
}
void BookListeners::publish (Json::Value& jvObj)
{
Json::FastWriter jfwWriter;
std::string sObj = jfwWriter.write (jvObj);
boost::recursive_mutex::scoped_lock sl (mLock);
NetworkOPs::SubMapType::const_iterator it = mListeners.begin ();
while (it != mListeners.end ())
{
InfoSub::pointer p = it->second.lock ();
if (p)
{
p->send (jvObj, sObj, true);
++it;
}
else
it = mListeners.erase (it);
}
}
// vim:ts=4

View File

@@ -1,73 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef ORDERBOOK_DB_H
#define ORDERBOOK_DB_H
//
// XXX Eventually make this cached and just update it as transactions come in.
// But, for now it is probably faster to just generate it each time.
//
typedef std::pair<uint160, uint160> currencyIssuer_t;
#ifdef C11X
typedef std::pair<const uint160&, const uint160&> currencyIssuer_ct;
#else
typedef std::pair<uint160, uint160> currencyIssuer_ct; // C++ defect 106
#endif
class BookListeners
{
public:
typedef boost::shared_ptr<BookListeners> pointer;
void addSubscriber (InfoSub::ref sub);
void removeSubscriber (uint64 sub);
void publish (Json::Value& jvObj);
private:
boost::unordered_map<uint64, InfoSub::wptr> mListeners;
boost::recursive_mutex mLock;
};
class OrderBookDB : LeakChecked <OrderBookDB>
{
public:
OrderBookDB ();
void setup (Ledger::ref ledger);
void invalidate ();
// return list of all orderbooks that want this issuerID and currencyID
void getBooksByTakerPays (const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet);
void getBooksByTakerGets (const uint160& issuerID, const uint160& currencyID,
std::vector<OrderBook::pointer>& bookRet);
BookListeners::pointer getBookListeners (const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets);
BookListeners::pointer makeBookListeners (const uint160& currencyPays, const uint160& currencyGets,
const uint160& issuerPays, const uint160& issuerGets);
// see if this txn effects any orderbook
void processTxn (Ledger::ref ledger, const AcceptedLedgerTx& alTx, Json::Value& jvObj);
private:
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> > mSourceMap; // by ci/ii
boost::unordered_map< currencyIssuer_t, std::vector<OrderBook::pointer> > mDestMap; // by co/io
// issuerPays, issuerGets, currencyPays, currencyGets
std::map<uint160, std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > > > mListeners;
uint32 mSeq;
boost::recursive_mutex mLock;
};
#endif
// vim:ts=4

View File

@@ -1,5 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================

View File

@@ -1,171 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef SCRIPT_DATA_H
#define SCRIPT_DATA_H
namespace Script
{
class Data
{
public:
typedef boost::shared_ptr<Data> pointer;
virtual ~Data ()
{
;
}
virtual bool isInt32 ()
{
return (false);
}
virtual bool isFloat ()
{
return (false);
}
virtual bool isUint160 ()
{
return (false);
}
virtual bool isError ()
{
return (false);
}
virtual bool isTrue ()
{
return (false);
}
virtual bool isBool ()
{
return (false);
}
//virtual bool isBlockEnd(){ return(false); }
virtual int getInt ()
{
return (0);
}
virtual float getFloat ()
{
return (0);
}
virtual uint160 getUint160 ()
{
return (0);
}
//virtual bool isCurrency(){ return(false); }
};
class IntData : public Data
{
int mValue;
public:
IntData (int value)
{
mValue = value;
}
bool isInt32 ()
{
return (true);
}
int getInt ()
{
return (mValue);
}
float getFloat ()
{
return ((float)mValue);
}
bool isTrue ()
{
return (mValue != 0);
}
};
class FloatData : public Data
{
float mValue;
public:
FloatData (float value)
{
mValue = value;
}
bool isFloat ()
{
return (true);
}
float getFloat ()
{
return (mValue);
}
bool isTrue ()
{
return (mValue != 0);
}
};
class Uint160Data : public Data
{
uint160 mValue;
public:
Uint160Data (uint160 value) : mValue (value)
{
;
}
bool isUint160 ()
{
return (true);
}
uint160 getUint160 ()
{
return (mValue);
}
};
class BoolData : public Data
{
bool mValue;
public:
BoolData (bool value)
{
mValue = value;
}
bool isBool ()
{
return (true);
}
bool isTrue ()
{
return (mValue);
}
};
class ErrorData : public Data
{
public:
bool isError ()
{
return (true);
}
};
class BlockEndData : public Data
{
public:
bool isBlockEnd ()
{
return (true);
}
};
}
#endif
// vim:ts=4

View File

@@ -1,144 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
SerializedValidation::SerializedValidation (SerializerIterator& sit, bool checkSignature)
: STObject (getFormat (), sit, sfValidation)
, mTrusted (false)
{
mNodeID = RippleAddress::createNodePublic (getFieldVL (sfSigningPubKey)).getNodeID ();
assert (mNodeID.isNonZero ());
if (checkSignature && !isValid ())
{
Log (lsTRACE) << "Invalid validation " << getJson (0);
throw std::runtime_error ("Invalid validation");
}
}
SerializedValidation::SerializedValidation (
uint256 const& ledgerHash, uint32 signTime,
const RippleAddress& raPub, bool isFull)
: STObject (getFormat (), sfValidation)
, mTrusted (false)
{
// Does not sign
setFieldH256 (sfLedgerHash, ledgerHash);
setFieldU32 (sfSigningTime, signTime);
setFieldVL (sfSigningPubKey, raPub.getNodePublic ());
mNodeID = raPub.getNodeID ();
assert (mNodeID.isNonZero ());
if (!isFull)
setFlag (sFullFlag);
}
void SerializedValidation::sign (const RippleAddress& raPriv)
{
uint256 signingHash;
sign (signingHash, raPriv);
}
void SerializedValidation::sign (uint256& signingHash, const RippleAddress& raPriv)
{
signingHash = getSigningHash ();
Blob signature;
raPriv.signNodePrivate (signingHash, signature);
setFieldVL (sfSignature, signature);
}
uint256 SerializedValidation::getSigningHash () const
{
return STObject::getSigningHash (theConfig.SIGN_VALIDATION);
}
uint256 SerializedValidation::getLedgerHash () const
{
return getFieldH256 (sfLedgerHash);
}
uint32 SerializedValidation::getSignTime () const
{
return getFieldU32 (sfSigningTime);
}
uint32 SerializedValidation::getFlags () const
{
return getFieldU32 (sfFlags);
}
bool SerializedValidation::isValid () const
{
return isValid (getSigningHash ());
}
bool SerializedValidation::isValid (uint256 const& signingHash) const
{
try
{
RippleAddress raPublicKey = RippleAddress::createNodePublic (getFieldVL (sfSigningPubKey));
return raPublicKey.isValid () && raPublicKey.verifyNodePublic (signingHash, getFieldVL (sfSignature));
}
catch (...)
{
Log (lsINFO) << "exception validating validation";
return false;
}
}
RippleAddress SerializedValidation::getSignerPublic () const
{
RippleAddress a;
a.setNodePublic (getFieldVL (sfSigningPubKey));
return a;
}
bool SerializedValidation::isFull () const
{
return (getFlags () & sFullFlag) != 0;
}
Blob SerializedValidation::getSignature () const
{
return getFieldVL (sfSignature);
}
Blob SerializedValidation::getSigned () const
{
Serializer s;
add (s);
return s.peekData ();
}
SOTemplate const& SerializedValidation::getFormat ()
{
struct FormatHolder
{
SOTemplate format;
FormatHolder ()
{
format.push_back (SOElement (sfFlags, SOE_REQUIRED));
format.push_back (SOElement (sfLedgerHash, SOE_REQUIRED));
format.push_back (SOElement (sfLedgerSequence, SOE_OPTIONAL));
format.push_back (SOElement (sfCloseTime, SOE_OPTIONAL));
format.push_back (SOElement (sfLoadFee, SOE_OPTIONAL));
format.push_back (SOElement (sfFeatures, SOE_OPTIONAL));
format.push_back (SOElement (sfBaseFee, SOE_OPTIONAL));
format.push_back (SOElement (sfReserveBase, SOE_OPTIONAL));
format.push_back (SOElement (sfReserveIncrement, SOE_OPTIONAL));
format.push_back (SOElement (sfSigningTime, SOE_REQUIRED));
format.push_back (SOElement (sfSigningPubKey, SOE_REQUIRED));
format.push_back (SOElement (sfSignature, SOE_OPTIONAL));
}
};
static FormatHolder holder;
return holder.format;
}
// vim:ts=4

View File

@@ -1,79 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_SERIALIZEDVALIDATION_H
#define RIPPLE_SERIALIZEDVALIDATION_H
class SerializedValidation
: public STObject
, public CountedObject <SerializedValidation>
{
public:
static char const* getCountedObjectName () { return "SerializedValidation"; }
typedef boost::shared_ptr<SerializedValidation> pointer;
typedef const boost::shared_ptr<SerializedValidation>& ref;
static const uint32 sFullFlag = 0x1;
// These throw if the object is not valid
SerializedValidation (SerializerIterator & sit, bool checkSignature = true);
// Does not sign the validation
SerializedValidation (uint256 const & ledgerHash, uint32 signTime, const RippleAddress & raPub, bool isFull);
uint256 getLedgerHash () const;
uint32 getSignTime () const;
uint32 getFlags () const;
RippleAddress getSignerPublic () const;
uint160 getNodeID () const
{
return mNodeID;
}
bool isValid () const;
bool isFull () const;
bool isTrusted () const
{
return mTrusted;
}
uint256 getSigningHash () const;
bool isValid (uint256 const& ) const;
void setTrusted ()
{
mTrusted = true;
}
Blob getSigned () const;
Blob getSignature () const;
void sign (uint256 & signingHash, const RippleAddress & raPrivate);
void sign (const RippleAddress & raPrivate);
// The validation this replaced
uint256 const& getPreviousHash ()
{
return mPreviousHash;
}
bool isPreviousHash (uint256 const & h) const
{
return mPreviousHash == h;
}
void setPreviousHash (uint256 const & h)
{
mPreviousHash = h;
}
private:
static SOTemplate const& getFormat ();
void setNode ();
uint256 mPreviousHash;
uint160 mNodeID;
bool mTrusted;
};
#endif
// vim:ts=4

View File

@@ -1,46 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
TaggedCache <uint256, AcceptedLedger, UptimeTimerAdapter> AcceptedLedger::s_cache ("AcceptedLedger", 4, 60);
AcceptedLedger::AcceptedLedger (Ledger::ref ledger) : mLedger (ledger)
{
SHAMap& txSet = *ledger->peekTransactionMap ();
for (SHAMapItem::pointer item = txSet.peekFirstItem (); !!item; item = txSet.peekNextItem (item->getTag ()))
{
SerializerIterator sit (item->peekSerializer ());
insert (boost::make_shared<AcceptedLedgerTx> (ledger->getLedgerSeq (), boost::ref (sit)));
}
}
AcceptedLedger::pointer AcceptedLedger::makeAcceptedLedger (Ledger::ref ledger)
{
AcceptedLedger::pointer ret = s_cache.fetch (ledger->getHash ());
if (ret)
return ret;
ret = AcceptedLedger::pointer (new AcceptedLedger (ledger));
s_cache.canonicalize (ledger->getHash (), ret);
return ret;
}
void AcceptedLedger::insert (AcceptedLedgerTx::ref at)
{
assert (mMap.find (at->getIndex ()) == mMap.end ());
mMap.insert (std::make_pair (at->getIndex (), at));
}
AcceptedLedgerTx::pointer AcceptedLedger::getTxn (int i) const
{
map_t::const_iterator it = mMap.find (i);
if (it == mMap.end ())
return AcceptedLedgerTx::pointer ();
return it->second;
}

View File

@@ -1,79 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_ACCEPTEDLEDGER_H
#define RIPPLE_ACCEPTEDLEDGER_H
/** A ledger that has become irrevocable.
An accepted ledger is a ledger that has a sufficient number of
validations to convince the local server that it is irrevocable.
The existence of an accepted ledger implies all preceding ledgers
are accepted.
*/
/* VFALCO TODO digest this terminology clarification:
Closed and accepted refer to ledgers that have not passed the
validation threshold yet. Once they pass the threshold, they are
"Validated". Closed just means its close time has passed and no
new transactions can get in. "Accepted" means we believe it to be
the result of the a consensus process (though haven't validated
it yet).
*/
class AcceptedLedger
{
public:
typedef boost::shared_ptr<AcceptedLedger> pointer;
typedef const pointer& ret;
typedef std::map<int, AcceptedLedgerTx::pointer> map_t; // Must be an ordered map!
typedef map_t::value_type value_type;
typedef map_t::const_iterator const_iterator;
public:
static pointer makeAcceptedLedger (Ledger::ref ledger);
static void sweep ()
{
s_cache.sweep ();
}
Ledger::ref getLedger () const
{
return mLedger;
}
const map_t& getMap () const
{
return mMap;
}
int getLedgerSeq () const
{
return mLedger->getLedgerSeq ();
}
int getTxnCount () const
{
return mMap.size ();
}
static float getCacheHitRate ()
{
return s_cache.getHitRate ();
}
AcceptedLedgerTx::pointer getTxn (int) const;
private:
explicit AcceptedLedger (Ledger::ref ledger);
void insert (AcceptedLedgerTx::ref);
private:
static TaggedCache <uint256, AcceptedLedger, UptimeTimerAdapter> s_cache;
Ledger::pointer mLedger;
map_t mMap;
};
#endif

View File

@@ -1,61 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
AcceptedLedgerTx::AcceptedLedgerTx (uint32 seq, SerializerIterator& sit)
{
Serializer txnSer (sit.getVL ());
SerializerIterator txnIt (txnSer);
mTxn = boost::make_shared<SerializedTransaction> (boost::ref (txnIt));
mRawMeta = sit.getVL ();
mMeta = boost::make_shared<TransactionMetaSet> (mTxn->getTransactionID (), seq, mRawMeta);
mAffected = mMeta->getAffectedAccounts ();
mResult = mMeta->getResultTER ();
buildJson ();
}
AcceptedLedgerTx::AcceptedLedgerTx (SerializedTransaction::ref txn, TransactionMetaSet::ref met) :
mTxn (txn), mMeta (met), mAffected (met->getAffectedAccounts ())
{
mResult = mMeta->getResultTER ();
buildJson ();
}
AcceptedLedgerTx::AcceptedLedgerTx (SerializedTransaction::ref txn, TER result) :
mTxn (txn), mResult (result), mAffected (txn->getMentionedAccounts ())
{
buildJson ();
}
std::string AcceptedLedgerTx::getEscMeta () const
{
assert (!mRawMeta.empty ());
return sqlEscape (mRawMeta);
}
void AcceptedLedgerTx::buildJson ()
{
mJson = Json::objectValue;
mJson["transaction"] = mTxn->getJson (0);
if (mMeta)
{
mJson["meta"] = mMeta->getJson (0);
mJson["raw_meta"] = strHex (mRawMeta);
}
mJson["result"] = transHuman (mResult);
if (!mAffected.empty ())
{
Json::Value& affected = (mJson["affected"] = Json::arrayValue);
BOOST_FOREACH (const RippleAddress & ra, mAffected)
{
affected.append (ra.humanAccountID ());
}
}
}

View File

@@ -1,97 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_ACCEPTEDLEDGERTX_H
#define RIPPLE_ACCEPTEDLEDGERTX_H
//------------------------------------------------------------------------------
/**
A transaction that is in a closed ledger.
Description
An accepted ledger transaction contains additional information that the
server needs to tell clients about the transaction. For example,
- The transaction in JSON form
- Which accounts are affected
* This is used by InfoSub to report to clients
- Cached stuff
@code
@endcode
@see {uri}
@ingroup ripple_ledger
*/
class AcceptedLedgerTx
{
public:
typedef boost::shared_ptr <AcceptedLedgerTx> pointer;
typedef const pointer& ref;
public:
AcceptedLedgerTx (LedgerIndex ledgerSeq, SerializerIterator& sit);
AcceptedLedgerTx (SerializedTransaction::ref, TransactionMetaSet::ref);
AcceptedLedgerTx (SerializedTransaction::ref, TER result);
SerializedTransaction::ref getTxn () const
{
return mTxn;
}
TransactionMetaSet::ref getMeta () const
{
return mMeta;
}
std::vector <RippleAddress> const& getAffected () const
{
return mAffected;
}
TxID getTransactionID () const
{
return mTxn->getTransactionID ();
}
TxType getTxnType () const
{
return mTxn->getTxnType ();
}
TER getResult () const
{
return mResult;
}
uint32 getTxnSeq () const
{
return mMeta->getIndex ();
}
bool isApplied () const
{
return !!mMeta;
}
int getIndex () const
{
return mMeta ? mMeta->getIndex () : 0;
}
std::string getEscMeta () const;
Json::Value getJson () const
{
return mJson;
}
private:
SerializedTransaction::pointer mTxn;
TransactionMetaSet::pointer mMeta;
TER mResult;
std::vector <RippleAddress> mAffected;
Blob mRawMeta;
Json::Value mJson;
void buildJson ();
};
#endif

View File

@@ -1,357 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// Transaction database holds transactions and public keys
const char* TxnDBInit[] =
{
"PRAGMA synchronous=NORMAL;",
"PRAGMA journal_mode=WAL;",
"PRAGMA journal_size_limit=1582080;",
#if (ULONG_MAX > UINT_MAX) && !defined (NO_SQLITE_MMAP)
"PRAGMA mmap_size=17179869184;",
#endif
"BEGIN TRANSACTION;",
"CREATE TABLE Transactions ( \
TransID CHARACTER(64) PRIMARY KEY, \
TransType CHARACTER(24), \
FromAcct CHARACTER(35), \
FromSeq BIGINT UNSIGNED, \
LedgerSeq BIGINT UNSIGNED, \
Status CHARACTER(1), \
RawTxn BLOB, \
TxnMeta BLOB \
);",
"CREATE INDEX TxLgrIndex ON \
Transactions(LedgerSeq);",
"CREATE TABLE AccountTransactions ( \
TransID CHARACTER(64), \
Account CHARACTER(64), \
LedgerSeq BIGINT UNSIGNED, \
TxnSeq INTEGER \
);",
"CREATE INDEX AcctTxIDIndex ON \
AccountTransactions(TransID);",
"CREATE INDEX AcctTxIndex ON \
AccountTransactions(Account, LedgerSeq, TxnSeq, TransID);",
"CREATE INDEX AcctLgrIndex ON \
AccountTransactions(LedgerSeq, Account, TransID);",
"END TRANSACTION;"
};
int TxnDBCount = NUMBER (TxnDBInit);
// Ledger database holds ledgers and ledger confirmations
const char* LedgerDBInit[] =
{
"PRAGMA synchronous=NORMAL;",
"PRAGMA journal_mode=WAL;",
"PRAGMA journal_size_limit=1582080;",
"BEGIN TRANSACTION;",
"CREATE TABLE Ledgers ( \
LedgerHash CHARACTER(64) PRIMARY KEY, \
LedgerSeq BIGINT UNSIGNED, \
PrevHash CHARACTER(64), \
TotalCoins BIGINT UNSIGNED, \
ClosingTime BIGINT UNSIGNED, \
PrevClosingTime BIGINT UNSIGNED, \
CloseTimeRes BIGINT UNSIGNED, \
CloseFlags BIGINT UNSIGNED, \
AccountSetHash CHARACTER(64), \
TransSetHash CHARACTER(64) \
);",
"CREATE INDEX SeqLedger ON Ledgers(LedgerSeq);",
"CREATE TABLE Validations ( \
LedgerHash CHARACTER(64), \
NodePubKey CHARACTER(56), \
SignTime BIGINT UNSIGNED, \
RawData BLOB \
);",
"CREATE INDEX ValidationsByHash ON \
Validations(LedgerHash);",
"CREATE INDEX ValidationsByTime ON \
Validations(SignTime);",
"END TRANSACTION;"
};
int LedgerDBCount = NUMBER (LedgerDBInit);
// RPC database holds persistent data for RPC clients.
const char* RpcDBInit[] =
{
// Local persistence of the RPC client
"CREATE TABLE RPCData ( \
Key TEXT PRIMARY Key, \
Value TEXT \
);",
};
int RpcDBCount = NUMBER (RpcDBInit);
// NodeIdentity database holds local accounts and trusted nodes
// VFALCO NOTE but its a table not a database, so...?
//
const char* WalletDBInit[] =
{
// Node identity must be persisted for CAS routing and responsibilities.
"BEGIN TRANSACTION;",
"CREATE TABLE NodeIdentity ( \
PublicKey CHARACTER(53), \
PrivateKey CHARACTER(52), \
Dh512 TEXT, \
Dh1024 TEXT \
);",
// Miscellaneous persistent information
// Integer: 1 : Used to simplify SQL.
// ScoreUpdated: when scores was last updated.
// FetchUpdated: when last fetch succeeded.
"CREATE TABLE Misc ( \
Magic INTEGER UNIQUE NOT NULL, \
ScoreUpdated DATETIME, \
FetchUpdated DATETIME \
);",
// Scoring and other information for domains.
//
// Domain:
// Domain source for https.
// PublicKey:
// Set if ever succeeded.
// XXX Use NULL in place of ""
// Source:
// 'M' = Manually added. : 1500
// 'V' = validators.txt : 1000
// 'W' = Web browsing. : 200
// 'R' = Referral : 0
// Next:
// Time of next fetch attempt.
// Scan:
// Time of last fetch attempt.
// Fetch:
// Time of last successful fetch.
// Sha256:
// Checksum of last fetch.
// Comment:
// User supplied comment.
// Table of Domains user has asked to trust.
"CREATE TABLE SeedDomains ( \
Domain TEXT PRIMARY KEY NOT NULL, \
PublicKey CHARACTER(53), \
Source CHARACTER(1) NOT NULL, \
Next DATETIME, \
Scan DATETIME, \
Fetch DATETIME, \
Sha256 CHARACTER[64], \
Comment TEXT \
);",
// Allow us to easily find the next SeedDomain to fetch.
"CREATE INDEX SeedDomainNext ON SeedDomains (Next);",
// Table of PublicKeys user has asked to trust.
// Fetches are made to the CAS. This gets the ripple.txt so even validators without a web server can publish a ripple.txt.
// Source:
// 'M' = Manually added. : 1500
// 'V' = validators.txt : 1000
// 'W' = Web browsing. : 200
// 'R' = Referral : 0
// Next:
// Time of next fetch attempt.
// Scan:
// Time of last fetch attempt.
// Fetch:
// Time of last successful fetch.
// Sha256:
// Checksum of last fetch.
// Comment:
// User supplied comment.
"CREATE TABLE SeedNodes ( \
PublicKey CHARACTER(53) PRIMARY KEY NOT NULL, \
Source CHARACTER(1) NOT NULL, \
Next DATETIME, \
Scan DATETIME, \
Fetch DATETIME, \
Sha256 CHARACTER[64], \
Comment TEXT \
);",
// Allow us to easily find the next SeedNode to fetch.
"CREATE INDEX SeedNodeNext ON SeedNodes (Next);",
// Nodes we trust to not grossly collude against us. Derived from SeedDomains, SeedNodes, and ValidatorReferrals.
//
// Score:
// Computed trust score. Higher is better.
// Seen:
// Last validation received.
"CREATE TABLE TrustedNodes ( \
PublicKey CHARACTER(53) PRIMARY KEY NOT NULL, \
Score INTEGER DEFAULT 0 NOT NULL, \
Seen DATETIME, \
Comment TEXT \
);",
// List of referrals.
// - There may be multiple sources for a Validator. The last source is used.
// Validator:
// Public key of referrer.
// Entry:
// Entry index in [validators] table.
// Referral:
// This is the form provided by the ripple.txt:
// - Public key for CAS based referral.
// - Domain for domain based referral.
// XXX Do garbage collection when validators have no references.
"CREATE TABLE ValidatorReferrals ( \
Validator CHARACTER(53) NOT NULL, \
Entry INTEGER NOT NULL, \
Referral TEXT NOT NULL, \
PRIMARY KEY (Validator,Entry) \
);",
// List of referrals from ripple.txt files.
// Validator:
// Public key of referree.
// Entry:
// Entry index in [validators] table.
// IP:
// IP of referred.
// Port:
// -1 = Default
// XXX Do garbage collection when ips have no references.
"CREATE TABLE IpReferrals ( \
Validator CHARACTER(53) NOT NULL, \
Entry INTEGER NOT NULL, \
IP TEXT NOT NULL, \
Port INTEGER NOT NULL DEFAULT -1, \
PRIMARY KEY (Validator,Entry) \
);",
// Table of IPs to contact the network.
// IP:
// IP address to contact.
// Port:
// Port to contact.
// -1 = Default
// Score:
// Computed trust score. Higher is better.
// Source:
// 'C' = Configuration file
// 'V' = Validation file
// 'M' = Manually added.
// 'I' = Inbound connection.
// 'T' = Told by other peer
// 'O' = Other.
// ScanNext:
// When to next scan. Null=not scanning.
// ScanInterval:
// Delay between scans.
"CREATE TABLE PeerIps ( \
IpPort TEXT NOT NULL PRIMARY KEY, \
Score INTEGER NOT NULL DEFAULT 0, \
Source CHARACTER(1) NOT NULL, \
ScanNext DATETIME DEFAULT 0, \
ScanInterval INTEGER NOT NULL DEFAULT 0 \
);",
"CREATE INDEX PeerScanIndex ON \
PeerIps(ScanNext);",
"CREATE TABLE Features ( \
Hash CHARACTER(64) PRIMARY KEY, \
FirstMajority BIGINT UNSIGNED, \
LastMajority BIGINT UNSIGNED \
);",
"END TRANSACTION;"
};
int WalletDBCount = NUMBER (WalletDBInit);
// Hash node database holds nodes indexed by hash
const char* HashNodeDBInit[] =
{
"PRAGMA synchronous=NORMAL;",
"PRAGMA journal_mode=WAL;",
"PRAGMA journal_size_limit=1582080;",
#if (ULONG_MAX > UINT_MAX) && !defined (NO_SQLITE_MMAP)
"PRAGMA mmap_size=171798691840;",
#endif
"BEGIN TRANSACTION;",
"CREATE TABLE CommittedObjects ( \
Hash CHARACTER(64) PRIMARY KEY, \
ObjType CHAR(1) NOT NULL, \
LedgerIndex BIGINT UNSIGNED, \
Object BLOB \
);",
"END TRANSACTION;"
};
int HashNodeDBCount = NUMBER (HashNodeDBInit);
// Net node database holds nodes seen on the network
// XXX Not really used needs replacement.
const char* NetNodeDBInit[] =
{
"CREATE TABLE KnownNodes ( \
Hanko CHARACTER(35) PRIMARY KEY, \
LastSeen TEXT, \
HaveContactInfo CHARACTER(1), \
ContactObject BLOB \
);"
};
int NetNodeDBCount = NUMBER (NetNodeDBInit);
const char* PathFindDBInit[] =
{
"PRAGMA synchronous = OFF; ",
"DROP TABLE TrustLines; ",
"CREATE TABLE TrustLines { "
"To CHARACTER(40), " // Hex of account trusted
"By CHARACTER(40), " // Hex of account trusting
"Currency CHARACTER(80), " // Hex currency, hex issuer
"Use INTEGER, " // Use count
"Seq BIGINT UNSIGNED " // Sequence when use count was updated
"}; ",
"CREATE INDEX TLBy ON TrustLines(By, Currency, Use);",
"CREATE INDEX TLTo ON TrustLines(To, Currency, Use);",
"DROP TABLE Exchanges;",
"CREATE TABLE Exchanges { "
"From CHARACTER(80), "
"To CHARACTER(80), "
"Currency CHARACTER(80), "
"Use INTEGER, "
"Seq BIGINT UNSIGNED "
"}; ",
"CREATE INDEX ExBy ON Exchanges(By, Currency, Use);",
"CREATE INDEX ExTo ON Exchanges(To, Currency, Use);",
};
int PathFindDBCount = NUMBER (PathFindDBInit);
// vim:ts=4

View File

@@ -1,30 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_DBINIT_H_INCLUDED
#define RIPPLE_DBINIT_H_INCLUDED
// VFALCO TODO Tidy these up into a class with functions and return types.
extern const char* RpcDBInit[];
extern const char* TxnDBInit[];
extern const char* LedgerDBInit[];
extern const char* WalletDBInit[];
extern const char* HashNodeDBInit[];
// VFALCO TODO Figure out what these counts are for
extern int RpcDBCount;
extern int TxnDBCount;
extern int LedgerDBCount;
extern int WalletDBCount;
extern int HashNodeDBCount;
// VFALCO TODO Seems these two aren't used so delete EVERYTHING.
extern const char* NetNodeDBInit[];
extern const char* PathFindDBInit[];
extern int NetNodeDBCount;
extern int PathFindDBCount;
#endif

View File

@@ -1,193 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
Database::Database (const char* host)
: mNumCol (0)
{
mHost = host;
}
Database::~Database ()
{
}
bool Database::getNull (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getNull (index);
}
return true;
}
char* Database::getStr (const char* colName, std::string& retStr)
{
int index;
if (getColNumber (colName, &index))
{
return getStr (index, retStr);
}
return NULL;
}
int32 Database::getInt (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getInt (index);
}
return 0;
}
float Database::getFloat (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getFloat (index);
}
return 0;
}
bool Database::getBool (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getBool (index);
}
return 0;
}
int Database::getBinary (const char* colName, unsigned char* buf, int maxSize)
{
int index;
if (getColNumber (colName, &index))
{
return (getBinary (index, buf, maxSize));
}
return (0);
}
Blob Database::getBinary (const std::string& strColName)
{
int index;
if (getColNumber (strColName.c_str (), &index))
{
return getBinary (index);
}
return Blob ();
}
std::string Database::getStrBinary (const std::string& strColName)
{
// YYY Could eliminate a copy if getStrBinary was a template.
return strCopy (getBinary (strColName.c_str ()));
}
uint64 Database::getBigInt (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getBigInt (index);
}
return 0;
}
// returns false if can't find col
bool Database::getColNumber (const char* colName, int* retIndex)
{
for (unsigned int n = 0; n < mColNameTable.size (); n++)
{
if (strcmp (colName, mColNameTable[n].c_str ()) == 0)
{
*retIndex = n;
return (true);
}
}
return false;
}
#if 0
int Database::getSingleDBValueInt (const char* sql)
{
int ret;
if ( executeSQL (sql) && startIterRows ()
{
ret = getInt (0);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif
#if 0
float Database::getSingleDBValueFloat (const char* sql)
{
float ret;
if (executeSQL (sql) && startIterRows () && getNextRow ())
{
ret = getFloat (0);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif
#if 0
char* Database::getSingleDBValueStr (const char* sql, std::string& retStr)
{
char* ret;
if (executeSQL (sql) && startIterRows ())
{
ret = getStr (0, retStr);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif
// vim:ts=4

View File

@@ -1,107 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_DATABASE_RIPPLEHEADER
#define RIPPLE_DATABASE_RIPPLEHEADER
// VFALCO Get rid of these macros
//
#define SQL_FOREACH(_db, _strQuery) \
if ((_db)->executeSQL(_strQuery)) \
for (bool _bMore = (_db)->startIterRows(); _bMore; _bMore = (_db)->getNextRow())
#define SQL_EXISTS(_db, _strQuery) \
((_db)->executeSQL(_strQuery) && (_db)->startIterRows())
/*
this maintains the connection to the database
*/
class SqliteDatabase;
class JobQueue;
class Database
{
public:
explicit Database (const char* host);
virtual ~Database ();
virtual void connect () = 0;
virtual void disconnect () = 0;
// returns true if the query went ok
virtual bool executeSQL (const char* sql, bool fail_okay = false) = 0;
bool executeSQL (std::string strSql, bool fail_okay = false)
{
return executeSQL (strSql.c_str (), fail_okay);
}
// returns false if there are no results
virtual bool startIterRows (bool finalize = true) = 0;
virtual void endIterRows () = 0;
// call this after you executeSQL
// will return false if there are no more rows
virtual bool getNextRow (bool finalize = true) = 0;
// get Data from the current row
bool getNull (const char* colName);
char* getStr (const char* colName, std::string& retStr);
std::string getStrBinary (const std::string& strColName);
int32 getInt (const char* colName);
float getFloat (const char* colName);
bool getBool (const char* colName);
// returns amount stored in buf
int getBinary (const char* colName, unsigned char* buf, int maxSize);
Blob getBinary (const std::string& strColName);
uint64 getBigInt (const char* colName);
virtual bool getNull (int colIndex) = 0;
virtual char* getStr (int colIndex, std::string& retStr) = 0;
virtual int32 getInt (int colIndex) = 0;
virtual float getFloat (int colIndex) = 0;
virtual bool getBool (int colIndex) = 0;
virtual int getBinary (int colIndex, unsigned char* buf, int maxSize) = 0;
virtual uint64 getBigInt (int colIndex) = 0;
virtual Blob getBinary (int colIndex) = 0;
// int getSingleDBValueInt(const char* sql);
// float getSingleDBValueFloat(const char* sql);
// char* getSingleDBValueStr(const char* sql, std::string& retStr);
virtual bool setupCheckpointing (JobQueue*)
{
return false;
}
virtual SqliteDatabase* getSqliteDB ()
{
return NULL;
}
virtual int getKBUsedAll ()
{
return -1;
}
virtual int getKBUsedDB ()
{
return -1;
}
protected:
bool getColNumber (const char* colName, int* retIndex);
int mNumCol;
std::string mHost;
std::vector <std::string> mColNameTable;
};
#endif
// vim:ts=4

View File

@@ -1,32 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
int DatabaseCon::sCount = 0;
DatabaseCon::DatabaseCon (const std::string& strName, const char* initStrings[], int initCount)
{
++sCount;
// VFALCO TODO remove this dependency on the config by making it the caller's
// responsibility to pass in the path. Add a member function to Application
// or Config to compute this path.
//
boost::filesystem::path pPath = (theConfig.RUN_STANDALONE && (theConfig.START_UP != Config::LOAD))
? "" // Use temporary files.
: (theConfig.DATA_DIR / strName); // Use regular db files.
mDatabase = new SqliteDatabase (pPath.string ().c_str ());
mDatabase->connect ();
for (int i = 0; i < initCount; ++i)
mDatabase->executeSQL (initStrings[i], true);
}
DatabaseCon::~DatabaseCon ()
{
mDatabase->disconnect ();
delete mDatabase;
}

View File

@@ -1,39 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_DATABASECON_H
#define RIPPLE_DATABASECON_H
// VFALCO NOTE This looks like a pointless class. Figure out
// what purpose it is really trying to serve and do it better.
class DatabaseCon : LeakChecked <DatabaseCon>
{
public:
DatabaseCon (const std::string& name, const char* initString[], int countInit);
~DatabaseCon ();
Database* getDB ()
{
return mDatabase;
}
boost::recursive_mutex& getDBLock ()
{
return mLock;
}
static int getCount ()
{
return sCount;
}
// VFALCO TODO change "protected" to "private" throughout the code
private:
Database* mDatabase;
// VFALCO TODO replace these with a single atomic counter.
boost::recursive_mutex mLock;
static int sCount;
};
#endif

View File

@@ -1,900 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
SETUP_LOG (InboundLedger)
// VFALCO TODO replace macros
#define LA_DEBUG
#define LEDGER_ACQUIRE_TIMEOUT 2000 // millisecond for each ledger timeout
#define LEDGER_TIMEOUT_COUNT 10 // how many timeouts before we giveup
#define LEDGER_TIMEOUT_AGGRESSIVE 6 // how many timeouts before we get aggressive
InboundLedger::InboundLedger (uint256 const& hash, uint32 seq)
: PeerSet (hash, LEDGER_ACQUIRE_TIMEOUT)
, mHaveBase (false)
, mHaveState (false)
, mHaveTransactions (false)
, mAborted (false)
, mSignaled (false)
, mAccept (false)
, mByHash (true)
, mWaitCount (0)
, mSeq (seq)
{
#ifdef LA_DEBUG
WriteLog (lsTRACE, InboundLedger) << "Acquiring ledger " << mHash;
#endif
tryLocal ();
}
void InboundLedger::checkLocal ()
{
boost::recursive_mutex::scoped_lock sl (mLock);
if (isDone ())
return;
if (tryLocal ())
done ();
}
bool InboundLedger::tryLocal ()
{
// return value: true = no more work to do
if (!mHaveBase)
{
// Nothing we can do without the ledger base
NodeObject::pointer node = getApp().getNodeStore ().retrieve (mHash);
if (!node)
{
Blob data;
if (!getApp().getOPs ().getFetchPack (mHash, data))
return false;
WriteLog (lsTRACE, InboundLedger) << "Ledger base found in fetch pack";
mLedger = boost::make_shared<Ledger> (data, true);
getApp().getNodeStore ().store (hotLEDGER, mLedger->getLedgerSeq (), data, mHash);
}
else
{
mLedger = boost::make_shared<Ledger> (strCopy (node->getData ()), true);
}
if (mLedger->getHash () != mHash)
{
// We know for a fact the ledger can never be acquired
WriteLog (lsWARNING, InboundLedger) << mHash << " cannot be a ledger";
mFailed = true;
return true;
}
mHaveBase = true;
}
if (!mHaveTransactions)
{
if (mLedger->getTransHash ().isZero ())
{
WriteLog (lsTRACE, InboundLedger) << "No TXNs to fetch";
mHaveTransactions = true;
}
else
{
TransactionStateSF filter (mLedger->getLedgerSeq ());
if (mLedger->peekTransactionMap ()->fetchRoot (mLedger->getTransHash (), &filter))
{
WriteLog (lsTRACE, InboundLedger) << "Got root txn map locally";
std::vector<uint256> h = mLedger->getNeededTransactionHashes (1, &filter);
if (h.empty ())
{
WriteLog (lsTRACE, InboundLedger) << "Had full txn map locally";
mHaveTransactions = true;
}
}
}
}
if (!mHaveState)
{
if (mLedger->getAccountHash ().isZero ())
{
WriteLog (lsFATAL, InboundLedger) << "We are acquiring a ledger with a zero account hash";
mHaveState = true;
}
else
{
AccountStateSF filter (mLedger->getLedgerSeq ());
if (mLedger->peekAccountStateMap ()->fetchRoot (mLedger->getAccountHash (), &filter))
{
WriteLog (lsTRACE, InboundLedger) << "Got root AS map locally";
std::vector<uint256> h = mLedger->getNeededAccountStateHashes (1, &filter);
if (h.empty ())
{
WriteLog (lsTRACE, InboundLedger) << "Had full AS map locally";
mHaveState = true;
}
}
}
}
if (mHaveTransactions && mHaveState)
{
WriteLog (lsDEBUG, InboundLedger) << "Had everything locally";
mComplete = true;
mLedger->setClosed ();
mLedger->setImmutable ();
}
return mComplete;
}
void InboundLedger::onTimer (bool progress)
{
mRecentTXNodes.clear ();
mRecentASNodes.clear ();
if (getTimeouts () > LEDGER_TIMEOUT_COUNT)
{
WriteLog (lsWARNING, InboundLedger) << "Too many timeouts( " << getTimeouts () << ") for ledger " << mHash;
setFailed ();
done ();
return;
}
if (!progress)
{
if (isDone())
{
WriteLog (lsINFO, InboundLedger) << "Already done " << mHash;
return;
}
checkLocal();
if (isDone())
{
WriteLog (lsINFO, InboundLedger) << "Completed fetch " << mHash;
return;
}
mAggressive = true;
mByHash = true;
int pc = getPeerCount ();
WriteLog (lsDEBUG, InboundLedger) << "No progress(" << pc << ") for ledger " << pc << mHash;
if (pc < 3)
addPeers ();
else
trigger (Peer::pointer ());
}
}
void InboundLedger::awaitData ()
{
++mWaitCount;
}
void InboundLedger::noAwaitData ()
{ // subtract one if mWaitCount is greater than zero
do
{
int j = mWaitCount.get();
if (j <= 0)
return;
if (mWaitCount.compareAndSetBool(j - 1, j))
return;
} while (1);
}
void InboundLedger::addPeers ()
{
std::vector<Peer::pointer> peerList = getApp().getPeers ().getPeerVector ();
int vSize = peerList.size ();
if (vSize == 0)
return;
// We traverse the peer list in random order so as not to favor any particular peer
int firstPeer = rand () & vSize;
int found = 0;
for (int i = 0; i < vSize; ++i)
{
Peer::ref peer = peerList[ (i + firstPeer) % vSize];
if (peer->hasLedger (getHash (), mSeq))
{
peerHas (peer);
if (++found == 3)
break;
}
}
if (!found)
for (int i = 0; i < vSize; ++i)
peerHas (peerList[ (i + firstPeer) % vSize]);
}
boost::weak_ptr<PeerSet> InboundLedger::pmDowncast ()
{
return boost::dynamic_pointer_cast<PeerSet> (shared_from_this ());
}
static void LADispatch (
Job& job,
InboundLedger::pointer la,
std::vector< FUNCTION_TYPE<void (InboundLedger::pointer)> > trig)
{
Ledger::ref ledger = la->getLedger();
if (ledger)
getApp().getLedgerMaster().checkAccept (ledger->getHash(), ledger->getLedgerSeq());
for (unsigned int i = 0; i < trig.size (); ++i)
trig[i] (la);
}
void InboundLedger::done ()
{
if (mSignaled)
return;
mSignaled = true;
touch ();
#ifdef LA_DEBUG
WriteLog (lsTRACE, InboundLedger) << "Done acquiring ledger " << mHash;
#endif
assert (isComplete () || isFailed ());
std::vector< FUNCTION_TYPE<void (InboundLedger::pointer)> > triggers;
{
boost::recursive_mutex::scoped_lock sl (mLock);
triggers.swap (mOnComplete);
}
if (isComplete () && !isFailed () && mLedger)
{
mLedger->setClosed ();
mLedger->setImmutable ();
if (mAccept)
mLedger->setAccepted ();
getApp().getLedgerMaster ().storeLedger (mLedger);
}
else
getApp().getInboundLedgers ().logFailure (mHash);
// We hold the PeerSet lock, so must dispatch
getApp().getJobQueue ().addJob (jtLEDGER_DATA, "triggers",
BIND_TYPE (LADispatch, P_1, shared_from_this (), triggers));
}
bool InboundLedger::addOnComplete (FUNCTION_TYPE<void (InboundLedger::pointer)> trigger)
{
boost::recursive_mutex::scoped_lock sl (mLock);
if (isDone ())
return false;
mOnComplete.push_back (trigger);
return true;
}
void InboundLedger::trigger (Peer::ref peer)
{
boost::recursive_mutex::scoped_lock sl (mLock);
if (isDone ())
{
WriteLog (lsDEBUG, InboundLedger) << "Trigger on ledger: " << mHash <<
(mAborted ? " aborted" : "") << (mComplete ? " completed" : "") << (mFailed ? " failed" : "");
return;
}
if ((mWaitCount.get() > 0) && peer)
{
WriteLog (lsTRACE, InboundLedger) << "Skipping peer";
return;
}
if (ShouldLog (lsTRACE, InboundLedger))
{
if (peer)
WriteLog (lsTRACE, InboundLedger) << "Trigger acquiring ledger " << mHash << " from " << peer->getIP ();
else
WriteLog (lsTRACE, InboundLedger) << "Trigger acquiring ledger " << mHash;
if (mComplete || mFailed)
WriteLog (lsTRACE, InboundLedger) << "complete=" << mComplete << " failed=" << mFailed;
else
WriteLog (lsTRACE, InboundLedger) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState;
}
if (!mHaveBase)
{
tryLocal ();
if (mFailed)
{
WriteLog (lsWARNING, InboundLedger) << " failed local for " << mHash;
return;
}
}
protocol::TMGetLedger tmGL;
tmGL.set_ledgerhash (mHash.begin (), mHash.size ());
if (getTimeouts () != 0)
{
tmGL.set_querytype (protocol::qtINDIRECT);
if (!isProgress () && !mFailed && mByHash && (getTimeouts () > LEDGER_TIMEOUT_AGGRESSIVE))
{
std::vector<neededHash_t> need = getNeededHashes ();
if (!need.empty ())
{
protocol::TMGetObjectByHash tmBH;
tmBH.set_query (true);
tmBH.set_ledgerhash (mHash.begin (), mHash.size ());
bool typeSet = false;
BOOST_FOREACH (neededHash_t & p, need)
{
WriteLog (lsWARNING, InboundLedger) << "Want: " << p.second;
if (!typeSet)
{
tmBH.set_type (p.first);
typeSet = true;
}
if (p.first == tmBH.type ())
{
protocol::TMIndexedObject* io = tmBH.add_objects ();
io->set_hash (p.second.begin (), p.second.size ());
}
}
PackedMessage::pointer packet = boost::make_shared<PackedMessage> (tmBH, protocol::mtGET_OBJECTS);
{
boost::recursive_mutex::scoped_lock sl (mLock);
for (boost::unordered_map<uint64, int>::iterator it = mPeers.begin (), end = mPeers.end ();
it != end; ++it)
{
Peer::pointer iPeer = getApp().getPeers ().getPeerById (it->first);
if (iPeer)
{
mByHash = false;
iPeer->sendPacket (packet, false);
}
}
}
WriteLog (lsINFO, InboundLedger) << "Attempting by hash fetch for ledger " << mHash;
}
else
{
WriteLog (lsINFO, InboundLedger) << "getNeededHashes says acquire is complete";
mHaveBase = true;
mHaveTransactions = true;
mHaveState = true;
mComplete = true;
}
}
}
if (!mHaveBase && !mFailed)
{
tmGL.set_itype (protocol::liBASE);
WriteLog (lsTRACE, InboundLedger) << "Sending base request to " << (peer ? "selected peer" : "all peers");
sendRequest (tmGL, peer);
return;
}
if (mLedger)
tmGL.set_ledgerseq (mLedger->getLedgerSeq ());
if (mHaveBase && !mHaveTransactions && !mFailed)
{
assert (mLedger);
if (mLedger->peekTransactionMap ()->getHash ().isZero ())
{
// we need the root node
tmGL.set_itype (protocol::liTX_NODE);
* (tmGL.add_nodeids ()) = SHAMapNode ().getRawString ();
WriteLog (lsTRACE, InboundLedger) << "Sending TX root request to " << (peer ? "selected peer" : "all peers");
sendRequest (tmGL, peer);
return;
}
else
{
std::vector<SHAMapNode> nodeIDs;
std::vector<uint256> nodeHashes;
nodeIDs.reserve (256);
nodeHashes.reserve (256);
TransactionStateSF filter (mSeq);
mLedger->peekTransactionMap ()->getMissingNodes (nodeIDs, nodeHashes, 256, &filter);
if (nodeIDs.empty ())
{
if (!mLedger->peekTransactionMap ()->isValid ())
mFailed = true;
else
{
mHaveTransactions = true;
if (mHaveState)
mComplete = true;
}
}
else
{
if (!mAggressive)
filterNodes (nodeIDs, nodeHashes, mRecentTXNodes, 128, !isProgress ());
if (!nodeIDs.empty ())
{
tmGL.set_itype (protocol::liTX_NODE);
BOOST_FOREACH (SHAMapNode const& it, nodeIDs)
{
* (tmGL.add_nodeids ()) = it.getRawString ();
}
WriteLog (lsTRACE, InboundLedger) << "Sending TX node " << nodeIDs.size ()
<< " request to " << (peer ? "selected peer" : "all peers");
sendRequest (tmGL, peer);
return;
}
}
}
}
if (mHaveBase && !mHaveState && !mFailed)
{
assert (mLedger);
if (mLedger->peekAccountStateMap ()->getHash ().isZero ())
{
// we need the root node
tmGL.set_itype (protocol::liAS_NODE);
* (tmGL.add_nodeids ()) = SHAMapNode ().getRawString ();
WriteLog (lsTRACE, InboundLedger) << "Sending AS root request to " << (peer ? "selected peer" : "all peers");
sendRequest (tmGL, peer);
return;
}
else
{
std::vector<SHAMapNode> nodeIDs;
std::vector<uint256> nodeHashes;
nodeIDs.reserve (256);
nodeHashes.reserve (256);
AccountStateSF filter (mSeq);
mLedger->peekAccountStateMap ()->getMissingNodes (nodeIDs, nodeHashes, 256, &filter);
if (nodeIDs.empty ())
{
if (!mLedger->peekAccountStateMap ()->isValid ())
mFailed = true;
else
{
mHaveState = true;
if (mHaveTransactions)
mComplete = true;
}
}
else
{
if (!mAggressive)
filterNodes (nodeIDs, nodeHashes, mRecentASNodes, 128, !isProgress ());
if (!nodeIDs.empty ())
{
tmGL.set_itype (protocol::liAS_NODE);
BOOST_FOREACH (SHAMapNode const& it, nodeIDs)
{
* (tmGL.add_nodeids ()) = it.getRawString ();
}
WriteLog (lsTRACE, InboundLedger) << "Sending AS node " << nodeIDs.size ()
<< " request to " << (peer ? "selected peer" : "all peers");
CondLog (nodeIDs.size () == 1, lsTRACE, InboundLedger) << "AS node: " << nodeIDs[0];
sendRequest (tmGL, peer);
return;
}
}
}
}
if (mComplete || mFailed)
{
WriteLog (lsDEBUG, InboundLedger) << "Done:" << (mComplete ? " complete" : "") << (mFailed ? " failed " : " ")
<< mLedger->getLedgerSeq ();
sl.unlock ();
done ();
}
}
void PeerSet::sendRequest (const protocol::TMGetLedger& tmGL, Peer::ref peer)
{
if (!peer)
sendRequest (tmGL);
else
peer->sendPacket (boost::make_shared<PackedMessage> (tmGL, protocol::mtGET_LEDGER), false);
}
void PeerSet::sendRequest (const protocol::TMGetLedger& tmGL)
{
boost::recursive_mutex::scoped_lock sl (mLock);
if (mPeers.empty ())
return;
PackedMessage::pointer packet = boost::make_shared<PackedMessage> (tmGL, protocol::mtGET_LEDGER);
for (boost::unordered_map<uint64, int>::iterator it = mPeers.begin (), end = mPeers.end (); it != end; ++it)
{
Peer::pointer peer = getApp().getPeers ().getPeerById (it->first);
if (peer)
peer->sendPacket (packet, false);
}
}
int PeerSet::takePeerSetFrom (const PeerSet& s)
{
int ret = 0;
mPeers.clear ();
for (boost::unordered_map<uint64, int>::const_iterator it = s.mPeers.begin (), end = s.mPeers.end ();
it != end; ++it)
{
mPeers.insert (std::make_pair (it->first, 0));
++ret;
}
return ret;
}
int PeerSet::getPeerCount () const
{
int ret = 0;
for (boost::unordered_map<uint64, int>::const_iterator it = mPeers.begin (), end = mPeers.end (); it != end; ++it)
if (getApp().getPeers ().hasPeer (it->first))
++ret;
return ret;
}
void InboundLedger::filterNodes (std::vector<SHAMapNode>& nodeIDs, std::vector<uint256>& nodeHashes,
std::set<SHAMapNode>& recentNodes, int max, bool aggressive)
{
// ask for new nodes in preference to ones we've already asked for
assert (nodeIDs.size () == nodeHashes.size ());
std::vector<bool> duplicates;
duplicates.reserve (nodeIDs.size ());
int dupCount = 0;
for (unsigned int i = 0; i < nodeIDs.size (); ++i)
{
bool isDup = recentNodes.count (nodeIDs[i]) != 0;
duplicates.push_back (isDup);
if (isDup)
++dupCount;
}
if (dupCount == nodeIDs.size ())
{
// all duplicates
if (!aggressive)
{
nodeIDs.clear ();
nodeHashes.clear ();
return;
}
}
else if (dupCount > 0)
{
// some, but not all, duplicates
int insertPoint = 0;
for (unsigned int i = 0; i < nodeIDs.size (); ++i)
if (!duplicates[i])
{
// Keep this node
if (insertPoint != i)
{
nodeIDs[insertPoint] = nodeIDs[i];
nodeHashes[insertPoint] = nodeHashes[i];
}
++insertPoint;
}
WriteLog (lsTRACE, InboundLedger) << "filterNodes " << nodeIDs.size () << " to " << insertPoint;
nodeIDs.resize (insertPoint);
nodeHashes.resize (insertPoint);
}
if (nodeIDs.size () > max)
{
nodeIDs.resize (max);
nodeHashes.resize (max);
}
BOOST_FOREACH (const SHAMapNode & n, nodeIDs)
{
recentNodes.insert (n);
}
}
bool InboundLedger::takeBase (const std::string& data) // data must not have hash prefix
{
// Return value: true=normal, false=bad data
#ifdef LA_DEBUG
WriteLog (lsTRACE, InboundLedger) << "got base acquiring ledger " << mHash;
#endif
boost::recursive_mutex::scoped_lock sl (mLock);
if (mComplete || mFailed || mHaveBase)
return true;
mLedger = boost::make_shared<Ledger> (data, false);
if (mLedger->getHash () != mHash)
{
WriteLog (lsWARNING, InboundLedger) << "Acquire hash mismatch";
WriteLog (lsWARNING, InboundLedger) << mLedger->getHash () << "!=" << mHash;
mLedger.reset ();
#ifdef TRUST_NETWORK
assert (false);
#endif
return false;
}
mHaveBase = true;
Serializer s (data.size () + 4);
s.add32 (HashPrefix::ledgerMaster);
s.addRaw (data);
getApp().getNodeStore ().store (hotLEDGER, mLedger->getLedgerSeq (), s.peekData (), mHash);
progress ();
if (!mLedger->getTransHash ())
mHaveTransactions = true;
if (!mLedger->getAccountHash ())
mHaveState = true;
mLedger->setAcquiring ();
return true;
}
bool InboundLedger::takeTxNode (const std::list<SHAMapNode>& nodeIDs,
const std::list< Blob >& data, SHAMapAddNode& san)
{
boost::recursive_mutex::scoped_lock sl (mLock);
if (!mHaveBase)
return false;
if (mHaveTransactions || mFailed)
return true;
std::list<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin ();
std::list< Blob >::const_iterator nodeDatait = data.begin ();
TransactionStateSF tFilter (mLedger->getLedgerSeq ());
while (nodeIDit != nodeIDs.end ())
{
if (nodeIDit->isRoot ())
{
if (!san.combine (mLedger->peekTransactionMap ()->addRootNode (mLedger->getTransHash (), *nodeDatait,
snfWIRE, &tFilter)))
return false;
}
else
{
if (!san.combine (mLedger->peekTransactionMap ()->addKnownNode (*nodeIDit, *nodeDatait, &tFilter)))
return false;
}
++nodeIDit;
++nodeDatait;
}
if (!mLedger->peekTransactionMap ()->isSynching ())
{
mHaveTransactions = true;
if (mHaveState)
{
mComplete = true;
done ();
}
}
progress ();
return true;
}
bool InboundLedger::takeAsNode (const std::list<SHAMapNode>& nodeIDs,
const std::list< Blob >& data, SHAMapAddNode& san)
{
WriteLog (lsTRACE, InboundLedger) << "got ASdata (" << nodeIDs.size () << ") acquiring ledger " << mHash;
CondLog (nodeIDs.size () == 1, lsTRACE, InboundLedger) << "got AS node: " << nodeIDs.front ();
boost::recursive_mutex::scoped_lock sl (mLock);
if (!mHaveBase)
{
WriteLog (lsWARNING, InboundLedger) << "Don't have ledger base";
return false;
}
if (mHaveState || mFailed)
return true;
std::list<SHAMapNode>::const_iterator nodeIDit = nodeIDs.begin ();
std::list< Blob >::const_iterator nodeDatait = data.begin ();
AccountStateSF tFilter (mLedger->getLedgerSeq ());
while (nodeIDit != nodeIDs.end ())
{
if (nodeIDit->isRoot ())
{
if (!san.combine (mLedger->peekAccountStateMap ()->addRootNode (mLedger->getAccountHash (),
*nodeDatait, snfWIRE, &tFilter)))
{
WriteLog (lsWARNING, InboundLedger) << "Bad ledger base";
return false;
}
}
else if (!san.combine (mLedger->peekAccountStateMap ()->addKnownNode (*nodeIDit, *nodeDatait, &tFilter)))
{
WriteLog (lsWARNING, InboundLedger) << "Unable to add AS node";
return false;
}
++nodeIDit;
++nodeDatait;
}
if (!mLedger->peekAccountStateMap ()->isSynching ())
{
mHaveState = true;
if (mHaveTransactions)
{
mComplete = true;
done ();
}
}
progress ();
return true;
}
bool InboundLedger::takeAsRootNode (Blob const& data, SHAMapAddNode& san)
{
boost::recursive_mutex::scoped_lock sl (mLock);
if (mFailed || mHaveState)
return true;
if (!mHaveBase)
return false;
AccountStateSF tFilter (mLedger->getLedgerSeq ());
return san.combine (
mLedger->peekAccountStateMap ()->addRootNode (mLedger->getAccountHash (), data, snfWIRE, &tFilter));
}
bool InboundLedger::takeTxRootNode (Blob const& data, SHAMapAddNode& san)
{
boost::recursive_mutex::scoped_lock sl (mLock);
if (mFailed || mHaveState)
return true;
if (!mHaveBase)
return false;
TransactionStateSF tFilter (mLedger->getLedgerSeq ());
return san.combine (
mLedger->peekTransactionMap ()->addRootNode (mLedger->getTransHash (), data, snfWIRE, &tFilter));
}
std::vector<InboundLedger::neededHash_t> InboundLedger::getNeededHashes ()
{
std::vector<neededHash_t> ret;
if (!mHaveBase)
{
ret.push_back (std::make_pair (protocol::TMGetObjectByHash::otLEDGER, mHash));
return ret;
}
if (!mHaveState)
{
AccountStateSF filter (mLedger->getLedgerSeq ());
std::vector<uint256> v = mLedger->getNeededAccountStateHashes (4, &filter);
BOOST_FOREACH (uint256 const & h, v)
{
ret.push_back (std::make_pair (protocol::TMGetObjectByHash::otSTATE_NODE, h));
}
}
if (!mHaveTransactions)
{
TransactionStateSF filter (mLedger->getLedgerSeq ());
std::vector<uint256> v = mLedger->getNeededAccountStateHashes (4, &filter);
BOOST_FOREACH (uint256 const & h, v)
{
ret.push_back (std::make_pair (protocol::TMGetObjectByHash::otTRANSACTION_NODE, h));
}
}
return ret;
}
Json::Value InboundLedger::getJson (int)
{
Json::Value ret (Json::objectValue);
ret["hash"] = mHash.GetHex ();
if (mComplete)
ret["complete"] = true;
if (mFailed)
ret["failed"] = true;
ret["have_base"] = mHaveBase;
ret["have_state"] = mHaveState;
ret["have_transactions"] = mHaveTransactions;
if (mAborted)
ret["aborted"] = true;
ret["timeouts"] = getTimeouts ();
if (mHaveBase && !mHaveState)
{
Json::Value hv (Json::arrayValue);
std::vector<uint256> v = mLedger->peekAccountStateMap ()->getNeededHashes (16, NULL);
BOOST_FOREACH (uint256 const & h, v)
{
hv.append (h.GetHex ());
}
ret["needed_state_hashes"] = hv;
}
if (mHaveBase && !mHaveTransactions)
{
Json::Value hv (Json::arrayValue);
std::vector<uint256> v = mLedger->peekTransactionMap ()->getNeededHashes (16, NULL);
BOOST_FOREACH (uint256 const & h, v)
{
hv.append (h.GetHex ());
}
ret["needed_transaction_hashes"] = hv;
}
return ret;
}

View File

@@ -1,124 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_INBOUNDLEDGER_H
#define RIPPLE_INBOUNDLEDGER_H
// VFALCO TODO Rename to InboundLedger
// A ledger we are trying to acquire
class InboundLedger
: public PeerSet
, public boost::enable_shared_from_this <InboundLedger>
, public CountedObject <InboundLedger>
{
public:
static char const* getCountedObjectName () { return "InboundLedger"; }
typedef boost::shared_ptr <InboundLedger> pointer;
public:
InboundLedger (uint256 const& hash, uint32 seq);
virtual ~InboundLedger ()
{
;
}
bool isBase () const
{
return mHaveBase;
}
bool isAcctStComplete () const
{
return mHaveState;
}
bool isTransComplete () const
{
return mHaveTransactions;
}
bool isDone () const
{
return mAborted || isComplete () || isFailed ();
}
Ledger::ref getLedger ()
{
return mLedger;
}
void abort ()
{
mAborted = true;
}
// VFALCO NOTE what is the meaning of the return value?
bool setAccept ()
{
if (mAccept)
return false;
mAccept = true;
return true;
}
// VFALCO TODO Make thise the Listener / Observer pattern
bool addOnComplete (FUNCTION_TYPE<void (InboundLedger::pointer)>);
bool takeBase (const std::string& data);
bool takeTxNode (const std::list<SHAMapNode>& IDs, const std::list<Blob >& data,
SHAMapAddNode&);
bool takeTxRootNode (Blob const& data, SHAMapAddNode&);
bool takeAsNode (const std::list<SHAMapNode>& IDs, const std::list<Blob >& data,
SHAMapAddNode&);
bool takeAsRootNode (Blob const& data, SHAMapAddNode&);
void trigger (Peer::ref);
bool tryLocal ();
void addPeers ();
void awaitData ();
void noAwaitData ();
void checkLocal ();
typedef std::pair <protocol::TMGetObjectByHash::ObjectType, uint256> neededHash_t;
std::vector<neededHash_t> getNeededHashes ();
static void filterNodes (std::vector<SHAMapNode>& nodeIDs, std::vector<uint256>& nodeHashes,
std::set<SHAMapNode>& recentNodes, int max, bool aggressive);
Json::Value getJson (int);
private:
void done ();
void onTimer (bool progress);
void newPeer (Peer::ref peer)
{
trigger (peer);
}
boost::weak_ptr <PeerSet> pmDowncast ();
private:
Ledger::pointer mLedger;
bool mHaveBase;
bool mHaveState;
bool mHaveTransactions;
bool mAborted;
bool mSignaled;
bool mAccept;
bool mByHash;
beast::Atomic<int> mWaitCount;
uint32 mSeq;
std::set <SHAMapNode> mRecentTXNodes;
std::set <SHAMapNode> mRecentASNodes;
std::vector <FUNCTION_TYPE <void (InboundLedger::pointer)> > mOnComplete;
};
#endif
// vim:ts=4

View File

@@ -1,266 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
InboundLedger::pointer InboundLedgers::findCreate (uint256 const& hash, uint32 seq)
{
assert (hash.isNonZero ());
boost::mutex::scoped_lock sl (mLock);
InboundLedger::pointer& ptr = mLedgers[hash];
if (ptr)
{
ptr->touch ();
return ptr;
}
ptr = boost::make_shared<InboundLedger> (hash, seq);
if (!ptr->isDone ())
{
ptr->addPeers ();
ptr->setTimer (); // Cannot call in constructor
}
else
{
Ledger::pointer ledger = ptr->getLedger ();
ledger->setClosed ();
ledger->setImmutable ();
getApp().getLedgerMaster ().storeLedger (ledger);
WriteLog (lsDEBUG, InboundLedger) << "Acquiring ledger we already have: " << hash;
}
return ptr;
}
InboundLedger::pointer InboundLedgers::find (uint256 const& hash)
{
assert (hash.isNonZero ());
boost::mutex::scoped_lock sl (mLock);
std::map<uint256, InboundLedger::pointer>::iterator it = mLedgers.find (hash);
if (it != mLedgers.end ())
{
it->second->touch ();
return it->second;
}
return InboundLedger::pointer ();
}
bool InboundLedgers::hasLedger (uint256 const& hash)
{
assert (hash.isNonZero ());
boost::mutex::scoped_lock sl (mLock);
return mLedgers.find (hash) != mLedgers.end ();
}
void InboundLedgers::dropLedger (uint256 const& hash)
{
assert (hash.isNonZero ());
boost::mutex::scoped_lock sl (mLock);
mLedgers.erase (hash);
}
bool InboundLedgers::awaitLedgerData (uint256 const& ledgerHash)
{
InboundLedger::pointer ledger = find (ledgerHash);
if (!ledger)
return false;
ledger->awaitData ();
return true;
}
/*
This gets called when
"We got some data from an inbound ledger"
inboundLedgerTrigger:
"What do we do with this partial data?"
Figures out what to do with the responses to our requests for information.
*/
// means "We got some data from an inbound ledger"
void InboundLedgers::gotLedgerData (Job&, uint256 hash,
boost::shared_ptr<protocol::TMLedgerData> packet_ptr, boost::weak_ptr<Peer> wPeer)
{
protocol::TMLedgerData& packet = *packet_ptr;
Peer::pointer peer = wPeer.lock ();
WriteLog (lsTRACE, InboundLedger) << "Got data (" << packet.nodes ().size () << ") for acquiring ledger: " << hash;
InboundLedger::pointer ledger = find (hash);
if (!ledger)
{
WriteLog (lsTRACE, InboundLedger) << "Got data for ledger we're not acquiring";
if (peer)
peer->applyLoadCharge (LT_InvalidRequest);
return;
}
ledger->noAwaitData ();
if (!peer)
return;
if (packet.type () == protocol::liBASE)
{
if (packet.nodes_size () < 1)
{
WriteLog (lsWARNING, InboundLedger) << "Got empty base data";
peer->applyLoadCharge (LT_InvalidRequest);
return;
}
if (!ledger->takeBase (packet.nodes (0).nodedata ()))
{
WriteLog (lsWARNING, InboundLedger) << "Got invalid base data";
peer->applyLoadCharge (LT_InvalidRequest);
return;
}
SHAMapAddNode san = SHAMapAddNode::useful ();
if ((packet.nodes ().size () > 1) && !ledger->takeAsRootNode (strCopy (packet.nodes (1).nodedata ()), san))
{
WriteLog (lsWARNING, InboundLedger) << "Included ASbase invalid";
}
if ((packet.nodes ().size () > 2) && !ledger->takeTxRootNode (strCopy (packet.nodes (2).nodedata ()), san))
{
WriteLog (lsWARNING, InboundLedger) << "Included TXbase invalid";
}
if (!san.isInvalid ())
{
ledger->progress ();
ledger->trigger (peer);
}
else
WriteLog (lsDEBUG, InboundLedger) << "Peer sends invalid base data";
return;
}
if ((packet.type () == protocol::liTX_NODE) || (packet.type () == protocol::liAS_NODE))
{
std::list<SHAMapNode> nodeIDs;
std::list< Blob > nodeData;
if (packet.nodes ().size () <= 0)
{
WriteLog (lsINFO, InboundLedger) << "Got response with no nodes";
peer->applyLoadCharge (LT_InvalidRequest);
return;
}
for (int i = 0; i < packet.nodes ().size (); ++i)
{
const protocol::TMLedgerNode& node = packet.nodes (i);
if (!node.has_nodeid () || !node.has_nodedata ())
{
WriteLog (lsWARNING, InboundLedger) << "Got bad node";
peer->applyLoadCharge (LT_InvalidRequest);
return;
}
nodeIDs.push_back (SHAMapNode (node.nodeid ().data (), node.nodeid ().size ()));
nodeData.push_back (Blob (node.nodedata ().begin (), node.nodedata ().end ()));
}
SHAMapAddNode ret;
if (packet.type () == protocol::liTX_NODE)
ledger->takeTxNode (nodeIDs, nodeData, ret);
else
ledger->takeAsNode (nodeIDs, nodeData, ret);
if (!ret.isInvalid ())
{
ledger->progress ();
ledger->trigger (peer);
}
else
WriteLog (lsDEBUG, InboundLedger) << "Peer sends invalid node data";
return;
}
WriteLog (lsWARNING, InboundLedger) << "Not sure what ledger data we got";
peer->applyLoadCharge (LT_InvalidRequest);
}
void InboundLedgers::sweep ()
{
mRecentFailures.sweep ();
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
boost::mutex::scoped_lock sl (mLock);
std::map<uint256, InboundLedger::pointer>::iterator it = mLedgers.begin ();
while (it != mLedgers.end ())
{
if (it->second->getLastAction () > now)
{
it->second->touch ();
++it;
}
else if ((it->second->getLastAction () + 60) < now)
mLedgers.erase (it++);
else
++it;
}
}
int InboundLedgers::getFetchCount (int& timeoutCount)
{
timeoutCount = 0;
int ret = 0;
std::map<uint256, InboundLedger::pointer> inboundLedgers;
{
boost::mutex::scoped_lock sl (mLock);
inboundLedgers = mLedgers;
}
typedef std::pair<uint256, InboundLedger::pointer> u256_acq_pair;
BOOST_FOREACH (const u256_acq_pair & it, inboundLedgers)
{
if (it.second->isActive ())
{
++ret;
timeoutCount += it.second->getTimeouts ();
}
}
return ret;
}
void InboundLedgers::gotFetchPack (Job&)
{
std::vector<InboundLedger::pointer> acquires;
{
boost::mutex::scoped_lock sl (mLock);
acquires.reserve (mLedgers.size ());
typedef std::pair<uint256, InboundLedger::pointer> u256_acq_pair;
BOOST_FOREACH (const u256_acq_pair & it, mLedgers)
acquires.push_back (it.second);
}
BOOST_FOREACH (const InboundLedger::pointer & acquire, acquires)
{
acquire->checkLocal ();
}
}
// vim:ts=4

View File

@@ -1,68 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_INBOUNDLEDGERS_H
#define RIPPLE_INBOUNDLEDGERS_H
/** Manages the lifetime of inbound ledgers.
@see InboundLedger
*/
// VFALCO TODO Rename to InboundLedgers
// VFALCO TODO Create abstract interface
class InboundLedgers : LeakChecked <InboundLedger>
{
public:
// How long before we try again to acquire the same ledger
static const int kReacquireIntervalSeconds = 600;
InboundLedgers ()
: mRecentFailures ("LedgerAcquireRecentFailures", 0, kReacquireIntervalSeconds)
{
}
// VFALCO TODO Should this be called findOrAdd ?
//
InboundLedger::pointer findCreate (uint256 const& hash, uint32 seq);
InboundLedger::pointer find (uint256 const& hash);
bool hasLedger (LedgerHash const& ledgerHash);
void dropLedger (LedgerHash const& ledgerHash);
bool awaitLedgerData (LedgerHash const& ledgerHash);
// VFALCO TODO Why is hash passed by value?
// VFALCO TODO Remove the dependency on the Peer object.
//
void gotLedgerData (Job&,
LedgerHash hash,
boost::shared_ptr <protocol::TMLedgerData> packet,
boost::weak_ptr<Peer> peer);
int getFetchCount (int& timeoutCount);
void logFailure (uint256 const& h)
{
mRecentFailures.add (h);
}
bool isFailure (uint256 const& h)
{
return mRecentFailures.isPresent (h, false);
}
void gotFetchPack (Job&);
void sweep ();
private:
boost::mutex mLock;
std::map <uint256, InboundLedger::pointer> mLedgers;
KeyCache <uint256, UptimeTimerAdapter> mRecentFailures;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,271 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LEDGERENTRYSET_H
#define RIPPLE_LEDGERENTRYSET_H
enum TransactionEngineParams
{
tapNONE = 0x00,
tapNO_CHECK_SIGN = 0x01, // Signature already checked
tapOPEN_LEDGER = 0x10, // Transaction is running against an open ledger
// true = failures are not forwarded, check transaction fee
// false = debit ledger for consumed funds
tapRETRY = 0x20, // This is not the transaction's last pass
// Transaction can be retried, soft failures allowed
tapADMIN = 0x400, // Transaction came from a privileged source
};
enum LedgerEntryAction
{
taaNONE,
taaCACHED, // Unmodified.
taaMODIFY, // Modifed, must have previously been taaCACHED.
taaDELETE, // Delete, must have previously been taaDELETE or taaMODIFY.
taaCREATE, // Newly created.
};
class LedgerEntrySetEntry
: public CountedObject <LedgerEntrySetEntry>
{
public:
static char const* getCountedObjectName () { return "LedgerEntrySetEntry"; }
SLE::pointer mEntry;
LedgerEntryAction mAction;
int mSeq;
LedgerEntrySetEntry (SLE::ref e, LedgerEntryAction a, int s)
: mEntry (e)
, mAction (a)
, mSeq (s)
{
}
};
/** An LES is a LedgerEntrySet.
It's a view into a ledger used while a transaction is processing.
The transaction manipulates the LES rather than the ledger
(because it's cheaper, can be checkpointed, and so on). When the
transaction finishes, the LES is committed into the ledger to make
the modifications. The transaction metadata is built from the LES too.
*/
class LedgerEntrySet
: public CountedObject <LedgerEntrySet>
{
public:
static char const* getCountedObjectName () { return "LedgerEntrySet"; }
LedgerEntrySet (Ledger::ref ledger, TransactionEngineParams tep, bool immutable = false) :
mLedger (ledger), mParams (tep), mSeq (0), mImmutable (immutable)
{
}
LedgerEntrySet () : mParams (tapNONE), mSeq (0), mImmutable (false)
{
}
// set functions
void setImmutable ()
{
mImmutable = true;
}
bool isImmutable () const
{
return mImmutable;
}
LedgerEntrySet duplicate () const; // Make a duplicate of this set
void setTo (const LedgerEntrySet&); // Set this set to have the same contents as another
void swapWith (LedgerEntrySet&); // Swap the contents of two sets
void invalidate ()
{
mLedger.reset ();
}
bool isValid () const
{
return mLedger != nullptr;
}
int getSeq () const
{
return mSeq;
}
TransactionEngineParams getParams () const
{
return mParams;
}
void bumpSeq ()
{
++mSeq;
}
void init (Ledger::ref ledger, uint256 const & transactionID, uint32 ledgerID, TransactionEngineParams params);
void clear ();
Ledger::pointer& getLedger ()
{
return mLedger;
}
Ledger::ref getLedgerRef () const
{
return mLedger;
}
// basic entry functions
SLE::pointer getEntry (uint256 const & index, LedgerEntryAction&);
LedgerEntryAction hasEntry (uint256 const & index) const;
void entryCache (SLE::ref); // Add this entry to the cache
void entryCreate (SLE::ref); // This entry will be created
void entryDelete (SLE::ref); // This entry will be deleted
void entryModify (SLE::ref); // This entry will be modified
bool hasChanges (); // True if LES has any changes
// higher-level ledger functions
SLE::pointer entryCreate (LedgerEntryType letType, uint256 const & uIndex);
SLE::pointer entryCache (LedgerEntryType letType, uint256 const & uIndex);
// Directory functions.
TER dirAdd (
uint64 & uNodeDir, // Node of entry.
uint256 const & uRootIndex,
uint256 const & uLedgerIndex,
FUNCTION_TYPE<void (SLE::ref)> fDescriber);
TER dirDelete (
const bool bKeepRoot,
const uint64 & uNodeDir, // Node item is mentioned in.
uint256 const & uRootIndex,
uint256 const & uLedgerIndex, // Item being deleted
const bool bStable,
const bool bSoft);
bool dirFirst (uint256 const & uRootIndex, SLE::pointer & sleNode, unsigned int & uDirEntry, uint256 & uEntryIndex);
bool dirNext (uint256 const & uRootIndex, SLE::pointer & sleNode, unsigned int & uDirEntry, uint256 & uEntryIndex);
TER dirCount (uint256 const & uDirIndex, uint32 & uCount);
uint256 getNextLedgerIndex (uint256 const & uHash);
uint256 getNextLedgerIndex (uint256 const & uHash, uint256 const & uEnd);
void ownerCountAdjust (const uint160 & uOwnerID, int iAmount, SLE::ref sleAccountRoot = SLE::pointer ());
// Offer functions.
TER offerDelete (uint256 const & uOfferIndex);
TER offerDelete (SLE::ref sleOffer, uint256 const & uOfferIndex, const uint160 & uOwnerID);
// Balance functions.
uint32 rippleTransferRate (const uint160 & uIssuerID);
uint32 rippleTransferRate (const uint160 & uSenderID, const uint160 & uReceiverID, const uint160 & uIssuerID);
STAmount rippleOwed (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID);
STAmount rippleLimit (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID);
uint32 rippleQualityIn (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID,
SField::ref sfLow = sfLowQualityIn, SField::ref sfHigh = sfHighQualityIn);
uint32 rippleQualityOut (const uint160 & uToAccountID, const uint160 & uFromAccountID, const uint160 & uCurrencyID)
{
return rippleQualityIn (uToAccountID, uFromAccountID, uCurrencyID, sfLowQualityOut, sfHighQualityOut);
}
STAmount rippleHolds (const uint160 & uAccountID, const uint160 & uCurrencyID, const uint160 & uIssuerID);
STAmount rippleTransferFee (const uint160 & uSenderID, const uint160 & uReceiverID, const uint160 & uIssuerID, const STAmount & saAmount);
TER rippleCredit (const uint160 & uSenderID, const uint160 & uReceiverID, const STAmount & saAmount, bool bCheckIssuer = true);
TER rippleSend (const uint160 & uSenderID, const uint160 & uReceiverID, const STAmount & saAmount, STAmount & saActual);
STAmount accountHolds (const uint160 & uAccountID, const uint160 & uCurrencyID, const uint160 & uIssuerID);
STAmount accountFunds (const uint160 & uAccountID, const STAmount & saDefault);
TER accountSend (const uint160 & uSenderID, const uint160 & uReceiverID, const STAmount & saAmount);
TER trustCreate (
const bool bSrcHigh,
const uint160 & uSrcAccountID,
const uint160 & uDstAccountID,
uint256 const & uIndex,
SLE::ref sleAccount,
const bool bAuth,
const STAmount & saSrcBalance,
const STAmount & saSrcLimit,
const uint32 uSrcQualityIn = 0,
const uint32 uSrcQualityOut = 0);
TER trustDelete (SLE::ref sleRippleState, const uint160 & uLowAccountID, const uint160 & uHighAccountID);
Json::Value getJson (int) const;
void calcRawMeta (Serializer&, TER result, uint32 index);
// iterator functions
typedef std::map<uint256, LedgerEntrySetEntry>::iterator iterator;
typedef std::map<uint256, LedgerEntrySetEntry>::const_iterator const_iterator;
bool isEmpty () const
{
return mEntries.empty ();
}
std::map<uint256, LedgerEntrySetEntry>::const_iterator begin () const
{
return mEntries.begin ();
}
std::map<uint256, LedgerEntrySetEntry>::const_iterator end () const
{
return mEntries.end ();
}
std::map<uint256, LedgerEntrySetEntry>::iterator begin ()
{
return mEntries.begin ();
}
std::map<uint256, LedgerEntrySetEntry>::iterator end ()
{
return mEntries.end ();
}
static bool intersect (const LedgerEntrySet & lesLeft, const LedgerEntrySet & lesRight);
private:
Ledger::pointer mLedger;
std::map<uint256, LedgerEntrySetEntry> mEntries; // cannot be unordered!
TransactionMetaSet mSet;
TransactionEngineParams mParams;
int mSeq;
bool mImmutable;
LedgerEntrySet (Ledger::ref ledger, const std::map<uint256, LedgerEntrySetEntry>& e,
const TransactionMetaSet & s, int m) :
mLedger (ledger), mEntries (e), mSet (s), mParams (tapNONE), mSeq (m), mImmutable (false)
{
;
}
SLE::pointer getForMod (uint256 const & node, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx (const RippleAddress & threadTo, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadTx (SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods);
bool threadOwners (SLE::ref node, Ledger::ref ledger, boost::unordered_map<uint256, SLE::pointer>& newMods);
};
inline LedgerEntrySet::iterator range_begin (LedgerEntrySet& x)
{
return x.begin ();
}
inline LedgerEntrySet::iterator range_end (LedgerEntrySet& x)
{
return x.end ();
}
#endif

View File

@@ -1,141 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// VFALCO TODO replace macros
#ifndef CACHED_LEDGER_NUM
#define CACHED_LEDGER_NUM 96
#endif
#ifndef CACHED_LEDGER_AGE
#define CACHED_LEDGER_AGE 120
#endif
// FIXME: Need to clean up ledgers by index at some point
LedgerHistory::LedgerHistory () : mLedgersByHash ("LedgerCache", CACHED_LEDGER_NUM, CACHED_LEDGER_AGE)
{
;
}
void LedgerHistory::addLedger (Ledger::pointer ledger)
{
assert (ledger->isImmutable ());
mLedgersByHash.canonicalize (ledger->getHash (), ledger, true);
}
void LedgerHistory::addAcceptedLedger (Ledger::pointer ledger, bool fromConsensus)
{
assert (ledger && ledger->isAccepted () && ledger->isImmutable ());
assert (ledger->peekAccountStateMap ()->getHash ().isNonZero ());
uint256 h (ledger->getHash ());
boost::recursive_mutex::scoped_lock sl (mLedgersByHash.peekMutex ());
mLedgersByHash.canonicalize (h, ledger, true);
assert (ledger);
assert (ledger->isAccepted ());
assert (ledger->isImmutable ());
mLedgersByIndex[ledger->getLedgerSeq ()] = ledger->getHash ();
ledger->pendSave (fromConsensus);
}
uint256 LedgerHistory::getLedgerHash (uint32 index)
{
boost::recursive_mutex::scoped_lock sl (mLedgersByHash.peekMutex ());
std::map<uint32, uint256>::iterator it (mLedgersByIndex.find (index));
if (it != mLedgersByIndex.end ())
return it->second;
sl.unlock ();
return uint256 ();
}
Ledger::pointer LedgerHistory::getLedgerBySeq (uint32 index)
{
boost::recursive_mutex::scoped_lock sl (mLedgersByHash.peekMutex ());
std::map<uint32, uint256>::iterator it (mLedgersByIndex.find (index));
if (it != mLedgersByIndex.end ())
{
uint256 hash = it->second;
sl.unlock ();
return getLedgerByHash (hash);
}
sl.unlock ();
Ledger::pointer ret (Ledger::loadByIndex (index));
if (!ret)
return ret;
assert (ret->getLedgerSeq () == index);
sl.lock ();
assert (ret->isImmutable ());
mLedgersByHash.canonicalize (ret->getHash (), ret);
mLedgersByIndex[ret->getLedgerSeq ()] = ret->getHash ();
return (ret->getLedgerSeq () == index) ? ret : Ledger::pointer ();
}
Ledger::pointer LedgerHistory::getLedgerByHash (uint256 const& hash)
{
Ledger::pointer ret = mLedgersByHash.fetch (hash);
if (ret)
{
assert (ret->isImmutable ());
assert (ret->getHash () == hash); // FIXME: We seem to be getting these
return ret;
}
ret = Ledger::loadByHash (hash);
if (!ret)
return ret;
assert (ret->isImmutable ());
assert (ret->getHash () == hash);
mLedgersByHash.canonicalize (ret->getHash (), ret);
assert (ret->getHash () == hash);
return ret;
}
Ledger::pointer LedgerHistory::canonicalizeLedger (Ledger::pointer ledger, bool save)
{
assert (ledger->isImmutable ());
uint256 h (ledger->getHash ());
if (!save)
{
// return input ledger if not in map, otherwise, return corresponding map ledger
Ledger::pointer ret = mLedgersByHash.fetch (h);
if (ret)
return ret;
return ledger;
}
// save input ledger in map if not in map, otherwise return corresponding map ledger
boost::recursive_mutex::scoped_lock sl (mLedgersByHash.peekMutex ());
mLedgersByHash.canonicalize (h, ledger);
if (ledger->isAccepted ())
mLedgersByIndex[ledger->getLedgerSeq ()] = ledger->getHash ();
return ledger;
}
void LedgerHistory::tune (int size, int age)
{
mLedgersByHash.setTargetSize (size);
mLedgersByHash.setTargetAge (age);
}
// vim:ts=4

View File

@@ -1,48 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LEDGERHISTORY_H
#define RIPPLE_LEDGERHISTORY_H
// VFALCO TODO Rename to OldLedgers ?
class LedgerHistory : LeakChecked <LedgerHistory>
{
public:
LedgerHistory ();
void addLedger (Ledger::pointer ledger);
void addAcceptedLedger (Ledger::pointer ledger, bool fromConsensus);
float getCacheHitRate ()
{
return mLedgersByHash.getHitRate ();
}
Ledger::pointer getLedgerBySeq (LedgerIndex ledgerIndex);
// VFALCO NOTE shouldn't this call the function above?
LedgerHash getLedgerHash (LedgerIndex ledgerIndex);
Ledger::pointer getLedgerByHash (LedgerHash const& ledgerHash);
Ledger::pointer canonicalizeLedger (Ledger::pointer ledger, bool cache);
void tune (int size, int age);
void sweep ()
{
mLedgersByHash.sweep ();
}
private:
TaggedCache <LedgerHash, Ledger, UptimeTimerAdapter> mLedgersByHash;
// Maps ledger indexes to the corresponding hash.
std::map <LedgerIndex, LedgerHash> mLedgersByIndex; // accepted ledgers
};
#endif

View File

@@ -1,440 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
SETUP_LOG (SqliteDatabase)
SqliteStatement::SqliteStatement (SqliteDatabase* db, const char* sql, bool aux)
{
assert (db);
sqlite3* conn = aux ? db->getAuxConnection () : db->peekConnection ();
int j = sqlite3_prepare_v2 (conn, sql, strlen (sql) + 1, &statement, NULL);
if (j != SQLITE_OK)
throw j;
}
SqliteStatement::SqliteStatement (SqliteDatabase* db, const std::string& sql, bool aux)
{
assert (db);
sqlite3* conn = aux ? db->getAuxConnection () : db->peekConnection ();
int j = sqlite3_prepare_v2 (conn, sql.c_str (), sql.size () + 1, &statement, NULL);
if (j != SQLITE_OK)
throw j;
}
SqliteStatement::~SqliteStatement ()
{
sqlite3_finalize (statement);
}
SqliteDatabase::SqliteDatabase (const char* host)
: Database (host)
, mWalQ (NULL)
, walRunning (false)
{
mConnection = NULL;
mAuxConnection = NULL;
mCurrentStmt = NULL;
}
void SqliteDatabase::connect ()
{
int rc = sqlite3_open (mHost.c_str (), &mConnection);
if (rc)
{
WriteLog (lsFATAL, SqliteDatabase) << "Can't open " << mHost << " " << rc;
sqlite3_close (mConnection);
assert ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
}
}
sqlite3* SqliteDatabase::getAuxConnection ()
{
boost::mutex::scoped_lock sl (walMutex);
if (mAuxConnection == NULL)
{
int rc = sqlite3_open (mHost.c_str (), &mAuxConnection);
if (rc)
{
WriteLog (lsFATAL, SqliteDatabase) << "Can't aux open " << mHost << " " << rc;
assert ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
if (mAuxConnection != NULL)
{
sqlite3_close (mConnection);
mAuxConnection = NULL;
}
}
}
return mAuxConnection;
}
void SqliteDatabase::disconnect ()
{
sqlite3_finalize (mCurrentStmt);
sqlite3_close (mConnection);
if (mAuxConnection != NULL)
sqlite3_close (mAuxConnection);
}
// returns true if the query went ok
bool SqliteDatabase::executeSQL (const char* sql, bool fail_ok)
{
#ifdef DEBUG_HANGING_LOCKS
assert (fail_ok || (mCurrentStmt == NULL));
#endif
sqlite3_finalize (mCurrentStmt);
int rc = sqlite3_prepare_v2 (mConnection, sql, -1, &mCurrentStmt, NULL);
if (SQLITE_OK != rc)
{
if (!fail_ok)
{
#ifdef BEAST_DEBUG
WriteLog (lsWARNING, SqliteDatabase) << "Perror:" << mHost << ": " << rc;
WriteLog (lsWARNING, SqliteDatabase) << "Statement: " << sql;
WriteLog (lsWARNING, SqliteDatabase) << "Error: " << sqlite3_errmsg (mConnection);
#endif
}
endIterRows ();
return false;
}
rc = sqlite3_step (mCurrentStmt);
if (rc == SQLITE_ROW)
{
mMoreRows = true;
}
else if (rc == SQLITE_DONE)
{
endIterRows ();
mMoreRows = false;
}
else
{
if ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED))
{
WriteLog (lsFATAL, SqliteDatabase) << mHost << " returns error " << rc << ": " << sqlite3_errmsg (mConnection);
assert (false);
}
mMoreRows = false;
if (!fail_ok)
{
#ifdef BEAST_DEBUG
WriteLog (lsWARNING, SqliteDatabase) << "SQL Serror:" << mHost << ": " << rc;
WriteLog (lsWARNING, SqliteDatabase) << "Statement: " << sql;
WriteLog (lsWARNING, SqliteDatabase) << "Error: " << sqlite3_errmsg (mConnection);
#endif
}
endIterRows ();
return false;
}
return true;
}
// returns false if there are no results
bool SqliteDatabase::startIterRows (bool finalize)
{
mColNameTable.clear ();
mColNameTable.resize (sqlite3_column_count (mCurrentStmt));
for (unsigned n = 0; n < mColNameTable.size (); n++)
{
mColNameTable[n] = sqlite3_column_name (mCurrentStmt, n);
}
if (!mMoreRows && finalize)
endIterRows ();
return (mMoreRows);
}
void SqliteDatabase::endIterRows ()
{
sqlite3_finalize (mCurrentStmt);
mCurrentStmt = NULL;
}
// call this after you executeSQL
// will return false if there are no more rows
bool SqliteDatabase::getNextRow (bool finalize)
{
if (mMoreRows)
{
int rc = sqlite3_step (mCurrentStmt);
if (rc == SQLITE_ROW)
return (true);
assert ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
CondLog ((rc != SQLITE_DONE), lsWARNING, SqliteDatabase) << "Rerror: " << mHost << ": " << rc;
}
if (finalize)
endIterRows ();
return false;
}
bool SqliteDatabase::getNull (int colIndex)
{
return (SQLITE_NULL == sqlite3_column_type (mCurrentStmt, colIndex));
}
char* SqliteDatabase::getStr (int colIndex, std::string& retStr)
{
const char* text = reinterpret_cast<const char*> (sqlite3_column_text (mCurrentStmt, colIndex));
retStr = (text == NULL) ? "" : text;
return const_cast<char*> (retStr.c_str ());
}
int32 SqliteDatabase::getInt (int colIndex)
{
return (sqlite3_column_int (mCurrentStmt, colIndex));
}
float SqliteDatabase::getFloat (int colIndex)
{
return (static_cast <float> (sqlite3_column_double (mCurrentStmt, colIndex)));
}
bool SqliteDatabase::getBool (int colIndex)
{
return (sqlite3_column_int (mCurrentStmt, colIndex) ? true : false);
}
int SqliteDatabase::getBinary (int colIndex, unsigned char* buf, int maxSize)
{
const void* blob = sqlite3_column_blob (mCurrentStmt, colIndex);
int size = sqlite3_column_bytes (mCurrentStmt, colIndex);
if (size < maxSize) maxSize = size;
memcpy (buf, blob, maxSize);
return (size);
}
Blob SqliteDatabase::getBinary (int colIndex)
{
const unsigned char* blob = reinterpret_cast<const unsigned char*> (sqlite3_column_blob (mCurrentStmt, colIndex));
size_t iSize = sqlite3_column_bytes (mCurrentStmt, colIndex);
Blob vucResult;
vucResult.resize (iSize);
std::copy (blob, blob + iSize, vucResult.begin ());
return vucResult;
}
uint64 SqliteDatabase::getBigInt (int colIndex)
{
return (sqlite3_column_int64 (mCurrentStmt, colIndex));
}
int SqliteDatabase::getKBUsedAll ()
{
return static_cast<int> (sqlite3_memory_used () / 1024);
}
int SqliteDatabase::getKBUsedDB ()
{
int cur = 0, hiw = 0;
sqlite3_db_status (mConnection, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiw, 0);
return cur / 1024;
}
static int SqliteWALHook (void* s, sqlite3* dbCon, const char* dbName, int walSize)
{
(reinterpret_cast<SqliteDatabase*> (s))->doHook (dbName, walSize);
return SQLITE_OK;
}
bool SqliteDatabase::setupCheckpointing (JobQueue* q)
{
mWalQ = q;
sqlite3_wal_hook (mConnection, SqliteWALHook, this);
return true;
}
void SqliteDatabase::doHook (const char* db, int pages)
{
if (pages < 1000)
return;
{
boost::mutex::scoped_lock sl (walMutex);
if (walRunning)
return;
walRunning = true;
}
if (mWalQ)
mWalQ->addJob (jtWAL, std::string ("WAL:") + mHost, BIND_TYPE (&SqliteDatabase::runWal, this));
else
boost::thread (BIND_TYPE (&SqliteDatabase::runWal, this)).detach ();
}
void SqliteDatabase::runWal ()
{
int log = 0, ckpt = 0;
int ret = sqlite3_wal_checkpoint_v2 (mConnection, NULL, SQLITE_CHECKPOINT_PASSIVE, &log, &ckpt);
if (ret != SQLITE_OK)
{
WriteLog ((ret == SQLITE_LOCKED) ? lsTRACE : lsWARNING, SqliteDatabase) << "WAL("
<< sqlite3_db_filename (mConnection, "main") << "): error " << ret;
}
else
WriteLog (lsTRACE, SqliteDatabase) << "WAL(" << sqlite3_db_filename (mConnection, "main") <<
"): frames=" << log << ", written=" << ckpt;
{
boost::mutex::scoped_lock sl (walMutex);
walRunning = false;
}
}
sqlite3_stmt* SqliteStatement::peekStatement ()
{
return statement;
}
int SqliteStatement::bind (int position, const void* data, int length)
{
return sqlite3_bind_blob (statement, position, data, length, SQLITE_TRANSIENT);
}
int SqliteStatement::bindStatic (int position, const void* data, int length)
{
return sqlite3_bind_blob (statement, position, data, length, SQLITE_STATIC);
}
int SqliteStatement::bindStatic (int position, Blob const& value)
{
return sqlite3_bind_blob (statement, position, &value.front (), value.size (), SQLITE_STATIC);
}
int SqliteStatement::bind (int position, uint32 value)
{
return sqlite3_bind_int64 (statement, position, static_cast<sqlite3_int64> (value));
}
int SqliteStatement::bind (int position, const std::string& value)
{
return sqlite3_bind_text (statement, position, value.data (), value.size (), SQLITE_TRANSIENT);
}
int SqliteStatement::bindStatic (int position, const std::string& value)
{
return sqlite3_bind_text (statement, position, value.data (), value.size (), SQLITE_STATIC);
}
int SqliteStatement::bind (int position)
{
return sqlite3_bind_null (statement, position);
}
int SqliteStatement::size (int column)
{
return sqlite3_column_bytes (statement, column);
}
const void* SqliteStatement::peekBlob (int column)
{
return sqlite3_column_blob (statement, column);
}
Blob SqliteStatement::getBlob (int column)
{
int size = sqlite3_column_bytes (statement, column);
Blob ret (size);
memcpy (& (ret.front ()), sqlite3_column_blob (statement, column), size);
return ret;
}
std::string SqliteStatement::getString (int column)
{
return reinterpret_cast<const char*> (sqlite3_column_text (statement, column));
}
const char* SqliteStatement::peekString (int column)
{
return reinterpret_cast<const char*> (sqlite3_column_text (statement, column));
}
uint32 SqliteStatement::getUInt32 (int column)
{
return static_cast<uint32> (sqlite3_column_int64 (statement, column));
}
int64 SqliteStatement::getInt64 (int column)
{
return sqlite3_column_int64 (statement, column);
}
int SqliteStatement::step ()
{
return sqlite3_step (statement);
}
int SqliteStatement::reset ()
{
return sqlite3_reset (statement);
}
bool SqliteStatement::isOk (int j)
{
return j == SQLITE_OK;
}
bool SqliteStatement::isDone (int j)
{
return j == SQLITE_DONE;
}
bool SqliteStatement::isRow (int j)
{
return j == SQLITE_ROW;
}
bool SqliteStatement::isError (int j)
{
switch (j)
{
case SQLITE_OK:
case SQLITE_ROW:
case SQLITE_DONE:
return true;
default:
return false;
}
}
std::string SqliteStatement::getError (int j)
{
return sqlite3_errstr (j);
}
// vim:ts=4

View File

@@ -1,125 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_SQLITEDATABASE_RIPPLEHEADER
#define RIPPLE_SQLITEDATABASE_RIPPLEHEADER
class SqliteDatabase : public Database
{
public:
explicit SqliteDatabase (char const* host);
void connect ();
void disconnect ();
// returns true if the query went ok
bool executeSQL (const char* sql, bool fail_okay);
// tells you how many rows were changed by an update or insert
int getNumRowsAffected ();
// returns false if there are no results
bool startIterRows (bool finalize);
void endIterRows ();
// call this after you executeSQL
// will return false if there are no more rows
bool getNextRow (bool finalize);
bool getNull (int colIndex);
char* getStr (int colIndex, std::string& retStr);
int32 getInt (int colIndex);
float getFloat (int colIndex);
bool getBool (int colIndex);
// returns amount stored in buf
int getBinary (int colIndex, unsigned char* buf, int maxSize);
Blob getBinary (int colIndex);
uint64 getBigInt (int colIndex);
sqlite3* peekConnection ()
{
return mConnection;
}
sqlite3* getAuxConnection ();
virtual bool setupCheckpointing (JobQueue*);
virtual SqliteDatabase* getSqliteDB ()
{
return this;
}
void runWal ();
void doHook (const char* db, int walSize);
int getKBUsedDB ();
int getKBUsedAll ();
private:
sqlite3* mConnection;
// VFALCO TODO Why do we need an "aux" connection? Should just use a second SqliteDatabase object.
sqlite3* mAuxConnection;
sqlite3_stmt* mCurrentStmt;
bool mMoreRows;
boost::mutex walMutex;
JobQueue* mWalQ;
bool walRunning;
};
class SqliteStatement
{
private:
SqliteStatement (const SqliteStatement&); // no implementation
SqliteStatement& operator= (const SqliteStatement&); // no implementation
protected:
sqlite3_stmt* statement;
public:
// VFALCO TODO This is quite a convoluted interface. A mysterious "aux" connection?
// Why not just have two SqliteDatabase objects?
//
SqliteStatement (SqliteDatabase* db, const char* statement, bool aux = false);
SqliteStatement (SqliteDatabase* db, const std::string& statement, bool aux = false);
~SqliteStatement ();
sqlite3_stmt* peekStatement ();
// positions start at 1
int bind (int position, const void* data, int length);
int bindStatic (int position, const void* data, int length);
int bindStatic (int position, Blob const& value);
int bind (int position, const std::string& value);
int bindStatic (int position, const std::string& value);
int bind (int position, uint32 value);
int bind (int position);
// columns start at 0
int size (int column);
const void* peekBlob (int column);
Blob getBlob (int column);
std::string getString (int column);
const char* peekString (int column);
uint32 getUInt32 (int column);
int64 getInt64 (int column);
int step ();
int reset ();
// translate return values of step and reset
bool isOk (int);
bool isDone (int);
bool isRow (int);
bool isError (int);
std::string getError (int);
};
#endif
// vim:ts=4