mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-01 16:35:53 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin
This commit is contained in:
@@ -227,8 +227,9 @@ void ConnectionPool::policyHandler(const boost::system::error_code& ecResult)
|
||||
|
||||
// YYY: Should probably do this in the background.
|
||||
// YYY: Might end up sending to disconnected peer?
|
||||
void ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg)
|
||||
int ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg)
|
||||
{
|
||||
int sentTo = 0;
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
BOOST_FOREACH(naPeer pair, mConnectedMap)
|
||||
@@ -237,8 +238,13 @@ void ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer&
|
||||
if (!peer)
|
||||
std::cerr << "CP::RM null peer in list" << std::endl;
|
||||
else if ((!fromPeer || !(peer.get() == fromPeer)) && peer->isConnected())
|
||||
{
|
||||
++sentTo;
|
||||
peer->sendPacket(msg);
|
||||
}
|
||||
}
|
||||
|
||||
return sentTo;
|
||||
}
|
||||
|
||||
// Schedule a connection via scanning.
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
void start();
|
||||
|
||||
// Send message to network.
|
||||
void relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg);
|
||||
int relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg);
|
||||
|
||||
// Manual connection request.
|
||||
// Queue for immediate scanning.
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
// #define EC_DEBUG
|
||||
|
||||
// Functions to add CKey support for deterministic EC keys
|
||||
|
||||
#include "Serializer.h"
|
||||
@@ -107,7 +109,9 @@ EC_KEY* CKey::GenerateRootDeterministicKey(const uint128& seed)
|
||||
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
assert(EC_KEY_check_key(pkey)==1);
|
||||
#ifdef EC_DEBUG
|
||||
assert(EC_KEY_check_key(pkey)==1); // CAUTION: This check is *very* expensive
|
||||
#endif
|
||||
return pkey;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
// These must stay at the top of this file
|
||||
std::map<int, SField::ptr> SField::codeToField;
|
||||
@@ -52,7 +53,8 @@ SField::ref SField::getField(int code)
|
||||
return sfInvalid;
|
||||
}
|
||||
|
||||
return *(new SField(code, static_cast<SerializedTypeID>(type), field, NULL));
|
||||
std::string dynName = lexical_cast_i(type) + "/" + lexical_cast_i(field);
|
||||
return *(new SField(code, static_cast<SerializedTypeID>(type), field, dynName.c_str()));
|
||||
}
|
||||
|
||||
int SField::compare(SField::ref f1, SField::ref f2)
|
||||
|
||||
@@ -52,7 +52,11 @@ public:
|
||||
|
||||
SField(int fc, SerializedTypeID tid, int fv, const char* fn) :
|
||||
fieldCode(fc), fieldType(tid), fieldValue(fv), fieldName(fn)
|
||||
{ codeToField[fc] = this; }
|
||||
{ codeToField[fieldCode] = this; }
|
||||
|
||||
SField(SerializedTypeID tid, int fv, const char *fn, bool temporary) :
|
||||
fieldCode(FIELD_CODE(tid, fv)), fieldType(tid), fieldValue(fv), fieldName(fn)
|
||||
{ if (!temporary) codeToField[fieldCode] = this; }
|
||||
|
||||
SField(int fc) : fieldCode(fc), fieldType(STI_UNKNOWN), fieldValue(0) { ; }
|
||||
|
||||
|
||||
@@ -267,7 +267,8 @@ void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL, Peer::ref peer)
|
||||
void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
if (mPeers.empty()) return;
|
||||
if (mPeers.empty())
|
||||
return;
|
||||
|
||||
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tmGL, newcoin::mtGET_LEDGER);
|
||||
|
||||
|
||||
@@ -50,9 +50,13 @@ boost::weak_ptr<PeerSet> TransactionAcquire::pmDowncast()
|
||||
void TransactionAcquire::trigger(Peer::ref peer, bool timer)
|
||||
{
|
||||
if (mComplete || mFailed)
|
||||
{
|
||||
Log(lsINFO) << "complete or failed";
|
||||
return;
|
||||
}
|
||||
if (!mHaveRoot)
|
||||
{
|
||||
Log(lsINFO) << "have no root";
|
||||
newcoin::TMGetLedger tmGL;
|
||||
tmGL.set_ledgerhash(mHash.begin(), mHash.size());
|
||||
tmGL.set_itype(newcoin::liTS_CANDIDATE);
|
||||
@@ -786,6 +790,14 @@ void LedgerConsensus::startAcquiring(const TransactionAcquire::pointer& acquire)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
BOOST_FOREACH(Peer::ref peer, peerList)
|
||||
{
|
||||
if (peer->hasTxSet(acquire->getHash()))
|
||||
acquire->peerHas(peer);
|
||||
}
|
||||
|
||||
acquire->resetTimer();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
// #define META_DEBUG
|
||||
|
||||
// Small for testing, should likely be 32 or 64.
|
||||
#define DIR_NODE_MAX 2
|
||||
|
||||
@@ -294,7 +296,9 @@ SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::ref ledger,
|
||||
bool LedgerEntrySet::threadTx(const NewcoinAddress& threadTo, Ledger::ref ledger,
|
||||
boost::unordered_map<uint256, SLE::pointer>& newMods)
|
||||
{
|
||||
#ifdef META_DEBUG
|
||||
Log(lsTRACE) << "Thread to " << threadTo.getAccountID();
|
||||
#endif
|
||||
SLE::pointer sle = getForMod(Ledger::getAccountRootIndex(threadTo.getAccountID()), ledger, newMods);
|
||||
if (!sle)
|
||||
{
|
||||
@@ -321,12 +325,16 @@ bool LedgerEntrySet::threadOwners(SLE::ref node, Ledger::ref ledger, boost::unor
|
||||
{ // thread new or modified node to owner or owners
|
||||
if (node->hasOneOwner()) // thread to owner's account
|
||||
{
|
||||
#ifdef META_DEBUG
|
||||
Log(lsTRACE) << "Thread to single owner";
|
||||
#endif
|
||||
return threadTx(node->getOwner(), ledger, newMods);
|
||||
}
|
||||
else if (node->hasTwoOwners()) // thread to owner's accounts]
|
||||
{
|
||||
#ifdef META_DEBUG
|
||||
Log(lsTRACE) << "Thread to two owners";
|
||||
#endif
|
||||
return
|
||||
threadTx(node->getFirstOwner(), ledger, newMods) &&
|
||||
threadTx(node->getSecondOwner(), ledger, newMods);
|
||||
@@ -349,17 +357,23 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
|
||||
switch (it->second.mAction)
|
||||
{
|
||||
case taaMODIFY:
|
||||
#ifdef META_DEBUG
|
||||
Log(lsTRACE) << "Modified Node " << it->first;
|
||||
#endif
|
||||
nType = TMNModifiedNode;
|
||||
break;
|
||||
|
||||
case taaDELETE:
|
||||
#ifdef META_DEBUG
|
||||
Log(lsTRACE) << "Deleted Node " << it->first;
|
||||
#endif
|
||||
nType = TMNDeletedNode;
|
||||
break;
|
||||
|
||||
case taaCREATE:
|
||||
#ifdef META_DEBUG
|
||||
Log(lsTRACE) << "Created Node " << it->first;
|
||||
#endif
|
||||
nType = TMNCreatedNode;
|
||||
break;
|
||||
|
||||
@@ -420,10 +434,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
|
||||
if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode))
|
||||
{
|
||||
if (curNode->isThreadedType()) // always thread to self
|
||||
{
|
||||
Log(lsTRACE) << "Thread to self";
|
||||
threadTx(curNode, mLedger, newMod);
|
||||
}
|
||||
}
|
||||
|
||||
if (nType == TMNModifiedNode)
|
||||
@@ -454,7 +465,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
|
||||
it != end; ++it)
|
||||
entryModify(it->second);
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef META_DEBUG
|
||||
Log(lsINFO) << "Metadata:" << mSet.getJson(0);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) :
|
||||
mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster), mCloseTimeOffset(0),
|
||||
mLastCloseProposers(0), mLastCloseConvergeTime(LEDGER_IDLE_INTERVAL), mLastValidationTime(0)
|
||||
mLastCloseProposers(0), mLastCloseConvergeTime(1000 * LEDGER_IDLE_INTERVAL), mLastValidationTime(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -114,7 +114,18 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
||||
}
|
||||
|
||||
TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tapOPEN_LEDGER);
|
||||
if (r == tefFAILURE) throw Fault(IO_ERROR);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (r != tesSUCCESS)
|
||||
{
|
||||
std::string token, human;
|
||||
if (transResultInfo(r, token, human))
|
||||
Log(lsINFO) << "TransactionResult: " << token << ": " << human;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (r == tefFAILURE)
|
||||
throw Fault(IO_ERROR);
|
||||
|
||||
if (r == terPRE_SEQ)
|
||||
{ // transaction should be held
|
||||
@@ -150,7 +161,8 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
||||
tx.set_receivetimestamp(getNetworkTimeNC());
|
||||
|
||||
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tx, newcoin::mtTRANSACTION);
|
||||
theApp->getConnectionPool().relayMessage(source, packet);
|
||||
int sentTo = theApp->getConnectionPool().relayMessage(source, packet);
|
||||
Log(lsINFO) << "Transaction relayed to " << sentTo << " node(s)";
|
||||
|
||||
return trans;
|
||||
}
|
||||
@@ -629,6 +641,24 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo
|
||||
return mConsensus->startup();
|
||||
}
|
||||
|
||||
bool NetworkOPs::haveConsensusObject()
|
||||
{
|
||||
if (mConsensus)
|
||||
return true;
|
||||
if (mMode != omFULL)
|
||||
return false;
|
||||
|
||||
uint256 networkClosed;
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
bool ledgerChange = checkLastClosedLedger(peerList, networkClosed);
|
||||
if (!ledgerChange)
|
||||
{
|
||||
Log(lsWARNING) << "Beginning consensus due to peer action";
|
||||
beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger());
|
||||
}
|
||||
return mConsensus;
|
||||
}
|
||||
|
||||
// <-- bool: true to relay
|
||||
bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger,
|
||||
uint32 closeTime, const std::string& pubKey, const std::string& signature, const NewcoinAddress& nodePublic)
|
||||
@@ -651,18 +681,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, cons
|
||||
|
||||
NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey));
|
||||
|
||||
if ((!mConsensus) && (mMode == omFULL))
|
||||
{
|
||||
uint256 networkClosed;
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
bool ledgerChange = checkLastClosedLedger(peerList, networkClosed);
|
||||
if (!ledgerChange)
|
||||
{
|
||||
Log(lsWARNING) << "Beginning consensus due to proposal from peer";
|
||||
beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger());
|
||||
}
|
||||
}
|
||||
if (!mConsensus)
|
||||
if (!haveConsensusObject())
|
||||
{
|
||||
Log(lsINFO) << "Received proposal outside consensus window";
|
||||
return mMode != omFULL;
|
||||
@@ -704,7 +723,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, cons
|
||||
|
||||
SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash)
|
||||
{
|
||||
if (!mConsensus)
|
||||
if (!haveConsensusObject())
|
||||
return SHAMap::pointer();
|
||||
return mConsensus->getTransactionTree(hash, false);
|
||||
}
|
||||
@@ -712,21 +731,24 @@ SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash)
|
||||
bool NetworkOPs::gotTXData(const boost::shared_ptr<Peer>& peer, const uint256& hash,
|
||||
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData)
|
||||
{
|
||||
if (!mConsensus)
|
||||
if (!haveConsensusObject())
|
||||
return false;
|
||||
return mConsensus->peerGaveNodes(peer, hash, nodeIDs, nodeData);
|
||||
}
|
||||
|
||||
bool NetworkOPs::hasTXSet(const boost::shared_ptr<Peer>& peer, const uint256& set, newcoin::TxSetStatus status)
|
||||
{
|
||||
if (!mConsensus)
|
||||
if (!haveConsensusObject())
|
||||
{
|
||||
Log(lsINFO) << "Peer has TX set, not during consensus";
|
||||
return false;
|
||||
}
|
||||
return mConsensus->peerHasSet(peer, set, status);
|
||||
}
|
||||
|
||||
void NetworkOPs::mapComplete(const uint256& hash, SHAMap::ref map)
|
||||
{
|
||||
if (mConsensus)
|
||||
if (!haveConsensusObject())
|
||||
mConsensus->mapComplete(hash, map, true);
|
||||
}
|
||||
|
||||
@@ -832,6 +854,11 @@ Json::Value NetworkOPs::getServerInfo()
|
||||
if (!theConfig.VALIDATION_SEED.isValid()) info["serverState"] = "none";
|
||||
else info["validationPKey"] = NewcoinAddress::createNodePublic(theConfig.VALIDATION_SEED).humanNodePublic();
|
||||
|
||||
Json::Value lastClose = Json::objectValue;
|
||||
lastClose["proposers"] = theApp->getOPs().getPreviousProposers();
|
||||
lastClose["convergeTime"] = theApp->getOPs().getPreviousConvergeTime();
|
||||
info["lastClose"] = lastClose;
|
||||
|
||||
if (mConsensus)
|
||||
info["consensus"] = mConsensus->getJson();
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ protected:
|
||||
Json::Value transJson(const SerializedTransaction& stTxn, TER terResult, const std::string& strStatus, int iSeq, const std::string& strType);
|
||||
void pubTransactionAll(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState);
|
||||
void pubTransactionAccounts(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState);
|
||||
bool haveConsensusObject();
|
||||
|
||||
Json::Value pubBootstrapAccountInfo(Ledger::ref lpAccepted, const NewcoinAddress& naAccountID);
|
||||
|
||||
|
||||
30
src/Peer.cpp
30
src/Peer.cpp
@@ -744,8 +744,11 @@ void Peer::recvHaveTxSet(newcoin::TMHaveTransactionSet& packet)
|
||||
punishPeer(PP_INVALID_REQUEST);
|
||||
return;
|
||||
}
|
||||
memcpy(hashes.begin(), packet.hash().data(), 32);
|
||||
if (!theApp->getOPs().hasTXSet(shared_from_this(), hashes, packet.status()))
|
||||
uint256 hash;
|
||||
memcpy(hash.begin(), packet.hash().data(), 32);
|
||||
if (packet.status() == newcoin::tsHAVE)
|
||||
addTxSet(hash);
|
||||
if (!theApp->getOPs().hasTXSet(shared_from_this(), hash, packet.status()))
|
||||
punishPeer(PP_UNWANTED_DATA);
|
||||
}
|
||||
|
||||
@@ -937,7 +940,6 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
|
||||
if (packet.itype() == newcoin::liTS_CANDIDATE)
|
||||
{ // Request is for a transaction candidate set
|
||||
Log(lsINFO) << "Received request for TX candidate set data " << getIP();
|
||||
Ledger::pointer ledger;
|
||||
if ((!packet.has_ledgerhash() || packet.ledgerhash().size() != 32))
|
||||
{
|
||||
punishPeer(PP_INVALID_REQUEST);
|
||||
@@ -948,7 +950,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
|
||||
map = theApp->getOPs().getTXMap(txHash);
|
||||
if (!map)
|
||||
{
|
||||
Log(lsERROR) << "We do not hav the map our peer wants";
|
||||
Log(lsERROR) << "We do not have the map our peer wants";
|
||||
punishPeer(PP_INVALID_REQUEST);
|
||||
return;
|
||||
}
|
||||
@@ -1143,11 +1145,29 @@ void Peer::addLedger(const uint256& hash)
|
||||
BOOST_FOREACH(const uint256& ledger, mRecentLedgers)
|
||||
if (ledger == hash)
|
||||
return;
|
||||
if (mRecentLedgers.size() == 16)
|
||||
if (mRecentLedgers.size() == 128)
|
||||
mRecentLedgers.pop_front();
|
||||
mRecentLedgers.push_back(hash);
|
||||
}
|
||||
|
||||
bool Peer::hasTxSet(const uint256& hash) const
|
||||
{
|
||||
BOOST_FOREACH(const uint256& set, mRecentTxSets)
|
||||
if (set == hash)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Peer::addTxSet(const uint256& hash)
|
||||
{
|
||||
BOOST_FOREACH(const uint256& set, mRecentTxSets)
|
||||
if (set == hash)
|
||||
return;
|
||||
if (mRecentTxSets.size() == 128)
|
||||
mRecentTxSets.pop_front();
|
||||
mRecentTxSets.push_back(hash);
|
||||
}
|
||||
|
||||
// Get session information we can sign to prevent man in the middle attack.
|
||||
// (both sides get the same information, neither side controls it)
|
||||
void Peer::getSessionCookie(std::string& strDst)
|
||||
|
||||
@@ -46,6 +46,7 @@ private:
|
||||
|
||||
uint256 mClosedLedgerHash, mPreviousLedgerHash;
|
||||
std::list<uint256> mRecentLedgers;
|
||||
std::list<uint256> mRecentTxSets;
|
||||
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> mSocketSsl;
|
||||
|
||||
@@ -118,6 +119,7 @@ protected:
|
||||
void getSessionCookie(std::string& strDst);
|
||||
|
||||
void addLedger(const uint256& ledger);
|
||||
void addTxSet(const uint256& TxSet);
|
||||
|
||||
public:
|
||||
|
||||
@@ -157,6 +159,7 @@ public:
|
||||
|
||||
uint256 getClosedLedgerHash() const { return mClosedLedgerHash; }
|
||||
bool hasLedger(const uint256& hash) const;
|
||||
bool hasTxSet(const uint256& hash) const;
|
||||
NewcoinAddress getNodePublic() const { return mNodePublic; }
|
||||
void cycleStatus() { mPreviousLedgerHash = mClosedLedgerHash; mClosedLedgerHash.zero(); }
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "../json/writer.h"
|
||||
|
||||
@@ -427,7 +428,7 @@ void STObject::makeFieldAbsent(SField::ref field)
|
||||
if (f.getSType() == STI_NOTPRESENT)
|
||||
return;
|
||||
|
||||
mData.replace(index, makeDefaultObject(f.getFName()));
|
||||
mData.replace(index, makeNonPresentObject(f.getFName()));
|
||||
}
|
||||
|
||||
bool STObject::delField(SField::ref field)
|
||||
@@ -761,17 +762,44 @@ Json::Value STVector256::getJson(int options) const
|
||||
|
||||
std::string STArray::getFullText() const
|
||||
{
|
||||
return "WRITEME";
|
||||
std::string r = "[";
|
||||
|
||||
bool first = true;
|
||||
BOOST_FOREACH(const STObject& o, value)
|
||||
{
|
||||
if (!first)
|
||||
r += ",";
|
||||
r += o.getFullText();
|
||||
first = false;
|
||||
}
|
||||
|
||||
r += "]";
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string STArray::getText() const
|
||||
{
|
||||
return "WRITEME";
|
||||
std::string r = "[";
|
||||
|
||||
bool first = true;
|
||||
BOOST_FOREACH(const STObject& o, value)
|
||||
{
|
||||
if (!first)
|
||||
r += ",";
|
||||
r += o.getText();
|
||||
first = false;
|
||||
}
|
||||
|
||||
r += "]";
|
||||
return r;
|
||||
}
|
||||
|
||||
Json::Value STArray::getJson(int) const
|
||||
Json::Value STArray::getJson(int p) const
|
||||
{
|
||||
return Json::Value("WRITEME");
|
||||
Json::Value v = Json::arrayValue;
|
||||
BOOST_FOREACH(const STObject& o, value)
|
||||
v.append(o.getJson(p));
|
||||
return v;
|
||||
}
|
||||
|
||||
void STArray::add(Serializer& s) const
|
||||
@@ -1004,13 +1032,24 @@ std::auto_ptr<STObject> STObject::parseJson(const Json::Value& object, SField::r
|
||||
if (!currency.isString())
|
||||
throw std::runtime_error("path element currencies must be strings");
|
||||
hasCurrency = true;
|
||||
// WRITEME
|
||||
if (currency.asString().size() == 40)
|
||||
uCurrency.SetHex(currency.asString());
|
||||
else if (!STAmount::currencyFromString(uCurrency, currency.asString()))
|
||||
throw std::runtime_error("invalid currency");
|
||||
}
|
||||
if (!issuer.isNull())
|
||||
{ // human account id
|
||||
if (!issuer.isString())
|
||||
throw std::runtime_error("path element issuers must be strings");
|
||||
// WRITEME
|
||||
if (issuer.asString().size() == 40)
|
||||
uIssuer.SetHex(issuer.asString());
|
||||
else
|
||||
{
|
||||
NewcoinAddress a;
|
||||
if (!a.setAccountPublic(issuer.asString()))
|
||||
throw std::runtime_error("path element issuer invalid");
|
||||
uIssuer = a.getAccountID();
|
||||
}
|
||||
}
|
||||
p.addElement(STPathElement(uAccount, uCurrency, uIssuer, hasCurrency));
|
||||
}
|
||||
@@ -1069,67 +1108,63 @@ std::auto_ptr<STObject> STObject::parseJson(const Json::Value& object, SField::r
|
||||
return std::auto_ptr<STObject>(new STObject(*name, data));
|
||||
}
|
||||
|
||||
#if 0
|
||||
BOOST_AUTO_TEST_SUITE(SerializedObject)
|
||||
|
||||
static SOElement testSOElements[2][16] =
|
||||
{ // field, name, id, type, flags
|
||||
{
|
||||
{ sfFlags, "Flags", STI_UINT32, SOE_FLAGS, 0 },
|
||||
{ sfTest1, "Test1", STI_VL, SOE_REQUIRED, 0 },
|
||||
{ sfTest2, "Test2", STI_HASH256, SOE_IFFLAG, 1 },
|
||||
{ sfTest3, "Test3", STI_UINT32, SOE_REQUIRED, 0 },
|
||||
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 }
|
||||
}
|
||||
};
|
||||
|
||||
void STObject::unitTest()
|
||||
BOOST_AUTO_TEST_CASE( FieldManipulation_test )
|
||||
{
|
||||
STObject object1(testSOElements[0], "TestElement1");
|
||||
SField sfTestVL(STI_VL, 10, "TestVL", true);
|
||||
SField sfTestH256(STI_HASH256, 32, "TestH256", true);
|
||||
SField sfTestU32(STI_UINT32, 15, "TestU32", true);
|
||||
SField sfTestObject(STI_OBJECT, 9, "TestObject", true);
|
||||
|
||||
std::vector<SOElement::ptr> elements;
|
||||
elements.push_back(new SOElement(sfFlags, SOE_REQUIRED));
|
||||
elements.push_back(new SOElement(sfTestVL, SOE_REQUIRED));
|
||||
elements.push_back(new SOElement(sfTestH256, SOE_OPTIONAL));
|
||||
elements.push_back(new SOElement(sfTestU32, SOE_REQUIRED));
|
||||
|
||||
STObject object1(elements, sfTestObject);
|
||||
STObject object2(object1);
|
||||
if (object1.getSerializer() != object2.getSerializer()) throw std::runtime_error("STObject error");
|
||||
if (object1.getSerializer() != object2.getSerializer()) BOOST_FAIL("STObject error");
|
||||
|
||||
if (object1.isFieldPresent(sfTest2) || !object1.isFieldPresent(sfTest1))
|
||||
throw std::runtime_error("STObject error");
|
||||
if (object1.isFieldPresent(sfTestH256) || !object1.isFieldPresent(sfTestVL))
|
||||
BOOST_FAIL("STObject error");
|
||||
|
||||
object1.makeFieldPresent(sfTest2);
|
||||
if (!object1.isFieldPresent(sfTest2)) throw std::runtime_error("STObject Error");
|
||||
object1.makeFieldPresent(sfTestH256);
|
||||
if (!object1.isFieldPresent(sfTestH256)) BOOST_FAIL("STObject Error");
|
||||
if (object1.getFieldH256(sfTestH256) != uint256()) BOOST_FAIL("STObject error");
|
||||
|
||||
if ((object1.getFlags() != 1) || (object2.getFlags() != 0)) throw std::runtime_error("STObject error");
|
||||
if (object1.getFieldH256(sfTest2) != uint256()) throw std::runtime_error("STObject error");
|
||||
|
||||
if (object1.getSerializer() == object2.getSerializer()) throw std::runtime_error("STObject error");
|
||||
object1.makeFieldAbsent(sfTest2);
|
||||
if (object1.isFieldPresent(sfTest2)) throw std::runtime_error("STObject error");
|
||||
if (object1.getFlags() != 0) throw std::runtime_error("STObject error");
|
||||
if (object1.getSerializer() != object2.getSerializer()) throw std::runtime_error("STObject error");
|
||||
if (object1.getSerializer() == object2.getSerializer()) BOOST_FAIL("STObject error");
|
||||
object1.makeFieldAbsent(sfTestH256);
|
||||
if (object1.isFieldPresent(sfTestH256)) BOOST_FAIL("STObject error");
|
||||
if (object1.getFlags() != 0) BOOST_FAIL("STObject error");
|
||||
if (object1.getSerializer() != object2.getSerializer()) BOOST_FAIL("STObject error");
|
||||
|
||||
STObject copy(object1);
|
||||
if (object1.isFieldPresent(sfTest2)) throw std::runtime_error("STObject error");
|
||||
if (copy.isFieldPresent(sfTest2)) throw std::runtime_error("STObject error");
|
||||
if (object1.getSerializer() != copy.getSerializer()) throw std::runtime_error("STObject error");
|
||||
copy.setFieldU32(sfTest3, 1);
|
||||
if (object1.getSerializer() == copy.getSerializer()) throw std::runtime_error("STObject error");
|
||||
#ifdef DEBUG
|
||||
Log(lsDEBUG) << copy.getJson(0);
|
||||
#endif
|
||||
if (object1.isFieldPresent(sfTestH256)) BOOST_FAIL("STObject error");
|
||||
if (copy.isFieldPresent(sfTestH256)) BOOST_FAIL("STObject error");
|
||||
if (object1.getSerializer() != copy.getSerializer()) BOOST_FAIL("STObject error");
|
||||
copy.setFieldU32(sfTestU32, 1);
|
||||
if (object1.getSerializer() == copy.getSerializer()) BOOST_FAIL("STObject error");
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
std::cerr << "tol: i=" << i << std::endl;
|
||||
std::vector<unsigned char> j(i, 2);
|
||||
object1.setFieldVL(sfTest1, j);
|
||||
|
||||
object1.setFieldVL(sfTestVL, j);
|
||||
|
||||
Serializer s;
|
||||
object1.add(s);
|
||||
SerializerIterator it(s);
|
||||
STObject object3(testSOElements[0], it, "TestElement3");
|
||||
|
||||
if (object1.getFieldVL(sfTest1) != j) throw std::runtime_error("STObject error");
|
||||
if (object3.getFieldVL(sfTest1) != j) throw std::runtime_error("STObject error");
|
||||
STObject object3(elements, it, sfTestObject);
|
||||
|
||||
if (object1.getFieldVL(sfTestVL) != j) BOOST_FAIL("STObject error");
|
||||
if (object3.getFieldVL(sfTestVL) != j) BOOST_FAIL("STObject error");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -145,8 +145,6 @@ public:
|
||||
{ return makeDefaultObject(STI_NOTPRESENT, name); }
|
||||
static std::auto_ptr<SerializedType> makeDefaultObject(SField::ref name)
|
||||
{ return makeDefaultObject(name.fieldType, name); }
|
||||
|
||||
static void unitTest();
|
||||
};
|
||||
|
||||
class STArray : public SerializedType
|
||||
|
||||
@@ -345,11 +345,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
|
||||
terResult = terPRE_SEQ;
|
||||
}
|
||||
else if (mLedger->hasTransaction(txID))
|
||||
{
|
||||
Log(lsWARNING) << "applyTransaction: duplicate sequence number";
|
||||
|
||||
terResult = tefALREADY;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(lsWARNING) << "applyTransaction: past sequence number";
|
||||
|
||||
Reference in New Issue
Block a user