1 // Aleth: Ethereum C++ client, tools and libraries.
2 // Copyright 2017-2019 Aleth Authors.
3 // Licensed under the GNU General Public License, Version 3.
4 
5 /// @file
6 /// Helper functions to work with json::spirit and test files.
7 #include <libdevcore/CommonData.h>
8 #include <libethereum/Transaction.h>
9 
10 #include <test/tools/libtesteth/ImportTest.h>
11 #include <test/tools/libtesteth/Options.h>
12 #include <test/tools/libtesteth/TestHelper.h>
13 #include <test/tools/libtesteth/TestOutputHelper.h>
14 
15 using namespace std;
16 using namespace dev;
17 using namespace dev::eth;
18 using namespace dev::test;
19 
20 namespace dev
21 {
22 namespace test
23 {
fillJsonWithTransaction(Transaction const & _txn)24 json_spirit::mObject fillJsonWithTransaction(Transaction const& _txn)
25 {
26     json_spirit::mObject txObject;
27     txObject["nonce"] = toCompactHexPrefixed(_txn.nonce(), 1);
28     txObject["data"] = _txn.data().size() ? toHexPrefixed(_txn.data()) : "";
29     txObject["gasLimit"] = toCompactHexPrefixed(_txn.gas(), 1);
30     txObject["gasPrice"] = toCompactHexPrefixed(_txn.gasPrice(), 1);
31     txObject["r"] = toCompactHexPrefixed(_txn.signature().r, 1);
32     txObject["s"] = toCompactHexPrefixed(_txn.signature().s, 1);
33     txObject["v"] = toCompactHexPrefixed(_txn.signature().v + 27, 1);
34     txObject["to"] = _txn.isCreation() ? "" : toHexPrefixed(_txn.receiveAddress());
35     txObject["value"] = toCompactHexPrefixed(_txn.value(), 1);
36     txObject = ImportTest::makeAllFieldsHex(txObject);
37     return txObject;
38 }
39 
fillJsonWithStateChange(State const & _stateOrig,eth::State const & _statePost,eth::ChangeLog const & _changeLog)40 json_spirit::mObject fillJsonWithStateChange(
41     State const& _stateOrig, eth::State const& _statePost, eth::ChangeLog const& _changeLog)
42 {
43     json_spirit::mObject oState;
44     if (!_changeLog.size())
45         return oState;
46 
47     // Sort the vector by address field
48     eth::ChangeLog changeLog = _changeLog;
49     std::sort(changeLog.begin(), changeLog.end(),
50         [](const eth::Change& lhs, const eth::Change& rhs) { return lhs.address < rhs.address; });
51 
52     std::ostringstream log;
53     json_spirit::mObject o;
54 
55     size_t i = 0;
56     while (i < changeLog.size())
57     {
58         json_spirit::mArray agregatedBalance;
59         json_spirit::mArray agregatedStorage;
60         std::map<string, ostringstream> logInfo;
61         Address currentAddress = changeLog.at(i).address;
62         u256 tmpBalance = _stateOrig.balance(currentAddress);
63 
64         while (i < changeLog.size() && changeLog[i].address == currentAddress)
65         {
66             // Agregate changes for the same addresses
67             string after;
68             string before;
69             json_spirit::mArray record;
70             eth::Change change = changeLog.at(i);
71             switch (change.kind)
72             {
73             case Change::Kind::Code:
74                 // take the original and final code only
75                 before = toHexPrefixed(_stateOrig.code(change.address));
76                 after = toHexPrefixed(_statePost.code(change.address));
77                 record.push_back(before);
78                 record.push_back("->");
79                 record.push_back(after);
80                 o["code"] = record;
81                 logInfo["code"] << "'code' : ['" + before + "', '->', '" + after + "']\n";
82                 break;
83             case Change::Kind::Nonce:
84                 // take the original and final nonce only
85                 before = toCompactHexPrefixed(_stateOrig.getNonce(change.address), 1);
86                 after = toCompactHexPrefixed(_statePost.getNonce(change.address), 1);
87                 record.push_back(before);
88                 record.push_back("->");
89                 record.push_back(after);
90                 o["nonce"] = record;
91                 logInfo["nonce"] << "'nonce' : ['" + before + "', '->', '" + after + "']\n";
92                 break;
93             case Change::Kind::Balance:
94                 before = toCompactHexPrefixed(tmpBalance, 1);
95                 after = toCompactHexPrefixed(change.value, 1);
96                 record.push_back(before);
97                 record.push_back("+=");
98                 record.push_back(after);
99                 tmpBalance += change.value;
100                 agregatedBalance.push_back(record);
101                 logInfo["balance"] << "'balance' : ['" + before + "', '+=', '" + after + "']\n";
102                 break;
103             case Change::Kind::Touch:
104                 o["hasBeenTouched"] = "true";
105                 logInfo["hasBeenTouched"] << "'hasBeenTouched' : ['true']\n";
106                 break;
107             case Change::Kind::Storage:
108                 // take the original and final storage only
109                 before = toCompactHexPrefixed(change.key, 1) + " : " +
110                          toCompactHexPrefixed(_stateOrig.storage(change.address, change.key), 1);
111                 after = toCompactHexPrefixed(change.key, 1) + " : " +
112                         toCompactHexPrefixed(_statePost.storage(change.address, change.key), 1);
113                 record.push_back(before);
114                 record.push_back("->");
115                 record.push_back(after);
116                 agregatedStorage.push_back(record);
117                 o["storage"] = agregatedStorage;
118                 logInfo["storage"] << "'storage' : ['" + before + "', '->', '" + after + "']\n";
119                 break;
120             case Change::Kind::Create:
121                 o["newlyCreated"] = "true";
122                 logInfo["newlyCreated"] << "'newlyCreated' : ['true']\n";
123                 break;
124             default:
125                 o["unknownChange"] = "true";
126                 logInfo["unknownChange"] << "'unknownChange' : ['true']\n";
127                 break;
128             }
129             ++i;
130         }
131 
132         // summaraize changes
133         if (agregatedBalance.size())
134         {
135             json_spirit::mArray record;
136             string before = toCompactHexPrefixed(_stateOrig.balance(currentAddress), 1);
137             string after = toCompactHexPrefixed(_statePost.balance(currentAddress), 1);
138             record.push_back(before);
139             record.push_back("->");
140             record.push_back(after);
141             agregatedBalance.push_back(record);
142             o["balance"] = agregatedBalance;
143             logInfo["balance"] << "'balance' : ['" + before + "', '->', '" + after + "']\n";
144         }
145 
146         // commit changes
147         oState[toHexPrefixed(currentAddress)] = o;
148         log << "\n" << currentAddress << "\n";
149         for (std::map<string, ostringstream>::iterator it = logInfo.begin(); it != logInfo.end();
150              it++)
151             log << (*it).second.str();
152     }
153 
154     clog(VerbosityInfo, "state") << log.str();
155     return oState;
156 }
157 
fillJsonWithState(State const & _state)158 json_spirit::mObject fillJsonWithState(State const& _state)
159 {
160     AccountMaskMap emptyMap;
161     return fillJsonWithState(_state, emptyMap);
162 }
163 
fillJsonWithState(State const & _state,eth::AccountMaskMap const & _map)164 json_spirit::mObject fillJsonWithState(State const& _state, eth::AccountMaskMap const& _map)
165 {
166     bool mapEmpty = (_map.size() == 0);
167     json_spirit::mObject oState;
168     for (auto const& a : _state.addresses())
169     {
170         if (_map.size() && _map.find(a.first) == _map.end())
171             continue;
172 
173         json_spirit::mObject o;
174         if (mapEmpty || _map.at(a.first).hasBalance())
175             o["balance"] = toCompactHexPrefixed(_state.balance(a.first), 1);
176         if (mapEmpty || _map.at(a.first).hasNonce())
177             o["nonce"] = toCompactHexPrefixed(_state.getNonce(a.first), 1);
178 
179         if (mapEmpty || _map.at(a.first).hasStorage())
180         {
181             json_spirit::mObject store;
182             for (auto const& s : _state.storage(a.first))
183                 store[toCompactHexPrefixed(s.second.first, 1)] =
184                     toCompactHexPrefixed(s.second.second, 1);
185             o["storage"] = store;
186         }
187 
188         if (mapEmpty || _map.at(a.first).hasCode())
189         {
190             if (_state.code(a.first).size() > 0)
191                 o["code"] = toHexPrefixed(_state.code(a.first));
192             else
193                 o["code"] = "";
194         }
195         oState[toHexPrefixed(a.first)] = o;
196     }
197     return oState;
198 }
199 
200 }  // test
201 }  // dev
202