Files
rippled/modules/ripple_app/tx/TransactionMeta.cpp
2013-07-23 18:47:02 -07:00

217 lines
6.3 KiB
C++

//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// VFALCO TODO rename class to TransactionMeta
SETUP_LOG (TransactionMetaSet)
TransactionMetaSet::TransactionMetaSet (uint256 const& txid, uint32 ledger, Blob const& vec) :
mTransactionID (txid), mLedger (ledger), mNodes (sfAffectedNodes, 32)
{
Serializer s (vec);
SerializerIterator sit (s);
UPTR_T<SerializedType> pobj = STObject::deserialize (sit, sfAffectedNodes);
STObject* obj = static_cast<STObject*> (pobj.get ());
if (!obj)
throw std::runtime_error ("bad metadata");
mResult = obj->getFieldU8 (sfTransactionResult);
mIndex = obj->getFieldU32 (sfTransactionIndex);
mNodes = * dynamic_cast<STArray*> (&obj->getField (sfAffectedNodes));
}
bool TransactionMetaSet::isNodeAffected (uint256 const& node) const
{
BOOST_FOREACH (const STObject & it, mNodes)
if (it.getFieldH256 (sfLedgerIndex) == node)
return true;
return false;
}
void TransactionMetaSet::setAffectedNode (uint256 const& node, SField::ref type, uint16 nodeType)
{
// make sure the node exists and force its type
BOOST_FOREACH (STObject & it, mNodes)
{
if (it.getFieldH256 (sfLedgerIndex) == node)
{
it.setFName (type);
it.setFieldU16 (sfLedgerEntryType, nodeType);
return;
}
}
mNodes.push_back (STObject (type));
STObject& obj = mNodes.back ();
assert (obj.getFName () == type);
obj.setFieldH256 (sfLedgerIndex, node);
obj.setFieldU16 (sfLedgerEntryType, nodeType);
}
static void addIfUnique (std::vector<RippleAddress>& vector, const RippleAddress& address)
{
BOOST_FOREACH (const RippleAddress & a, vector)
if (a == address)
return;
vector.push_back (address);
}
std::vector<RippleAddress> TransactionMetaSet::getAffectedAccounts ()
{
std::vector<RippleAddress> accounts;
accounts.reserve (10);
// This code should match the behavior of the JS method:
// Meta#getAffectedAccounts
BOOST_FOREACH (const STObject & it, mNodes)
{
int index = it.getFieldIndex ((it.getFName () == sfCreatedNode) ? sfNewFields : sfFinalFields);
if (index != -1)
{
const STObject* inner = dynamic_cast<const STObject*> (&it.peekAtIndex (index));
if (inner)
{
BOOST_FOREACH (const SerializedType & field, inner->peekData ())
{
const STAccount* sa = dynamic_cast<const STAccount*> (&field);
if (sa)
addIfUnique (accounts, sa->getValueNCA ());
else if ((field.getFName () == sfLowLimit) || (field.getFName () == sfHighLimit) ||
(field.getFName () == sfTakerPays) || (field.getFName () == sfTakerGets))
{
const STAmount* lim = dynamic_cast<const STAmount*> (&field);
if (lim != NULL)
{
uint160 issuer = lim->getIssuer ();
if (issuer.isNonZero ())
{
RippleAddress na;
na.setAccountID (issuer);
addIfUnique (accounts, na);
}
}
else
{
WriteLog (lsFATAL, TransactionMetaSet) << "limit is not amount " << field.getJson (0);
}
}
}
}
else assert (false);
}
}
return accounts;
}
STObject& TransactionMetaSet::getAffectedNode (SLE::ref node, SField::ref type)
{
assert (&type);
uint256 index = node->getIndex ();
BOOST_FOREACH (STObject & it, mNodes)
{
if (it.getFieldH256 (sfLedgerIndex) == index)
return it;
}
mNodes.push_back (STObject (type));
STObject& obj = mNodes.back ();
assert (obj.getFName () == type);
obj.setFieldH256 (sfLedgerIndex, index);
obj.setFieldU16 (sfLedgerEntryType, node->getFieldU16 (sfLedgerEntryType));
return obj;
}
STObject& TransactionMetaSet::getAffectedNode (uint256 const& node)
{
BOOST_FOREACH (STObject & it, mNodes)
{
if (it.getFieldH256 (sfLedgerIndex) == node)
return it;
}
assert (false);
throw std::runtime_error ("Affected node not found");
}
const STObject& TransactionMetaSet::peekAffectedNode (uint256 const& node) const
{
BOOST_FOREACH (const STObject & it, mNodes)
if (it.getFieldH256 (sfLedgerIndex) == node)
return it;
throw std::runtime_error ("Affected node not found");
}
void TransactionMetaSet::init (uint256 const& id, uint32 ledger)
{
mTransactionID = id;
mLedger = ledger;
mNodes = STArray (sfAffectedNodes, 32);
}
void TransactionMetaSet::swap (TransactionMetaSet& s)
{
assert ((mTransactionID == s.mTransactionID) && (mLedger == s.mLedger));
mNodes.swap (s.mNodes);
}
bool TransactionMetaSet::thread (STObject& node, uint256 const& prevTxID, uint32 prevLgrID)
{
if (node.getFieldIndex (sfPreviousTxnID) == -1)
{
assert (node.getFieldIndex (sfPreviousTxnLgrSeq) == -1);
node.setFieldH256 (sfPreviousTxnID, prevTxID);
node.setFieldU32 (sfPreviousTxnLgrSeq, prevLgrID);
return true;
}
assert (node.getFieldH256 (sfPreviousTxnID) == prevTxID);
assert (node.getFieldU32 (sfPreviousTxnLgrSeq) == prevLgrID);
return false;
}
static bool compare (const STObject& o1, const STObject& o2)
{
return o1.getFieldH256 (sfLedgerIndex) < o2.getFieldH256 (sfLedgerIndex);
}
STObject TransactionMetaSet::getAsObject () const
{
STObject metaData (sfTransactionMetaData);
assert (mResult != 255);
metaData.setFieldU8 (sfTransactionResult, mResult);
metaData.setFieldU32 (sfTransactionIndex, mIndex);
metaData.addObject (mNodes);
return metaData;
}
void TransactionMetaSet::addRaw (Serializer& s, TER result, uint32 index)
{
mResult = static_cast<int> (result);
mIndex = index;
assert ((mResult == 0) || ((mResult > 100) && (mResult <= 255)));
mNodes.sort (compare);
getAsObject ().add (s);
}
// vim:ts=4