Blob Manifest::getMasterSignature () const { STObject st (sfGeneric); SerialIter sit (serialized.data (), serialized.size ()); st.set (sit); return st.getFieldVL (sfMasterSignature); }
uint256 Manifest::hash () const { STObject st (sfGeneric); SerialIter sit (serialized.data (), serialized.size ()); st.set (sit); return st.getHash (HashPrefix::manifest); }
UPTR_T<SerializedType> STObject::deserialize (SerializerIterator& sit, SField::ref name) { STObject* o; UPTR_T<SerializedType> object (o = new STObject (name)); o->set (sit, 1); return object; }
void FeeVoteImpl::doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation) { if (lastClosedLedger->getBaseFee () != target_.reference_fee) { if (journal_.info) journal_.info << "Voting for base fee of " << target_.reference_fee; baseValidation.setFieldU64 (sfBaseFee, target_.reference_fee); } if (lastClosedLedger->getReserve (0) != target_.account_reserve) { if (journal_.info) journal_.info << "Voting for base resrve of " << target_.account_reserve; baseValidation.setFieldU32(sfReserveBase, target_.account_reserve); } if (lastClosedLedger->getReserveInc () != target_.owner_reserve) { if (journal_.info) journal_.info << "Voting for reserve increment of " << target_.owner_reserve; baseValidation.setFieldU32 (sfReserveIncrement, target_.owner_reserve); } }
void FeeVoteImpl::doValidation( std::shared_ptr<ReadView const> const& lastClosedLedger, STObject& baseValidation) { if (lastClosedLedger->fees().base != target_.reference_fee) { if (journal_.info) journal_.info << "Voting for base fee of " << target_.reference_fee; baseValidation.setFieldU64 (sfBaseFee, target_.reference_fee); } if (lastClosedLedger->fees().accountReserve(0) != target_.account_reserve) { if (journal_.info) journal_.info << "Voting for base resrve of " << target_.account_reserve; baseValidation.setFieldU32(sfReserveBase, target_.account_reserve); } if (lastClosedLedger->fees().increment != target_.owner_reserve) { if (journal_.info) journal_.info << "Voting for reserve increment of " << target_.owner_reserve; baseValidation.setFieldU32 (sfReserveIncrement, target_.owner_reserve); } }
// 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; } }
STObject TransactionMetaSet::getAsObject () const { STObject metaData (sfTransactionMetaData); assert (mResult != 255); metaData.setFieldU8 (sfTransactionResult, mResult); metaData.setFieldU32 (sfTransactionIndex, mIndex); metaData.emplace_back (mNodes); if (hasDeliveredAmount ()) metaData.setFieldAmount (sfDeliveredAmount, getDeliveredAmount ()); return metaData; }
// Ensure all account fields are 160-bits static bool isAccountFieldOkay (STObject const& st) { for (int i = 0; i < st.getCount(); ++i) { auto t = dynamic_cast<STAccount const*>(st.peekAtPIndex (i)); if (t && t->isDefault ()) return false; } return true; }
bool STObject::equivalentSTObjectSameTemplate ( STObject const& obj1, STObject const& obj2) { assert (obj1.mType != nullptr); assert (obj1.mType == obj2.mType); return std::equal (obj1.begin (), obj1.end (), obj2.begin (), obj2.end (), [] (STBase const& st1, STBase const& st2) { return (st1.getSType() == st2.getSType()) && st1.isEquivalent (st2); }); }
bool Manifest::verify () const { STObject st (sfGeneric); SerialIter sit (serialized.data (), serialized.size ()); st.set (sit); // Signing key and signature are not required for // master key revocations if (! revoked () && ! ripple::verify (st, HashPrefix::manifest, signingKey)) return false; return ripple::verify ( st, HashPrefix::manifest, masterKey, sfMasterSignature); }
std::vector<STBase const*> STObject::getSortedFields (STObject const& objToSort) { std::vector<STBase const*> sf; sf.reserve (objToSort.getCount ()); // Choose the fields that we need to sort. for (detail::STVar const& elem : objToSort.v_) { // Pick out the fields and sort them. STBase const& base = elem.get(); if ((base.getSType () != STI_NOTPRESENT) && base.getFName ().shouldInclude (true)) { sf.push_back (&base); } } // Sort the fields by fieldCode. std::sort (sf.begin (), sf.end (), [] (STBase const* a, STBase const* b) -> bool { return a->getFName ().fieldCode < b->getFName ().fieldCode; }); // There should never be duplicate fields in an STObject. Verify that // in debug mode. assert (std::adjacent_find (sf.cbegin (), sf.cend ()) == sf.cend ()); return sf; }
boost::optional<Manifest> Manifest::make_Manifest (std::string s) { try { STObject st (sfGeneric); SerialIter sit (s.data (), s.size ()); st.set (sit); auto const pk = st.getFieldVL (sfPublicKey); if (! publicKeyType (makeSlice(pk))) return boost::none; auto const opt_seq = get (st, sfSequence); auto const opt_msig = get (st, sfMasterSignature); if (!opt_seq || !opt_msig) return boost::none; // Signing key and signature are not required for // master key revocations if (*opt_seq != std::numeric_limits<std::uint32_t>::max ()) { auto const spk = st.getFieldVL (sfSigningPubKey); if (! publicKeyType (makeSlice(spk))) return boost::none; auto const opt_sig = get (st, sfSignature); if (! opt_sig) return boost::none; return Manifest (std::move (s), PublicKey (makeSlice(pk)), PublicKey (makeSlice(spk)), *opt_seq); } return Manifest (std::move (s), PublicKey (makeSlice(pk)), PublicKey(), *opt_seq); } catch (std::exception const&) { return boost::none; } }
std::pair<std::vector<SignerEntries::SignerEntry>, TER> SignerEntries::deserialize ( STObject const& obj, beast::Journal journal, std::string const& annotation) { std::pair<std::vector<SignerEntry>, TER> s; if (!obj.isFieldPresent (sfSignerEntries)) { if (journal.trace) journal.trace << "Malformed " << annotation << ": Need signer entry array."; s.second = temMALFORMED; return s; } auto& accountVec = s.first; accountVec.reserve (STTx::maxMultiSigners); STArray const& sEntries (obj.getFieldArray (sfSignerEntries)); for (STObject const& sEntry : sEntries) { // Validate the SignerEntry. if (sEntry.getFName () != sfSignerEntry) { journal.trace << "Malformed " << annotation << ": Expected SignerEntry."; s.second = temMALFORMED; return s; } // Extract SignerEntry fields. AccountID const account = sEntry.getAccountID (sfAccount); std::uint16_t const weight = sEntry.getFieldU16 (sfSignerWeight); accountVec.emplace_back (account, weight); } s.second = tesSUCCESS; return s; }
void AmendmentTableImpl::doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation) { amendmentList_t lAmendments = getDesired(); if (lAmendments.empty()) return; STVector256 vAmendments (sfAmendments); for (auto const& uAmendment : lAmendments) vAmendments.push_back (uAmendment); vAmendments.sort (); baseValidation.setFieldV256 (sfAmendments, vAmendments); }
bool TransactionMetaSet::thread (STObject& node, uint256 const& prevTxID, std::uint32_t 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; }
TxMeta::TxMeta (uint256 const& txid, std::uint32_t ledger, STObject const& obj, beast::Journal j) : mTransactionID (txid) , mLedger (ledger) , mNodes (obj.getFieldArray (sfAffectedNodes)) , j_ (j) { mResult = obj.getFieldU8 (sfTransactionResult); mIndex = obj.getFieldU32 (sfTransactionIndex); auto affectedNodes = dynamic_cast <STArray const*> (obj.peekAtPField (sfAffectedNodes)); assert (affectedNodes); if (affectedNodes) mNodes = *affectedNodes; if (obj.isFieldPresent (sfDeliveredAmount)) setDeliveredAmount (obj.getFieldAmount (sfDeliveredAmount)); }
static bool isMemoOkay (STObject const& st, std::string& reason) { if (!st.isFieldPresent (sfMemos)) return true; auto const& memos = st.getFieldArray (sfMemos); // The number 2048 is a preallocation hint, not a hard limit // to avoid allocate/copy/free's Serializer s (2048); memos.add (s); // FIXME move the memo limit into a config tunable if (s.getDataLength () > 1024) { reason = "The memo exceeds the maximum allowed size."; return false; } for (auto const& memo : memos) { auto memoObj = dynamic_cast <STObject const*> (&memo); if (!memoObj || (memoObj->getFName() != sfMemo)) { reason = "A memo array may contain only Memo objects."; return false; } for (auto const& memoElement : *memoObj) { auto const& name = memoElement.getFName(); if (name != sfMemoType && name != sfMemoData && name != sfMemoFormat) { reason = "A memo may contain only MemoType, MemoData or " "MemoFormat fields."; return false; } // The raw data is stored as hex-octets, which we want to decode. auto data = strUnHex (memoElement.getText ()); if (!data.second) { reason = "The MemoType, MemoData and MemoFormat fields may " "only contain hex-encoded data."; return false; } if (name == sfMemoData) continue; // The only allowed characters for MemoType and MemoFormat are the // characters allowed in URLs per RFC 3986: alphanumerics and the // following symbols: -._~:/?#[]@!$&'()*+,;=% static std::array<char, 256> const allowedSymbols = [] { std::array<char, 256> a; a.fill(0); std::string symbols ( "0123456789" "-._~:/?#[]@!$&'()*+,;=%" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"); for(char c : symbols) a[c] = 1; return a; }(); for (auto c : data.first) { if (!allowedSymbols[c]) { reason = "The MemoType and MemoFormat fields may only " "contain characters that are allowed in URLs " "under RFC 3986."; return false; } } } } return true; }
TER doApply () override { Account const refereeID (mTxn.getFieldAccount160 (sfDestination)); Account const referenceID (mTxnAccountID); if (!refereeID) { m_journal.warning << "Malformed transaction: Referee account not specified."; return temDST_NEEDED; } else if (referenceID == refereeID) { // You're referring yourself. m_journal.trace << "Malformed transaction: Redundant transaction:" << " reference=" << to_string(referenceID) << " referee=" << to_string(refereeID); return temREDUNDANT; } // // Open a ledger for editing. SLE::pointer sleReferee(mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(refereeID))); SLE::pointer sleReference(mEngine->entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(referenceID))); if (!sleReferee) { // Referee account does not exist. m_journal.trace << "Malformed transaction: Referee account does not exist."; return tecNO_DST; } else if (!sleReference) { // Reference account does not exist. m_journal.trace << "Malformed transaction: Reference account does not exist."; return terNO_ACCOUNT; } else if (sleReference->getFieldAccount(sfReferee).getAccountID().isNonZero()) { // The tag is basically account-specific information we don't // understand, but we can require someone to fill it in. // We didn't make this test for a newly-formed account because there's // no way for this field to be set. m_journal.trace << "Malformed transaction: Referee has been set."; return tefREFEREE_EXIST; } else { // Tell the engine that we are intending to change the the destination // account. The source account gets always charged a fee so it's always // marked as modified. STArray references = sleReferee->getFieldArray(sfReferences); for (auto it = references.begin(); it != references.end(); ++it) { Account id = it->getFieldAccount(sfReference).getAccountID(); if (id == referenceID) { m_journal.trace << "Malformed transaction: Reference has been set."; return tefREFERENCE_EXIST; } } mEngine->entryModify(sleReference); mEngine->entryModify(sleReferee); sleReference->setFieldAccount(sfReferee, refereeID); STObject obj; obj.setFieldAccount(sfReference, referenceID); references.push_back(obj); sleReferee->setFieldArray(sfReferences, references); } return tesSUCCESS; }
static bool compare (const STObject& o1, const STObject& o2) { return o1.getFieldH256 (sfLedgerIndex) < o2.getFieldH256 (sfLedgerIndex); }
void testSerialization () { testcase ("serialization"); unexpected (sfGeneric.isUseful (), "sfGeneric must not be useful"); SField const& sfTestVL = SField::getField (STI_VL, 255); SField const& sfTestH256 = SField::getField (STI_HASH256, 255); SField const& sfTestU32 = SField::getField (STI_UINT32, 255); SField const& sfTestObject = SField::getField (STI_OBJECT, 255); SOTemplate elements; elements.push_back (SOElement (sfFlags, SOE_REQUIRED)); elements.push_back (SOElement (sfTestVL, SOE_REQUIRED)); elements.push_back (SOElement (sfTestH256, SOE_OPTIONAL)); elements.push_back (SOElement (sfTestU32, SOE_REQUIRED)); STObject object1 (elements, sfTestObject); STObject object2 (object1); unexpected (object1.getSerializer () != object2.getSerializer (), "STObject error 1"); unexpected (object1.isFieldPresent (sfTestH256) || !object1.isFieldPresent (sfTestVL), "STObject error"); object1.makeFieldPresent (sfTestH256); unexpected (!object1.isFieldPresent (sfTestH256), "STObject Error 2"); unexpected (object1.getFieldH256 (sfTestH256) != uint256 (), "STObject error 3"); if (object1.getSerializer () == object2.getSerializer ()) { WriteLog (lsINFO, STObject) << "O1: " << object1.getJson (0); WriteLog (lsINFO, STObject) << "O2: " << object2.getJson (0); fail ("STObject error 4"); } else { pass (); } object1.makeFieldAbsent (sfTestH256); unexpected (object1.isFieldPresent (sfTestH256), "STObject error 5"); unexpected (object1.getFlags () != 0, "STObject error 6"); unexpected (object1.getSerializer () != object2.getSerializer (), "STObject error 7"); STObject copy (object1); unexpected (object1.isFieldPresent (sfTestH256), "STObject error 8"); unexpected (copy.isFieldPresent (sfTestH256), "STObject error 9"); unexpected (object1.getSerializer () != copy.getSerializer (), "STObject error 10"); copy.setFieldU32 (sfTestU32, 1); unexpected (object1.getSerializer () == copy.getSerializer (), "STObject error 11"); for (int i = 0; i < 1000; i++) { Blob j (i, 2); object1.setFieldVL (sfTestVL, j); Serializer s; object1.add (s); SerialIter it (s.slice()); STObject object3 (elements, it, sfTestObject); unexpected (object1.getFieldVL (sfTestVL) != j, "STObject error"); unexpected (object3.getFieldVL (sfTestVL) != j, "STObject error"); } }