// Aleth: Ethereum C++ client, tools and libraries. // Copyright 2017-2019 Aleth Authors. // Licensed under the GNU General Public License, Version 3. /// @file /// Helper functions to work with json::spirit and test files. #include #include #include #include #include #include using namespace std; using namespace dev; using namespace dev::eth; using namespace dev::test; namespace dev { namespace test { json_spirit::mObject fillJsonWithTransaction(Transaction const& _txn) { json_spirit::mObject txObject; txObject["nonce"] = toCompactHexPrefixed(_txn.nonce(), 1); txObject["data"] = _txn.data().size() ? toHexPrefixed(_txn.data()) : ""; txObject["gasLimit"] = toCompactHexPrefixed(_txn.gas(), 1); txObject["gasPrice"] = toCompactHexPrefixed(_txn.gasPrice(), 1); txObject["r"] = toCompactHexPrefixed(_txn.signature().r, 1); txObject["s"] = toCompactHexPrefixed(_txn.signature().s, 1); txObject["v"] = toCompactHexPrefixed(_txn.signature().v + 27, 1); txObject["to"] = _txn.isCreation() ? "" : toHexPrefixed(_txn.receiveAddress()); txObject["value"] = toCompactHexPrefixed(_txn.value(), 1); txObject = ImportTest::makeAllFieldsHex(txObject); return txObject; } json_spirit::mObject fillJsonWithStateChange( State const& _stateOrig, eth::State const& _statePost, eth::ChangeLog const& _changeLog) { json_spirit::mObject oState; if (!_changeLog.size()) return oState; // Sort the vector by address field eth::ChangeLog changeLog = _changeLog; std::sort(changeLog.begin(), changeLog.end(), [](const eth::Change& lhs, const eth::Change& rhs) { return lhs.address < rhs.address; }); std::ostringstream log; json_spirit::mObject o; size_t i = 0; while (i < changeLog.size()) { json_spirit::mArray agregatedBalance; json_spirit::mArray agregatedStorage; std::map logInfo; Address currentAddress = changeLog.at(i).address; u256 tmpBalance = _stateOrig.balance(currentAddress); while (i < changeLog.size() && changeLog[i].address == currentAddress) { // Agregate changes for the same addresses string after; string before; json_spirit::mArray record; eth::Change change = changeLog.at(i); switch (change.kind) { case Change::Kind::Code: // take the original and final code only before = toHexPrefixed(_stateOrig.code(change.address)); after = toHexPrefixed(_statePost.code(change.address)); record.push_back(before); record.push_back("->"); record.push_back(after); o["code"] = record; logInfo["code"] << "'code' : ['" + before + "', '->', '" + after + "']\n"; break; case Change::Kind::Nonce: // take the original and final nonce only before = toCompactHexPrefixed(_stateOrig.getNonce(change.address), 1); after = toCompactHexPrefixed(_statePost.getNonce(change.address), 1); record.push_back(before); record.push_back("->"); record.push_back(after); o["nonce"] = record; logInfo["nonce"] << "'nonce' : ['" + before + "', '->', '" + after + "']\n"; break; case Change::Kind::Balance: before = toCompactHexPrefixed(tmpBalance, 1); after = toCompactHexPrefixed(change.value, 1); record.push_back(before); record.push_back("+="); record.push_back(after); tmpBalance += change.value; agregatedBalance.push_back(record); logInfo["balance"] << "'balance' : ['" + before + "', '+=', '" + after + "']\n"; break; case Change::Kind::Touch: o["hasBeenTouched"] = "true"; logInfo["hasBeenTouched"] << "'hasBeenTouched' : ['true']\n"; break; case Change::Kind::Storage: // take the original and final storage only before = toCompactHexPrefixed(change.key, 1) + " : " + toCompactHexPrefixed(_stateOrig.storage(change.address, change.key), 1); after = toCompactHexPrefixed(change.key, 1) + " : " + toCompactHexPrefixed(_statePost.storage(change.address, change.key), 1); record.push_back(before); record.push_back("->"); record.push_back(after); agregatedStorage.push_back(record); o["storage"] = agregatedStorage; logInfo["storage"] << "'storage' : ['" + before + "', '->', '" + after + "']\n"; break; case Change::Kind::Create: o["newlyCreated"] = "true"; logInfo["newlyCreated"] << "'newlyCreated' : ['true']\n"; break; default: o["unknownChange"] = "true"; logInfo["unknownChange"] << "'unknownChange' : ['true']\n"; break; } ++i; } // summaraize changes if (agregatedBalance.size()) { json_spirit::mArray record; string before = toCompactHexPrefixed(_stateOrig.balance(currentAddress), 1); string after = toCompactHexPrefixed(_statePost.balance(currentAddress), 1); record.push_back(before); record.push_back("->"); record.push_back(after); agregatedBalance.push_back(record); o["balance"] = agregatedBalance; logInfo["balance"] << "'balance' : ['" + before + "', '->', '" + after + "']\n"; } // commit changes oState[toHexPrefixed(currentAddress)] = o; log << "\n" << currentAddress << "\n"; for (std::map::iterator it = logInfo.begin(); it != logInfo.end(); it++) log << (*it).second.str(); } clog(VerbosityInfo, "state") << log.str(); return oState; } json_spirit::mObject fillJsonWithState(State const& _state) { AccountMaskMap emptyMap; return fillJsonWithState(_state, emptyMap); } json_spirit::mObject fillJsonWithState(State const& _state, eth::AccountMaskMap const& _map) { bool mapEmpty = (_map.size() == 0); json_spirit::mObject oState; for (auto const& a : _state.addresses()) { if (_map.size() && _map.find(a.first) == _map.end()) continue; json_spirit::mObject o; if (mapEmpty || _map.at(a.first).hasBalance()) o["balance"] = toCompactHexPrefixed(_state.balance(a.first), 1); if (mapEmpty || _map.at(a.first).hasNonce()) o["nonce"] = toCompactHexPrefixed(_state.getNonce(a.first), 1); if (mapEmpty || _map.at(a.first).hasStorage()) { json_spirit::mObject store; for (auto const& s : _state.storage(a.first)) store[toCompactHexPrefixed(s.second.first, 1)] = toCompactHexPrefixed(s.second.second, 1); o["storage"] = store; } if (mapEmpty || _map.at(a.first).hasCode()) { if (_state.code(a.first).size() > 0) o["code"] = toHexPrefixed(_state.code(a.first)); else o["code"] = ""; } oState[toHexPrefixed(a.first)] = o; } return oState; } } // test } // dev