arkpar
10 years ago
38 changed files with 1947 additions and 1237 deletions
@ -0,0 +1,664 @@ |
|||||
|
/*
|
||||
|
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 WebThreeStubServerBase.cpp
|
||||
|
* @authors: |
||||
|
* Gav Wood <i@gavwood.com> |
||||
|
* Marek Kotewicz <marek@ethdev.com> |
||||
|
* @date 2014 |
||||
|
*/ |
||||
|
|
||||
|
#include <libsolidity/CompilerStack.h> |
||||
|
#include <libsolidity/Scanner.h> |
||||
|
#include <libsolidity/SourceReferenceFormatter.h> |
||||
|
#include <libevmcore/Instruction.h> |
||||
|
#include <liblll/Compiler.h> |
||||
|
#include <libethereum/Client.h> |
||||
|
#include <libwebthree/WebThree.h> |
||||
|
#include <libdevcore/CommonJS.h> |
||||
|
#include <libwhisper/Message.h> |
||||
|
#include <libwhisper/WhisperHost.h> |
||||
|
#include <libserpent/funcs.h> |
||||
|
#include "WebThreeStubServerBase.h" |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace dev; |
||||
|
using namespace dev::eth; |
||||
|
|
||||
|
static Json::Value toJson(dev::eth::BlockInfo const& _bi) |
||||
|
{ |
||||
|
Json::Value res; |
||||
|
res["hash"] = boost::lexical_cast<string>(_bi.hash); |
||||
|
res["parentHash"] = toJS(_bi.parentHash); |
||||
|
res["sha3Uncles"] = toJS(_bi.sha3Uncles); |
||||
|
res["miner"] = toJS(_bi.coinbaseAddress); |
||||
|
res["stateRoot"] = toJS(_bi.stateRoot); |
||||
|
res["transactionsRoot"] = toJS(_bi.transactionsRoot); |
||||
|
res["difficulty"] = toJS(_bi.difficulty); |
||||
|
res["number"] = (int)_bi.number; |
||||
|
res["gasLimit"] = (int)_bi.gasLimit; |
||||
|
res["timestamp"] = (int)_bi.timestamp; |
||||
|
res["extraData"] = jsFromBinary(_bi.extraData); |
||||
|
res["nonce"] = toJS(_bi.nonce); |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
static Json::Value toJson(dev::eth::Transaction const& _t) |
||||
|
{ |
||||
|
Json::Value res; |
||||
|
res["hash"] = toJS(_t.sha3()); |
||||
|
res["input"] = jsFromBinary(_t.data()); |
||||
|
res["to"] = toJS(_t.receiveAddress()); |
||||
|
res["from"] = toJS(_t.sender()); |
||||
|
res["gas"] = (int)_t.gas(); |
||||
|
res["gasPrice"] = toJS(_t.gasPrice()); |
||||
|
res["nonce"] = toJS(_t.nonce()); |
||||
|
res["value"] = toJS(_t.value()); |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
static Json::Value toJson(dev::eth::LogEntry const& _e) |
||||
|
{ |
||||
|
Json::Value res; |
||||
|
|
||||
|
res["data"] = jsFromBinary(_e.data); |
||||
|
res["address"] = toJS(_e.address); |
||||
|
for (auto const& t: _e.topics) |
||||
|
res["topics"].append(toJS(t)); |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
static Json::Value toJson(dev::eth::LogEntries const& _es) // commented to avoid warning. Uncomment once in use @ poC-7.
|
||||
|
{ |
||||
|
Json::Value res; |
||||
|
for (dev::eth::LogEntry const& e: _es) |
||||
|
res.append(toJson(e)); |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
static Json::Value toJson(std::map<u256, u256> const& _storage) |
||||
|
{ |
||||
|
Json::Value res(Json::objectValue); |
||||
|
for (auto i: _storage) |
||||
|
res[toJS(i.first)] = toJS(i.second); |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
static dev::eth::LogFilter toLogFilter(Json::Value const& _json) // commented to avoid warning. Uncomment once in use @ PoC-7.
|
||||
|
{ |
||||
|
dev::eth::LogFilter filter; |
||||
|
if (!_json.isObject() || _json.empty()) |
||||
|
return filter; |
||||
|
|
||||
|
if (_json["earliest"].isInt()) |
||||
|
filter.withEarliest(_json["earliest"].asInt()); |
||||
|
if (_json["latest"].isInt()) |
||||
|
filter.withLatest(_json["lastest"].asInt()); |
||||
|
if (_json["max"].isInt()) |
||||
|
filter.withMax(_json["max"].asInt()); |
||||
|
if (_json["skip"].isInt()) |
||||
|
filter.withSkip(_json["skip"].asInt()); |
||||
|
if (!_json["address"].empty()) |
||||
|
{ |
||||
|
if (_json["address"].isArray()) |
||||
|
{ |
||||
|
for (auto i : _json["address"]) |
||||
|
if (i.isString()) |
||||
|
filter.address(jsToAddress(i.asString())); |
||||
|
} |
||||
|
else if (_json["address"].isString()) |
||||
|
filter.address(jsToAddress(_json["address"].asString())); |
||||
|
} |
||||
|
if (!_json["topics"].empty()) |
||||
|
{ |
||||
|
if (_json["topics"].isArray()) |
||||
|
{ |
||||
|
for (auto i: _json["topics"]) |
||||
|
if (i.isString()) |
||||
|
filter.topic(jsToU256(i.asString())); |
||||
|
} |
||||
|
else if(_json["topics"].isString()) |
||||
|
filter.topic(jsToU256(_json["topics"].asString())); |
||||
|
} |
||||
|
return filter; |
||||
|
} |
||||
|
|
||||
|
static shh::Message toMessage(Json::Value const& _json) |
||||
|
{ |
||||
|
shh::Message ret; |
||||
|
if (_json["from"].isString()) |
||||
|
ret.setFrom(jsToPublic(_json["from"].asString())); |
||||
|
if (_json["to"].isString()) |
||||
|
ret.setTo(jsToPublic(_json["to"].asString())); |
||||
|
if (_json["payload"].isString()) |
||||
|
ret.setPayload(jsToBytes(_json["payload"].asString())); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, Secret _from) |
||||
|
{ |
||||
|
unsigned ttl = 50; |
||||
|
unsigned workToProve = 50; |
||||
|
shh::BuildTopic bt; |
||||
|
|
||||
|
if (_json["ttl"].isInt()) |
||||
|
ttl = _json["ttl"].asInt(); |
||||
|
if (_json["workToProve"].isInt()) |
||||
|
workToProve = _json["workToProve"].asInt(); |
||||
|
if (!_json["topic"].empty()) |
||||
|
{ |
||||
|
if (_json["topic"].isString()) |
||||
|
bt.shift(jsToBytes(_json["topic"].asString())); |
||||
|
else if (_json["topic"].isArray()) |
||||
|
for (auto i: _json["topic"]) |
||||
|
if (i.isString()) |
||||
|
bt.shift(jsToBytes(i.asString())); |
||||
|
} |
||||
|
return _m.seal(_from, bt, ttl, workToProve); |
||||
|
} |
||||
|
|
||||
|
static pair<shh::TopicMask, Public> toWatch(Json::Value const& _json) |
||||
|
{ |
||||
|
shh::BuildTopicMask bt; |
||||
|
Public to; |
||||
|
|
||||
|
if (_json["to"].isString()) |
||||
|
to = jsToPublic(_json["to"].asString()); |
||||
|
|
||||
|
if (!_json["topic"].empty()) |
||||
|
{ |
||||
|
if (_json["topic"].isString()) |
||||
|
bt.shift(jsToBytes(_json["topic"].asString())); |
||||
|
else if (_json["topic"].isArray()) |
||||
|
for (auto i: _json["topic"]) |
||||
|
if (i.isString()) |
||||
|
bt.shift(jsToBytes(i.asString())); |
||||
|
} |
||||
|
return make_pair(bt.toTopicMask(), to); |
||||
|
} |
||||
|
|
||||
|
static Json::Value toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m) |
||||
|
{ |
||||
|
Json::Value res; |
||||
|
res["hash"] = toJS(_h); |
||||
|
res["expiry"] = (int)_e.expiry(); |
||||
|
res["sent"] = (int)_e.sent(); |
||||
|
res["ttl"] = (int)_e.ttl(); |
||||
|
res["workProved"] = (int)_e.workProved(); |
||||
|
for (auto const& t: _e.topics()) |
||||
|
res["topics"].append(toJS(t)); |
||||
|
res["payload"] = toJS(_m.payload()); |
||||
|
res["from"] = toJS(_m.from()); |
||||
|
res["to"] = toJS(_m.to()); |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
WebThreeStubServerBase::WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts): |
||||
|
AbstractWebThreeStubServer(_conn) |
||||
|
{ |
||||
|
setAccounts(_accounts); |
||||
|
} |
||||
|
|
||||
|
void WebThreeStubServerBase::setAccounts(std::vector<dev::KeyPair> const& _accounts) |
||||
|
{ |
||||
|
m_accounts.clear(); |
||||
|
for (auto i: _accounts) |
||||
|
m_accounts[i.address()] = i.secret(); |
||||
|
} |
||||
|
|
||||
|
void WebThreeStubServerBase::setIdentities(std::vector<dev::KeyPair> const& _ids) |
||||
|
{ |
||||
|
m_ids.clear(); |
||||
|
for (auto i: _ids) |
||||
|
m_ids[i.pub()] = i.secret(); |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::web3_sha3(std::string const& _param1) |
||||
|
{ |
||||
|
return toJS(sha3(jsToBytes(_param1))); |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_accounts() |
||||
|
{ |
||||
|
Json::Value ret(Json::arrayValue); |
||||
|
for (auto i: m_accounts) |
||||
|
ret.append(toJS(i.first)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::shh_addToGroup(std::string const& _group, std::string const& _who) |
||||
|
{ |
||||
|
(void)_group; |
||||
|
(void)_who; |
||||
|
return ""; |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::eth_balanceAt(string const& _address) |
||||
|
{ |
||||
|
return toJS(client()->balanceAt(jsToAddress(_address), client()->getDefault())); |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_blockByHash(std::string const& _hash) |
||||
|
{ |
||||
|
return toJson(client()->blockInfo(jsToFixed<32>(_hash))); |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_blockByNumber(int const& _number) |
||||
|
{ |
||||
|
return toJson(client()->blockInfo(client()->hashFromNumber(_number))); |
||||
|
} |
||||
|
|
||||
|
static TransactionSkeleton toTransaction(Json::Value const& _json) |
||||
|
{ |
||||
|
TransactionSkeleton ret; |
||||
|
if (!_json.isObject() || _json.empty()) |
||||
|
return ret; |
||||
|
|
||||
|
if (_json["from"].isString()) |
||||
|
ret.from = jsToAddress(_json["from"].asString()); |
||||
|
if (_json["to"].isString()) |
||||
|
ret.to = jsToAddress(_json["to"].asString()); |
||||
|
if (!_json["value"].empty()) |
||||
|
{ |
||||
|
if (_json["value"].isString()) |
||||
|
ret.value = jsToU256(_json["value"].asString()); |
||||
|
else if (_json["value"].isInt()) |
||||
|
ret.value = u256(_json["value"].asInt()); |
||||
|
} |
||||
|
if (!_json["gas"].empty()) |
||||
|
{ |
||||
|
if (_json["gas"].isString()) |
||||
|
ret.gas = jsToU256(_json["gas"].asString()); |
||||
|
else if (_json["gas"].isInt()) |
||||
|
ret.gas = u256(_json["gas"].asInt()); |
||||
|
} |
||||
|
if (!_json["gasPrice"].empty()) |
||||
|
{ |
||||
|
if (_json["gasPrice"].isString()) |
||||
|
ret.gasPrice = jsToU256(_json["gasPrice"].asString()); |
||||
|
else if (_json["gasPrice"].isInt()) |
||||
|
ret.gas = u256(_json["gas"].asInt()); |
||||
|
} |
||||
|
if (!_json["data"].empty()) |
||||
|
{ |
||||
|
if (_json["data"].isString()) // ethereum.js has preconstructed the data array
|
||||
|
ret.data = jsToBytes(_json["data"].asString()); |
||||
|
else if (_json["data"].isArray()) // old style: array of 32-byte-padded values. TODO: remove PoC-8
|
||||
|
for (auto i: _json["data"]) |
||||
|
dev::operator +=(ret.data, padded(jsToBytes(i.asString()), 32)); |
||||
|
} |
||||
|
|
||||
|
if (_json["code"].isString()) |
||||
|
ret.data = jsToBytes(_json["code"].asString()); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::eth_call(Json::Value const& _json) |
||||
|
{ |
||||
|
std::string ret; |
||||
|
TransactionSkeleton t = toTransaction(_json); |
||||
|
if (!t.from && m_accounts.size()) |
||||
|
{ |
||||
|
auto b = m_accounts.begin()->first; |
||||
|
for (auto a: m_accounts) |
||||
|
if (client()->balanceAt(a.first) > client()->balanceAt(b)) |
||||
|
b = a.first; |
||||
|
t.from = b; |
||||
|
} |
||||
|
if (!m_accounts.count(t.from)) |
||||
|
return ret; |
||||
|
if (!t.gasPrice) |
||||
|
t.gasPrice = 10 * dev::eth::szabo; |
||||
|
if (!t.gas) |
||||
|
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); |
||||
|
ret = toJS(client()->call(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::eth_changed(int const& _id) |
||||
|
{ |
||||
|
return client()->checkWatch(_id); |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::eth_codeAt(string const& _address) |
||||
|
{ |
||||
|
return jsFromBinary(client()->codeAt(jsToAddress(_address), client()->getDefault())); |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::eth_coinbase() |
||||
|
{ |
||||
|
return toJS(client()->address()); |
||||
|
} |
||||
|
|
||||
|
double WebThreeStubServerBase::eth_countAt(string const& _address) |
||||
|
{ |
||||
|
return (double)(uint64_t)client()->countAt(jsToAddress(_address), client()->getDefault()); |
||||
|
} |
||||
|
|
||||
|
int WebThreeStubServerBase::eth_defaultBlock() |
||||
|
{ |
||||
|
return client()->getDefault(); |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::eth_gasPrice() |
||||
|
{ |
||||
|
return toJS(10 * dev::eth::szabo); |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::db_get(std::string const& _name, std::string const& _key) |
||||
|
{ |
||||
|
string ret = db()->get(_name, _key); |
||||
|
return toJS(dev::asBytes(ret)); |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_filterLogs(int const& _id) |
||||
|
{ |
||||
|
return toJson(client()->logs(_id)); |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_logs(Json::Value const& _json) |
||||
|
{ |
||||
|
return toJson(client()->logs(toLogFilter(_json))); |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::db_getString(std::string const& _name, std::string const& _key) |
||||
|
{ |
||||
|
return db()->get(_name, _key);; |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::shh_haveIdentity(std::string const& _id) |
||||
|
{ |
||||
|
return m_ids.count(jsToPublic(_id)) > 0; |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::eth_listening() |
||||
|
{ |
||||
|
return network()->isNetworkStarted(); |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::eth_mining() |
||||
|
{ |
||||
|
return client()->isMining(); |
||||
|
} |
||||
|
|
||||
|
int WebThreeStubServerBase::eth_newFilter(Json::Value const& _json) |
||||
|
{ |
||||
|
unsigned ret = -1; |
||||
|
ret = client()->installWatch(toLogFilter(_json)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
int WebThreeStubServerBase::eth_newFilterString(std::string const& _filter) |
||||
|
{ |
||||
|
unsigned ret = -1; |
||||
|
if (_filter.compare("chain") == 0) |
||||
|
ret = client()->installWatch(dev::eth::ChainChangedFilter); |
||||
|
else if (_filter.compare("pending") == 0) |
||||
|
ret = client()->installWatch(dev::eth::PendingChangedFilter); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::shh_newGroup(std::string const& _id, std::string const& _who) |
||||
|
{ |
||||
|
(void)_id; |
||||
|
(void)_who; |
||||
|
return ""; |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::shh_newIdentity() |
||||
|
{ |
||||
|
// cnote << this << m_ids;
|
||||
|
KeyPair kp = KeyPair::create(); |
||||
|
m_ids[kp.pub()] = kp.secret(); |
||||
|
return toJS(kp.pub()); |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_compilers() |
||||
|
{ |
||||
|
Json::Value ret(Json::arrayValue); |
||||
|
ret.append("lll"); |
||||
|
ret.append("solidity"); |
||||
|
ret.append("serpent"); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::eth_lll(std::string const& _code) |
||||
|
{ |
||||
|
string res; |
||||
|
vector<string> errors; |
||||
|
res = toJS(dev::eth::compileLLL(_code, true, &errors)); |
||||
|
cwarn << "LLL compilation errors: " << errors; |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::eth_serpent(std::string const& _code) |
||||
|
{ |
||||
|
string res; |
||||
|
try |
||||
|
{ |
||||
|
res = toJS(dev::asBytes(::compile(_code))); |
||||
|
} |
||||
|
catch (string err) |
||||
|
{ |
||||
|
cwarn << "Solidity compilation error: " << err; |
||||
|
} |
||||
|
catch (...) |
||||
|
{ |
||||
|
cwarn << "Uncought serpent compilation exception"; |
||||
|
} |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::eth_solidity(std::string const& _code) |
||||
|
{ |
||||
|
string res; |
||||
|
dev::solidity::CompilerStack compiler; |
||||
|
try |
||||
|
{ |
||||
|
res = toJS(compiler.compile(_code, true)); |
||||
|
} |
||||
|
catch (dev::Exception const& exception) |
||||
|
{ |
||||
|
ostringstream error; |
||||
|
solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler); |
||||
|
cwarn << "Solidity compilation error: " << error.str(); |
||||
|
} |
||||
|
catch (...) |
||||
|
{ |
||||
|
cwarn << "Uncought solidity compilation exception"; |
||||
|
} |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
int WebThreeStubServerBase::eth_number() |
||||
|
{ |
||||
|
return client()->number() + 1; |
||||
|
} |
||||
|
|
||||
|
int WebThreeStubServerBase::eth_peerCount() |
||||
|
{ |
||||
|
return network()->peerCount(); |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::shh_post(Json::Value const& _json) |
||||
|
{ |
||||
|
shh::Message m = toMessage(_json); |
||||
|
Secret from; |
||||
|
|
||||
|
if (m.from() && m_ids.count(m.from())) |
||||
|
{ |
||||
|
cwarn << "Silently signing message from identity" << m.from().abridged() << ": User validation hook goes here."; |
||||
|
// TODO: insert validification hook here.
|
||||
|
from = m_ids[m.from()]; |
||||
|
} |
||||
|
|
||||
|
face()->inject(toSealed(_json, m, from)); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::db_put(std::string const& _name, std::string const& _key, std::string const& _value) |
||||
|
{ |
||||
|
string v = asString(jsToBytes(_value)); |
||||
|
db()->put(_name, _key, v); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::db_putString(std::string const& _name, std::string const& _key, std::string const& _value) |
||||
|
{ |
||||
|
db()->put(_name, _key,_value); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::eth_setCoinbase(std::string const& _address) |
||||
|
{ |
||||
|
client()->setAddress(jsToAddress(_address)); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::eth_setDefaultBlock(int const& _block) |
||||
|
{ |
||||
|
client()->setDefault(_block); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::eth_setListening(bool const& _listening) |
||||
|
{ |
||||
|
if (_listening) |
||||
|
network()->startNetwork(); |
||||
|
else |
||||
|
network()->stopNetwork(); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::eth_setMining(bool const& _mining) |
||||
|
{ |
||||
|
if (_mining) |
||||
|
client()->startMining(); |
||||
|
else |
||||
|
client()->stopMining(); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::shh_changed(int const& _id) |
||||
|
{ |
||||
|
Json::Value ret(Json::arrayValue); |
||||
|
auto pub = m_shhWatches[_id]; |
||||
|
if (!pub || m_ids.count(pub)) |
||||
|
for (h256 const& h: face()->checkWatch(_id)) |
||||
|
{ |
||||
|
auto e = face()->envelope(h); |
||||
|
shh::Message m; |
||||
|
if (pub) |
||||
|
{ |
||||
|
cwarn << "Silently decrypting message from identity" << pub.abridged() << ": User validation hook goes here."; |
||||
|
m = e.open(m_ids[pub]); |
||||
|
if (!m) |
||||
|
continue; |
||||
|
} |
||||
|
else |
||||
|
m = e.open(); |
||||
|
ret.append(toJson(h, e, m)); |
||||
|
} |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
int WebThreeStubServerBase::shh_newFilter(Json::Value const& _json) |
||||
|
{ |
||||
|
auto w = toWatch(_json); |
||||
|
auto ret = face()->installWatch(w.first); |
||||
|
m_shhWatches.insert(make_pair(ret, w.second)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::shh_uninstallFilter(int const& _id) |
||||
|
{ |
||||
|
face()->uninstallWatch(_id); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::eth_stateAt(string const& _address, string const& _storage) |
||||
|
{ |
||||
|
return toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), client()->getDefault())); |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_storageAt(string const& _address) |
||||
|
{ |
||||
|
return toJson(client()->storageAt(jsToAddress(_address))); |
||||
|
} |
||||
|
|
||||
|
std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json) |
||||
|
{ |
||||
|
std::string ret; |
||||
|
TransactionSkeleton t = toTransaction(_json); |
||||
|
if (!t.from && m_accounts.size()) |
||||
|
{ |
||||
|
auto b = m_accounts.begin()->first; |
||||
|
for (auto a: m_accounts) |
||||
|
if (client()->balanceAt(a.first) > client()->balanceAt(b)) |
||||
|
b = a.first; |
||||
|
t.from = b; |
||||
|
} |
||||
|
if (!m_accounts.count(t.from)) |
||||
|
return ret; |
||||
|
if (!t.gasPrice) |
||||
|
t.gasPrice = 10 * dev::eth::szabo; |
||||
|
if (!t.gas) |
||||
|
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice); |
||||
|
if (authenticate(t)) |
||||
|
{ |
||||
|
if (t.to) |
||||
|
// TODO: from qethereum, insert validification hook here.
|
||||
|
client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice); |
||||
|
else |
||||
|
ret = toJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice)); |
||||
|
client()->flushTransactions(); |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::authenticate(TransactionSkeleton const& _t) const |
||||
|
{ |
||||
|
cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here."; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_transactionByHash(std::string const& _hash, int const& _i) |
||||
|
{ |
||||
|
return toJson(client()->transaction(jsToFixed<32>(_hash), _i)); |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_transactionByNumber(int const& _number, int const& _i) |
||||
|
{ |
||||
|
return toJson(client()->transaction(client()->hashFromNumber(_number), _i)); |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_uncleByHash(std::string const& _hash, int const& _i) |
||||
|
{ |
||||
|
return toJson(client()->uncle(jsToFixed<32>(_hash), _i)); |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_uncleByNumber(int const& _number, int const& _i) |
||||
|
{ |
||||
|
return toJson(client()->uncle(client()->hashFromNumber(_number), _i)); |
||||
|
} |
||||
|
|
||||
|
bool WebThreeStubServerBase::eth_uninstallFilter(int const& _id) |
||||
|
{ |
||||
|
client()->uninstallWatch(_id); |
||||
|
return true; |
||||
|
} |
||||
|
|
@ -0,0 +1,138 @@ |
|||||
|
/*
|
||||
|
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 WebThreeStubServer.h
|
||||
|
* @authors: |
||||
|
* Gav Wood <i@gavwood.com> |
||||
|
* Marek Kotewicz <marek@ethdev.com> |
||||
|
* @date 2014 |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <iostream> |
||||
|
#include <jsonrpccpp/server.h> |
||||
|
#include <libdevcrypto/Common.h> |
||||
|
#pragma GCC diagnostic push |
||||
|
#pragma GCC diagnostic ignored "-Wunused-parameter" |
||||
|
#include "abstractwebthreestubserver.h" |
||||
|
#pragma GCC diagnostic pop |
||||
|
|
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
class WebThreeNetworkFace; |
||||
|
class KeyPair; |
||||
|
class TransactionSkeleton; |
||||
|
namespace eth |
||||
|
{ |
||||
|
class Interface; |
||||
|
} |
||||
|
namespace shh |
||||
|
{ |
||||
|
class Interface; |
||||
|
} |
||||
|
|
||||
|
class WebThreeStubDatabaseFace |
||||
|
{ |
||||
|
public: |
||||
|
virtual std::string get(std::string const& _name, std::string const& _key) = 0; |
||||
|
virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) = 0; |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
* @brief JSON-RPC api implementation |
||||
|
* @todo filters should work on unsigned instead of int |
||||
|
* unsigned are not supported in json-rpc-cpp and there are bugs with double in json-rpc-cpp version 0.2.1 |
||||
|
* @todo split these up according to subprotocol (eth, shh, db, p2p, web3) and make it /very/ clear about how to add other subprotocols. |
||||
|
* @todo modularise everything so additional subprotocols don't need to change this file. |
||||
|
*/ |
||||
|
class WebThreeStubServerBase: public AbstractWebThreeStubServer |
||||
|
{ |
||||
|
public: |
||||
|
WebThreeStubServerBase(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts); |
||||
|
|
||||
|
virtual std::string web3_sha3(std::string const& _param1); |
||||
|
virtual Json::Value eth_accounts(); |
||||
|
virtual std::string eth_balanceAt(std::string const& _address); |
||||
|
virtual Json::Value eth_blockByHash(std::string const& _hash); |
||||
|
virtual Json::Value eth_blockByNumber(int const& _number); |
||||
|
virtual std::string eth_call(Json::Value const& _json); |
||||
|
virtual bool eth_changed(int const& _id); |
||||
|
virtual std::string eth_codeAt(std::string const& _address); |
||||
|
virtual std::string eth_coinbase(); |
||||
|
virtual Json::Value eth_compilers(); |
||||
|
virtual double eth_countAt(std::string const& _address); |
||||
|
virtual int eth_defaultBlock(); |
||||
|
virtual std::string eth_gasPrice(); |
||||
|
virtual Json::Value eth_filterLogs(int const& _id); |
||||
|
virtual Json::Value eth_logs(Json::Value const& _json); |
||||
|
virtual bool eth_listening(); |
||||
|
virtual bool eth_mining(); |
||||
|
virtual int eth_newFilter(Json::Value const& _json); |
||||
|
virtual int eth_newFilterString(std::string const& _filter); |
||||
|
virtual int eth_number(); |
||||
|
virtual int eth_peerCount(); |
||||
|
virtual bool eth_setCoinbase(std::string const& _address); |
||||
|
virtual bool eth_setDefaultBlock(int const& _block); |
||||
|
virtual bool eth_setListening(bool const& _listening); |
||||
|
virtual std::string eth_lll(std::string const& _s); |
||||
|
virtual std::string eth_serpent(std::string const& _s); |
||||
|
virtual bool eth_setMining(bool const& _mining); |
||||
|
virtual std::string eth_solidity(std::string const& _code); |
||||
|
virtual std::string eth_stateAt(std::string const& _address, std::string const& _storage); |
||||
|
virtual Json::Value eth_storageAt(std::string const& _address); |
||||
|
virtual std::string eth_transact(Json::Value const& _json); |
||||
|
virtual Json::Value eth_transactionByHash(std::string const& _hash, int const& _i); |
||||
|
virtual Json::Value eth_transactionByNumber(int const& _number, int const& _i); |
||||
|
virtual Json::Value eth_uncleByHash(std::string const& _hash, int const& _i); |
||||
|
virtual Json::Value eth_uncleByNumber(int const& _number, int const& _i); |
||||
|
virtual bool eth_uninstallFilter(int const& _id); |
||||
|
|
||||
|
virtual std::string db_get(std::string const& _name, std::string const& _key); |
||||
|
virtual std::string db_getString(std::string const& _name, std::string const& _key); |
||||
|
virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value); |
||||
|
virtual bool db_putString(std::string const& _name, std::string const& _key, std::string const& _value); |
||||
|
|
||||
|
virtual std::string shh_addToGroup(std::string const& _group, std::string const& _who); |
||||
|
virtual Json::Value shh_changed(int const& _id); |
||||
|
virtual bool shh_haveIdentity(std::string const& _id); |
||||
|
virtual int shh_newFilter(Json::Value const& _json); |
||||
|
virtual std::string shh_newGroup(std::string const& _id, std::string const& _who); |
||||
|
virtual std::string shh_newIdentity(); |
||||
|
virtual bool shh_post(Json::Value const& _json); |
||||
|
virtual bool shh_uninstallFilter(int const& _id); |
||||
|
|
||||
|
void setAccounts(std::vector<dev::KeyPair> const& _accounts); |
||||
|
void setIdentities(std::vector<dev::KeyPair> const& _ids); |
||||
|
std::map<dev::Public, dev::Secret> const& ids() const { return m_ids; } |
||||
|
|
||||
|
protected: |
||||
|
virtual bool authenticate(dev::TransactionSkeleton const& _t) const; |
||||
|
|
||||
|
protected: |
||||
|
virtual dev::eth::Interface* client() = 0; |
||||
|
virtual std::shared_ptr<dev::shh::Interface> face() = 0; |
||||
|
virtual dev::WebThreeNetworkFace* network() = 0; |
||||
|
virtual dev::WebThreeStubDatabaseFace* db() = 0; |
||||
|
|
||||
|
std::map<dev::Address, dev::KeyPair> m_accounts; |
||||
|
|
||||
|
std::map<dev::Public, dev::Secret> m_ids; |
||||
|
std::map<unsigned, dev::Public> m_shhWatches; |
||||
|
}; |
||||
|
|
||||
|
} //namespace dev
|
@ -1,119 +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 AssemblyDebuggerModel.cpp
|
|
||||
* @author Yann yann@ethdev.com |
|
||||
* @date 2014 |
|
||||
* used as a model to debug contract assembly code. |
|
||||
*/ |
|
||||
|
|
||||
#include <QApplication> |
|
||||
#include <libdevcore/Common.h> |
|
||||
#include <libevm/VM.h> |
|
||||
#include <libethereum/Executive.h> |
|
||||
#include <libethereum/Transaction.h> |
|
||||
#include <libethereum/ExtVM.h> |
|
||||
#include "AssemblyDebuggerModel.h" |
|
||||
#include "AppContext.h" |
|
||||
#include "DebuggingStateWrapper.h" |
|
||||
|
|
||||
using namespace std; |
|
||||
using namespace dev; |
|
||||
using namespace dev::eth; |
|
||||
|
|
||||
namespace dev |
|
||||
{ |
|
||||
namespace mix |
|
||||
{ |
|
||||
|
|
||||
AssemblyDebuggerModel::AssemblyDebuggerModel(): |
|
||||
m_userAccount(KeyPair::create()) |
|
||||
{ |
|
||||
resetState(10000000 * ether); |
|
||||
} |
|
||||
|
|
||||
DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& _rawTransaction) |
|
||||
{ |
|
||||
QList<DebuggingState> machineStates; |
|
||||
eth::Executive execution(m_executiveState, LastHashes(), 0); |
|
||||
execution.setup(_rawTransaction); |
|
||||
std::vector<DebuggingState const*> levels; |
|
||||
bytes code; |
|
||||
bytesConstRef data; |
|
||||
bool firstIteration = true; |
|
||||
auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt) |
|
||||
{ |
|
||||
VM& vm = *(VM*)voidVM; |
|
||||
ExtVM const& ext = *(ExtVM const*)voidExt; |
|
||||
|
|
||||
if (firstIteration) |
|
||||
{ |
|
||||
code = ext.code; |
|
||||
data = ext.data; |
|
||||
firstIteration = false; |
|
||||
} |
|
||||
|
|
||||
if (levels.size() < ext.depth) |
|
||||
levels.push_back(&machineStates.back()); |
|
||||
else |
|
||||
levels.resize(ext.depth); |
|
||||
|
|
||||
machineStates.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), |
|
||||
vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); |
|
||||
}; |
|
||||
|
|
||||
execution.go(onOp); |
|
||||
execution.finalize(); |
|
||||
|
|
||||
DebuggingContent d; |
|
||||
d.returnValue = execution.out().toVector(); |
|
||||
d.machineStates = machineStates; |
|
||||
d.executionCode = code; |
|
||||
d.executionData = data; |
|
||||
d.contentAvailable = true; |
|
||||
d.message = "ok"; |
|
||||
return d; |
|
||||
} |
|
||||
|
|
||||
DebuggingContent AssemblyDebuggerModel::deployContract(bytes const& _code) |
|
||||
{ |
|
||||
u256 gasPrice = 10000000000000; |
|
||||
u256 gas = 1000000; |
|
||||
u256 amount = 100; |
|
||||
Transaction _tr(amount, gasPrice, min(gas, m_executiveState.gasLimitRemaining()), _code, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); |
|
||||
bytes b = _tr.rlp(); |
|
||||
dev::bytesConstRef bytesRef = &b; |
|
||||
DebuggingContent d = executeTransaction(bytesRef); |
|
||||
h256 th = sha3(rlpList(_tr.sender(), _tr.nonce())); |
|
||||
d.contractAddress = right160(th); |
|
||||
return d; |
|
||||
} |
|
||||
|
|
||||
DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) |
|
||||
{ |
|
||||
Transaction tr = Transaction(_tr.value, _tr.gasPrice, min(_tr.gas, m_executiveState.gasLimitRemaining()), _contract, _data, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret()); |
|
||||
bytes b = tr.rlp(); |
|
||||
dev::bytesConstRef bytesRef = &b; |
|
||||
DebuggingContent d = executeTransaction(bytesRef); |
|
||||
d.contractAddress = tr.receiveAddress(); |
|
||||
return d; |
|
||||
} |
|
||||
|
|
||||
void AssemblyDebuggerModel::resetState(u256 _balance) |
|
||||
{ |
|
||||
m_executiveState = eth::State(Address(), m_overlayDB, BaseState::Empty); |
|
||||
m_executiveState.addBalance(m_userAccount.address(), _balance); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
} |
|
@ -1,76 +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 AssemblyDebuggerModel.h
|
|
||||
* @author Yann yann@ethdev.com |
|
||||
* @date 2014 |
|
||||
* Used as a model to debug contract assembly code. |
|
||||
*/ |
|
||||
|
|
||||
#pragma once |
|
||||
|
|
||||
#include <QObject> |
|
||||
#include <QList> |
|
||||
#include <libdevcore/Common.h> |
|
||||
#include <libdevcrypto/Common.h> |
|
||||
#include <libethereum/State.h> |
|
||||
#include <libethereum/Executive.h> |
|
||||
#include "DebuggingStateWrapper.h" |
|
||||
|
|
||||
namespace dev |
|
||||
{ |
|
||||
namespace mix |
|
||||
{ |
|
||||
|
|
||||
/// Backend transaction config class
|
|
||||
struct TransactionSettings |
|
||||
{ |
|
||||
TransactionSettings(QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice): |
|
||||
functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {} |
|
||||
|
|
||||
/// Contract function name
|
|
||||
QString functionId; |
|
||||
/// Transaction value
|
|
||||
u256 value; |
|
||||
/// Gas
|
|
||||
u256 gas; |
|
||||
/// Gas price
|
|
||||
u256 gasPrice; |
|
||||
/// Mapping from contract function parameter name to value
|
|
||||
std::map<QString, u256> parameterValues; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
/**
|
|
||||
* @brief Long-life object for managing all executions. |
|
||||
*/ |
|
||||
class AssemblyDebuggerModel |
|
||||
{ |
|
||||
public: |
|
||||
AssemblyDebuggerModel(); |
|
||||
/// Call function in a already deployed contract.
|
|
||||
DebuggingContent callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); |
|
||||
/// Deploy the contract described by _code.
|
|
||||
DebuggingContent deployContract(bytes const& _code); |
|
||||
/// Reset state to the empty state with given balance.
|
|
||||
void resetState(u256 _balance); |
|
||||
|
|
||||
private: |
|
||||
KeyPair m_userAccount; |
|
||||
OverlayDB m_overlayDB; |
|
||||
eth::State m_executiveState; |
|
||||
DebuggingContent executeTransaction(dev::bytesConstRef const& _rawTransaction); |
|
||||
}; |
|
||||
|
|
||||
} |
|
||||
} |
|
@ -0,0 +1,222 @@ |
|||||
|
/*
|
||||
|
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 ClientModel.cpp
|
||||
|
* @author Yann yann@ethdev.com |
||||
|
* @author Arkadiy Paronyan arkadiy@ethdev.com |
||||
|
* @date 2015 |
||||
|
* Ethereum IDE client. |
||||
|
*/ |
||||
|
|
||||
|
#include <QtConcurrent/QtConcurrent> |
||||
|
#include <QDebug> |
||||
|
#include <QQmlContext> |
||||
|
#include <QQmlApplicationEngine> |
||||
|
#include <libdevcore/CommonJS.h> |
||||
|
#include <libethereum/Transaction.h> |
||||
|
#include "ClientModel.h" |
||||
|
#include "AppContext.h" |
||||
|
#include "DebuggingStateWrapper.h" |
||||
|
#include "QContractDefinition.h" |
||||
|
#include "QVariableDeclaration.h" |
||||
|
#include "ContractCallDataEncoder.h" |
||||
|
#include "CodeModel.h" |
||||
|
#include "ClientModel.h" |
||||
|
|
||||
|
using namespace dev::eth; |
||||
|
using namespace dev::mix; |
||||
|
|
||||
|
/// @todo Move this to QML
|
||||
|
dev::u256 fromQString(QString const& _s) |
||||
|
{ |
||||
|
return dev::jsToU256(_s.toStdString()); |
||||
|
} |
||||
|
|
||||
|
/// @todo Move this to QML
|
||||
|
QString toQString(dev::u256 _value) |
||||
|
{ |
||||
|
std::ostringstream s; |
||||
|
s << _value; |
||||
|
return QString::fromStdString(s.str()); |
||||
|
} |
||||
|
|
||||
|
ClientModel::ClientModel(AppContext* _context): |
||||
|
m_context(_context), m_running(false) |
||||
|
{ |
||||
|
qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*"); |
||||
|
qRegisterMetaType<QVariableDefinitionList*>("QVariableDefinitionList*"); |
||||
|
qRegisterMetaType<QList<QVariableDefinition*>>("QList<QVariableDefinition*>"); |
||||
|
qRegisterMetaType<QList<QVariableDeclaration*>>("QList<QVariableDeclaration*>"); |
||||
|
qRegisterMetaType<QVariableDeclaration*>("QVariableDeclaration*"); |
||||
|
qRegisterMetaType<AssemblyDebuggerData>("AssemblyDebuggerData"); |
||||
|
|
||||
|
connect(this, &ClientModel::dataAvailable, this, &ClientModel::showDebugger, Qt::QueuedConnection); |
||||
|
m_client.reset(new MixClient()); |
||||
|
|
||||
|
_context->appEngine()->rootContext()->setContextProperty("clientModel", this); |
||||
|
} |
||||
|
|
||||
|
void ClientModel::debugDeployment() |
||||
|
{ |
||||
|
executeSequence(std::vector<TransactionSettings>(), 10000000 * ether); |
||||
|
} |
||||
|
|
||||
|
void ClientModel::debugState(QVariantMap _state) |
||||
|
{ |
||||
|
u256 balance = fromQString(_state.value("balance").toString()); |
||||
|
QVariantList transactions = _state.value("transactions").toList(); |
||||
|
|
||||
|
std::vector<TransactionSettings> transactionSequence; |
||||
|
|
||||
|
for (auto const& t: transactions) |
||||
|
{ |
||||
|
QVariantMap transaction = t.toMap(); |
||||
|
|
||||
|
QString functionId = transaction.value("functionId").toString(); |
||||
|
u256 value = fromQString(transaction.value("value").toString()); |
||||
|
u256 gas = fromQString(transaction.value("gas").toString()); |
||||
|
u256 gasPrice = fromQString(transaction.value("gasPrice").toString()); |
||||
|
QVariantMap params = transaction.value("parameters").toMap(); |
||||
|
TransactionSettings transactionSettings(functionId, value, gas, gasPrice); |
||||
|
|
||||
|
for (auto p = params.cbegin(); p != params.cend(); ++p) |
||||
|
transactionSettings.parameterValues.insert(std::make_pair(p.key(), fromQString(p.value().toString()))); |
||||
|
|
||||
|
transactionSequence.push_back(transactionSettings); |
||||
|
} |
||||
|
executeSequence(transactionSequence, balance); |
||||
|
} |
||||
|
|
||||
|
void ClientModel::executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance) |
||||
|
{ |
||||
|
if (m_running) |
||||
|
throw (std::logic_error("debugging already running")); |
||||
|
auto compilerRes = m_context->codeModel()->code(); |
||||
|
std::shared_ptr<QContractDefinition> contractDef = compilerRes->sharedContract(); |
||||
|
m_running = true; |
||||
|
|
||||
|
emit runStarted(); |
||||
|
emit stateChanged(); |
||||
|
|
||||
|
//run sequence
|
||||
|
QtConcurrent::run([=]() |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
bytes contractCode = compilerRes->bytes(); |
||||
|
std::vector<dev::bytes> transactonData; |
||||
|
QFunctionDefinition* f; |
||||
|
ContractCallDataEncoder c; |
||||
|
//encode data for all transactions
|
||||
|
for (auto const& t: _sequence) |
||||
|
{ |
||||
|
f = nullptr; |
||||
|
for (int tf = 0; tf < contractDef->functionsList().size(); tf++) |
||||
|
{ |
||||
|
if (contractDef->functionsList().at(tf)->name() == t.functionId) |
||||
|
{ |
||||
|
f = contractDef->functionsList().at(tf); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
if (!f) |
||||
|
throw std::runtime_error("function " + t.functionId.toStdString() + " not found"); |
||||
|
|
||||
|
c.encode(f); |
||||
|
for (int p = 0; p < f->parametersList().size(); p++) |
||||
|
{ |
||||
|
QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(p); |
||||
|
u256 value = 0; |
||||
|
auto v = t.parameterValues.find(var->name()); |
||||
|
if (v != t.parameterValues.cend()) |
||||
|
value = v->second; |
||||
|
c.encode(var, value); |
||||
|
} |
||||
|
transactonData.emplace_back(c.encodedData()); |
||||
|
} |
||||
|
|
||||
|
//run contract creation first
|
||||
|
m_client->resetState(_balance); |
||||
|
ExecutionResult debuggingContent = deployContract(contractCode); |
||||
|
Address address = debuggingContent.contractAddress; |
||||
|
for (unsigned i = 0; i < _sequence.size(); ++i) |
||||
|
debuggingContent = callContract(address, transactonData.at(i), _sequence.at(i)); |
||||
|
|
||||
|
QList<QVariableDefinition*> returnParameters; |
||||
|
|
||||
|
if (f) |
||||
|
returnParameters = c.decode(f->returnParameters(), debuggingContent.returnValue); |
||||
|
|
||||
|
//we need to wrap states in a QObject before sending to QML.
|
||||
|
QList<QObject*> wStates; |
||||
|
for (unsigned i = 0; i < debuggingContent.machineStates.size(); i++) |
||||
|
{ |
||||
|
QPointer<DebuggingStateWrapper> s(new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes())); |
||||
|
s->setState(debuggingContent.machineStates[i]); |
||||
|
wStates.append(s); |
||||
|
} |
||||
|
//collect states for last transaction
|
||||
|
AssemblyDebuggerData code = DebuggingStateWrapper::getHumanReadableCode(debuggingContent.executionCode); |
||||
|
emit dataAvailable(returnParameters, wStates, code); |
||||
|
emit runComplete(); |
||||
|
} |
||||
|
catch(boost::exception const&) |
||||
|
{ |
||||
|
emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); |
||||
|
} |
||||
|
|
||||
|
catch(std::exception const& e) |
||||
|
{ |
||||
|
emit runFailed(e.what()); |
||||
|
} |
||||
|
m_running = false; |
||||
|
emit stateChanged(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
void ClientModel::showDebugger(QList<QVariableDefinition*> const& _returnParam, QList<QObject*> const& _wStates, AssemblyDebuggerData const& _code) |
||||
|
{ |
||||
|
m_context->appEngine()->rootContext()->setContextProperty("debugStates", QVariant::fromValue(_wStates)); |
||||
|
m_context->appEngine()->rootContext()->setContextProperty("humanReadableExecutionCode", QVariant::fromValue(std::get<0>(_code))); |
||||
|
m_context->appEngine()->rootContext()->setContextProperty("bytesCodeMapping", QVariant::fromValue(std::get<1>(_code))); |
||||
|
m_context->appEngine()->rootContext()->setContextProperty("contractCallReturnParameters", QVariant::fromValue(new QVariableDefinitionList(_returnParam))); |
||||
|
showDebuggerWindow(); |
||||
|
} |
||||
|
|
||||
|
void ClientModel::showDebugError(QString const& _error) |
||||
|
{ |
||||
|
//TODO: change that to a signal
|
||||
|
m_context->displayMessageDialog(tr("Debugger"), _error); |
||||
|
} |
||||
|
|
||||
|
ExecutionResult ClientModel::deployContract(bytes const& _code) |
||||
|
{ |
||||
|
u256 gasPrice = 10000000000000; |
||||
|
u256 gas = 125000; |
||||
|
u256 amount = 100; |
||||
|
|
||||
|
Address contractAddress = m_client->transact(m_client->userAccount().secret(), amount, _code, gas, gasPrice); |
||||
|
ExecutionResult r = m_client->lastExecutionResult(); |
||||
|
r.contractAddress = contractAddress; |
||||
|
return r; |
||||
|
} |
||||
|
|
||||
|
ExecutionResult ClientModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr) |
||||
|
{ |
||||
|
//bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override;
|
||||
|
m_client->transact(m_client->userAccount().secret(), _tr.value, _contract, _data, _tr.gas, _tr.gasPrice); |
||||
|
ExecutionResult r = m_client->lastExecutionResult(); |
||||
|
r.contractAddress = _contract; |
||||
|
return r; |
||||
|
} |
||||
|
|
@ -0,0 +1,113 @@ |
|||||
|
/*
|
||||
|
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 ClientModel.h
|
||||
|
* @author Yann yann@ethdev.com |
||||
|
* @author Arkadiy Paronyan arkadiy@ethdev.com |
||||
|
* @date 2015 |
||||
|
* Ethereum IDE client. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <atomic> |
||||
|
#include "DebuggingStateWrapper.h" |
||||
|
#include "MixClient.h" |
||||
|
|
||||
|
using AssemblyDebuggerData = std::tuple<QList<QObject*>, dev::mix::QQMLMap*>; |
||||
|
|
||||
|
Q_DECLARE_METATYPE(AssemblyDebuggerData) |
||||
|
Q_DECLARE_METATYPE(dev::mix::ExecutionResult) |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace mix |
||||
|
{ |
||||
|
|
||||
|
class AppContext; |
||||
|
|
||||
|
/// Backend transaction config class
|
||||
|
struct TransactionSettings |
||||
|
{ |
||||
|
TransactionSettings(QString const& _functionId, u256 _value, u256 _gas, u256 _gasPrice): |
||||
|
functionId(_functionId), value(_value), gas(_gas), gasPrice(_gasPrice) {} |
||||
|
|
||||
|
/// Contract function name
|
||||
|
QString functionId; |
||||
|
/// Transaction value
|
||||
|
u256 value; |
||||
|
/// Gas
|
||||
|
u256 gas; |
||||
|
/// Gas price
|
||||
|
u256 gasPrice; |
||||
|
/// Mapping from contract function parameter name to value
|
||||
|
std::map<QString, u256> parameterValues; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
* @brief Ethereum state control |
||||
|
*/ |
||||
|
class ClientModel: public QObject |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
|
||||
|
public: |
||||
|
ClientModel(AppContext* _context); |
||||
|
|
||||
|
Q_PROPERTY(bool running MEMBER m_running NOTIFY stateChanged) |
||||
|
|
||||
|
public slots: |
||||
|
/// Run the contract constructor and show debugger window.
|
||||
|
void debugDeployment(); |
||||
|
/// Setup state, run transaction sequence, show debugger for the last transaction
|
||||
|
/// @param _state JS object with state configuration
|
||||
|
void debugState(QVariantMap _state); |
||||
|
|
||||
|
private slots: |
||||
|
/// Update UI with machine states result. Display a modal dialog.
|
||||
|
void showDebugger(QList<QVariableDefinition*> const& _returnParams = QList<QVariableDefinition*>(), QList<QObject*> const& _wStates = QList<QObject*>(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); |
||||
|
/// Update UI with transaction run error.
|
||||
|
void showDebugError(QString const& _error); |
||||
|
|
||||
|
signals: |
||||
|
/// Transaction execution started
|
||||
|
void runStarted(); |
||||
|
/// Transaction execution completed successfully
|
||||
|
void runComplete(); |
||||
|
/// Transaction execution completed with error
|
||||
|
/// @param _message Error message
|
||||
|
void runFailed(QString const& _message); |
||||
|
/// Execution state changed
|
||||
|
void stateChanged(); |
||||
|
/// Show debugger window request
|
||||
|
void showDebuggerWindow(); |
||||
|
|
||||
|
/// Emited when machine states are available.
|
||||
|
void dataAvailable(QList<QVariableDefinition*> const& _returnParams = QList<QVariableDefinition*>(), QList<QObject*> const& _wStates = QList<QObject*>(), AssemblyDebuggerData const& _code = AssemblyDebuggerData()); |
||||
|
|
||||
|
private: |
||||
|
void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance); |
||||
|
ExecutionResult deployContract(bytes const& _code); |
||||
|
ExecutionResult callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); |
||||
|
|
||||
|
AppContext* m_context; |
||||
|
std::atomic<bool> m_running; |
||||
|
std::unique_ptr<MixClient> m_client; |
||||
|
}; |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,336 @@ |
|||||
|
/*
|
||||
|
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 MixClient.cpp
|
||||
|
* @author Yann yann@ethdev.com |
||||
|
* @author Arkadiy Paronyan arkadiy@ethdev.com |
||||
|
* @date 2015 |
||||
|
* Ethereum IDE client. |
||||
|
*/ |
||||
|
|
||||
|
#include <vector> |
||||
|
#include <libdevcore/Exceptions.h> |
||||
|
#include <libethereum/BlockChain.h> |
||||
|
#include <libethereum/Transaction.h> |
||||
|
#include <libethereum/Executive.h> |
||||
|
#include <libethereum/ExtVM.h> |
||||
|
#include <libevm/VM.h> |
||||
|
|
||||
|
#include "MixClient.h" |
||||
|
|
||||
|
using namespace dev; |
||||
|
using namespace dev::eth; |
||||
|
using namespace dev::mix; |
||||
|
|
||||
|
MixClient::MixClient(): |
||||
|
m_userAccount(KeyPair::create()) |
||||
|
{ |
||||
|
resetState(10000000 * ether); |
||||
|
} |
||||
|
|
||||
|
void MixClient::resetState(u256 _balance) |
||||
|
{ |
||||
|
WriteGuard l(x_state); |
||||
|
m_state = eth::State(Address(), m_stateDB, BaseState::Empty); |
||||
|
m_state.addBalance(m_userAccount.address(), _balance); |
||||
|
} |
||||
|
|
||||
|
void MixClient::executeTransaction(bytesConstRef _rlp, State& _state) |
||||
|
{ |
||||
|
Executive execution(_state, LastHashes(), 0); |
||||
|
execution.setup(_rlp); |
||||
|
bytes code; |
||||
|
bytesConstRef data; |
||||
|
bool firstIteration = true; |
||||
|
std::vector<MachineState> machineStates; |
||||
|
std::vector<MachineState const*> levels; |
||||
|
auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt) |
||||
|
{ |
||||
|
VM& vm = *(VM*)voidVM; |
||||
|
ExtVM const& ext = *(ExtVM const*)voidExt; |
||||
|
|
||||
|
if (firstIteration) |
||||
|
{ |
||||
|
code = ext.code; |
||||
|
data = ext.data; |
||||
|
firstIteration = false; |
||||
|
} |
||||
|
|
||||
|
if (levels.size() < ext.depth) |
||||
|
levels.push_back(&machineStates.back()); |
||||
|
else |
||||
|
levels.resize(ext.depth); |
||||
|
|
||||
|
machineStates.push_back(MachineState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), |
||||
|
vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); |
||||
|
}; |
||||
|
|
||||
|
execution.go(onOp); |
||||
|
execution.finalize(); |
||||
|
|
||||
|
ExecutionResult d; |
||||
|
d.returnValue = execution.out().toVector(); |
||||
|
d.machineStates = machineStates; |
||||
|
d.executionCode = code; |
||||
|
d.executionData = data; |
||||
|
d.contentAvailable = true; |
||||
|
d.message = "ok"; |
||||
|
m_lastExecutionResult = d; |
||||
|
} |
||||
|
|
||||
|
void MixClient::validateBlock(int _block) const |
||||
|
{ |
||||
|
//TODO: throw exception here if _block != 0
|
||||
|
(void)_block; |
||||
|
} |
||||
|
|
||||
|
void MixClient::transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) |
||||
|
{ |
||||
|
WriteGuard l(x_state); |
||||
|
u256 n = m_state.transactionsFrom(toAddress(_secret)); |
||||
|
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); |
||||
|
bytes rlp = t.rlp(); |
||||
|
executeTransaction(&rlp, m_state); |
||||
|
} |
||||
|
|
||||
|
Address MixClient::transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) |
||||
|
{ |
||||
|
WriteGuard l(x_state); |
||||
|
u256 n = m_state.transactionsFrom(toAddress(_secret)); |
||||
|
eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); |
||||
|
bytes rlp = t.rlp(); |
||||
|
executeTransaction(&rlp, m_state); |
||||
|
return right160(sha3(rlpList(t.sender(), t.nonce()))); |
||||
|
} |
||||
|
|
||||
|
void MixClient::inject(bytesConstRef _rlp) |
||||
|
{ |
||||
|
WriteGuard l(x_state); |
||||
|
executeTransaction(_rlp, m_state); |
||||
|
} |
||||
|
|
||||
|
void MixClient::flushTransactions() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
bytes MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) |
||||
|
{ |
||||
|
bytes out; |
||||
|
u256 n; |
||||
|
State temp; |
||||
|
{ |
||||
|
ReadGuard lr(x_state); |
||||
|
temp = m_state; |
||||
|
n = temp.transactionsFrom(toAddress(_secret)); |
||||
|
} |
||||
|
Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); |
||||
|
bytes rlp = t.rlp(); |
||||
|
WriteGuard lw(x_state); //TODO: lock is required only for last executoin state
|
||||
|
executeTransaction(&rlp, temp); |
||||
|
return m_lastExecutionResult.returnValue; |
||||
|
} |
||||
|
|
||||
|
u256 MixClient::balanceAt(Address _a, int _block) const |
||||
|
{ |
||||
|
validateBlock(_block); |
||||
|
ReadGuard l(x_state); |
||||
|
return m_state.balance(_a); |
||||
|
} |
||||
|
|
||||
|
u256 MixClient::countAt(Address _a, int _block) const |
||||
|
{ |
||||
|
validateBlock(_block); |
||||
|
ReadGuard l(x_state); |
||||
|
return m_state.transactionsFrom(_a); |
||||
|
} |
||||
|
|
||||
|
u256 MixClient::stateAt(Address _a, u256 _l, int _block) const |
||||
|
{ |
||||
|
validateBlock(_block); |
||||
|
ReadGuard l(x_state); |
||||
|
return m_state.storage(_a, _l); |
||||
|
} |
||||
|
|
||||
|
bytes MixClient::codeAt(Address _a, int _block) const |
||||
|
{ |
||||
|
validateBlock(_block); |
||||
|
ReadGuard l(x_state); |
||||
|
return m_state.code(_a); |
||||
|
} |
||||
|
|
||||
|
std::map<u256, u256> MixClient::storageAt(Address _a, int _block) const |
||||
|
{ |
||||
|
validateBlock(_block); |
||||
|
ReadGuard l(x_state); |
||||
|
return m_state.storage(_a); |
||||
|
} |
||||
|
|
||||
|
eth::LogEntries MixClient::logs(unsigned _watchId) const |
||||
|
{ |
||||
|
(void)_watchId; |
||||
|
return LogEntries(); |
||||
|
} |
||||
|
|
||||
|
eth::LogEntries MixClient::logs(eth::LogFilter const& _filter) const |
||||
|
{ |
||||
|
(void)_filter; |
||||
|
return LogEntries(); |
||||
|
} |
||||
|
|
||||
|
unsigned MixClient::installWatch(eth::LogFilter const& _filter) |
||||
|
{ |
||||
|
(void)_filter; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::installWatch")); |
||||
|
} |
||||
|
|
||||
|
unsigned MixClient::installWatch(h256 _filterId) |
||||
|
{ |
||||
|
(void)_filterId; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::installWatch")); |
||||
|
} |
||||
|
|
||||
|
void MixClient::uninstallWatch(unsigned _watchId) |
||||
|
{ |
||||
|
(void)_watchId; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::uninstallWatch")); |
||||
|
} |
||||
|
|
||||
|
bool MixClient::peekWatch(unsigned _watchId) const |
||||
|
{ |
||||
|
(void)_watchId; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::peekWatch")); |
||||
|
} |
||||
|
|
||||
|
bool MixClient::checkWatch(unsigned _watchId) |
||||
|
{ |
||||
|
(void)_watchId; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::checkWatch")); |
||||
|
} |
||||
|
|
||||
|
h256 MixClient::hashFromNumber(unsigned _number) const |
||||
|
{ |
||||
|
(void)_number; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::hashFromNumber")); |
||||
|
} |
||||
|
|
||||
|
eth::BlockInfo MixClient::blockInfo(h256 _hash) const |
||||
|
{ |
||||
|
(void)_hash; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::blockInfo")); |
||||
|
} |
||||
|
|
||||
|
eth::BlockDetails MixClient::blockDetails(h256 _hash) const |
||||
|
{ |
||||
|
(void)_hash; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::blockDetails")); |
||||
|
} |
||||
|
|
||||
|
eth::Transaction MixClient::transaction(h256 _blockHash, unsigned _i) const |
||||
|
{ |
||||
|
(void)_blockHash; |
||||
|
(void)_i; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::transaction")); |
||||
|
} |
||||
|
|
||||
|
eth::BlockInfo MixClient::uncle(h256 _blockHash, unsigned _i) const |
||||
|
{ |
||||
|
(void)_blockHash; |
||||
|
(void)_i; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::uncle")); |
||||
|
} |
||||
|
|
||||
|
unsigned MixClient::number() const |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
eth::Transactions MixClient::pending() const |
||||
|
{ |
||||
|
return eth::Transactions(); |
||||
|
} |
||||
|
|
||||
|
eth::StateDiff MixClient::diff(unsigned _txi, h256 _block) const |
||||
|
{ |
||||
|
(void)_txi; |
||||
|
(void)_block; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::diff")); |
||||
|
} |
||||
|
|
||||
|
eth::StateDiff MixClient::diff(unsigned _txi, int _block) const |
||||
|
{ |
||||
|
(void)_txi; |
||||
|
(void)_block; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::diff")); |
||||
|
} |
||||
|
|
||||
|
Addresses MixClient::addresses(int _block) const |
||||
|
{ |
||||
|
validateBlock(_block); |
||||
|
ReadGuard l(x_state); |
||||
|
Addresses ret; |
||||
|
for (auto const& i: m_state.addresses()) |
||||
|
ret.push_back(i.first); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
u256 MixClient::gasLimitRemaining() const |
||||
|
{ |
||||
|
ReadGuard l(x_state); |
||||
|
return m_state.gasLimitRemaining(); |
||||
|
} |
||||
|
|
||||
|
void MixClient::setAddress(Address _us) |
||||
|
{ |
||||
|
WriteGuard l(x_state); |
||||
|
m_state.setAddress(_us); |
||||
|
} |
||||
|
|
||||
|
Address MixClient::address() const |
||||
|
{ |
||||
|
ReadGuard l(x_state); |
||||
|
return m_state.address(); |
||||
|
} |
||||
|
|
||||
|
void MixClient::setMiningThreads(unsigned _threads) |
||||
|
{ |
||||
|
(void)_threads; |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::setMiningThreads")); |
||||
|
} |
||||
|
|
||||
|
unsigned MixClient::miningThreads() const |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void MixClient::startMining() |
||||
|
{ |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::startMining")); |
||||
|
} |
||||
|
|
||||
|
void MixClient::stopMining() |
||||
|
{ |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::Interface::stopMining")); |
||||
|
} |
||||
|
|
||||
|
bool MixClient::isMining() |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
eth::MineProgress MixClient::miningProgress() const |
||||
|
{ |
||||
|
return eth::MineProgress(); |
||||
|
} |
@ -0,0 +1,125 @@ |
|||||
|
/*
|
||||
|
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 MixClient.h
|
||||
|
* @author Yann yann@ethdev.com |
||||
|
* @author Arkadiy Paronyan arkadiy@ethdev.com |
||||
|
* @date 2015 |
||||
|
* Ethereum IDE client. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <libethereum/Interface.h> |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace mix |
||||
|
{ |
||||
|
|
||||
|
/**
|
||||
|
* @brief Store information about a machine state. |
||||
|
*/ |
||||
|
struct MachineState |
||||
|
{ |
||||
|
uint64_t steps; |
||||
|
dev::Address cur; |
||||
|
dev::u256 curPC; |
||||
|
dev::eth::Instruction inst; |
||||
|
dev::bigint newMemSize; |
||||
|
dev::u256 gas; |
||||
|
dev::u256s stack; |
||||
|
dev::bytes memory; |
||||
|
dev::bigint gasCost; |
||||
|
std::map<dev::u256, dev::u256> storage; |
||||
|
std::vector<MachineState const*> levels; |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
* @brief Store information about a machine states. |
||||
|
*/ |
||||
|
struct ExecutionResult |
||||
|
{ |
||||
|
std::vector<MachineState> machineStates; |
||||
|
bytes executionCode; |
||||
|
bytesConstRef executionData; |
||||
|
Address contractAddress; |
||||
|
bool contentAvailable; |
||||
|
std::string message; |
||||
|
bytes returnValue; |
||||
|
}; |
||||
|
|
||||
|
class MixClient: public dev::eth::Interface |
||||
|
{ |
||||
|
public: |
||||
|
MixClient(); |
||||
|
/// Reset state to the empty state with given balance.
|
||||
|
void resetState(u256 _balance); |
||||
|
const KeyPair& userAccount() const { return m_userAccount; } |
||||
|
const ExecutionResult lastExecutionResult() const { ReadGuard l(x_state); return m_lastExecutionResult; } |
||||
|
|
||||
|
//dev::eth::Interface
|
||||
|
void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; |
||||
|
Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) override; |
||||
|
void inject(bytesConstRef _rlp) override; |
||||
|
void flushTransactions() override; |
||||
|
bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; |
||||
|
u256 balanceAt(Address _a, int _block) const override; |
||||
|
u256 countAt(Address _a, int _block) const override; |
||||
|
u256 stateAt(Address _a, u256 _l, int _block) const override; |
||||
|
bytes codeAt(Address _a, int _block) const override; |
||||
|
std::map<u256, u256> storageAt(Address _a, int _block) const override; |
||||
|
eth::LogEntries logs(unsigned _watchId) const override; |
||||
|
eth::LogEntries logs(eth::LogFilter const& _filter) const override; |
||||
|
unsigned installWatch(eth::LogFilter const& _filter) override; |
||||
|
unsigned installWatch(h256 _filterId) override; |
||||
|
void uninstallWatch(unsigned _watchId) override; |
||||
|
bool peekWatch(unsigned _watchId) const override; |
||||
|
bool checkWatch(unsigned _watchId) override; |
||||
|
h256 hashFromNumber(unsigned _number) const override; |
||||
|
eth::BlockInfo blockInfo(h256 _hash) const override; |
||||
|
eth::BlockDetails blockDetails(h256 _hash) const override; |
||||
|
eth::Transaction transaction(h256 _blockHash, unsigned _i) const override; |
||||
|
eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override; |
||||
|
unsigned number() const override; |
||||
|
eth::Transactions pending() const override; |
||||
|
eth::StateDiff diff(unsigned _txi, h256 _block) const override; |
||||
|
eth::StateDiff diff(unsigned _txi, int _block) const override; |
||||
|
Addresses addresses(int _block) const override; |
||||
|
u256 gasLimitRemaining() const override; |
||||
|
void setAddress(Address _us) override; |
||||
|
Address address() const override; |
||||
|
void setMiningThreads(unsigned _threads) override; |
||||
|
unsigned miningThreads() const override; |
||||
|
void startMining() override; |
||||
|
void stopMining() override; |
||||
|
bool isMining() override; |
||||
|
eth::MineProgress miningProgress() const override; |
||||
|
|
||||
|
private: |
||||
|
void executeTransaction(bytesConstRef _rlp, eth::State& _state); |
||||
|
void validateBlock(int _block) const; |
||||
|
|
||||
|
KeyPair m_userAccount; |
||||
|
eth::State m_state; |
||||
|
OverlayDB m_stateDB; |
||||
|
mutable boost::shared_mutex x_state; |
||||
|
ExecutionResult m_lastExecutionResult; |
||||
|
}; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,55 @@ |
|||||
|
/*
|
||||
|
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 Web3Server.h.cpp
|
||||
|
* @author Arkadiy Paronyan arkadiy@ethdev.com |
||||
|
* @date 2014 |
||||
|
* Ethereum IDE client. |
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
#include <libdevcore/Exceptions.h> |
||||
|
#include "Web3Server.h" |
||||
|
|
||||
|
using namespace dev::mix; |
||||
|
|
||||
|
Web3Server::Web3Server(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts, dev::eth::Interface* _client): |
||||
|
WebThreeStubServerBase(_conn, _accounts), |
||||
|
m_client(_client) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
std::shared_ptr<dev::shh::Interface> Web3Server::face() |
||||
|
{ |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::shh::Interface")); |
||||
|
} |
||||
|
|
||||
|
dev::WebThreeNetworkFace* Web3Server::network() |
||||
|
{ |
||||
|
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::WebThreeNetworkFace")); |
||||
|
} |
||||
|
|
||||
|
std::string Web3Server::get(std::string const& _name, std::string const& _key) |
||||
|
{ |
||||
|
std::string k(_name + "/" + _key); |
||||
|
return m_db[k]; |
||||
|
} |
||||
|
|
||||
|
void Web3Server::put(std::string const& _name, std::string const& _key, std::string const& _value) |
||||
|
{ |
||||
|
std::string k(_name + "/" + _key); |
||||
|
m_db[k] = _value; |
||||
|
} |
@ -0,0 +1,56 @@ |
|||||
|
/*
|
||||
|
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 Web3Server.h
|
||||
|
* @author Arkadiy Paronyan arkadiy@ethdev.com |
||||
|
* @date 2015 |
||||
|
* Ethereum IDE client. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <map> |
||||
|
#include <string> |
||||
|
#include <libweb3jsonrpc/WebThreeStubServerBase.h> |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
|
||||
|
namespace mix |
||||
|
{ |
||||
|
|
||||
|
class Web3Server: public dev::WebThreeStubServerBase, public dev::WebThreeStubDatabaseFace |
||||
|
{ |
||||
|
public: |
||||
|
Web3Server(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts, dev::eth::Interface* _client); |
||||
|
|
||||
|
private: |
||||
|
dev::eth::Interface* client() override { return m_client; } |
||||
|
std::shared_ptr<dev::shh::Interface> face() override; |
||||
|
dev::WebThreeNetworkFace* network() override; |
||||
|
dev::WebThreeStubDatabaseFace* db() override { return this; } |
||||
|
|
||||
|
std::string get(std::string const& _name, std::string const& _key) override; |
||||
|
void put(std::string const& _name, std::string const& _key, std::string const& _value) override; |
||||
|
|
||||
|
private: |
||||
|
dev::eth::Interface* m_client; |
||||
|
std::map<std::string, std::string> m_db; |
||||
|
}; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,81 @@ |
|||||
|
import QtQuick 2.0 |
||||
|
import QtQuick.Window 2.0 |
||||
|
import QtQuick.Layouts 1.0 |
||||
|
import QtQuick.Controls 1.0 |
||||
|
import QtQuick.Controls.Styles 1.1 |
||||
|
|
||||
|
Component { |
||||
|
Item { |
||||
|
signal editorTextChanged |
||||
|
|
||||
|
function setText(text) { |
||||
|
codeEditor.text = text; |
||||
|
} |
||||
|
|
||||
|
function getText() { |
||||
|
return codeEditor.text; |
||||
|
} |
||||
|
|
||||
|
anchors.fill: parent |
||||
|
id: contentView |
||||
|
width: parent.width |
||||
|
height: parent.height * 0.7 |
||||
|
Rectangle { |
||||
|
id: lineColumn |
||||
|
property int rowHeight: codeEditor.font.pixelSize + 3 |
||||
|
color: "#202020" |
||||
|
width: 50 |
||||
|
height: parent.height |
||||
|
Column { |
||||
|
y: -codeEditor.flickableItem.contentY + 4 |
||||
|
width: parent.width |
||||
|
Repeater { |
||||
|
model: Math.max(codeEditor.lineCount + 2, (lineColumn.height/lineColumn.rowHeight)) |
||||
|
delegate: Text { |
||||
|
id: text |
||||
|
color: codeEditor.textColor |
||||
|
font: codeEditor.font |
||||
|
width: lineColumn.width - 4 |
||||
|
horizontalAlignment: Text.AlignRight |
||||
|
verticalAlignment: Text.AlignVCenter |
||||
|
height: lineColumn.rowHeight |
||||
|
renderType: Text.NativeRendering |
||||
|
text: index + 1 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
TextArea { |
||||
|
id: codeEditor |
||||
|
textColor: "#EEE8D5" |
||||
|
style: TextAreaStyle { |
||||
|
backgroundColor: "#002B36" |
||||
|
} |
||||
|
|
||||
|
anchors.left: lineColumn.right |
||||
|
anchors.right: parent.right |
||||
|
anchors.top: parent.top |
||||
|
anchors.bottom: parent.bottom |
||||
|
wrapMode: TextEdit.NoWrap |
||||
|
frameVisible: false |
||||
|
|
||||
|
height: parent.height |
||||
|
font.family: "Monospace" |
||||
|
font.pointSize: 12 |
||||
|
width: parent.width |
||||
|
|
||||
|
tabChangesFocus: false |
||||
|
Keys.onPressed: { |
||||
|
if (event.key === Qt.Key_Tab) { |
||||
|
codeEditor.insert(codeEditor.cursorPosition, "\t"); |
||||
|
event.accepted = true; |
||||
|
} |
||||
|
} |
||||
|
onTextChanged: { |
||||
|
editorTextChanged(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue