diff --git a/abi/main.cpp b/abi/main.cpp index 2225dd4b3..4e6caa5d5 100644 --- a/abi/main.cpp +++ b/abi/main.cpp @@ -21,6 +21,7 @@ */ #include #include +#include #include #include "../test/JsonSpiritHeaders.h" #include @@ -105,13 +106,45 @@ enum class Base Fixed }; +static const map s_bases = +{ + { Base::Bytes, "bytes" }, + { Base::Address, "address" }, + { Base::Int, "int" }, + { Base::Uint, "uint" }, + { Base::Fixed, "fixed" } +}; + struct ABIType { Base base = Base::Unknown; unsigned size = 32; unsigned ssize = 0; vector dims; + string name; ABIType() = default; + ABIType(std::string const& _type, std::string const& _name): + name(_name) + { + string rest; + for (auto const& i: s_bases) + if (boost::algorithm::starts_with(_type, i.second)) + { + base = i.first; + rest = _type.substr(i.second.size()); + } + if (base == Base::Unknown) + throw InvalidFormat(); + boost::regex r("(\\d*)(x(\\d+))?((\\[\\d*\\])*)"); + boost::smatch res; + boost::regex_match(rest, res, r); + size = res[1].length() > 0 ? stoi(res[1]) : 0; + ssize = res[3].length() > 0 ? stoi(res[3]) : 0; + boost::regex r2("\\[(\\d*)\\](.*)"); + for (rest = res[4]; boost::regex_match(rest, res, r2); rest = res[2]) + dims.push_back(!res[1].length() ? -1 : stoi(res[1])); + } + ABIType(std::string const& _s) { if (_s.size() < 1) @@ -133,13 +166,21 @@ struct ABIType size = 32; return; } - if (_s.find_first_of('x') == string::npos) - size = stoi(_s.substr(1)); + strings d; + boost::algorithm::split(d, _s, boost::is_any_of("*")); + string s = d[0]; + if (s.find_first_of('x') == string::npos) + size = stoi(s.substr(1)); else { - size = stoi(_s.substr(1, _s.find_first_of('x') - 1)); - ssize = stoi(_s.substr(_s.find_first_of('x') + 1)); + size = stoi(s.substr(1, s.find_first_of('x') - 1)); + ssize = stoi(s.substr(s.find_first_of('x') + 1)); } + for (unsigned i = 1; i < d.size(); ++i) + if (d[i].empty()) + dims.push_back(-1); + else + dims.push_back(stoi(d[i])); } string canon() const @@ -185,7 +226,7 @@ tuple fromUser(std::string const& _arg, Tristate _prefix type.noteHexInput(val.size() - 2); return make_tuple(fromHex(val), type, Format::Hex); } - if (val.substr(0, 1) == ".") + if (val.substr(0, 1) == "+") { type.noteDecimalInput(); return make_tuple(toCompactBigEndian(bigint(val.substr(1))), type, Format::Decimal); @@ -214,6 +255,63 @@ tuple fromUser(std::string const& _arg, Tristate _prefix throw InvalidUserString(); } +struct ABIMethod +{ + string name; + vector ins; + vector outs; + bool isConstant; + + // isolation *IS* documentation. + + ABIMethod() = default; + + ABIMethod(js::mObject _o) + { + name = _o["name"].get_str(); + isConstant = _o["constant"].get_bool(); + if (_o.count("inputs")) + for (auto const& i: _o["inputs"].get_array()) + { + js::mObject a = i.get_obj(); + ins.push_back(ABIType(a["type"].get_str(), a["name"].get_str())); + } + if (_o.count("outputs")) + for (auto const& i: _o["outputs"].get_array()) + { + js::mObject a = i.get_obj(); + outs.push_back(ABIType(a["type"].get_str(), a["name"].get_str())); + } + } + + string sig() const + { + string methodArgs; + for (auto const& arg: ins) + methodArgs += (methodArgs.empty() ? "" : ",") + arg.canon(); + return name + "(" + methodArgs + ")"; + } + FixedHash<4> id() const { return FixedHash<4>(sha3(sig())); } +}; + +using ABI = map, ABIMethod>; + +ABI readABI(std::string const& _json) +{ + ABI ret; + js::mValue v; + js::read_string(_json, v); + for (auto const& i: v.get_array()) + { + js::mObject o = i.get_obj(); + if (o["type"].get_str() != "function") + continue; + ABIMethod m(o); + ret[m.id()] = m; + } + return ret; +} + void userOutput(ostream& _out, bytes const& _data, Encoding _e) { switch (_e) @@ -300,17 +398,17 @@ int main(int argc, char** argv) args.push_back(fromUser(arg, prefix, typePrefix)); } - string abi; + string abiData; if (abiFile == "--") for (int i = cin.get(); i != -1; i = cin.get()) - abi.push_back((char)i); + abiData.push_back((char)i); else if (!abiFile.empty()) - abi = contentsString(abiFile); + abiData = contentsString(abiFile); if (mode == Mode::Encode) { bytes ret; - if (abi.empty()) + if (abiData.empty()) { if (!method.empty()) { @@ -326,7 +424,24 @@ int main(int argc, char** argv) } else { - // TODO: read abi. + ABI abi = readABI(abiData); + if (verbose) + { + cerr << "ABI:" << endl; + for (auto const& i: abi) + { + ABIMethod const& m = i.second; + cerr << " " << i.first.abridged() << ": function " << m.name; + int f = 0; + for (ABIType const& i: m.ins) + cerr << (f++ ? ", " : "(") << i.canon() << " " << i.name; + cerr << ") returns ("; + f = 0; + for (ABIType const& i: m.outs) + cerr << (f ? ", " : "(") << i.canon() << " " << i.name; + cerr << ")" << endl; + } + } } userOutput(cout, ret, encoding); }