subtly
10 years ago
141 changed files with 5660 additions and 2769 deletions
@ -0,0 +1,7 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
cd ethereumjs |
||||
|
export PATH=$PATH:$1:$2 |
||||
|
npm install |
||||
|
npm run-script build |
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,37 @@ |
|||||
|
var assert = require('assert'); |
||||
|
var abi = require('../lib/abi.js'); |
||||
|
|
||||
|
describe('abi', function() { |
||||
|
describe('inputParser', function() { |
||||
|
it('should parse ...', function() { |
||||
|
|
||||
|
var desc = [{ |
||||
|
"name": "multiply", |
||||
|
"inputs": [ |
||||
|
{ |
||||
|
"name": "a", |
||||
|
"type": "uint256" |
||||
|
} |
||||
|
], |
||||
|
"outputs": [ |
||||
|
{ |
||||
|
"name": "d", |
||||
|
"type": "uint256" |
||||
|
} |
||||
|
] |
||||
|
}]; |
||||
|
|
||||
|
var iParser = abi.inputParser(desc); |
||||
|
assert.equal(iParser.multiply(1), "0x000000000000000000000000000000000000000000000000000000000000000001"); |
||||
|
|
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
|
||||
|
describe('outputParser', function() { |
||||
|
it('parse ...', function() { |
||||
|
|
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
|
@ -0,0 +1,18 @@ |
|||||
|
require('es6-promise').polyfill(); |
||||
|
|
||||
|
var assert = require('assert'); |
||||
|
var web3 = require('../index.js'); |
||||
|
var u = require('./utils.js'); |
||||
|
web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
|
||||
|
|
||||
|
describe('web3', function() { |
||||
|
describe('db', function() { |
||||
|
it('should have all methods implemented', function() { |
||||
|
u.methodExists(web3.db, 'put'); |
||||
|
u.methodExists(web3.db, 'get'); |
||||
|
u.methodExists(web3.db, 'putString'); |
||||
|
u.methodExists(web3.db, 'getString'); |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
|
@ -0,0 +1,42 @@ |
|||||
|
require('es6-promise').polyfill(); |
||||
|
|
||||
|
var assert = require('assert'); |
||||
|
var web3 = require('../index.js'); |
||||
|
var u = require('./utils.js'); |
||||
|
web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
|
||||
|
|
||||
|
describe('web3', function() { |
||||
|
describe('eth', function() { |
||||
|
it('should have all methods implemented', function() { |
||||
|
u.methodExists(web3.eth, 'balanceAt'); |
||||
|
u.methodExists(web3.eth, 'stateAt'); |
||||
|
u.methodExists(web3.eth, 'storageAt'); |
||||
|
u.methodExists(web3.eth, 'countAt'); |
||||
|
u.methodExists(web3.eth, 'codeAt'); |
||||
|
u.methodExists(web3.eth, 'transact'); |
||||
|
u.methodExists(web3.eth, 'call'); |
||||
|
u.methodExists(web3.eth, 'block'); |
||||
|
u.methodExists(web3.eth, 'transaction'); |
||||
|
u.methodExists(web3.eth, 'uncle'); |
||||
|
u.methodExists(web3.eth, 'compilers'); |
||||
|
u.methodExists(web3.eth, 'lll'); |
||||
|
u.methodExists(web3.eth, 'solidity'); |
||||
|
u.methodExists(web3.eth, 'serpent'); |
||||
|
u.methodExists(web3.eth, 'logs'); |
||||
|
}); |
||||
|
|
||||
|
it('should have all properties implemented', function () { |
||||
|
u.propertyExists(web3.eth, 'coinbase'); |
||||
|
u.propertyExists(web3.eth, 'listening'); |
||||
|
u.propertyExists(web3.eth, 'mining'); |
||||
|
u.propertyExists(web3.eth, 'gasPrice'); |
||||
|
u.propertyExists(web3.eth, 'account'); |
||||
|
u.propertyExists(web3.eth, 'accounts'); |
||||
|
u.propertyExists(web3.eth, 'peerCount'); |
||||
|
u.propertyExists(web3.eth, 'defaultBlock'); |
||||
|
u.propertyExists(web3.eth, 'number'); |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
|
@ -0,0 +1,2 @@ |
|||||
|
--reporter Spec |
||||
|
|
@ -0,0 +1,19 @@ |
|||||
|
require('es6-promise').polyfill(); |
||||
|
|
||||
|
var assert = require('assert'); |
||||
|
var web3 = require('../index.js'); |
||||
|
var u = require('./utils.js'); |
||||
|
web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
|
||||
|
|
||||
|
describe('web3', function() { |
||||
|
describe('shh', function() { |
||||
|
it('should have all methods implemented', function() { |
||||
|
u.methodExists(web3.shh, 'post'); |
||||
|
u.methodExists(web3.shh, 'newIdentity'); |
||||
|
u.methodExists(web3.shh, 'haveIdentity'); |
||||
|
u.methodExists(web3.shh, 'newGroup'); |
||||
|
u.methodExists(web3.shh, 'addToGroup'); |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
|
@ -0,0 +1,15 @@ |
|||||
|
var assert = require('assert'); |
||||
|
|
||||
|
var methodExists = function (object, method) { |
||||
|
assert.equal('function', typeof object[method], 'method ' + method + ' is not implemented'); |
||||
|
}; |
||||
|
|
||||
|
var propertyExists = function (object, property) { |
||||
|
assert.equal('object', typeof object[property], 'property ' + property + ' is not implemented'); |
||||
|
}; |
||||
|
|
||||
|
module.exports = { |
||||
|
methodExists: methodExists, |
||||
|
propertyExists: propertyExists |
||||
|
}; |
||||
|
|
@ -0,0 +1,18 @@ |
|||||
|
require('es6-promise').polyfill(); |
||||
|
|
||||
|
var assert = require('assert'); |
||||
|
var web3 = require('../index.js'); |
||||
|
var u = require('./utils.js'); |
||||
|
web3.setProvider(new web3.providers.WebSocketProvider('http://localhost:8080')); // TODO: create some mock provider
|
||||
|
|
||||
|
describe('web3', function() { |
||||
|
it('should have all methods implemented', function() { |
||||
|
u.methodExists(web3, 'sha3'); |
||||
|
u.methodExists(web3, 'toAscii'); |
||||
|
u.methodExists(web3, 'fromAscii'); |
||||
|
u.methodExists(web3, 'toFixed'); |
||||
|
u.methodExists(web3, 'fromFixed'); |
||||
|
u.methodExists(web3, 'offset'); |
||||
|
}); |
||||
|
}); |
||||
|
|
@ -1,7 +1,7 @@ |
|||||
<RCC version="1.0"> |
<RCC> |
||||
<qresource prefix="/js"> |
<qresource prefix="/js"> |
||||
<file>es6-promise-2.0.0.js</file> |
<file>es6-promise-2.0.0.js</file> |
||||
<file>setup.js</file> |
<file>setup.js</file> |
||||
<file alias="ethereum.js">ethereumjs/dist/ethereum.js</file> |
<file alias="webthree.js">ethereumjs/dist/ethereum.js</file> |
||||
</qresource> |
</qresource> |
||||
</RCC> |
</RCC> |
||||
|
@ -0,0 +1,665 @@ |
|||||
|
/*
|
||||
|
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::LocalisedLogEntry 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)); |
||||
|
res["number"] = _e.number; |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
static Json::Value toJson(dev::eth::LocalisedLogEntries const& _es) // commented to avoid warning. Uncomment once in use @ poC-7.
|
||||
|
{ |
||||
|
Json::Value res; |
||||
|
for (dev::eth::LocalisedLogEntry 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; |
||||
|
} |
||||
|
|
||||
|
Json::Value WebThreeStubServerBase::eth_changed(int const& _id) |
||||
|
{ |
||||
|
return toJson(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; |
||||
|
struct 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 Json::Value 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
|
@ -0,0 +1,4 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
git checkout master && git merge --no-ff $1+ && git push && git tag -f $1 && git push --tags -f |
||||
|
|
@ -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; |
||||
|
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) |
||||
|
{ |
||||
|
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; |
||||
|
}; |
||||
|
|
||||
|
} |
||||
|
} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue