0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-03-06 14:19:59 -05:00

Merge #12658: Sanitize some wallet serialization

42343c748 Split up and sanitize CAccountingEntry serialization (Pieter Wuille)
029ecac1b Split up and sanitize CWalletTx serialization (Pieter Wuille)

Pull request description:

  This is a small subset of changes taken from #10785, fixing a few of the craziest constness violations in the serialization code.

  `CWalletTx` currently serializes some of its fields by embedding them in a key-value `mapValue`, which is modified (and then fixed up) even from the `Serialize` method (for which `mapValue` is const). `CAccountingEntry` goes even further in that it stores such a map by appending it into `strComment` after a null char, which is again later fixed up again.

  Fix this by splitting the serialization and deserialization code, and making the serialization act on a copy of `mapValue` / `strComment`.

Tree-SHA512: 487e04996dea6aba5b9b8bdaf2c4e680808f111a15afc557b8d078e14b01e4f40f8ef27588869be62f9a87052117c17e0a0c26c59150f83472a9076936af035e
This commit is contained in:
Wladimir J. van der Laan 2018-03-13 18:26:45 +01:00
commit af88094e4f
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D

View file

@ -390,43 +390,37 @@ public:
nOrderPos = -1; nOrderPos = -1;
} }
ADD_SERIALIZE_METHODS; template<typename Stream>
void Serialize(Stream& s) const
template <typename Stream, typename Operation> {
inline void SerializationOp(Stream& s, Operation ser_action) {
if (ser_action.ForRead())
Init(nullptr);
char fSpent = false; char fSpent = false;
mapValue_t mapValueCopy = mapValue;
if (!ser_action.ForRead()) mapValueCopy["fromaccount"] = strFromAccount;
{ WriteOrderPos(nOrderPos, mapValueCopy);
mapValue["fromaccount"] = strFromAccount; if (nTimeSmart) {
mapValueCopy["timesmart"] = strprintf("%u", nTimeSmart);
WriteOrderPos(nOrderPos, mapValue);
if (nTimeSmart)
mapValue["timesmart"] = strprintf("%u", nTimeSmart);
} }
READWRITE(*static_cast<CMerkleTx*>(this)); s << *static_cast<const CMerkleTx*>(this);
std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev
READWRITE(vUnused); s << vUnused << mapValueCopy << vOrderForm << fTimeReceivedIsTxTime << nTimeReceived << fFromMe << fSpent;
READWRITE(mapValue);
READWRITE(vOrderForm);
READWRITE(fTimeReceivedIsTxTime);
READWRITE(nTimeReceived);
READWRITE(fFromMe);
READWRITE(fSpent);
if (ser_action.ForRead())
{
strFromAccount = mapValue["fromaccount"];
ReadOrderPos(nOrderPos, mapValue);
nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
} }
template<typename Stream>
void Unserialize(Stream& s)
{
Init(nullptr);
char fSpent;
s >> *static_cast<CMerkleTx*>(this);
std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev
s >> vUnused >> mapValue >> vOrderForm >> fTimeReceivedIsTxTime >> nTimeReceived >> fFromMe >> fSpent;
strFromAccount = std::move(mapValue["fromaccount"]);
ReadOrderPos(nOrderPos, mapValue);
nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
mapValue.erase("fromaccount"); mapValue.erase("fromaccount");
mapValue.erase("spent"); mapValue.erase("spent");
mapValue.erase("n"); mapValue.erase("n");
@ -608,48 +602,49 @@ public:
nEntryNo = 0; nEntryNo = 0;
} }
ADD_SERIALIZE_METHODS; template <typename Stream>
void Serialize(Stream& s) const {
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
int nVersion = s.GetVersion(); int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) if (!(s.GetType() & SER_GETHASH)) {
READWRITE(nVersion); s << nVersion;
}
//! Note: strAccount is serialized as part of the key, not here. //! Note: strAccount is serialized as part of the key, not here.
READWRITE(nCreditDebit); s << nCreditDebit << nTime << strOtherAccount;
READWRITE(nTime);
READWRITE(LIMITED_STRING(strOtherAccount, 65536));
if (!ser_action.ForRead()) mapValue_t mapValueCopy = mapValue;
{ WriteOrderPos(nOrderPos, mapValueCopy);
WriteOrderPos(nOrderPos, mapValue);
if (!(mapValue.empty() && _ssExtra.empty())) std::string strCommentCopy = strComment;
{ if (!mapValueCopy.empty() || !_ssExtra.empty()) {
CDataStream ss(s.GetType(), s.GetVersion()); CDataStream ss(s.GetType(), s.GetVersion());
ss.insert(ss.begin(), '\0'); ss.insert(ss.begin(), '\0');
ss << mapValue; ss << mapValueCopy;
ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end()); ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
strComment.append(ss.str()); strCommentCopy.append(ss.str());
} }
s << strCommentCopy;
} }
READWRITE(LIMITED_STRING(strComment, 65536)); template <typename Stream>
void Unserialize(Stream& s) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) {
s >> nVersion;
}
//! Note: strAccount is serialized as part of the key, not here.
s >> nCreditDebit >> nTime >> LIMITED_STRING(strOtherAccount, 65536) >> LIMITED_STRING(strComment, 65536);
size_t nSepPos = strComment.find("\0", 0, 1); size_t nSepPos = strComment.find("\0", 0, 1);
if (ser_action.ForRead())
{
mapValue.clear(); mapValue.clear();
if (std::string::npos != nSepPos) if (std::string::npos != nSepPos) {
{
CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), s.GetType(), s.GetVersion()); CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), s.GetType(), s.GetVersion());
ss >> mapValue; ss >> mapValue;
_ssExtra = std::vector<char>(ss.begin(), ss.end()); _ssExtra = std::vector<char>(ss.begin(), ss.end());
} }
ReadOrderPos(nOrderPos, mapValue); ReadOrderPos(nOrderPos, mapValue);
} if (std::string::npos != nSepPos) {
if (std::string::npos != nSepPos)
strComment.erase(nSepPos); strComment.erase(nSepPos);
}
mapValue.erase("n"); mapValue.erase("n");
} }