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)); }
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; }
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; }