Browse Source

First JSON-RPC stubs.

cl-refactor
Gav Wood 11 years ago
parent
commit
2eee2b2af5
  1. 4
      eth/CMakeLists.txt
  2. 65
      eth/CommonJS.cpp
  3. 88
      eth/CommonJS.h
  4. 59
      eth/EthStubServer.cpp
  5. 41
      eth/EthStubServer.h
  6. 237
      eth/main.cpp

4
eth/CMakeLists.txt

@ -23,6 +23,10 @@ if (${TARGET_PLATFORM} STREQUAL "w64")
target_link_libraries(eth boost_thread_win32-mt-s)
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
elseif (UNIX)
add_definitions(-DETH_JSONRPC)
add_definitions(-DETH_READLINE)
target_link_libraries(eth jsonrpc)
target_link_libraries(eth readline)
target_link_libraries(eth form)
else ()
target_link_libraries(eth ${CRYPTOPP_LIBRARIES})

65
eth/CommonJS.cpp

@ -0,0 +1,65 @@
/*
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 CommonJS.cpp
* @authors:
* Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "CommonJS.h"
using namespace std;
using namespace eth;
bytes eth::jsToBytes(string const& _s)
{
if (_s.substr(0, 2) == "0x")
// Hex
return fromHex(_s.substr(2));
else if (_s.find_first_not_of("0123456789") == string::npos)
// Decimal
return toCompactBigEndian(bigint(_s));
else
// Binary
return asBytes(_s);
}
string eth::jsPadded(string const& _s, unsigned _l, unsigned _r)
{
bytes b = jsToBytes(_s);
while (b.size() < _l)
b.insert(b.begin(), 0);
while (b.size() < _r)
b.push_back(0);
return asString(b).substr(b.size() - max(_l, _r));
}
string eth::jsPadded(string const& _s, unsigned _l)
{
if (_s.substr(0, 2) == "0x" || _s.find_first_not_of("0123456789") == string::npos)
// Numeric: pad to right
return jsPadded(_s, _l, _l);
else
// Text: pad to the left
return jsPadded(_s, 0, _l);
}
string eth::jsUnpadded(string _s)
{
auto p = _s.find_last_not_of((char)0);
_s.resize(p == string::npos ? 0 : (p + 1));
return _s;
}

88
eth/CommonJS.h

@ -0,0 +1,88 @@
/*
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 CommonJS.h
* @authors:
* Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <string>
#include <libethcore/Common.h>
#include <libethcore/CommonIO.h>
#include <libethcore/CommonData.h>
#include <libethcore/FixedHash.h>
#include <libethereum/CommonEth.h>
namespace eth
{
eth::bytes jsToBytes(std::string const& _s);
std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r);
std::string jsPadded(std::string const& _s, unsigned _l);
std::string jsUnpadded(std::string _s);
template <unsigned N> eth::FixedHash<N> jsToFixed(std::string const& _s)
{
if (_s.substr(0, 2) == "0x")
// Hex
return eth::FixedHash<N>(_s.substr(2));
else if (_s.find_first_not_of("0123456789") == std::string::npos)
// Decimal
return (typename eth::FixedHash<N>::Arith)(_s);
else
// Binary
return eth::FixedHash<N>(asBytes(jsPadded(_s, N)));
}
template <unsigned N> boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> jsToInt(std::string const& _s)
{
if (_s.substr(0, 2) == "0x")
// Hex
return eth::fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(eth::fromHex(_s.substr(2)));
else if (_s.find_first_not_of("0123456789") == std::string::npos)
// Decimal
return boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>(_s);
else
// Binary
return eth::fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(asBytes(jsPadded(_s, N)));
}
inline eth::Address jsToAddress(std::string const& _s) { return jsToFixed<20>(_s); }
inline eth::Secret jsToSecret(std::string const& _s) { return jsToFixed<32>(_s); }
inline eth::u256 jsToU256(std::string const& _s) { return jsToInt<32>(_s); }
template <unsigned S> std::string toJS(eth::FixedHash<S> const& _h) { return "0x" + toHex(_h.ref()); }
template <unsigned N> std::string toJS(boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> const& _n) { return "0x" + eth::toHex(eth::toCompactBigEndian(_n)); }
inline std::string jsToBinary(std::string const& _s)
{
return eth::asString(jsToBytes(_s));
}
inline std::string jsToDecimal(std::string const& _s)
{
return eth::toString(jsToU256(_s));
}
inline std::string jsToHex(std::string const& _s)
{
return "0x" + eth::toHex(asBytes(_s));
}
}

59
eth/EthStubServer.cpp

@ -0,0 +1,59 @@
/*
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 EthStubServer.cpp
* @authors:
* Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "EthStubServer.h"
#include <libethereum/Client.h>
#include "CommonJS.h"
using namespace std;
using namespace eth;
EthStubServer::EthStubServer(jsonrpc::AbstractServerConnector* _conn, Client& _client):
AbstractEthStubServer(_conn),
m_client(_client)
{
}
std::string EthStubServer::coinbase()
{
return toJS(m_client.address());
}
std::string EthStubServer::balanceAt(std::string const& _a)
{
return toJS(m_client.postState().balance(jsToAddress(_a)));
}
Json::Value EthStubServer::check(Json::Value const& _as)
{
if (m_client.changed())
return _as;
else
{
Json::Value ret;
ret.resize(0);
return ret;
}
}

41
eth/EthStubServer.h

@ -0,0 +1,41 @@
/*
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 EthStubServer.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <iostream>
#include <jsonrpc/rpc.h>
#include "abstractethstubserver.h"
namespace eth { class Client; }
class EthStubServer: public AbstractEthStubServer
{
public:
EthStubServer(jsonrpc::AbstractServerConnector* _conn, eth::Client& _client);
virtual std::string coinbase();
virtual std::string balanceAt(std::string const& _a);
virtual Json::Value check(Json::Value const& _as);
private:
eth::Client& m_client;
};

237
eth/main.cpp

@ -20,6 +20,9 @@
* Ethereum client.
*/
#define ETH_READLINE 1
#define ETH_JSONRPC 1
#include <thread>
#include <chrono>
#include <fstream>
@ -31,6 +34,13 @@
#include <libethereum/BlockChain.h>
#include <libethereum/State.h>
#include <libethereum/Instruction.h>
#if ETH_READLINE
#include <readline/readline.h>
#include <readline/history.h>
#endif
#if ETH_JSONRPC
#include "EthStubServer.h"
#endif
#include "BuildInfo.h"
using namespace std;
using namespace eth;
@ -47,6 +57,29 @@ bool isFalse(std::string const& _m)
return _m == "off" || _m == "no" || _m == "false" || _m == "0";
}
void interactiveHelp()
{
cout
<< "Commands:" << endl
<< " netstart <port> Starts the network subsystem on a specific port." << endl
<< " netstop Stops the network subsystem." << endl
<< " jsonstart <port> Starts the JSON-RPC server." << endl
<< " jsonstop Stops the JSON-RPC server." << endl
<< " connect <addr> <port> Connects to a specific peer." << endl
<< " minestart Starts mining." << endl
<< " minestop Stops mining." << endl
<< " address Gives the current address." << endl
<< " secret Gives the current secret" << endl
<< " block Gives the current block height." << endl
<< " balance Gives the current balance." << endl
<< " peers List the peers that are connected" << endl
<< " transact Execute a given transaction. TODO." << endl
<< " send Execute a given transaction with current secret. TODO." << endl
<< " create Create a new contract with current secret. TODO." << endl
<< " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl
<< " exit Exits the application." << endl;
}
void help()
{
cout
@ -58,6 +91,9 @@ void help()
<< " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl
<< " -h,--help Show this help message and exit." << endl
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << endl
#if ETH_JSONRPC
<< " -j,--json-rpc <port> Start JSON-RPC server." << endl
#endif
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
@ -74,8 +110,8 @@ void help()
string credits(bool _interactive = false)
{
std::ostringstream ccout;
ccout
std::ostringstream cout;
cout
<< "Ethereum (++) " << ETH_QUOTED(ETH_VERSION) << endl
<< " Code by Gav Wood, (c) 2013, 2014." << endl
<< " Based on a design by Vitalik Buterin." << endl << endl;
@ -91,11 +127,11 @@ string credits(bool _interactive = false)
if (pocnumber == 4)
m_servers = "54.72.31.55";
ccout << "Type 'netstart 30303' to start networking" << endl;
ccout << "Type 'connect " << m_servers << " 30303' to connect" << endl;
ccout << "Type 'exit' to quit" << endl << endl;
cout << "Type 'netstart 30303' to start networking" << endl;
cout << "Type 'connect " << m_servers << " 30303' to connect" << endl;
cout << "Type 'exit' to quit" << endl << endl;
}
return ccout.str();
return cout.str();
}
void version()
@ -133,6 +169,10 @@ int main(int argc, char** argv)
eth::uint mining = ~(eth::uint)0;
NodeMode mode = NodeMode::Full;
unsigned peers = 5;
bool interactive = false;
#if ETH_JSONRPC
int jsonrpc = -1;
#endif
string publicIP;
bool upnp = true;
string clientName;
@ -206,6 +246,12 @@ int main(int argc, char** argv)
return -1;
}
}
else if (arg == "-i" || arg == "--interactive")
interactive = true;
#if ETH_JSONRPC
else if ((arg == "-j" || arg == "--json-rpc") && i + 1 < argc)
jsonrpc = atoi(argv[++i]);
#endif
else if ((arg == "-v" || arg == "--verbosity") && i + 1 < argc)
g_logVerbosity = atoi(argv[++i]);
else if ((arg == "-x" || arg == "--peers") && i + 1 < argc)
@ -238,15 +284,180 @@ int main(int argc, char** argv)
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
c.startNetwork(listenPort, remoteHost, remotePort, mode, peers, publicIP, upnp);
eth::uint n = c.blockChain().details().number;
if (mining)
c.startMining();
while (true)
#if ETH_JSONRPC
auto_ptr<EthStubServer> jsonrpcServer;
if (jsonrpc > -1)
{
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(jsonrpc), c));
jsonrpcServer->StartListening();
}
#endif
if (interactive)
{
string l;
while (true)
{
#if ETH_READLINE
if (l.size())
add_history(l.c_str());
if (auto c = readline("> "))
{
l = c;
free(c);
}
else
break;
#else
string l;
cout << "> " << flush;
std::getline(cin, l);
#endif
istringstream iss(l);
string cmd;
iss >> cmd;
if (cmd == "netstart")
{
eth::uint port;
iss >> port;
c.lock();
c.startNetwork((short)port);
c.unlock();
}
else if (cmd == "connect")
{
string addr;
eth::uint port;
iss >> addr >> port;
c.lock();
c.connect(addr, (short)port);
c.unlock();
}
else if (cmd == "netstop")
{
c.lock();
c.stopNetwork();
c.unlock();
}
else if (cmd == "minestart")
{
c.lock();
c.startMining();
c.unlock();
}
else if (cmd == "minestop")
{
c.lock();
c.stopMining();
c.unlock();
}
else if (cmd == "jsonstart")
{
unsigned port;
iss >> port;
jsonrpcServer = auto_ptr<EthStubServer>(new EthStubServer(new jsonrpc::HttpServer(port), c));
jsonrpcServer->StartListening();
}
else if (cmd == "jsonstop")
{
jsonrpcServer->StopListening();
jsonrpcServer.reset();
}
else if (cmd == "address")
{
cout << "Current address:" << endl;
const char* addchr = toHex(us.address().asArray()).c_str();
cout << addchr << endl;
}
else if (cmd == "secret")
{
cout << "Current secret:" << endl;
const char* addchr = toHex(us.secret().asArray()).c_str();
cout << addchr << endl;
}
else if (cmd == "block")
{
eth::uint n = c.blockChain().details().number;
cout << "Current block # ";
const char* addchr = toString(n).c_str();
cout << addchr << endl;
}
else if (cmd == "peers")
{
for (auto it: c.peers())
cout << it.host << ":" << it.port << ", " << it.clientVersion << ", "
<< std::chrono::duration_cast<std::chrono::milliseconds>(it.lastPing).count() << "ms"
<< endl;
}
else if (cmd == "balance")
{
u256 balance = c.state().balance(us.address());
cout << "Current balance:" << endl;
const char* addchr = toString(balance).c_str();
cout << addchr << endl;
}
else if (cmd == "transact")
{
//TODO.
}
else if (cmd == "send")
{
//TODO
}
else if (cmd == "create")
{
//TODO
}
else if (cmd == "inspect")
{
string rechex;
iss >> rechex;
if (rechex.length() != 40)
cwarn << "Invalid address length";
else
{
c.lock();
auto h = h160(fromHex(rechex));
stringstream s;
auto mem = c.state().storage(h);
for (auto const& i: mem)
s << "@" << showbase << hex << i.first << " " << showbase << hex << i.second << endl;
s << endl << disassemble(c.state().code(h));
string outFile = getDataDir() + "/" + rechex + ".evm";
ofstream ofs;
ofs.open(outFile, ofstream::binary);
ofs.write(s.str().c_str(), s.str().length());
ofs.close();
c.unlock();
}
}
else if (cmd == "help")
interactiveHelp();
else if (cmd == "exit")
break;
else
cout << "Unrecognised command. Type 'help' for help in interactive mode." << endl;
}
jsonrpcServer->StopListening();
}
else
{
if (c.blockChain().details().number - n == mining)
c.stopMining();
this_thread::sleep_for(chrono::milliseconds(100));
eth::uint n = c.blockChain().details().number;
if (mining)
c.startMining();
while (true)
{
if (c.blockChain().details().number - n == mining)
c.stopMining();
this_thread::sleep_for(chrono::milliseconds(100));
}
}
return 0;
}

Loading…
Cancel
Save