|
34 | 34 | #include <liblangutil/CharStream.h>
|
35 | 35 | #include <liblangutil/Exceptions.h>
|
36 | 36 |
|
37 |
| -#include <json/json.h> |
| 37 | +#include <libsolutil/JSON.h> |
38 | 38 |
|
39 | 39 | #include <range/v3/algorithm/any_of.hpp>
|
40 | 40 | #include <range/v3/view/enumerate.hpp>
|
@@ -74,6 +74,123 @@ unsigned Assembly::codeSize(unsigned subTagSize) const
|
74 | 74 | }
|
75 | 75 | }
|
76 | 76 |
|
| 77 | +void Assembly::addAssemblyItemsFromJSON(Json::Value const& _code) |
| 78 | +{ |
| 79 | + solAssert(m_items.empty(), ""); |
| 80 | + solAssert(_code.isArray(), ""); |
| 81 | + for (auto const& jsonItem: _code) |
| 82 | + m_items.emplace_back(createAssemblyItemFromJSON(jsonItem)); |
| 83 | + |
| 84 | + for (auto current = m_items.begin(); current != m_items.end(); ++current) |
| 85 | + { |
| 86 | + // During the assembly json export a `JUMPDEST` is always generated after a `tag`. |
| 87 | + // So we just ignore exactly these `JUMPDEST`'s. |
| 88 | + auto const next = std::next(current); |
| 89 | + if ( |
| 90 | + next != m_items.end() && |
| 91 | + current->type() == AssemblyItemType::Tag && |
| 92 | + next->type() == AssemblyItemType::Operation && |
| 93 | + next->instruction() == Instruction::JUMPDEST |
| 94 | + ) |
| 95 | + m_items.erase(next); |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +AssemblyItem Assembly::createAssemblyItemFromJSON(Json::Value const& _json) |
| 100 | +{ |
| 101 | + solAssert(isOfType<std::string>(_json["name"])); |
| 102 | + solAssert(isOfType<int>(_json["begin"])); |
| 103 | + solAssert(isOfType<int>(_json["end"])); |
| 104 | + solAssert(isOfType<int>(_json["source"])); |
| 105 | + solAssert(isOfTypeIfExists<std::string>(_json, "value")); |
| 106 | + solAssert(isOfTypeIfExists<int>(_json, "modifierDepth")); |
| 107 | + solAssert(isOfTypeIfExists<std::string>(_json, "jumpType")); |
| 108 | + |
| 109 | + std::string name = getOrDefault<std::string>(_json["name"], ""); |
| 110 | + solAssert(!name.empty()); |
| 111 | + |
| 112 | + SourceLocation location; |
| 113 | + location.start = get<int>(_json["begin"]); |
| 114 | + location.end = get<int>(_json["end"]); |
| 115 | + int srcIndex = get<int>(_json["source"]); |
| 116 | + size_t modifierDepth = static_cast<size_t>(getOrDefault<int>(_json["modifierDepth"], 0)); |
| 117 | + std::string value = getOrDefault<std::string>(_json["value"], ""); |
| 118 | + std::string jumpType = getOrDefault<std::string>(_json["jumpType"], ""); |
| 119 | + |
| 120 | + |
| 121 | + auto updateUsedTags = [&](u256 const& data) { |
| 122 | + m_usedTags = max(m_usedTags, static_cast<unsigned>(data) + 1); |
| 123 | + return data; |
| 124 | + }; |
| 125 | + |
| 126 | + auto immutableHash = [&](string const& _immutableName) -> h256 { |
| 127 | + h256 hash(util::keccak256(_immutableName)); |
| 128 | + m_immutables[hash] = _immutableName; |
| 129 | + return hash; |
| 130 | + }; |
| 131 | + |
| 132 | + auto libraryHash = [&](string const& _libraryName) -> h256 { |
| 133 | + h256 hash(util::keccak256(_libraryName)); |
| 134 | + m_libraries[hash] = _libraryName; |
| 135 | + return hash; |
| 136 | + }; |
| 137 | + |
| 138 | + if (srcIndex > -1 && srcIndex < static_cast<int>(sources().size())) |
| 139 | + location.sourceName = sources()[static_cast<size_t>(srcIndex)]; |
| 140 | + |
| 141 | + AssemblyItem result(0); |
| 142 | + |
| 143 | + if (c_instructions.count(name)) |
| 144 | + { |
| 145 | + AssemblyItem item{c_instructions.at(name), location}; |
| 146 | + if (!jumpType.empty()) |
| 147 | + item.setJumpType(jumpType); |
| 148 | + result = item; |
| 149 | + } |
| 150 | + else |
| 151 | + { |
| 152 | + if (name == "PUSH") |
| 153 | + { |
| 154 | + AssemblyItem item{AssemblyItemType::Push, u256("0x" + value)}; |
| 155 | + if (!jumpType.empty()) |
| 156 | + item.setJumpType(jumpType); |
| 157 | + result = item; |
| 158 | + } |
| 159 | + else if (name == "PUSH [ErrorTag]") |
| 160 | + result = {AssemblyItemType::PushTag, 0}; |
| 161 | + else if (name == "PUSH [tag]") |
| 162 | + result = {AssemblyItemType::PushTag, updateUsedTags(u256(value))}; |
| 163 | + else if (name == "PUSH [$]") |
| 164 | + result = {AssemblyItemType::PushSub, u256("0x" + value)}; |
| 165 | + else if (name == "PUSH #[$]") |
| 166 | + result = {AssemblyItemType::PushSubSize, u256("0x" + value)}; |
| 167 | + else if (name == "PUSHSIZE") |
| 168 | + result = {AssemblyItemType::PushProgramSize, 0}; |
| 169 | + else if (name == "PUSHLIB") |
| 170 | + result = {AssemblyItemType::PushLibraryAddress, libraryHash(value)}; |
| 171 | + else if (name == "PUSHDEPLOYADDRESS") |
| 172 | + result = {AssemblyItemType::PushDeployTimeAddress, 0}; |
| 173 | + else if (name == "PUSHIMMUTABLE") |
| 174 | + result = {AssemblyItemType::PushImmutable, immutableHash(value)}; |
| 175 | + else if (name == "ASSIGNIMMUTABLE") |
| 176 | + result = {AssemblyItemType::AssignImmutable, immutableHash(value)}; |
| 177 | + else if (name == "tag") |
| 178 | + result = {AssemblyItemType::Tag, updateUsedTags(u256(value))}; |
| 179 | + else if (name == "PUSH data") |
| 180 | + result = {AssemblyItemType::PushData, u256("0x" + value)}; |
| 181 | + else if (name == "VERBATIM") |
| 182 | + { |
| 183 | + AssemblyItem item(fromHex(value), 0, 0); |
| 184 | + result = item; |
| 185 | + } |
| 186 | + else |
| 187 | + assertThrow(false, InvalidOpcode, ""); |
| 188 | + } |
| 189 | + result.setLocation(location); |
| 190 | + result.m_modifierDepth = modifierDepth; |
| 191 | + return result; |
| 192 | +} |
| 193 | + |
77 | 194 | namespace
|
78 | 195 | {
|
79 | 196 |
|
@@ -298,6 +415,43 @@ Json::Value Assembly::assemblyJSON(map<string, unsigned> const& _sourceIndices,
|
298 | 415 | return root;
|
299 | 416 | }
|
300 | 417 |
|
| 418 | +std::shared_ptr<Assembly> Assembly::loadFromAssemblyJSON(Json::Value const& _json, std::vector<std::string> const& _sourceList /* = {} */, bool _isCreation /* = true */) |
| 419 | +{ |
| 420 | + if (!_json[".code"].isArray()) |
| 421 | + return {}; |
| 422 | + |
| 423 | + std::shared_ptr<Assembly> result = std::make_shared<Assembly>(_isCreation, ""); |
| 424 | + vector<string> sourceList; |
| 425 | + if (_sourceList.empty()) |
| 426 | + { |
| 427 | + if (_json.isMember("sourceList")) |
| 428 | + for (auto const& it: _json["sourceList"]) |
| 429 | + sourceList.emplace_back(it.asString()); |
| 430 | + } |
| 431 | + else |
| 432 | + sourceList = _sourceList; |
| 433 | + result->setSources(sourceList); |
| 434 | + result->addAssemblyItemsFromJSON(_json[".code"]); |
| 435 | + if (_json[".auxdata"].isString()) |
| 436 | + result->m_auxiliaryData = fromHex(_json[".auxdata"].asString()); |
| 437 | + Json::Value const& data = _json[".data"]; |
| 438 | + for (Json::ValueConstIterator itr = data.begin(); itr != data.end(); itr++) |
| 439 | + { |
| 440 | + solAssert(itr.key().isString(), ""); |
| 441 | + std::string key = itr.key().asString(); |
| 442 | + Json::Value const& code = data[key]; |
| 443 | + if (code.isString()) |
| 444 | + result->m_data[h256(fromHex(key))] = fromHex(code.asString()); |
| 445 | + else |
| 446 | + { |
| 447 | + std::shared_ptr<Assembly> subassembly(Assembly::loadFromAssemblyJSON(code, sourceList, /* isCreation = */ false)); |
| 448 | + assertThrow(subassembly, AssemblyException, ""); |
| 449 | + result->m_subs.emplace_back(std::make_shared<Assembly>(*subassembly)); |
| 450 | + } |
| 451 | + } |
| 452 | + return result; |
| 453 | +} |
| 454 | + |
301 | 455 | AssemblyItem Assembly::namedTag(string const& _name, size_t _params, size_t _returns, optional<uint64_t> _sourceID)
|
302 | 456 | {
|
303 | 457 | assertThrow(!_name.empty(), AssemblyException, "Empty named tag.");
|
|
0 commit comments