From 88084c835ef19d545be8114d96e344db2d4b29df Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 26 Mar 2015 20:04:28 +0100 Subject: [PATCH] Encode according to JSON. --- abi/main.cpp | 215 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 157 insertions(+), 58 deletions(-) diff --git a/abi/main.cpp b/abi/main.cpp index 4e6caa5d5..7a5fbc584 100644 --- a/abi/main.cpp +++ b/abi/main.cpp @@ -205,6 +205,23 @@ struct ABIType void noteDecimalInput() { if (base == Base::Unknown) { base = Base::Uint; size = 32; } } }; +bytes aligned(bytes const& _b, ABIType _t, Format _f, unsigned _length) +{ + (void)_t; + bytes ret = _b; + while (ret.size() < _length) + if (_f == Format::Binary) + ret.push_back(0); + else + ret.insert(ret.begin(), 0); + while (ret.size() > _length) + if (_f == Format::Binary) + ret.pop_back(); + else + ret.erase(ret.begin()); + return ret; +} + tuple fromUser(std::string const& _arg, Tristate _prefix, Tristate _typing) { ABIType type; @@ -260,7 +277,7 @@ struct ABIMethod string name; vector ins; vector outs; - bool isConstant; + bool isConstant = false; // isolation *IS* documentation. @@ -284,6 +301,12 @@ struct ABIMethod } } + ABIMethod(string const& _name, vector const& _args) + { + name = _name; + ins = _args; + } + string sig() const { string methodArgs; @@ -292,24 +315,123 @@ struct ABIMethod return name + "(" + methodArgs + ")"; } FixedHash<4> id() const { return FixedHash<4>(sha3(sig())); } + + std::string solidityDeclaration() const + { + ostringstream ss; + ss << "function " << name << "("; + int f = 0; + for (ABIType const& i: ins) + ss << (f++ ? ", " : "") << i.canon() << " " << i.name; + ss << ") "; + if (isConstant) + ss << "constant "; + if (!outs.empty()) + { + ss << "returns ("; + f = 0; + for (ABIType const& i: outs) + ss << (f ? ", " : "") << i.canon() << " " << i.name; + ss << ")"; + } + return ss.str(); + } + + bytes encode(vector> const& _params) const + { + bytes ret = name.empty() ? bytes() : id().asBytes(); + unsigned pi = 0; + vector inArity; + for (ABIType const& i: ins) + { + unsigned arity = 1; + for (auto j: i.dims) + if (j == -1) + { + ret += aligned(_params[pi].first, ABIType(), Format::Decimal, 32); + arity *= fromBigEndian(_params[pi].first); + pi++; + } + else + arity *= j; + inArity.push_back(arity); + } + unsigned ii = 0; + for (ABIType const& i: ins) + { + for (unsigned j = 0; j < inArity[ii]; ++j) + { + ret += aligned(_params[pi].first, i, _params[pi].second, (i.base == Base::Bytes && i.size == 1) ? 1 : 32); + ++pi; + } + ++ii; + while (ret.size() % 32 != 0) + ret.push_back(0); + } + return ret; + } }; -using ABI = map, ABIMethod>; +string canonSig(string const& _name, vector const& _args) +{ + string methodArgs; + for (auto const& arg: _args) + methodArgs += (methodArgs.empty() ? "" : ",") + arg.canon(); + return _name + "(" + methodArgs + ")"; +} + +struct UnknownMethod: public Exception {}; +struct OverloadedMethod: public Exception {}; -ABI readABI(std::string const& _json) +class ABI { - ABI ret; - js::mValue v; - js::read_string(_json, v); - for (auto const& i: v.get_array()) +public: + ABI() = default; + ABI(std::string const& _json) { - js::mObject o = i.get_obj(); - if (o["type"].get_str() != "function") - continue; - ABIMethod m(o); - ret[m.id()] = m; + 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); + m_methods[m.id()] = m; + } } - return ret; + + ABIMethod method(string _nameOrSig, vector const& _args) const + { + auto id = FixedHash<4>(sha3(_nameOrSig)); + if (!m_methods.count(id)) + id = FixedHash<4>(sha3(canonSig(_nameOrSig, _args))); + if (!m_methods.count(id)) + for (auto const& m: m_methods) + if (m.second.name == _nameOrSig) + { + if (m_methods.count(id)) + throw OverloadedMethod(); + id = m.first; + } + if (m_methods.count(id)) + return m_methods.at(id); + throw UnknownMethod(); + } + + friend ostream& operator<<(ostream& _out, ABI const& _abi); + +private: + map, ABIMethod> m_methods; +}; + +ostream& operator<<(ostream& _out, ABI const& _abi) +{ + _out << "contract {" << endl; + for (auto const& i: _abi.m_methods) + _out << " " << i.second.solidityDeclaration() << "; // " << i.first.abridged() << endl; + _out << "}" << endl; + return _out; } void userOutput(ostream& _out, bytes const& _data, Encoding _e) @@ -324,20 +446,11 @@ void userOutput(ostream& _out, bytes const& _data, Encoding _e) } } -bytes aligned(bytes const& _b, ABIType _t, Format _f, unsigned _length) +template vector(T()))>::type> retrieve(vector const& _t) { - (void)_t; - bytes ret = _b; - while (ret.size() < _length) - if (_f == Format::Binary) - ret.push_back(0); - else - ret.insert(ret.begin(), 0); - while (ret.size() > _length) - if (_f == Format::Binary) - ret.pop_back(); - else - ret.erase(ret.begin()); + vector(T()))>::type> ret; + for (T const& i: _t) + ret.push_back(get(i)); return ret; } @@ -353,7 +466,8 @@ int main(int argc, char** argv) bool clearNulls = false; bool verbose = false; int outputIndex = -1; - vector> args; + vector> params; + vector args; for (int i = 1; i < argc; ++i) { @@ -395,7 +509,11 @@ int main(int argc, char** argv) else if (method.empty()) method = arg; else - args.push_back(fromUser(arg, prefix, typePrefix)); + { + auto u = fromUser(arg, prefix, typePrefix); + args.push_back(get<1>(u)); + params.push_back(make_pair(get<0>(u), get<2>(u))); + } } string abiData; @@ -407,43 +525,24 @@ int main(int argc, char** argv) if (mode == Mode::Encode) { - bytes ret; + ABIMethod m; if (abiData.empty()) - { - if (!method.empty()) - { - string methodArgs; - for (auto const& arg: args) - methodArgs += (methodArgs.empty() ? "" : ",") + get<1>(arg).canon(); - ret = FixedHash<4>(sha3(method + "(" + methodArgs + ")")).asBytes(); - if (verbose) - cerr << "Method signature: " << (method + "(" + methodArgs + ")") << endl; - } - for (tuple const& arg: args) - ret += aligned(get<0>(arg), get<1>(arg), get<2>(arg), 32); - } + m = ABIMethod(method, args); else { - ABI abi = readABI(abiData); + ABI abi(abiData); if (verbose) + cerr << "ABI:" << endl << abi; + try { + m = abi.method(method, args); + } + catch(...) { - 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; - } + cerr << "Unknown method in ABI." << endl; + exit(-1); } } - userOutput(cout, ret, encoding); + userOutput(cout, m.encode(params), encoding); } else if (mode == Mode::Decode) {