From 370bfb7a221a9902a6c3045777582ffdc68d0a53 Mon Sep 17 00:00:00 2001 From: David Schwartz Date: Wed, 19 Feb 2014 15:28:43 -0800 Subject: [PATCH] Permit memos up to 1Kb. * Overlong memos are basically treated like invalid signatures. * Ability to clear message key. --- src/ripple_app/misc/NetworkOPs.cpp | 2 +- src/ripple_app/misc/SerializedTransaction.cpp | 13 +++++++++++++ src/ripple_app/misc/SerializedTransaction.h | 2 ++ src/ripple_app/rpc/RPCHandler.cpp | 14 ++++++++++++-- src/ripple_app/tx/AccountSetTransactor.cpp | 8 +++++++- src/ripple_app/tx/Transaction.cpp | 2 +- .../protocol/SerializeDeclarations.h | 3 +++ src/ripple_data/protocol/SerializedObject.cpp | 19 +++++++++++++++++++ src/ripple_data/protocol/SerializedObject.h | 3 +++ src/ripple_data/protocol/TxFormats.cpp | 1 + 10 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/ripple_app/misc/NetworkOPs.cpp b/src/ripple_app/misc/NetworkOPs.cpp index 9083adf9f..4b91e216e 100644 --- a/src/ripple_app/misc/NetworkOPs.cpp +++ b/src/ripple_app/misc/NetworkOPs.cpp @@ -733,7 +733,7 @@ void NetworkOPsImp::submitTransaction (Job&, SerializedTransaction::pointer iTra { try { - if (!trans->checkSign ()) + if (!trans->isMemoOkay () || !trans->checkSign ()) { m_journal.warning << "Submitted transaction has bad signature"; getApp().getHashRouter ().setFlag (suppress, SF_BAD); diff --git a/src/ripple_app/misc/SerializedTransaction.cpp b/src/ripple_app/misc/SerializedTransaction.cpp index 6473cf9b4..b07166685 100644 --- a/src/ripple_app/misc/SerializedTransaction.cpp +++ b/src/ripple_app/misc/SerializedTransaction.cpp @@ -307,6 +307,19 @@ std::string SerializedTransaction::getMetaSQL (Serializer rawTxn, uint32 inLedge % getSequence () % inLedger % status % rTxn % escapedMetaData); } +bool SerializedTransaction::isMemoOkay () +{ + bool ret = true; + if (isFieldPresent (sfMemos)) + { + Serializer s (2048); // Try to avoid allocate/copy/free's + getFieldArray (sfMemos).add (s); + if (s.getDataLength () > 1024) + ret = false; + } + return ret; +} + //------------------------------------------------------------------------------ class SerializedTransactionTests : public UnitTest diff --git a/src/ripple_app/misc/SerializedTransaction.h b/src/ripple_app/misc/SerializedTransaction.h index bc1c4feb3..506aab307 100644 --- a/src/ripple_app/misc/SerializedTransaction.h +++ b/src/ripple_app/misc/SerializedTransaction.h @@ -124,6 +124,8 @@ public: mSigBad = true; } + bool isMemoOkay (); + // SQL Functions static std::string getSQLValueHeader (); static std::string getSQLInsertHeader (); diff --git a/src/ripple_app/rpc/RPCHandler.cpp b/src/ripple_app/rpc/RPCHandler.cpp index 856395054..77b3c7836 100644 --- a/src/ripple_app/rpc/RPCHandler.cpp +++ b/src/ripple_app/rpc/RPCHandler.cpp @@ -165,7 +165,6 @@ static void autofill_fee (Json::Value& request, Json::Value RPCHandler::transactionSign (Json::Value params, bool bSubmit, bool bFailHard, Application::ScopedLockType& mlh) { - mlh.unlock(); Json::Value jvResult; WriteLog (lsDEBUG, RPCHandler) << boost::str (boost::format ("transactionSign: %s") % params); @@ -431,6 +430,14 @@ Json::Value RPCHandler::transactionSign (Json::Value params, return jvResult; } + if (!stpTrans->isMemoOkay ()) + { + jvResult["error"] = "invalidTransaction"; + jvResult["error_exception"] = "overlong memos"; + + return jvResult; + } + if (params.isMember ("debug_signing")) { jvResult["tx_unsigned"] = strHex (stpTrans->getSerializer ().peekData ()); @@ -1975,6 +1982,8 @@ Json::Value RPCHandler::doRipplePathFind (Json::Value params, Resource::Charge& // } Json::Value RPCHandler::doSign (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder) { + masterLockHolder.unlock (); + loadType = Resource::feeHighBurdenRPC; bool bFailHard = params.isMember ("fail_hard") && params["fail_hard"].asBool (); return transactionSign (params, false, bFailHard, masterLockHolder); @@ -1986,6 +1995,8 @@ Json::Value RPCHandler::doSign (Json::Value params, Resource::Charge& loadType, // } Json::Value RPCHandler::doSubmit (Json::Value params, Resource::Charge& loadType, Application::ScopedLockType& masterLockHolder) { + masterLockHolder.unlock (); + loadType = Resource::feeMediumBurdenRPC; if (!params.isMember ("tx_blob")) @@ -2048,7 +2059,6 @@ Json::Value RPCHandler::doSubmit (Json::Value params, Resource::Charge& loadType return jvResult; } - masterLockHolder.unlock (); try { diff --git a/src/ripple_app/tx/AccountSetTransactor.cpp b/src/ripple_app/tx/AccountSetTransactor.cpp index 876fa7443..c2391bcee 100644 --- a/src/ripple_app/tx/AccountSetTransactor.cpp +++ b/src/ripple_app/tx/AccountSetTransactor.cpp @@ -226,6 +226,12 @@ TER AccountSetTransactor::doApply () { Blob vucPublic = mTxn.getFieldVL (sfMessageKey); + if (vucPublic.empty ()) + { + WriteLog (lsDEBUG, AccountSetTransactor) << "AccountSet: set message key"; + + mTxnAccount->makeFieldAbsent (sfMessageKey); + } if (vucPublic.size () > PUBLIC_BYTES_MAX) { WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: message key too long"; @@ -234,7 +240,7 @@ TER AccountSetTransactor::doApply () } else { - WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: set message key"; + WriteLog (lsDEBUG, AccountSetTransactor) << "AccountSet: set message key"; mTxnAccount->setFieldVL (sfMessageKey, vucPublic); } diff --git a/src/ripple_app/tx/Transaction.cpp b/src/ripple_app/tx/Transaction.cpp index dec779819..ee072a205 100644 --- a/src/ripple_app/tx/Transaction.cpp +++ b/src/ripple_app/tx/Transaction.cpp @@ -31,7 +31,7 @@ Transaction::Transaction (SerializedTransaction::ref sit, bool bValidate) return; } - if (!bValidate || checkSign ()) + if (!bValidate || (mTransaction->isMemoOkay () && checkSign ())) mStatus = NEW; } diff --git a/src/ripple_data/protocol/SerializeDeclarations.h b/src/ripple_data/protocol/SerializeDeclarations.h index 14d2de12a..f796a5686 100644 --- a/src/ripple_data/protocol/SerializeDeclarations.h +++ b/src/ripple_data/protocol/SerializeDeclarations.h @@ -160,6 +160,7 @@ FIELD (FundCode, VL, 8) FIELD (RemoveCode, VL, 9) FIELD (ExpireCode, VL, 10) FIELD (CreateCode, VL, 11) +FIELD (MemoType, VL, 12) // account FIELD (Account, ACCOUNT, 1) @@ -187,6 +188,7 @@ FIELD (PreviousFields, OBJECT, 6) FIELD (FinalFields, OBJECT, 7) FIELD (NewFields, OBJECT, 8) FIELD (TemplateEntry, OBJECT, 9) +FIELD (Memo, OBJECT, 10) // array of objects // ARRAY/1 is reserved for end of array @@ -197,5 +199,6 @@ FIELD (Template, ARRAY, 5) FIELD (Necessary, ARRAY, 6) FIELD (Sufficient, ARRAY, 7) FIELD (AffectedNodes, ARRAY, 8) +FIELD (Memos, ARRAY, 9) // vim:ts=4 diff --git a/src/ripple_data/protocol/SerializedObject.cpp b/src/ripple_data/protocol/SerializedObject.cpp index cfe64dc06..f6d759052 100644 --- a/src/ripple_data/protocol/SerializedObject.cpp +++ b/src/ripple_data/protocol/SerializedObject.cpp @@ -832,6 +832,25 @@ const STAmount& STObject::getFieldAmount (SField::ref field) const return *cf; } +const STArray& STObject::getFieldArray (SField::ref field) const +{ + static STArray empty; + const SerializedType* rf = peekAtPField (field); + + if (!rf) throw std::runtime_error ("Field not found"); + + SerializedTypeID id = rf->getSType (); + + if (id == STI_NOTPRESENT) return empty; + + const STArray* cf = dynamic_cast (rf); + + if (!cf) + throw std::runtime_error ("Wrong field type"); + + return *cf; +} + const STPathSet& STObject::getFieldPathSet (SField::ref field) const { static STPathSet empty; diff --git a/src/ripple_data/protocol/SerializedObject.h b/src/ripple_data/protocol/SerializedObject.h index 66f4c5f63..4b4f11380 100644 --- a/src/ripple_data/protocol/SerializedObject.h +++ b/src/ripple_data/protocol/SerializedObject.h @@ -20,6 +20,8 @@ #ifndef RIPPLE_SERIALIZEDOBJECT_H #define RIPPLE_SERIALIZEDOBJECT_H +class STArray; + class STObject : public SerializedType , public CountedObject @@ -197,6 +199,7 @@ public: const STAmount& getFieldAmount (SField::ref field) const; const STPathSet& getFieldPathSet (SField::ref field) const; const STVector256& getFieldV256 (SField::ref field) const; + const STArray& getFieldArray (SField::ref field) const; void setFieldU8 (SField::ref field, unsigned char); void setFieldU16 (SField::ref field, uint16); diff --git a/src/ripple_data/protocol/TxFormats.cpp b/src/ripple_data/protocol/TxFormats.cpp index edea5cc31..920d1b57c 100644 --- a/src/ripple_data/protocol/TxFormats.cpp +++ b/src/ripple_data/protocol/TxFormats.cpp @@ -100,6 +100,7 @@ void TxFormats::addCommonFields (Item& item) << SOElement(sfAccountTxnID, SOE_OPTIONAL) << SOElement(sfFee, SOE_REQUIRED) << SOElement(sfOperationLimit, SOE_OPTIONAL) + << SOElement(sfMemos, SOE_OPTIONAL) << SOElement(sfSigningPubKey, SOE_REQUIRED) << SOElement(sfTxnSignature, SOE_OPTIONAL) ;