Browse Source

Ability to decode ABIs.

cl-refactor
Gav Wood 10 years ago
parent
commit
ff6503e51f
  1. 135
      abi/main.cpp

135
abi/main.cpp

@ -21,6 +21,7 @@
*/
#include <fstream>
#include <iostream>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include "../test/JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h>
@ -105,13 +106,45 @@ enum class Base
Fixed
};
static const map<Base, string> 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<int> 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<bytes, ABIType, Format> 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<bytes, ABIType, Format> fromUser(std::string const& _arg, Tristate _prefix
throw InvalidUserString();
}
struct ABIMethod
{
string name;
vector<ABIType> ins;
vector<ABIType> 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<FixedHash<4>, 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);
}

Loading…
Cancel
Save