mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 19:15:54 +00:00
Move files to ripple_app
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 ()
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1,5 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user