Paweł Bylica
9 years ago
10 changed files with 0 additions and 2348 deletions
@ -1,19 +0,0 @@ |
|||
cmake_policy(SET CMP0015 NEW) |
|||
set(CMAKE_AUTOMOC OFF) |
|||
|
|||
aux_source_directory(. SRC_LIST) |
|||
|
|||
include_directories(BEFORE ..) |
|||
include_directories(${DB_INCLUDE_DIRS}) |
|||
|
|||
set(EXECUTABLE abi) |
|||
|
|||
add_executable(${EXECUTABLE} ${SRC_LIST}) |
|||
|
|||
target_link_libraries(${EXECUTABLE} ethereum) |
|||
|
|||
if (APPLE) |
|||
install(TARGETS ${EXECUTABLE} DESTINATION bin) |
|||
else() |
|||
eth_install_executable(${EXECUTABLE}) |
|||
endif() |
@ -1,769 +0,0 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file main.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
* RLP tool. |
|||
*/ |
|||
#include <fstream> |
|||
#include <iostream> |
|||
#include <boost/regex.hpp> |
|||
#include <boost/algorithm/string.hpp> |
|||
#include "../test/JsonSpiritHeaders.h" |
|||
#include <libdevcore/CommonIO.h> |
|||
#include <libdevcore/RLP.h> |
|||
#include <libdevcore/SHA3.h> |
|||
#include <libethereum/Client.h> |
|||
using namespace std; |
|||
using namespace dev; |
|||
namespace js = json_spirit; |
|||
|
|||
void help() |
|||
{ |
|||
cout |
|||
<< "Usage abi enc <method_name> (<arg1>, (<arg2>, ... ))" << endl |
|||
<< " abi enc -a <abi.json> <method_name> (<arg1>, (<arg2>, ... ))" << endl |
|||
<< " abi dec -a <abi.json> [ <signature> | <unique_method_name> ]" << endl |
|||
<< "Options:" << endl |
|||
<< " -a,--abi-file <filename> Specify the JSON ABI file." << endl |
|||
<< " -h,--help Print this help message and exit." << endl |
|||
<< " -V,--version Show the version and exit." << endl |
|||
<< "Input options:" << endl |
|||
<< " -f,--format-prefix Require all input formats to be prefixed e.g. 0x for hex, + for decimal, ' for binary." << endl |
|||
<< " -F,--no-format-prefix Require no input format to be prefixed." << endl |
|||
<< " -t,--typing Require all arguments to be typed e.g. b32: (bytes32), u64: (uint64), b[]: (byte[]), i: (int256)." << endl |
|||
<< " -T,--no-typing Require no arguments to be typed." << endl |
|||
<< "Output options:" << endl |
|||
<< " -i,--index <n> Output only the nth (counting from 0) return value." << endl |
|||
<< " -d,--decimal All data should be displayed as decimal." << endl |
|||
<< " -x,--hex Display all data as hex." << endl |
|||
<< " -b,--binary Display all data as binary." << endl |
|||
<< " -p,--prefix Prefix by a base identifier." << endl |
|||
; |
|||
exit(0); |
|||
} |
|||
|
|||
void version() |
|||
{ |
|||
cout << "abi version " << dev::Version << endl; |
|||
exit(0); |
|||
} |
|||
|
|||
enum class Mode |
|||
{ |
|||
Encode, |
|||
Decode |
|||
}; |
|||
|
|||
enum class Encoding |
|||
{ |
|||
Auto, |
|||
Decimal, |
|||
Hex, |
|||
Binary, |
|||
}; |
|||
|
|||
enum class Tristate |
|||
{ |
|||
False = false, |
|||
True = true, |
|||
Mu |
|||
}; |
|||
|
|||
enum class Format |
|||
{ |
|||
Binary, |
|||
Hex, |
|||
Decimal, |
|||
Open, |
|||
Close |
|||
}; |
|||
|
|||
struct InvalidUserString: public Exception {}; |
|||
struct InvalidFormat: public Exception {}; |
|||
|
|||
enum class Base |
|||
{ |
|||
Unknown, |
|||
Bytes, |
|||
Address, |
|||
Int, |
|||
Uint, |
|||
Fixed |
|||
}; |
|||
|
|||
static const map<Base, string> s_bases = |
|||
{ |
|||
{ Base::Bytes, "bytes" }, |
|||
{ Base::Address, "address" }, |
|||
{ Base::Int, "int" }, |
|||
{ Base::Uint, "uint" }, |
|||
{ Base::Fixed, "fixed" } |
|||
}; |
|||
|
|||
struct EncodingPrefs |
|||
{ |
|||
Encoding e = Encoding::Auto; |
|||
bool prefix = true; |
|||
}; |
|||
|
|||
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) |
|||
return; |
|||
switch (_s[0]) |
|||
{ |
|||
case 'b': base = Base::Bytes; break; |
|||
case 'a': base = Base::Address; break; |
|||
case 'i': base = Base::Int; break; |
|||
case 'u': base = Base::Uint; break; |
|||
case 'f': base = Base::Fixed; break; |
|||
default: throw InvalidFormat(); |
|||
} |
|||
if (_s.size() < 2) |
|||
{ |
|||
if (base == Base::Fixed) |
|||
size = ssize = 16; |
|||
else if (base == Base::Address || base == Base::Bytes) |
|||
size = 0; |
|||
else |
|||
size = 32; |
|||
return; |
|||
} |
|||
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)); |
|||
} |
|||
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 |
|||
{ |
|||
string ret; |
|||
switch (base) |
|||
{ |
|||
case Base::Bytes: ret = "bytes" + (size > 0 ? toString(size) : ""); break; |
|||
case Base::Address: ret = "address"; break; |
|||
case Base::Int: ret = "int" + toString(size); break; |
|||
case Base::Uint: ret = "uint" + toString(size); break; |
|||
case Base::Fixed: ret = "fixed" + toString(size) + "x" + toString(ssize); break; |
|||
default: throw InvalidFormat(); |
|||
} |
|||
for (int i: dims) |
|||
ret += "[" + ((i > -1) ? toString(i) : "") + "]"; |
|||
return ret; |
|||
} |
|||
|
|||
bool isBytes() const { return base == Base::Bytes && !size; } |
|||
|
|||
string render(bytes const& _data, EncodingPrefs _e) const |
|||
{ |
|||
if (base == Base::Uint || base == Base::Int) |
|||
{ |
|||
if (_e.e == Encoding::Hex) |
|||
return (_e.prefix ? "0x" : "") + toHex(toCompactBigEndian(fromBigEndian<bigint>(bytesConstRef(&_data).cropped(32 - size / 8)))); |
|||
else |
|||
{ |
|||
bigint i = fromBigEndian<bigint>(bytesConstRef(&_data).cropped(32 - size / 8)); |
|||
if (base == Base::Int && i > (bigint(1) << (size - 1))) |
|||
i -= (bigint(1) << size); |
|||
return toString(i); |
|||
} |
|||
} |
|||
else if (base == Base::Address) |
|||
{ |
|||
Address a = Address(h256(_data), Address::AlignRight); |
|||
return _e.e == Encoding::Binary ? asString(a.asBytes()) : ((_e.prefix ? "0x" : "") + toString(a)); |
|||
} |
|||
else if (isBytes()) |
|||
{ |
|||
return _e.e == Encoding::Binary ? asString(_data) : ((_e.prefix ? "0x" : "") + toHex(_data)); |
|||
} |
|||
else if (base == Base::Bytes) |
|||
{ |
|||
bytesConstRef b(&_data); |
|||
b = b.cropped(0, size); |
|||
return _e.e == Encoding::Binary ? asString(b) : ((_e.prefix ? "0x" : "") + toHex(b)); |
|||
} |
|||
else |
|||
throw InvalidFormat(); |
|||
} |
|||
|
|||
bytes unrender(bytes const& _data, Format _f) const |
|||
{ |
|||
if (isBytes()) |
|||
{ |
|||
auto ret = _data; |
|||
while (ret.size() % 32 != 0) |
|||
ret.push_back(0); |
|||
return ret; |
|||
} |
|||
else |
|||
return aligned(_data, _f, 32); |
|||
} |
|||
|
|||
void noteHexInput(unsigned _nibbles) { if (base == Base::Unknown) { if (_nibbles == 40) base = Base::Address; else { base = Base::Bytes; size = _nibbles / 2; } } } |
|||
void noteBinaryInput() { if (base == Base::Unknown) { base = Base::Bytes; size = 32; } } |
|||
void noteDecimalInput() { if (base == Base::Unknown) { base = Base::Uint; size = 32; } } |
|||
|
|||
bytes aligned(bytes const& _b, Format _f, unsigned _length) const |
|||
{ |
|||
bytes ret = _b; |
|||
while (ret.size() < _length) |
|||
if (base == Base::Bytes || (base == Base::Unknown && _f == Format::Binary)) |
|||
ret.push_back(0); |
|||
else |
|||
ret.insert(ret.begin(), 0); |
|||
while (ret.size() > _length) |
|||
if (base == Base::Bytes || (base == Base::Unknown && _f == Format::Binary)) |
|||
ret.pop_back(); |
|||
else |
|||
ret.erase(ret.begin()); |
|||
return ret; |
|||
} |
|||
}; |
|||
|
|||
tuple<bytes, ABIType, Format> fromUser(std::string const& _arg, Tristate _prefix, Tristate _typing) |
|||
{ |
|||
ABIType type; |
|||
string val; |
|||
if (_typing == Tristate::True || (_typing == Tristate::Mu && _arg.find(':') != string::npos)) |
|||
{ |
|||
if (_arg.find(':') == string::npos) |
|||
throw InvalidUserString(); |
|||
type = ABIType(_arg.substr(0, _arg.find(':'))); |
|||
val = _arg.substr(_arg.find(':') + 1); |
|||
} |
|||
else |
|||
val = _arg; |
|||
|
|||
if (_prefix != Tristate::False) |
|||
{ |
|||
if (val.substr(0, 2) == "0x") |
|||
{ |
|||
type.noteHexInput(val.size() - 2); |
|||
return make_tuple(fromHex(val), type, Format::Hex); |
|||
} |
|||
if (val.substr(0, 1) == "+") |
|||
{ |
|||
type.noteDecimalInput(); |
|||
return make_tuple(toCompactBigEndian(bigint(val.substr(1))), type, Format::Decimal); |
|||
} |
|||
if (val.substr(0, 1) == "'") |
|||
{ |
|||
type.noteBinaryInput(); |
|||
return make_tuple(asBytes(val.substr(1)), type, Format::Binary); |
|||
} |
|||
if (val == "[") |
|||
return make_tuple(bytes(), type, Format::Open); |
|||
if (val == "]") |
|||
return make_tuple(bytes(), type, Format::Close); |
|||
} |
|||
if (_prefix != Tristate::True) |
|||
{ |
|||
if (val.find_first_not_of("0123456789") == string::npos) |
|||
{ |
|||
type.noteDecimalInput(); |
|||
return make_tuple(toCompactBigEndian(bigint(val)), type, Format::Decimal); |
|||
} |
|||
if (val.find_first_not_of("0123456789abcdefABCDEF") == string::npos) |
|||
{ |
|||
type.noteHexInput(val.size()); |
|||
return make_tuple(fromHex(val), type, Format::Hex); |
|||
} |
|||
if (val == "[") |
|||
return make_tuple(bytes(), type, Format::Open); |
|||
if (val == "]") |
|||
return make_tuple(bytes(), type, Format::Close); |
|||
type.noteBinaryInput(); |
|||
return make_tuple(asBytes(val), type, Format::Binary); |
|||
} |
|||
throw InvalidUserString(); |
|||
} |
|||
|
|||
struct ExpectedAdditionalParameter: public Exception {}; |
|||
struct ExpectedOpen: public Exception {}; |
|||
struct ExpectedClose: public Exception {}; |
|||
|
|||
struct ABIMethod |
|||
{ |
|||
string name; |
|||
vector<ABIType> ins; |
|||
vector<ABIType> outs; |
|||
bool isConstant = false; |
|||
|
|||
// 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())); |
|||
} |
|||
} |
|||
|
|||
ABIMethod(string const& _name, vector<ABIType> const& _args) |
|||
{ |
|||
name = _name; |
|||
ins = _args; |
|||
} |
|||
|
|||
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())); } |
|||
|
|||
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<pair<bytes, Format>> const& _params) const |
|||
{ |
|||
bytes ret = name.empty() ? bytes() : id().asBytes(); |
|||
bytes suffix; |
|||
|
|||
// int int[] int
|
|||
// example: 42 [ 1 2 3 ] 69
|
|||
// int[2][][3]
|
|||
// example: [ [ [ 1 2 3 ] [ 4 5 6 ] ] [ ] ]
|
|||
|
|||
unsigned pi = 0; |
|||
|
|||
for (ABIType const& a: ins) |
|||
{ |
|||
if (pi >= _params.size()) |
|||
throw ExpectedAdditionalParameter(); |
|||
auto put = [&]() { |
|||
if (a.isBytes()) |
|||
ret += h256(u256(_params[pi].first.size())).asBytes(); |
|||
suffix += a.unrender(_params[pi].first, _params[pi].second); |
|||
pi++; |
|||
if (pi >= _params.size()) |
|||
throw ExpectedAdditionalParameter(); |
|||
}; |
|||
function<void(vector<int>, unsigned)> putDim = [&](vector<int> addr, unsigned q) { |
|||
if (addr.size() == a.dims.size()) |
|||
put(); |
|||
else |
|||
{ |
|||
if (_params[pi].second != Format::Open) |
|||
throw ExpectedOpen(); |
|||
++pi; |
|||
int l = a.dims[a.dims.size() - 1 - addr.size()]; |
|||
if (l == -1) |
|||
{ |
|||
// read ahead in params and discover the arity.
|
|||
unsigned depth = 0; |
|||
l = 0; |
|||
for (unsigned pi2 = pi; depth || _params[pi2].second != Format::Close;) |
|||
{ |
|||
if (_params[pi2].second == Format::Open) |
|||
++depth; |
|||
if (_params[pi2].second == Format::Close) |
|||
--depth; |
|||
if (!depth) |
|||
++l; |
|||
if (++pi2 == _params.size()) |
|||
throw ExpectedClose(); |
|||
} |
|||
ret += h256(u256(l)).asBytes(); |
|||
} |
|||
q *= l; |
|||
for (addr.push_back(0); addr.back() < l; ++addr.back()) |
|||
putDim(addr, q); |
|||
if (_params[pi].second != Format::Close) |
|||
throw ExpectedClose(); |
|||
++pi; |
|||
} |
|||
}; |
|||
putDim(vector<int>(), 1); |
|||
} |
|||
return ret + suffix; |
|||
} |
|||
string decode(bytes const& _data, int _index, EncodingPrefs _ep) |
|||
{ |
|||
stringstream out; |
|||
unsigned di = 0; |
|||
vector<unsigned> catDims; |
|||
for (ABIType const& a: outs) |
|||
{ |
|||
auto put = [&]() { |
|||
if (a.isBytes()) |
|||
{ |
|||
catDims.push_back(fromBigEndian<unsigned>(bytesConstRef(&_data).cropped(di, 32))); |
|||
di += 32; |
|||
} |
|||
}; |
|||
function<void(vector<int>, unsigned)> putDim = [&](vector<int> addr, unsigned q) { |
|||
if (addr.size() == a.dims.size()) |
|||
put(); |
|||
else |
|||
{ |
|||
int l = a.dims[a.dims.size() - 1 - addr.size()]; |
|||
if (l == -1) |
|||
{ |
|||
l = fromBigEndian<unsigned>(bytesConstRef(&_data).cropped(di, 32)); |
|||
catDims.push_back(l); |
|||
di += 32; |
|||
} |
|||
q *= l; |
|||
for (addr.push_back(0); addr.back() < l; ++addr.back()) |
|||
putDim(addr, q); |
|||
} |
|||
}; |
|||
putDim(vector<int>(), 1); |
|||
} |
|||
unsigned d = 0; |
|||
for (ABIType const& a: outs) |
|||
{ |
|||
if (_index == -1 && out.tellp() > 0) |
|||
out << ", "; |
|||
auto put = [&]() { |
|||
if (a.isBytes()) |
|||
{ |
|||
out << a.render(bytesConstRef(&_data).cropped(di, catDims[d]).toBytes(), _ep); |
|||
di += ((catDims[d] + 31) / 32) * 32; |
|||
d++; |
|||
} |
|||
else |
|||
{ |
|||
out << a.render(bytesConstRef(&_data).cropped(di, 32).toBytes(), _ep); |
|||
di += 32; |
|||
} |
|||
}; |
|||
function<void(vector<int>)> putDim = [&](vector<int> addr) { |
|||
if (addr.size() == a.dims.size()) |
|||
put(); |
|||
else |
|||
{ |
|||
out << "["; |
|||
addr.push_back(0); |
|||
int l = a.dims[a.dims.size() - 1 - (addr.size() - 1)]; |
|||
if (l == -1) |
|||
l = catDims[d++]; |
|||
for (addr.back() = 0; addr.back() < l; ++addr.back()) |
|||
{ |
|||
if (addr.back()) |
|||
out << ", "; |
|||
putDim(addr); |
|||
} |
|||
out << "]"; |
|||
} |
|||
}; |
|||
putDim(vector<int>()); |
|||
} |
|||
return out.str(); |
|||
} |
|||
}; |
|||
|
|||
string canonSig(string const& _name, vector<ABIType> const& _args) |
|||
{ |
|||
try { |
|||
string methodArgs; |
|||
for (auto const& arg: _args) |
|||
methodArgs += (methodArgs.empty() ? "" : ",") + arg.canon(); |
|||
return _name + "(" + methodArgs + ")"; |
|||
} |
|||
catch (...) { |
|||
return string(); |
|||
} |
|||
} |
|||
|
|||
struct UnknownMethod: public Exception {}; |
|||
struct OverloadedMethod: public Exception {}; |
|||
|
|||
class ABI |
|||
{ |
|||
public: |
|||
ABI() = default; |
|||
ABI(std::string const& _json) |
|||
{ |
|||
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; |
|||
} |
|||
} |
|||
|
|||
ABIMethod method(string _nameOrSig, vector<ABIType> 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<FixedHash<4>, 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) |
|||
{ |
|||
switch (_e) |
|||
{ |
|||
case Encoding::Binary: |
|||
_out.write((char const*)_data.data(), _data.size()); |
|||
break; |
|||
default: |
|||
_out << toHex(_data) << endl; |
|||
} |
|||
} |
|||
|
|||
template <unsigned n, class T> vector<typename std::remove_reference<decltype(get<n>(T()))>::type> retrieve(vector<T> const& _t) |
|||
{ |
|||
vector<typename std::remove_reference<decltype(get<n>(T()))>::type> ret; |
|||
for (T const& i: _t) |
|||
ret.push_back(get<n>(i)); |
|||
return ret; |
|||
} |
|||
|
|||
int main(int argc, char** argv) |
|||
{ |
|||
Encoding encoding = Encoding::Auto; |
|||
Mode mode = Mode::Encode; |
|||
string abiFile; |
|||
string method; |
|||
Tristate formatPrefix = Tristate::Mu; |
|||
Tristate typePrefix = Tristate::Mu; |
|||
EncodingPrefs prefs; |
|||
bool verbose = false; |
|||
int outputIndex = -1; |
|||
vector<pair<bytes, Format>> params; |
|||
vector<ABIType> args; |
|||
string incoming; |
|||
|
|||
for (int i = 1; i < argc; ++i) |
|||
{ |
|||
string arg = argv[i]; |
|||
if (arg == "-h" || arg == "--help") |
|||
help(); |
|||
else if (arg == "enc" && i == 1) |
|||
mode = Mode::Encode; |
|||
else if (arg == "dec" && i == 1) |
|||
mode = Mode::Decode; |
|||
else if ((arg == "-a" || arg == "--abi") && argc > i) |
|||
abiFile = argv[++i]; |
|||
else if ((arg == "-i" || arg == "--index") && argc > i) |
|||
outputIndex = atoi(argv[++i]); |
|||
else if (arg == "-p" || arg == "--prefix") |
|||
prefs.prefix = true; |
|||
else if (arg == "-f" || arg == "--format-prefix") |
|||
formatPrefix = Tristate::True; |
|||
else if (arg == "-F" || arg == "--no-format-prefix") |
|||
formatPrefix = Tristate::False; |
|||
else if (arg == "-t" || arg == "--typing") |
|||
typePrefix = Tristate::True; |
|||
else if (arg == "-T" || arg == "--no-typing") |
|||
typePrefix = Tristate::False; |
|||
else if (arg == "-x" || arg == "--hex") |
|||
prefs.e = Encoding::Hex; |
|||
else if (arg == "-d" || arg == "--decimal" || arg == "--dec") |
|||
prefs.e = Encoding::Decimal; |
|||
else if (arg == "-b" || arg == "--binary" || arg == "--bin") |
|||
prefs.e = Encoding::Binary; |
|||
else if (arg == "-v" || arg == "--verbose") |
|||
verbose = true; |
|||
else if (arg == "-V" || arg == "--version") |
|||
version(); |
|||
else if (method.empty()) |
|||
method = arg; |
|||
else if (mode == Mode::Encode) |
|||
{ |
|||
auto u = fromUser(arg, formatPrefix, typePrefix); |
|||
args.push_back(get<1>(u)); |
|||
params.push_back(make_pair(get<0>(u), get<2>(u))); |
|||
} |
|||
else if (mode == Mode::Decode) |
|||
incoming += arg; |
|||
} |
|||
|
|||
string abiData; |
|||
if (!abiFile.empty()) |
|||
abiData = contentsString(abiFile); |
|||
|
|||
if (mode == Mode::Encode) |
|||
{ |
|||
ABIMethod m; |
|||
if (abiData.empty()) |
|||
m = ABIMethod(method, args); |
|||
else |
|||
{ |
|||
ABI abi(abiData); |
|||
if (verbose) |
|||
cerr << "ABI:" << endl << abi; |
|||
try { |
|||
m = abi.method(method, args); |
|||
} |
|||
catch (...) |
|||
{ |
|||
cerr << "Unknown method in ABI." << endl; |
|||
exit(-1); |
|||
} |
|||
} |
|||
try { |
|||
userOutput(cout, m.encode(params), encoding); |
|||
} |
|||
catch (ExpectedAdditionalParameter const&) |
|||
{ |
|||
cerr << "Expected additional parameter in input." << endl; |
|||
exit(-1); |
|||
} |
|||
catch (ExpectedOpen const&) |
|||
{ |
|||
cerr << "Expected open-bracket '[' in input." << endl; |
|||
exit(-1); |
|||
} |
|||
catch (ExpectedClose const&) |
|||
{ |
|||
cerr << "Expected close-bracket ']' in input." << endl; |
|||
exit(-1); |
|||
} |
|||
} |
|||
else if (mode == Mode::Decode) |
|||
{ |
|||
if (abiData.empty()) |
|||
{ |
|||
cerr << "Please specify an ABI file." << endl; |
|||
exit(-1); |
|||
} |
|||
else |
|||
{ |
|||
ABI abi(abiData); |
|||
ABIMethod m; |
|||
if (verbose) |
|||
cerr << "ABI:" << endl << abi; |
|||
try { |
|||
m = abi.method(method, args); |
|||
} |
|||
catch(...) |
|||
{ |
|||
cerr << "Unknown method in ABI." << endl; |
|||
exit(-1); |
|||
} |
|||
string encoded; |
|||
if (incoming == "--" || incoming.empty()) |
|||
for (int i = cin.get(); i != -1; i = cin.get()) |
|||
encoded.push_back((char)i); |
|||
else |
|||
{ |
|||
encoded = contentsString(incoming); |
|||
} |
|||
cout << m.decode(fromHex(boost::trim_copy(encoded)), outputIndex, prefs) << endl; |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
} |
@ -1,33 +0,0 @@ |
|||
cmake_policy(SET CMP0015 NEW) |
|||
set(CMAKE_AUTOMOC OFF) |
|||
|
|||
aux_source_directory(. SRC_LIST) |
|||
|
|||
include_directories(BEFORE ..) |
|||
include_directories(${Boost_INCLUDE_DIRS}) |
|||
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) |
|||
|
|||
if (JSCONSOLE) |
|||
include_directories(${V8_INCLUDE_DIRS}) |
|||
endif() |
|||
|
|||
set(EXECUTABLE ethkey) |
|||
|
|||
file(GLOB HEADERS "*.h") |
|||
|
|||
add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) |
|||
|
|||
add_dependencies(${EXECUTABLE} BuildInfo.h) |
|||
|
|||
target_link_libraries(${EXECUTABLE} devcrypto) |
|||
target_link_libraries(${EXECUTABLE} ethcore) |
|||
|
|||
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) |
|||
eth_copy_dlls("${EXECUTABLE}" MHD_DLLS) |
|||
endif() |
|||
|
|||
if (APPLE) |
|||
install(TARGETS ${EXECUTABLE} DESTINATION bin) |
|||
else() |
|||
eth_install_executable(${EXECUTABLE}) |
|||
endif() |
@ -1,769 +0,0 @@ |
|||
#pragma once |
|||
|
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file KeyAux.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
* CLI module for key management. |
|||
*/ |
|||
|
|||
#include <thread> |
|||
#include <chrono> |
|||
#include <fstream> |
|||
#include <iostream> |
|||
#include <boost/algorithm/string.hpp> |
|||
#include <boost/algorithm/string/trim_all.hpp> |
|||
#include <libdevcore/SHA3.h> |
|||
#include <libdevcore/FileSystem.h> |
|||
#include <libethcore/KeyManager.h> |
|||
#include <libethcore/ICAP.h> |
|||
#include <libethcore/Transaction.h> |
|||
#include <libdevcrypto/WordList.h> |
|||
#include "BuildInfo.h" |
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace dev::eth; |
|||
using namespace boost::algorithm; |
|||
|
|||
#undef RETURN |
|||
|
|||
class BadArgument: public Exception {}; |
|||
|
|||
string getAccountPassword(KeyManager& keyManager, Address const& a) |
|||
{ |
|||
return getPassword("Enter password for address " + keyManager.accountName(a) + " (" + a.abridged() + "; hint:" + keyManager.passwordHint(a) + "): "); |
|||
} |
|||
|
|||
string createPassword(std::string const& _prompt) |
|||
{ |
|||
string ret; |
|||
while (true) |
|||
{ |
|||
ret = getPassword(_prompt); |
|||
string confirm = getPassword("Please confirm the password by entering it again: "); |
|||
if (ret == confirm) |
|||
break; |
|||
cout << "Passwords were different. Try again." << endl; |
|||
} |
|||
return ret; |
|||
// cout << "Enter a hint to help you remember this password: " << flush;
|
|||
// cin >> hint;
|
|||
// return make_pair(ret, hint);
|
|||
} |
|||
|
|||
pair<string, string> createPassword(KeyManager& _keyManager, std::string const& _prompt, std::string const& _pass = std::string(), std::string const& _hint = std::string()) |
|||
{ |
|||
string pass = _pass; |
|||
if (pass.empty()) |
|||
while (true) |
|||
{ |
|||
pass = getPassword(_prompt); |
|||
string confirm = getPassword("Please confirm the password by entering it again: "); |
|||
if (pass == confirm) |
|||
break; |
|||
cout << "Passwords were different. Try again." << endl; |
|||
} |
|||
string hint = _hint; |
|||
if (hint.empty() && !pass.empty() && !_keyManager.haveHint(pass)) |
|||
{ |
|||
cout << "Enter a hint to help you remember this password: " << flush; |
|||
getline(cin, hint); |
|||
} |
|||
return make_pair(pass, hint); |
|||
} |
|||
|
|||
class KeyCLI |
|||
{ |
|||
public: |
|||
enum class OperationMode |
|||
{ |
|||
None, |
|||
ListBare, |
|||
NewBare, |
|||
ImportBare, |
|||
ExportBare, |
|||
RecodeBare, |
|||
KillBare, |
|||
InspectBare, |
|||
CreateWallet, |
|||
List, |
|||
New, |
|||
Import, |
|||
ImportWithAddress, |
|||
ImportPresale, |
|||
Export, |
|||
Recode, |
|||
Kill, |
|||
NewBrain, |
|||
ImportBrain, |
|||
InspectBrain, |
|||
SignTx, |
|||
DecodeTx, |
|||
}; |
|||
|
|||
KeyCLI(OperationMode _mode = OperationMode::None): m_mode(_mode) {} |
|||
|
|||
bool interpretOption(int& i, int argc, char** argv) |
|||
{ |
|||
string arg = argv[i]; |
|||
if (arg == "--wallet-path" && i + 1 < argc) |
|||
m_walletPath = argv[++i]; |
|||
else if (arg == "--secrets-path" && i + 1 < argc) |
|||
m_secretsPath = argv[++i]; |
|||
else if ((arg == "-m" || arg == "--master") && i + 1 < argc) |
|||
m_masterPassword = argv[++i]; |
|||
else if (arg == "--unlock" && i + 1 < argc) |
|||
m_unlocks.push_back(argv[++i]); |
|||
else if (arg == "--lock" && i + 1 < argc) |
|||
m_lock = argv[++i]; |
|||
else if (arg == "--kdf" && i + 1 < argc) |
|||
m_kdf = argv[++i]; |
|||
else if (arg == "--kdf-param" && i + 2 < argc) |
|||
{ |
|||
auto n = argv[++i]; |
|||
auto v = argv[++i]; |
|||
m_kdfParams[n] = v; |
|||
} |
|||
else if (arg == "--sign-tx" && i + 1 < argc) |
|||
{ |
|||
m_mode = OperationMode::SignTx; |
|||
m_signKey = argv[++i]; |
|||
} |
|||
else if (arg == "--tx-data" && i + 1 < argc) |
|||
try |
|||
{ |
|||
m_toSign.data = fromHex(argv[++i]); |
|||
} |
|||
catch (...) |
|||
{ |
|||
cerr << "Invalid argument to " << arg << endl; |
|||
exit(-1); |
|||
} |
|||
else if (arg == "--tx-nonce" && i + 1 < argc) |
|||
try |
|||
{ |
|||
m_toSign.nonce = u256(argv[++i]); |
|||
} |
|||
catch (...) |
|||
{ |
|||
cerr << "Invalid argument to " << arg << endl; |
|||
exit(-1); |
|||
} |
|||
else if ((arg == "--tx-dest" || arg == "--tx-to" || arg == "--tx-destination") && i + 1 < argc) |
|||
try |
|||
{ |
|||
m_toSign.creation = false; |
|||
m_toSign.to = toAddress(argv[++i]); |
|||
} |
|||
catch (...) |
|||
{ |
|||
cerr << "Invalid argument to " << arg << endl; |
|||
exit(-1); |
|||
} |
|||
else if (arg == "--tx-gas" && i + 1 < argc) |
|||
try |
|||
{ |
|||
m_toSign.gas = u256(argv[++i]); |
|||
} |
|||
catch (...) |
|||
{ |
|||
cerr << "Invalid argument to " << arg << endl; |
|||
exit(-1); |
|||
} |
|||
else if (arg == "--tx-gasprice" && i + 1 < argc) |
|||
try |
|||
{ |
|||
m_toSign.gasPrice = u256(argv[++i]); |
|||
} |
|||
catch (...) |
|||
{ |
|||
cerr << "Invalid argument to " << arg << endl; |
|||
exit(-1); |
|||
} |
|||
else if (arg == "--tx-value" && i + 1 < argc) |
|||
try |
|||
{ |
|||
m_toSign.value = u256(argv[++i]); |
|||
} |
|||
catch (...) |
|||
{ |
|||
cerr << "Invalid argument to " << arg << endl; |
|||
exit(-1); |
|||
} |
|||
else if (arg == "--decode-tx") |
|||
m_mode = OperationMode::DecodeTx; |
|||
else if (arg == "--import-bare") |
|||
m_mode = OperationMode::ImportBare; |
|||
else if (arg == "--list-bare") |
|||
m_mode = OperationMode::ListBare; |
|||
else if (arg == "--export-bare") |
|||
m_mode = OperationMode::ExportBare; |
|||
else if (arg == "--inspect-bare") |
|||
m_mode = OperationMode::InspectBare; |
|||
else if (arg == "--recode-bare") |
|||
m_mode = OperationMode::RecodeBare; |
|||
else if (arg == "--kill-bare") |
|||
m_mode = OperationMode::KillBare; |
|||
else if (arg == "--create-wallet") |
|||
m_mode = OperationMode::CreateWallet; |
|||
else if (arg == "-l" || arg == "--list") |
|||
m_mode = OperationMode::List; |
|||
else if ((arg == "-n" || arg == "--new") && i + 1 < argc) |
|||
{ |
|||
m_mode = OperationMode::New; |
|||
m_name = argv[++i]; |
|||
} |
|||
else if ((arg == "-i" || arg == "--import") && i + 2 < argc) |
|||
{ |
|||
m_mode = OperationMode::Import; |
|||
m_inputs = strings(1, argv[++i]); |
|||
m_name = argv[++i]; |
|||
} |
|||
else if (arg == "--import-presale" && i + 2 < argc) |
|||
{ |
|||
m_mode = OperationMode::ImportPresale; |
|||
m_inputs = strings(1, argv[++i]); |
|||
m_name = argv[++i]; |
|||
} |
|||
else if (arg == "--new-brain" && i + 1 < argc) |
|||
{ |
|||
m_mode = OperationMode::NewBrain; |
|||
m_name = argv[++i]; |
|||
} |
|||
else if (arg == "--import-brain" && i + 1 < argc) |
|||
{ |
|||
m_mode = OperationMode::ImportBrain; |
|||
m_name = argv[++i]; |
|||
} |
|||
else if (arg == "--inspect-brain") |
|||
m_mode = OperationMode::InspectBrain; |
|||
else if (arg == "--import-with-address" && i + 3 < argc) |
|||
{ |
|||
m_mode = OperationMode::ImportWithAddress; |
|||
m_inputs = strings(1, argv[++i]); |
|||
m_address = Address(argv[++i]); |
|||
m_name = argv[++i]; |
|||
} |
|||
else if (arg == "--export") |
|||
m_mode = OperationMode::Export; |
|||
else if (arg == "--recode") |
|||
m_mode = OperationMode::Recode; |
|||
else if (arg == "--no-icap") |
|||
m_icap = false; |
|||
else if (m_mode == OperationMode::DecodeTx || m_mode == OperationMode::SignTx || m_mode == OperationMode::ImportBare || m_mode == OperationMode::InspectBare || m_mode == OperationMode::KillBare || m_mode == OperationMode::Recode || m_mode == OperationMode::Export || m_mode == OperationMode::RecodeBare || m_mode == OperationMode::ExportBare) |
|||
m_inputs.push_back(arg); |
|||
else |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
KeyPair makeKey() const |
|||
{ |
|||
KeyPair k(Secret::random()); |
|||
while (m_icap && k.address()[0]) |
|||
k = KeyPair(Secret(sha3(k.secret().ref()))); |
|||
return k; |
|||
} |
|||
|
|||
Secret getSecret(std::string const& _signKey) |
|||
{ |
|||
string json = contentsString(_signKey); |
|||
if (!json.empty()) |
|||
return Secret(secretStore().secret(secretStore().readKeyContent(json), [&](){ return getPassword("Enter password for key: "); })); |
|||
else |
|||
{ |
|||
if (h128 u = fromUUID(_signKey)) |
|||
return Secret(secretStore().secret(u, [&](){ return getPassword("Enter password for key: "); })); |
|||
if (_signKey.substr(0, 6) == "brain#" && _signKey.find(":") != string::npos) |
|||
return KeyManager::subkey(KeyManager::brain(_signKey.substr(_signKey.find(":"))), stoul(_signKey.substr(6, _signKey.find(":") - 7))); |
|||
if (_signKey.substr(0, 6) == "brain:") |
|||
return KeyManager::brain(_signKey.substr(6)); |
|||
if (_signKey == "brain") |
|||
return KeyManager::brain(getPassword("Enter brain wallet phrase: ")); |
|||
Address a; |
|||
DEV_IGNORE_EXCEPTIONS(a = Address(_signKey)); |
|||
if (a) |
|||
return keyManager().secret(a, [&](){ return getPassword("Enter password for key (hint:" + keyManager().passwordHint(a) + "): "); }); |
|||
cerr << "Bad file, UUID and address: " << _signKey << endl; |
|||
exit(-1); |
|||
} |
|||
} |
|||
|
|||
void execute() |
|||
{ |
|||
switch (m_mode) |
|||
{ |
|||
case OperationMode::CreateWallet: |
|||
{ |
|||
KeyManager wallet(m_walletPath, m_secretsPath); |
|||
if (m_masterPassword.empty()) |
|||
m_masterPassword = createPassword("Please enter a MASTER password to protect your key store (make it strong!): "); |
|||
if (m_masterPassword.empty()) |
|||
cerr << "Aborted (empty password not allowed)." << endl; |
|||
else |
|||
{ |
|||
try |
|||
{ |
|||
wallet.create(m_masterPassword); |
|||
} |
|||
catch (Exception const& _e) |
|||
{ |
|||
cerr << "unable to create wallet" << endl << boost::diagnostic_information(_e); |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
case OperationMode::DecodeTx: |
|||
{ |
|||
bytes b = inputData(m_inputs[0]); |
|||
if (b.empty()) |
|||
cerr << "Unknown file or bad hex: '" << m_inputs[0] << "'" << endl; |
|||
else |
|||
try |
|||
{ |
|||
TransactionBase t(b, CheckTransaction::None); |
|||
cout << "Transaction " << t.sha3().hex() << endl; |
|||
if (t.isCreation()) |
|||
{ |
|||
cout << " type: creation" << endl; |
|||
cout << " code: " << toHex(t.data()) << endl; |
|||
} |
|||
else |
|||
{ |
|||
cout << " type: message" << endl; |
|||
cout << " to: " << t.to().hex() << endl; |
|||
cout << " data: " << (t.data().empty() ? "none" : toHex(t.data())) << endl; |
|||
} |
|||
try |
|||
{ |
|||
auto s = t.sender(); |
|||
if (t.isCreation()) |
|||
cout << " creates: " << toAddress(s, t.nonce()).hex() << endl; |
|||
cout << " from: " << s.hex() << endl; |
|||
} |
|||
catch (...) |
|||
{ |
|||
cout << " from: <unsigned>" << endl; |
|||
} |
|||
cout << " value: " << formatBalance(t.value()) << " (" << t.value() << " wei)" << endl; |
|||
cout << " nonce: " << t.nonce() << endl; |
|||
cout << " gas: " << t.gas() << endl; |
|||
cout << " gas price: " << formatBalance(t.gasPrice()) << " (" << t.gasPrice() << " wei)" << endl; |
|||
cout << " signing hash: " << t.sha3(WithoutSignature).hex() << endl; |
|||
cout << " v: " << (int)t.signature().v << endl; |
|||
cout << " r: " << t.signature().r << endl; |
|||
cout << " s: " << t.signature().s << endl; |
|||
} |
|||
catch (Exception& ex) |
|||
{ |
|||
cerr << "Invalid transaction: " << ex.what() << endl; |
|||
} |
|||
break; |
|||
} |
|||
case OperationMode::SignTx: |
|||
{ |
|||
Secret s = getSecret(m_signKey); |
|||
if (m_inputs.empty()) |
|||
m_inputs.push_back(string()); |
|||
for (string const& i: m_inputs) |
|||
{ |
|||
bool isFile = false; |
|||
try |
|||
{ |
|||
TransactionBase t = i.empty() ? TransactionBase(m_toSign) : TransactionBase(inputData(i, &isFile), CheckTransaction::None); |
|||
t.sign(s); |
|||
cout << t.sha3() << ": "; |
|||
if (isFile) |
|||
{ |
|||
writeFile(i + ".signed", toHex(t.rlp())); |
|||
cout << i + ".signed" << endl; |
|||
} |
|||
else |
|||
cout << toHex(t.rlp()) << endl; |
|||
} |
|||
catch (Exception& ex) |
|||
{ |
|||
cerr << "Invalid transaction: " << ex.what() << endl; |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
case OperationMode::NewBrain: |
|||
{ |
|||
if (m_name != "--") |
|||
keyManager(); |
|||
boost::random_device d; |
|||
boost::random::uniform_int_distribution<unsigned> pickWord(0, WordList.size() - 1); |
|||
string seed; |
|||
for (int i = 0; i < 13; ++i) |
|||
seed += (seed.size() ? " " : "") + WordList[pickWord(d)]; |
|||
cout << "Your brain key phrase: <<" << seed << ">>" << endl; |
|||
if (m_name != "--") |
|||
{ |
|||
std::string hint; |
|||
cout << "Enter a hint for the phrase if you want: " << flush; |
|||
getline(cin, hint); |
|||
Address a = keyManager().importBrain(seed, m_name, hint); |
|||
cout << a.abridged() << endl; |
|||
cout << " ICAP: " << ICAP(a).encoded() << endl; |
|||
cout << " Address: " << a.hex() << endl; |
|||
} |
|||
break; |
|||
} |
|||
case OperationMode::InspectBrain: |
|||
{ |
|||
Address a = toAddress(KeyManager::brain(getPassword("Enter brain wallet key phrase: "))); |
|||
cout << a.abridged() << endl; |
|||
cout << " ICAP: " << ICAP(a).encoded() << endl; |
|||
cout << " Address: " << a.hex() << endl; |
|||
break; |
|||
} |
|||
case OperationMode::ListBare: |
|||
for (h128 const& u: std::set<h128>() + secretStore().keys()) |
|||
cout << toUUID(u) << endl; |
|||
break; |
|||
case OperationMode::NewBare: |
|||
{ |
|||
if (m_lock.empty()) |
|||
m_lock = createPassword("Enter a password with which to secure this account: "); |
|||
auto k = makeKey(); |
|||
h128 u = secretStore().importSecret(k.secret().ref(), m_lock); |
|||
cout << "Created key " << toUUID(u) << endl; |
|||
cout << " Address: " << k.address().hex() << endl; |
|||
cout << " ICAP: " << ICAP(k.address()).encoded() << endl; |
|||
break; |
|||
} |
|||
case OperationMode::ImportBare: |
|||
for (string const& input: m_inputs) |
|||
{ |
|||
h128 u; |
|||
bytesSec b; |
|||
b.writable() = fromHex(input); |
|||
if (b.size() != 32) |
|||
{ |
|||
std::string s = contentsString(input); |
|||
b.writable() = fromHex(s); |
|||
if (b.size() != 32) |
|||
u = secretStore().importKey(input); |
|||
} |
|||
if (!u && b.size() == 32) |
|||
u = secretStore().importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); |
|||
if (!u) |
|||
{ |
|||
cerr << "Cannot import " << input << " not a file or secret." << endl; |
|||
continue; |
|||
} |
|||
cout << "Successfully imported " << input << " as " << toUUID(u); |
|||
} |
|||
break; |
|||
case OperationMode::InspectBare: |
|||
for (auto const& i: m_inputs) |
|||
if (!contents(i).empty()) |
|||
{ |
|||
h128 u = secretStore().readKey(i, false); |
|||
bytesSec s = secretStore().secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); }); |
|||
cout << "Key " << i << ":" << endl; |
|||
cout << " UUID: " << toUUID(u) << ":" << endl; |
|||
cout << " Address: " << toAddress(Secret(s)).hex() << endl; |
|||
cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; |
|||
} |
|||
else if (h128 u = fromUUID(i)) |
|||
{ |
|||
bytesSec s = secretStore().secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }); |
|||
cout << "Key " << i << ":" << endl; |
|||
cout << " Address: " << toAddress(Secret(s)).hex() << endl; |
|||
cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; |
|||
} |
|||
else |
|||
cerr << "Couldn't inspect " << i << "; not found." << endl; |
|||
break; |
|||
case OperationMode::ExportBare: break; |
|||
case OperationMode::RecodeBare: |
|||
for (auto const& i: m_inputs) |
|||
if (h128 u = fromUUID(i)) |
|||
if (secretStore().recode(u, lockPassword(toUUID(u)), [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }, kdf())) |
|||
cerr << "Re-encoded " << toUUID(u) << endl; |
|||
else |
|||
cerr << "Couldn't re-encode " << toUUID(u) << "; key corrupt or incorrect password supplied." << endl; |
|||
else |
|||
cerr << "Couldn't re-encode " << i << "; not found." << endl; |
|||
break; |
|||
case OperationMode::KillBare: |
|||
for (auto const& i: m_inputs) |
|||
if (h128 u = fromUUID(i)) |
|||
secretStore().kill(u); |
|||
else |
|||
cerr << "Couldn't kill " << i << "; not found." << endl; |
|||
break; |
|||
case OperationMode::New: |
|||
{ |
|||
keyManager(); |
|||
tie(m_lock, m_lockHint) = createPassword(keyManager(), "Enter a password with which to secure this account (or nothing to use the master password): ", m_lock, m_lockHint); |
|||
auto k = makeKey(); |
|||
bool usesMaster = m_lock.empty(); |
|||
h128 u = usesMaster ? keyManager().import(k.secret(), m_name) : keyManager().import(k.secret(), m_name, m_lock, m_lockHint); |
|||
cout << "Created key " << toUUID(u) << endl; |
|||
cout << " Name: " << m_name << endl; |
|||
if (usesMaster) |
|||
cout << " Uses master password." << endl; |
|||
else |
|||
cout << " Password hint: " << m_lockHint << endl; |
|||
cout << " Address: " << k.address().hex() << endl; |
|||
cout << " ICAP: " << ICAP(k.address()).encoded() << endl; |
|||
break; |
|||
} |
|||
case OperationMode::ImportWithAddress: |
|||
{ |
|||
keyManager(); |
|||
string const& i = m_inputs[0]; |
|||
h128 u; |
|||
bytesSec b; |
|||
b.writable() = fromHex(i); |
|||
if (b.size() != 32) |
|||
{ |
|||
std::string s = contentsString(i); |
|||
b.writable() = fromHex(s); |
|||
if (b.size() != 32) |
|||
u = keyManager().store().importKey(i); |
|||
} |
|||
if (!u && b.size() == 32) |
|||
u = keyManager().store().importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); |
|||
if (!u) |
|||
{ |
|||
cerr << "Cannot import " << i << " not a file or secret." << endl; |
|||
break; |
|||
} |
|||
keyManager().importExisting(u, m_name, m_address); |
|||
cout << "Successfully imported " << i << ":" << endl; |
|||
cout << " Name: " << m_name << endl; |
|||
cout << " Address: " << m_address << endl; |
|||
cout << " UUID: " << toUUID(u) << endl; |
|||
break; |
|||
} |
|||
case OperationMode::ImportBrain: |
|||
{ |
|||
keyManager(); |
|||
std::string seed = getPassword("Enter brain wallet key phrase: "); |
|||
std::string hint; |
|||
cout << "Enter a hint for the phrase if you want: " << flush; |
|||
getline(cin, hint); |
|||
Address a = keyManager().importBrain(seed, m_name, hint); |
|||
cout << a << endl; |
|||
cout << " ICAP: " << ICAP(a).encoded() << endl; |
|||
cout << " Address: " << a.hex() << endl; |
|||
break; |
|||
} |
|||
case OperationMode::ImportPresale: |
|||
{ |
|||
keyManager(); |
|||
std::string pw; |
|||
KeyPair k = keyManager().presaleSecret(contentsString(m_inputs[0]), [&](bool){ return (pw = getPassword("Enter the password for the presale key: ")); }); |
|||
keyManager().import(k.secret(), m_name, pw, "Same password as used for presale key"); |
|||
break; |
|||
} |
|||
case OperationMode::List: |
|||
{ |
|||
vector<u128> bare; |
|||
AddressHash got; |
|||
|
|||
for (auto const& u: keyManager().store().keys()) |
|||
if (Address a = keyManager().address(u)) |
|||
{ |
|||
got.insert(a); |
|||
cout << toUUID(u) << " " << a.abridged(); |
|||
string s = ICAP(a).encoded(); |
|||
cout << " " << s << string(35 - s.size(), ' '); |
|||
cout << " " << keyManager().accountName(a) << endl; |
|||
} |
|||
else |
|||
bare.push_back(u); |
|||
for (auto const& a: keyManager().accounts()) |
|||
if (!got.count(a)) |
|||
{ |
|||
cout << " (Brain) " << a.abridged(); |
|||
cout << " " << ICAP(a).encoded() << " "; |
|||
cout << " " << keyManager().accountName(a) << endl; |
|||
} |
|||
for (auto const& u: bare) |
|||
cout << toUUID(u) << " (Bare)" << endl; |
|||
} |
|||
default: break; |
|||
} |
|||
} |
|||
|
|||
std::string lockPassword(std::string const& _accountName) |
|||
{ |
|||
return m_lock.empty() ? createPassword("Enter a password with which to secure account " + _accountName + ": ") : m_lock; |
|||
} |
|||
|
|||
static void streamHelp(ostream& _out) |
|||
{ |
|||
_out |
|||
<< "Secret-store (\"bare\") operation modes:" << endl |
|||
<< " --list-bare List all secret available in secret-store." << endl |
|||
<< " --new-bare Generate and output a key without interacting with wallet and dump the JSON." << endl |
|||
<< " --import-bare [ <file>|<secret-hex> , ... ] Import keys from given sources." << endl |
|||
<< " --recode-bare [ <uuid>|<file> , ... ] Decrypt and re-encrypt given keys." << endl |
|||
<< " --inspect-bare [ <uuid>|<file> , ... ] Output information on given keys." << endl |
|||
// << " --export-bare [ <uuid> , ... ] Export given keys." << endl
|
|||
<< " --kill-bare [ <uuid> , ... ] Delete given keys." << endl |
|||
<< "Secret-store configuration:" << endl |
|||
<< " --secrets-path <path> Specify Web3 secret-store path (default: " << SecretStore::defaultPath() << ")" << endl |
|||
<< endl |
|||
<< "Wallet operating modes:" << endl |
|||
<< " -l,--list List all keys available in wallet." << endl |
|||
<< " -n,--new <name> Create a new key with given name and add it in the wallet." << endl |
|||
<< " -i,--import [<uuid>|<file>|<secret-hex>] <name> Import keys from given source and place in wallet." << endl |
|||
<< " --import-presale <file> <name> Import a presale wallet into a key with the given name." << endl |
|||
<< " --import-with-address [<uuid>|<file>|<secret-hex>] <address> <name> Import keys from given source with given address and place in wallet." << endl |
|||
<< " -e,--export [ <address>|<uuid> , ... ] Export given keys." << endl |
|||
<< " -r,--recode [ <address>|<uuid>|<file> , ... ] Decrypt and re-encrypt given keys." << endl |
|||
<< "Brain wallet operating modes:" << endl |
|||
<< "WARNING: Brain wallets with human-generated passphrasses are highly susceptible to attack. Don't use such a thing for" << endl |
|||
<< "anything important." << endl |
|||
<< " --new-brain [ <name>|-- ] Create a new 13-word brain wallet; argument is the name or if --, do not add to wallet."<< endl |
|||
<< " --import-brain <name> Import your own brain wallet." << endl |
|||
<< " --inspect-brain Check the address of a particular brain wallet." << endl |
|||
<< "Wallet configuration:" << endl |
|||
<< " --create-wallet Create an Ethereum master wallet." << endl |
|||
<< " --wallet-path <path> Specify Ethereum wallet path (default: " << KeyManager::defaultPath() << ")" << endl |
|||
<< " -m, --master <password> Specify wallet (master) password." << endl |
|||
<< endl |
|||
<< "Transaction operating modes:" << endl |
|||
<< " -d,--decode-tx [<hex>|<file>] Decode given transaction." << endl |
|||
<< " -s,--sign-tx [ <address>|<uuid>|<file>|brain((#<HD-index>):<brain-phrase>) ] [ <hex>|<file> , ... ] (Re-)Sign given transaction." << endl |
|||
<< endl |
|||
<< "Encryption configuration:" << endl |
|||
<< " --kdf <kdfname> Specify KDF to use when encrypting (default: sc rypt)" << endl |
|||
<< " --kdf-param <name> <value> Specify a parameter for the KDF." << endl |
|||
// << " --cipher <ciphername> Specify cipher to use when encrypting (default: aes-128-ctr)" << endl
|
|||
// << " --cipher-param <name> <value> Specify a parameter for the cipher." << endl
|
|||
<< " --lock <password> Specify password for when encrypting a (the) key." << endl |
|||
<< " --hint <hint> Specify hint for the --lock password." << endl |
|||
<< endl |
|||
<< "Decryption configuration:" << endl |
|||
<< " --unlock <password> Specify password for a (the) key." << endl |
|||
<< "Key generation configuration:" << endl |
|||
<< " --no-icap Don't bother to make a direct-ICAP capable key." << endl |
|||
; |
|||
} |
|||
|
|||
static bytes inputData(std::string const& _input, bool* _isFile = nullptr) |
|||
{ |
|||
bytes b = fromHex(_input); |
|||
if (_isFile) |
|||
*_isFile = false; |
|||
if (b.empty()) |
|||
{ |
|||
if (_isFile) |
|||
*_isFile = true; |
|||
std::string s = boost::trim_copy_if(contentsString(_input), is_any_of(" \t\n")); |
|||
b = fromHex(s); |
|||
if (b.empty()) |
|||
b = asBytes(s); |
|||
} |
|||
return b; |
|||
} |
|||
|
|||
static bool isTrue(std::string const& _m) |
|||
{ |
|||
return _m == "on" || _m == "yes" || _m == "true" || _m == "1"; |
|||
} |
|||
|
|||
static bool isFalse(std::string const& _m) |
|||
{ |
|||
return _m == "off" || _m == "no" || _m == "false" || _m == "0"; |
|||
} |
|||
|
|||
private: |
|||
void openWallet(KeyManager& _w) |
|||
{ |
|||
while (true) |
|||
{ |
|||
if (_w.load(m_masterPassword)) |
|||
break; |
|||
if (!m_masterPassword.empty()) |
|||
{ |
|||
cout << "Password invalid. Try again." << endl; |
|||
m_masterPassword.clear(); |
|||
} |
|||
m_masterPassword = getPassword("Please enter your MASTER password: "); |
|||
} |
|||
} |
|||
|
|||
KDF kdf() const { return m_kdf == "pbkdf2" ? KDF::PBKDF2_SHA256 : KDF::Scrypt; } |
|||
|
|||
KeyManager& keyManager() |
|||
{ |
|||
if (!m_keyManager) |
|||
{ |
|||
m_keyManager.reset(new KeyManager(m_walletPath, m_secretsPath)); |
|||
if (m_keyManager->exists()) |
|||
openWallet(*m_keyManager); |
|||
else |
|||
{ |
|||
cerr << "Couldn't open wallet. Does it exist?" << endl; |
|||
exit(-1); |
|||
} |
|||
} |
|||
return *m_keyManager; |
|||
} |
|||
|
|||
SecretStore& secretStore() |
|||
{ |
|||
if (m_keyManager) |
|||
return m_keyManager->store(); |
|||
if (!m_secretStore) |
|||
m_secretStore.reset(new SecretStore(m_secretsPath)); |
|||
return *m_secretStore; |
|||
} |
|||
|
|||
/// Where the keys are.
|
|||
unique_ptr<SecretStore> m_secretStore; |
|||
unique_ptr<KeyManager> m_keyManager; |
|||
|
|||
/// Operating mode.
|
|||
OperationMode m_mode; |
|||
|
|||
/// Wallet stuff
|
|||
string m_secretsPath = SecretStore::defaultPath(); |
|||
string m_walletPath = KeyManager::defaultPath(); |
|||
|
|||
/// Wallet password stuff
|
|||
string m_masterPassword; |
|||
strings m_unlocks; |
|||
string m_lock; |
|||
string m_lockHint; |
|||
bool m_icap = true; |
|||
|
|||
/// Creating/importing
|
|||
string m_name; |
|||
Address m_address; |
|||
|
|||
/// Importing
|
|||
strings m_inputs; |
|||
|
|||
/// Signing
|
|||
string m_signKey; |
|||
TransactionSkeleton m_toSign; |
|||
|
|||
string m_kdf = "scrypt"; |
|||
map<string, string> m_kdfParams; |
|||
// string m_cipher;
|
|||
// map<string, string> m_cipherParams;
|
|||
}; |
@ -1,84 +0,0 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file main.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
* Ethereum client. |
|||
*/ |
|||
|
|||
#include <thread> |
|||
#include <chrono> |
|||
#include <fstream> |
|||
#include <iostream> |
|||
#include <libdevcore/FileSystem.h> |
|||
#include <libdevcore/Log.h> |
|||
#include <libethcore/KeyManager.h> |
|||
#include "BuildInfo.h" |
|||
#include "KeyAux.h" |
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace dev::eth; |
|||
|
|||
void help() |
|||
{ |
|||
cout |
|||
<< "Usage ethkey [OPTIONS]" << endl |
|||
<< "Options:" << endl << endl; |
|||
KeyCLI::streamHelp(cout); |
|||
cout |
|||
<< "General Options:" << endl |
|||
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl |
|||
<< " -V,--version Show the version and exit." << endl |
|||
<< " -h,--help Show this help message and exit." << endl |
|||
; |
|||
exit(0); |
|||
} |
|||
|
|||
void version() |
|||
{ |
|||
cout << "ethkey version " << dev::Version << endl; |
|||
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; |
|||
exit(0); |
|||
} |
|||
|
|||
int main(int argc, char** argv) |
|||
{ |
|||
KeyCLI m(KeyCLI::OperationMode::ListBare); |
|||
g_logVerbosity = 0; |
|||
|
|||
for (int i = 1; i < argc; ++i) |
|||
{ |
|||
string arg = argv[i]; |
|||
if (m.interpretOption(i, argc, argv)) {} |
|||
else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc) |
|||
g_logVerbosity = atoi(argv[++i]); |
|||
else if (arg == "-h" || arg == "--help") |
|||
help(); |
|||
else if (arg == "-V" || arg == "--version") |
|||
version(); |
|||
else |
|||
{ |
|||
cerr << "Invalid argument: " << arg << endl; |
|||
exit(-1); |
|||
} |
|||
} |
|||
|
|||
m.execute(); |
|||
|
|||
return 0; |
|||
} |
|||
|
@ -1,19 +0,0 @@ |
|||
cmake_policy(SET CMP0015 NEW) |
|||
set(CMAKE_AUTOMOC OFF) |
|||
|
|||
aux_source_directory(. SRC_LIST) |
|||
|
|||
include_directories(BEFORE ..) |
|||
include_directories(${DB_INCLUDE_DIRS}) |
|||
|
|||
set(EXECUTABLE ethvm) |
|||
|
|||
add_executable(${EXECUTABLE} ${SRC_LIST}) |
|||
|
|||
target_link_libraries(${EXECUTABLE} ethereum) |
|||
|
|||
if (APPLE) |
|||
install(TARGETS ${EXECUTABLE} DESTINATION bin) |
|||
else() |
|||
eth_install_executable(${EXECUTABLE}) |
|||
endif() |
@ -1,224 +0,0 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file main.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
* EVM Execution tool. |
|||
*/ |
|||
#include <fstream> |
|||
#include <iostream> |
|||
#include <ctime> |
|||
#include <boost/algorithm/string.hpp> |
|||
#include <libdevcore/CommonIO.h> |
|||
#include <libdevcore/RLP.h> |
|||
#include <libdevcore/SHA3.h> |
|||
#include <libethereum/Block.h> |
|||
#include <libethereum/Executive.h> |
|||
#include <libevm/VM.h> |
|||
#include <libevm/VMFactory.h> |
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace eth; |
|||
|
|||
void help() |
|||
{ |
|||
cout |
|||
<< "Usage ethvm <options> [trace|stats|output] (<file>|--)" << endl |
|||
<< "Transaction options:" << endl |
|||
<< " --value <n> Transaction should transfer the <n> wei (default: 0)." << endl |
|||
<< " --gas <n> Transaction should be given <n> gas (default: block gas limit)." << endl |
|||
<< " --gas-price <n> Transaction's gas price' should be <n> (default: 0)." << endl |
|||
<< " --sender <a> Transaction sender should be <a> (default: 0000...0069)." << endl |
|||
<< " --origin <a> Transaction origin should be <a> (default: 0000...0069)." << endl |
|||
#if ETH_EVMJIT || !ETH_TRUE |
|||
<< endl |
|||
<< "VM options:" << endl |
|||
<< " --vm <vm-kind> Select VM. Options are: interpreter, jit, smart. (default: interpreter)" << endl |
|||
#endif |
|||
<< endl |
|||
<< "Options for trace:" << endl |
|||
<< " --flat Minimal whitespace in the JSON." << endl |
|||
<< " --mnemonics Show instruction mnemonics in the trace (non-standard)." << endl |
|||
<< endl |
|||
<< "General options:" << endl |
|||
<< " -V,--version Show the version and exit." << endl |
|||
<< " -h,--help Show this help message and exit." << endl; |
|||
exit(0); |
|||
} |
|||
|
|||
void version() |
|||
{ |
|||
cout << "ethvm version " << dev::Version << endl; |
|||
cout << "By Gav Wood, 2015." << endl; |
|||
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; |
|||
exit(0); |
|||
} |
|||
|
|||
enum class Mode |
|||
{ |
|||
Trace, |
|||
Statistics, |
|||
OutputOnly |
|||
}; |
|||
|
|||
int main(int argc, char** argv) |
|||
{ |
|||
string incoming = "--"; |
|||
|
|||
Mode mode = Mode::Statistics; |
|||
State state; |
|||
Address sender = Address(69); |
|||
Address origin = Address(69); |
|||
u256 value = 0; |
|||
u256 gas = Block().gasLimitRemaining(); |
|||
u256 gasPrice = 0; |
|||
bool styledJson = true; |
|||
StandardTrace st; |
|||
EnvInfo envInfo; |
|||
|
|||
for (int i = 1; i < argc; ++i) |
|||
{ |
|||
string arg = argv[i]; |
|||
if (arg == "-h" || arg == "--help") |
|||
help(); |
|||
else if (arg == "-V" || arg == "--version") |
|||
version(); |
|||
#if ETH_EVMJIT |
|||
else if (arg == "--vm" && i + 1 < argc) |
|||
{ |
|||
string vmKind = argv[++i]; |
|||
if (vmKind == "interpreter") |
|||
VMFactory::setKind(VMKind::Interpreter); |
|||
else if (vmKind == "jit") |
|||
VMFactory::setKind(VMKind::JIT); |
|||
else if (vmKind == "smart") |
|||
VMFactory::setKind(VMKind::Smart); |
|||
else |
|||
{ |
|||
cerr << "Unknown VM kind: " << vmKind << endl; |
|||
return -1; |
|||
} |
|||
} |
|||
#endif |
|||
else if (arg == "--mnemonics") |
|||
st.setShowMnemonics(); |
|||
else if (arg == "--flat") |
|||
styledJson = false; |
|||
else if (arg == "--value" && i + 1 < argc) |
|||
value = u256(argv[++i]); |
|||
else if (arg == "--sender" && i + 1 < argc) |
|||
sender = Address(argv[++i]); |
|||
else if (arg == "--origin" && i + 1 < argc) |
|||
origin = Address(argv[++i]); |
|||
else if (arg == "--gas" && i + 1 < argc) |
|||
gas = u256(argv[++i]); |
|||
else if (arg == "--gas-price" && i + 1 < argc) |
|||
gasPrice = u256(argv[++i]); |
|||
else if (arg == "--value" && i + 1 < argc) |
|||
value = u256(argv[++i]); |
|||
else if (arg == "--value" && i + 1 < argc) |
|||
value = u256(argv[++i]); |
|||
else if (arg == "--beneficiary" && i + 1 < argc) |
|||
envInfo.setBeneficiary(Address(argv[++i])); |
|||
else if (arg == "--number" && i + 1 < argc) |
|||
envInfo.setNumber(u256(argv[++i])); |
|||
else if (arg == "--difficulty" && i + 1 < argc) |
|||
envInfo.setDifficulty(u256(argv[++i])); |
|||
else if (arg == "--timestamp" && i + 1 < argc) |
|||
envInfo.setTimestamp(u256(argv[++i])); |
|||
else if (arg == "--gas-limit" && i + 1 < argc) |
|||
envInfo.setGasLimit(u256(argv[++i])); |
|||
else if (arg == "--value" && i + 1 < argc) |
|||
value = u256(argv[++i]); |
|||
else if (arg == "stats") |
|||
mode = Mode::Statistics; |
|||
else if (arg == "output") |
|||
mode = Mode::OutputOnly; |
|||
else if (arg == "trace") |
|||
mode = Mode::Trace; |
|||
else |
|||
incoming = arg; |
|||
} |
|||
|
|||
bytes code; |
|||
if (incoming == "--" || incoming.empty()) |
|||
for (int i = cin.get(); i != -1; i = cin.get()) |
|||
code.push_back((char)i); |
|||
else |
|||
code = contents(incoming); |
|||
bytes data = fromHex(boost::trim_copy(asString(code))); |
|||
if (data.empty()) |
|||
data = code; |
|||
|
|||
state.addBalance(sender, value); |
|||
Executive executive(state, envInfo); |
|||
ExecutionResult res; |
|||
executive.setResultRecipient(res); |
|||
Transaction t = eth::Transaction(value, gasPrice, gas, data, 0); |
|||
t.forceSender(sender); |
|||
|
|||
unordered_map<byte, pair<unsigned, bigint>> counts; |
|||
unsigned total = 0; |
|||
bigint memTotal; |
|||
auto onOp = [&](uint64_t step, Instruction inst, bigint m, bigint gasCost, bigint gas, VM* vm, ExtVMFace const* extVM) { |
|||
if (mode == Mode::Statistics) |
|||
{ |
|||
counts[(byte)inst].first++; |
|||
counts[(byte)inst].second += gasCost; |
|||
total++; |
|||
if (m > 0) |
|||
memTotal = m; |
|||
} |
|||
else if (mode == Mode::Trace) |
|||
st(step, inst, m, gasCost, gas, vm, extVM); |
|||
}; |
|||
|
|||
executive.initialize(t); |
|||
executive.create(sender, value, gasPrice, gas, &data, origin); |
|||
Timer timer; |
|||
executive.go(onOp); |
|||
double execTime = timer.elapsed(); |
|||
executive.finalize(); |
|||
bytes output = std::move(res.output); |
|||
|
|||
if (mode == Mode::Statistics) |
|||
{ |
|||
cout << "Gas used: " << res.gasUsed << " (+" << t.gasRequired() << " for transaction, -" << res.gasRefunded << " refunded)" << endl; |
|||
cout << "Output: " << toHex(output) << endl; |
|||
LogEntries logs = executive.logs(); |
|||
cout << logs.size() << " logs" << (logs.empty() ? "." : ":") << endl; |
|||
for (LogEntry const& l: logs) |
|||
{ |
|||
cout << " " << l.address.hex() << ": " << toHex(t.data()) << endl; |
|||
for (h256 const& t: l.topics) |
|||
cout << " " << t.hex() << endl; |
|||
} |
|||
|
|||
cout << total << " operations in " << execTime << " seconds." << endl; |
|||
cout << "Maximum memory usage: " << memTotal * 32 << " bytes" << endl; |
|||
cout << "Expensive operations:" << endl; |
|||
for (auto const& c: {Instruction::SSTORE, Instruction::SLOAD, Instruction::CALL, Instruction::CREATE, Instruction::CALLCODE, Instruction::MSTORE8, Instruction::MSTORE, Instruction::MLOAD, Instruction::SHA3}) |
|||
if (!!counts[(byte)c].first) |
|||
cout << " " << instructionInfo(c).name << " x " << counts[(byte)c].first << " (" << counts[(byte)c].second << " gas)" << endl; |
|||
} |
|||
else if (mode == Mode::Trace) |
|||
cout << st.json(styledJson); |
|||
else if (mode == Mode::OutputOnly) |
|||
cout << toHex(output); |
|||
|
|||
return 0; |
|||
} |
@ -1,21 +0,0 @@ |
|||
cmake_policy(SET CMP0015 NEW) |
|||
set(CMAKE_AUTOMOC OFF) |
|||
|
|||
aux_source_directory(. SRC_LIST) |
|||
|
|||
include_directories(BEFORE ..) |
|||
include_directories(${DB_INCLUDE_DIRS}) |
|||
|
|||
set(EXECUTABLE rlp) |
|||
|
|||
add_executable(${EXECUTABLE} ${SRC_LIST}) |
|||
|
|||
target_link_libraries(${EXECUTABLE} devcrypto) |
|||
target_link_libraries(${EXECUTABLE} ${DB_LIBRARIES}) |
|||
|
|||
if (APPLE) |
|||
install(TARGETS ${EXECUTABLE} DESTINATION bin) |
|||
else() |
|||
eth_install_executable(${EXECUTABLE}) |
|||
endif() |
|||
|
@ -1,394 +0,0 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file main.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
* RLP tool. |
|||
*/ |
|||
#include <fstream> |
|||
#include <iostream> |
|||
#include <boost/algorithm/string.hpp> |
|||
#include "../test/JsonSpiritHeaders.h" |
|||
#include <libdevcore/CommonIO.h> |
|||
#include <libdevcore/RLP.h> |
|||
#include <libdevcore/SHA3.h> |
|||
using namespace std; |
|||
using namespace dev; |
|||
namespace js = json_spirit; |
|||
|
|||
void help() |
|||
{ |
|||
cout |
|||
<< "Usage rlp [OPTIONS] [ <file> | -- ]" << endl |
|||
<< "Options:" << endl |
|||
<< " -r,--render Render the given RLP. Options:" << endl |
|||
<< " --indent <string> Use string as the level indentation (default ' ')." << endl |
|||
<< " --hex-ints Render integers in hex." << endl |
|||
<< " --string-ints Render integers in the same way as strings." << endl |
|||
<< " --ascii-strings Render data as C-style strings or hex depending on content being ASCII." << endl |
|||
<< " --force-string Force all data to be rendered as C-style strings." << endl |
|||
<< " --force-escape When rendering as C-style strings, force all characters to be escaped." << endl |
|||
<< " --force-hex Force all data to be rendered as raw hex." << endl |
|||
<< " -l,--list-archive List the items in the RLP list by hash and size." << endl |
|||
<< " -e,--extract-archive Extract all items in the RLP list, named by hash." << endl |
|||
<< " -c,--create Given a simplified JSON string, output the RLP." << endl |
|||
<< "General options:" << endl |
|||
<< " -L,--lenience Try not to bomb out early if possible." << endl |
|||
<< " -x,--hex,--base-16 Treat input RLP as hex encoded data." << endl |
|||
<< " -k,--keccak Output Keccak-256 hash only." << endl |
|||
<< " --64,--base-64 Treat input RLP as base-64 encoded data." << endl |
|||
<< " -b,--bin,--base-256 Treat input RLP as raw binary data." << endl |
|||
<< " -h,--help Print this help message and exit." << endl |
|||
<< " -V,--version Show the version and exit." << endl |
|||
; |
|||
exit(0); |
|||
} |
|||
|
|||
void version() |
|||
{ |
|||
cout << "rlp version " << dev::Version << endl; |
|||
exit(0); |
|||
} |
|||
|
|||
enum class Mode { |
|||
ListArchive, |
|||
ExtractArchive, |
|||
Render, |
|||
Create |
|||
}; |
|||
|
|||
enum class Encoding { |
|||
Auto, |
|||
Hex, |
|||
Base64, |
|||
Binary, |
|||
Keccak, |
|||
}; |
|||
|
|||
bool isAscii(string const& _s) |
|||
{ |
|||
// Always hex-encode anything beginning with 0x to avoid ambiguity.
|
|||
if (_s.size() >= 2 && _s.substr(0, 2) == "0x") |
|||
return false; |
|||
|
|||
for (char c: _s) |
|||
if (c < 32) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
class RLPStreamer |
|||
{ |
|||
public: |
|||
struct Prefs |
|||
{ |
|||
string indent; |
|||
bool hexInts = false; |
|||
bool stringInts = true; |
|||
bool hexPrefix = true; |
|||
bool forceString = false; |
|||
bool escapeAll = false; |
|||
bool forceHex = true; |
|||
}; |
|||
|
|||
RLPStreamer(ostream& _out, Prefs _p): m_out(_out), m_prefs(_p) {} |
|||
|
|||
void output(RLP const& _d, unsigned _level = 0) |
|||
{ |
|||
if (_d.isNull()) |
|||
m_out << "null"; |
|||
else if (_d.isInt() && !m_prefs.stringInts) |
|||
if (m_prefs.hexInts) |
|||
m_out << (m_prefs.hexPrefix ? "0x" : "") << toHex(toCompactBigEndian(_d.toInt<bigint>(RLP::LaissezFaire), 1), 1); |
|||
else |
|||
m_out << _d.toInt<bigint>(RLP::LaissezFaire); |
|||
else if (_d.isData() || (_d.isInt() && m_prefs.stringInts)) |
|||
if (m_prefs.forceString || (!m_prefs.forceHex && isAscii(_d.toString()))) |
|||
m_out << escaped(_d.toString(), m_prefs.escapeAll); |
|||
else |
|||
m_out << "\"" << (m_prefs.hexPrefix ? "0x" : "") << toHex(_d.toBytes()) << "\""; |
|||
else if (_d.isList()) |
|||
{ |
|||
m_out << "["; |
|||
string newline = "\n"; |
|||
for (unsigned i = 0; i < _level + 1; ++i) |
|||
newline += m_prefs.indent; |
|||
int j = 0; |
|||
for (auto i: _d) |
|||
{ |
|||
m_out << (j++ ? |
|||
(m_prefs.indent.empty() ? ", " : ("," + newline)) : |
|||
(m_prefs.indent.empty() ? " " : newline)); |
|||
output(i, _level + 1); |
|||
} |
|||
newline = newline.substr(0, newline.size() - m_prefs.indent.size()); |
|||
m_out << (m_prefs.indent.empty() ? (j ? " ]" : "]") : (j ? newline + "]" : "]")); |
|||
} |
|||
} |
|||
|
|||
private: |
|||
std::ostream& m_out; |
|||
Prefs m_prefs; |
|||
}; |
|||
|
|||
int main(int argc, char** argv) |
|||
{ |
|||
Encoding encoding = Encoding::Auto; |
|||
Mode mode = Mode::Render; |
|||
string inputFile = "--"; |
|||
bool lenience = false; |
|||
RLPStreamer::Prefs prefs; |
|||
|
|||
for (int i = 1; i < argc; ++i) |
|||
{ |
|||
string arg = argv[i]; |
|||
if (arg == "-h" || arg == "--help") |
|||
help(); |
|||
else if (arg == "-r" || arg == "--render") |
|||
mode = Mode::Render; |
|||
else if (arg == "-c" || arg == "--create") |
|||
mode = Mode::Create; |
|||
else if ((arg == "-i" || arg == "--indent") && argc > i) |
|||
prefs.indent = argv[++i]; |
|||
else if (arg == "--hex-ints") |
|||
prefs.hexInts = true; |
|||
else if (arg == "--string-ints") |
|||
prefs.stringInts = true; |
|||
else if (arg == "--ascii-strings") |
|||
prefs.forceString = prefs.forceHex = false; |
|||
else if (arg == "--force-string") |
|||
prefs.forceString = true; |
|||
else if (arg == "--force-hex") |
|||
prefs.forceHex = true, prefs.forceString = false; |
|||
else if (arg == "--force-escape") |
|||
prefs.escapeAll = true; |
|||
else if (arg == "-n" || arg == "--nice") |
|||
prefs.forceString = true, prefs.stringInts = false, prefs.forceHex = false, prefs.indent = " "; |
|||
else if (arg == "-l" || arg == "--list-archive") |
|||
mode = Mode::ListArchive; |
|||
else if (arg == "-e" || arg == "--extract-archive") |
|||
mode = Mode::ExtractArchive; |
|||
else if (arg == "-L" || arg == "--lenience") |
|||
lenience = true; |
|||
else if (arg == "-V" || arg == "--version") |
|||
version(); |
|||
else if (arg == "-x" || arg == "--hex" || arg == "--base-16") |
|||
encoding = Encoding::Hex; |
|||
else if (arg == "-k" || arg == "--keccak") |
|||
encoding = Encoding::Keccak; |
|||
else if (arg == "--64" || arg == "--base-64") |
|||
encoding = Encoding::Base64; |
|||
else if (arg == "-b" || arg == "--bin" || arg == "--base-256") |
|||
encoding = Encoding::Binary; |
|||
else |
|||
inputFile = arg; |
|||
} |
|||
|
|||
bytes in; |
|||
if (inputFile == "--") |
|||
for (int i = cin.get(); i != -1; i = cin.get()) |
|||
in.push_back((byte)i); |
|||
else |
|||
in = contents(inputFile); |
|||
|
|||
bytes b; |
|||
|
|||
if (mode != Mode::Create) |
|||
{ |
|||
if (encoding == Encoding::Auto) |
|||
{ |
|||
encoding = Encoding::Hex; |
|||
for (char b: in) |
|||
if (b != '\n' && b != ' ' && b != '\t') |
|||
{ |
|||
if (encoding == Encoding::Hex && (b < '0' || b > '9' ) && (b < 'a' || b > 'f' ) && (b < 'A' || b > 'F' )) |
|||
{ |
|||
cerr << "'" << b << "':" << (int)b << endl; |
|||
encoding = Encoding::Base64; |
|||
} |
|||
if (encoding == Encoding::Base64 && (b < '0' || b > '9' ) && (b < 'a' || b > 'z' ) && (b < 'A' || b > 'Z' ) && b != '+' && b != '/') |
|||
{ |
|||
encoding = Encoding::Binary; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
switch (encoding) |
|||
{ |
|||
case Encoding::Hex: |
|||
{ |
|||
string s = asString(in); |
|||
boost::algorithm::replace_all(s, " ", ""); |
|||
boost::algorithm::replace_all(s, "\n", ""); |
|||
boost::algorithm::replace_all(s, "\t", ""); |
|||
b = fromHex(s); |
|||
break; |
|||
} |
|||
case Encoding::Base64: |
|||
{ |
|||
string s = asString(in); |
|||
boost::algorithm::replace_all(s, " ", ""); |
|||
boost::algorithm::replace_all(s, "\n", ""); |
|||
boost::algorithm::replace_all(s, "\t", ""); |
|||
b = fromBase64(s); |
|||
break; |
|||
} |
|||
default: |
|||
swap(b, in); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
try |
|||
{ |
|||
RLP rlp(b); |
|||
switch (mode) |
|||
{ |
|||
case Mode::ListArchive: |
|||
{ |
|||
if (!rlp.isList()) |
|||
{ |
|||
cout << "Error: Invalid format; RLP data is not a list." << endl; |
|||
exit(1); |
|||
} |
|||
cout << rlp.itemCount() << " items:" << endl; |
|||
for (auto i: rlp) |
|||
{ |
|||
if (!i.isData()) |
|||
{ |
|||
cout << "Error: Invalid format; RLP list item is not data." << endl; |
|||
if (!lenience) |
|||
exit(1); |
|||
} |
|||
cout << " " << i.size() << " bytes: " << sha3(i.data()) << endl; |
|||
} |
|||
break; |
|||
} |
|||
case Mode::ExtractArchive: |
|||
{ |
|||
if (!rlp.isList()) |
|||
{ |
|||
cout << "Error: Invalid format; RLP data is not a list." << endl; |
|||
exit(1); |
|||
} |
|||
cout << rlp.itemCount() << " items:" << endl; |
|||
for (auto i: rlp) |
|||
{ |
|||
if (!i.isData()) |
|||
{ |
|||
cout << "Error: Invalid format; RLP list item is not data." << endl; |
|||
if (!lenience) |
|||
exit(1); |
|||
} |
|||
ofstream fout; |
|||
fout.open(toString(sha3(i.data()))); |
|||
fout.write(reinterpret_cast<char const*>(i.data().data()), i.data().size()); |
|||
} |
|||
break; |
|||
} |
|||
case Mode::Render: |
|||
{ |
|||
RLPStreamer s(cout, prefs); |
|||
s.output(rlp); |
|||
cout << endl; |
|||
break; |
|||
} |
|||
case Mode::Create: |
|||
{ |
|||
vector<js::mValue> v(1); |
|||
try { |
|||
js::read_string(asString(in), v[0]); |
|||
} |
|||
catch (...) |
|||
{ |
|||
cerr << "Error: Invalid format; bad JSON." << endl; |
|||
exit(1); |
|||
} |
|||
RLPStream out; |
|||
while (!v.empty()) |
|||
{ |
|||
auto vb = v.back(); |
|||
v.pop_back(); |
|||
switch (vb.type()) |
|||
{ |
|||
case js::array_type: |
|||
{ |
|||
js::mArray a = vb.get_array(); |
|||
out.appendList(a.size()); |
|||
for (int i = a.size() - 1; i >= 0; --i) |
|||
v.push_back(a[i]); |
|||
break; |
|||
} |
|||
case js::str_type: |
|||
{ |
|||
string const& s = vb.get_str(); |
|||
if (s.size() >= 2 && s.substr(0, 2) == "0x") |
|||
out << fromHex(s); |
|||
else |
|||
{ |
|||
// assume it's a normal JS escaped string.
|
|||
bytes ss; |
|||
ss.reserve(s.size()); |
|||
for (unsigned i = 0; i < s.size(); ++i) |
|||
if (s[i] == '\\' && i + 1 < s.size()) |
|||
{ |
|||
if (s[++i] == 'x' && i + 2 < s.size()) |
|||
ss.push_back(fromHex(s.substr(i, 2))[0]); |
|||
} |
|||
else if (s[i] != '\\') |
|||
ss.push_back((byte)s[i]); |
|||
out << ss; |
|||
} |
|||
break; |
|||
} |
|||
case js::int_type: |
|||
out << vb.get_int(); |
|||
break; |
|||
default: |
|||
cerr << "ERROR: Unsupported type in JSON." << endl; |
|||
if (!lenience) |
|||
exit(1); |
|||
} |
|||
} |
|||
switch (encoding) |
|||
{ |
|||
case Encoding::Hex: case Encoding::Auto: |
|||
cout << toHex(out.out()) << endl; |
|||
break; |
|||
case Encoding::Base64: |
|||
cout << toBase64(&out.out()) << endl; |
|||
break; |
|||
case Encoding::Binary: |
|||
cout.write((char const*)out.out().data(), out.out().size()); |
|||
break; |
|||
case Encoding::Keccak: |
|||
cout << sha3(out.out()).hex() << endl; |
|||
break; |
|||
} |
|||
break; |
|||
} |
|||
default:; |
|||
} |
|||
} |
|||
catch (...) |
|||
{ |
|||
cerr << "Error: Invalid format; bad RLP." << endl; |
|||
exit(1); |
|||
} |
|||
|
|||
return 0; |
|||
} |
Loading…
Reference in new issue