Browse Source

Merge branch 'develop' into mk_jsonrpc

Conflicts:
	alethzero/MainWin.cpp
	libqethereum/QEthereum.cpp
	libqethereum/QEthereum.h
	third/MainWin.cpp
cl-refactor
Marek Kotewicz 10 years ago
parent
commit
da7f2aef78
  1. 18
      CodingStandards.txt
  2. 4
      alethzero/MainWin.cpp
  3. 1
      alethzero/MainWin.h
  4. 4
      eth/main.cpp
  5. 2
      libdevcore/Common.cpp
  6. 2
      libdevcore/Exceptions.h
  7. 1
      libdevcore/Worker.cpp
  8. 1
      libdevcore/Worker.h
  9. 16
      libethcore/Exceptions.h
  10. 15
      libethereum/Client.cpp
  11. 2
      libethereum/Client.h
  12. 5
      libethereum/EthereumHost.cpp
  13. 3
      libethereum/EthereumPeer.cpp
  14. 2
      libevm/VM.h
  15. 2
      libp2p/Common.h
  16. 125
      libp2p/Host.cpp
  17. 13
      libp2p/Host.h
  18. 4
      libp2p/Session.cpp
  19. 2
      libp2p/UPnP.h
  20. 90
      libqethereum/QEthereum.cpp
  21. 134
      libqethereum/QEthereum.h
  22. 22
      libwebthree/WebThree.cpp
  23. 8
      libwebthree/WebThree.h
  24. 7
      test/CMakeLists.txt
  25. 152
      test/createRandomTest.cpp
  26. 29
      test/randomTestFiller.json
  27. 63
      test/vm.cpp
  28. 85
      test/vmArithmeticTestFiller.json
  29. 83
      test/vmIOandFlowOperationsTestFiller.json
  30. 100
      test/vmSystemOperationsTestFiller.json
  31. 4
      third/MainWin.cpp
  32. 1
      third/MainWin.h

18
CodingStandards.txt

@ -1,7 +1,7 @@
0. Formatting
a. Use tabs for indentation!
- 1 tab is 4 spaces wide.
- tab stops are every 4 characters.
- One indentation level -> exactly one byte (i.e. a tab character) in the source file.
b. Line widths:
- Don't worry about having lines of code > 80-char wide.
@ -11,8 +11,9 @@ d. Never place condition bodies on same line as condition.
e. Space between first paren and keyword, but *not* following first paren or preceeding final paren.
f. No spaces when fewer than intra-expression three parens together; when three or more, space according to clarity.
g. No spaces for subscripting.
h. Space all other operators.
i. Braces, when used, always have their own lines and are at same indentation level as "parent" scope.
h. No space before ':' but one after it, except in the ternary operator: one on both sides.
i. Space all other operators.
j. Braces, when used, always have their own lines and are at same indentation level as "parent" scope.
(WRONG)
if( a==b[ i ] ) { printf ("Hello\n"); }
@ -147,8 +148,17 @@ e. A dictionary and thesaurus are your friends.
- Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments.
10. Type-definitions
10. Commenting
a. Prefer using to typedef. e.g. using ints = std::vector<int>; rather than typedef std::vector<int> ints;
b. Generally avoid shortening a standard form that already includes all important information:
- e.g. stick to shared_ptr<X> rather than shortening to ptr<X>.
c. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently.
- e.g. using Guard = boost::lock_guard<std::mutex>; ///< Guard is used throughout the codebase since it's clear in meaning and used commonly.
d. In general expressions should be roughly as important/semantically meaningful as the space they occupy.
11. Commenting
a. Comments should be doxygen-compilable, using @notation rather than \notation.

4
alethzero/MainWin.cpp

@ -135,6 +135,7 @@ Main::Main(QWidget *parent) :
connect(ui->webView, &QWebView::loadStarted, [this]()
{
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_dev = new QDev(this);
m_ethereum = new QEthereum(this, ethereum(), owned());
m_whisper = new QWhisper(this, whisper());
m_p2p = new QPeer2Peer(this, peer2peer());
@ -142,10 +143,11 @@ Main::Main(QWidget *parent) :
QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
auto qdev = m_dev;
auto qeth = m_ethereum;
auto qshh = m_whisper;
auto qp2p = m_p2p;
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, qshh, qp2p, this));
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qp2p));
});
connect(ui->webView, &QWebView::loadFinished, [=]()

1
alethzero/MainWin.h

@ -248,6 +248,7 @@ private:
QString m_logHistory;
bool m_logChanged = true;
QDev* m_dev = nullptr;
QEthereum* m_ethereum = nullptr;
QWhisper* m_whisper = nullptr;
QPeer2Peer* m_p2p = nullptr;

4
eth/main.cpp

@ -325,7 +325,7 @@ int main(int argc, char** argv)
c->setAddress(coinbase);
}
auto nodesState = contents(dbPath + "/nodeState.rlp");
auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp");
web3.restoreNodes(&nodesState);
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
@ -792,7 +792,7 @@ int main(int argc, char** argv)
while (!g_exit)
this_thread::sleep_for(chrono::milliseconds(1000));
writeFile(dbPath + "/nodeState.rlp", web3.saveNodes());
writeFile((dbPath.size() ? dbPath : getDataDir()) + "/nodeState.rlp", web3.saveNodes());
return 0;
}

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
namespace dev
{
char const* Version = "0.7.4";
char const* Version = "0.7.5";
}

2
libdevcore/Exceptions.h

@ -44,6 +44,6 @@ struct FileError: virtual Exception {};
// error information to be added to exceptions
typedef boost::error_info<struct tag_invalidSymbol, char> errinfo_invalidSymbol;
typedef boost::error_info<struct tag_comment, Address> errinfo_wrongAddress;
typedef boost::error_info<struct tag_comment, std::string> errinfo_wrongAddress;
typedef boost::error_info<struct tag_comment, std::string> errinfo_comment;
}

1
libdevcore/Worker.cpp

@ -38,6 +38,7 @@ void Worker::startWorking()
m_work.reset(new thread([&]()
{
setThreadName(m_name.c_str());
startedWorking();
while (!m_stop)
{
this_thread::sleep_for(chrono::milliseconds(30));

1
libdevcore/Worker.h

@ -46,6 +46,7 @@ protected:
void startWorking();
void stopWorking();
bool isWorking() const { Guard l(x_work); return !!m_work; }
virtual void startedWorking() {}
virtual void doWork() = 0;
virtual void doneWorking() {}

16
libethcore/Exceptions.h

@ -44,26 +44,26 @@ struct FeeTooSmall: virtual dev::Exception {};
struct TooMuchGasUsed: virtual dev::Exception {};
struct ExtraDataTooBig: virtual dev::Exception {};
struct InvalidSignature: virtual dev::Exception {};
class InvalidBlockFormat: public dev::Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual const char* what() const noexcept; };
class InvalidBlockFormat: virtual public dev::Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual const char* what() const noexcept; };
struct InvalidUnclesHash: virtual dev::Exception {};
struct InvalidUncle: virtual dev::Exception {};
struct UncleTooOld: virtual dev::Exception {};
class UncleInChain: public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; };
class UncleInChain: virtual public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block): m_uncles(_uncles), m_block(_block) {} h256Set m_uncles; h256 m_block; virtual const char* what() const noexcept; };
struct DuplicateUncleNonce: virtual dev::Exception {};
struct InvalidStateRoot: virtual dev::Exception {};
class InvalidTransactionsHash: public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; };
class InvalidTransactionsHash: virtual public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual const char* what() const noexcept; };
struct InvalidTransaction: virtual dev::Exception {};
struct InvalidDifficulty: virtual dev::Exception {};
class InvalidGasLimit: public dev::Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0): provided(_provided), valid(_valid) {} u256 provided; u256 valid; virtual const char* what() const noexcept; };
class InvalidMinGasPrice: public dev::Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual const char* what() const noexcept; };
class InvalidGasLimit: virtual public dev::Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0): provided(_provided), valid(_valid) {} u256 provided; u256 valid; virtual const char* what() const noexcept; };
class InvalidMinGasPrice: virtual public dev::Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual const char* what() const noexcept; };
struct InvalidTransactionGasUsed: virtual dev::Exception {};
struct InvalidTransactionStateRoot: virtual dev::Exception {};
struct InvalidTimestamp: virtual dev::Exception {};
class InvalidNonce: public dev::Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual const char* what() const noexcept; };
class InvalidBlockNonce: public dev::Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; virtual const char* what() const noexcept; };
class InvalidNonce: virtual public dev::Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual const char* what() const noexcept; };
class InvalidBlockNonce: virtual public dev::Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; virtual const char* what() const noexcept; };
struct InvalidParentHash: virtual dev::Exception {};
struct InvalidNumber: virtual dev::Exception {};
struct InvalidContractAddress: virtual dev::Exception {};
struct InvalidContractAddress: virtual public dev::Exception {};
}
}

15
libethereum/Client.cpp

@ -88,8 +88,19 @@ void Client::setNetworkId(u256 _n)
h->setNetworkId(_n);
}
DownloadMan const* Client::downloadMan() const { if (auto h = m_host.lock()) return &(h->downloadMan()); return nullptr; }
bool Client::isSyncing() const { if (auto h = m_host.lock()) return h->isSyncing(); return false; }
DownloadMan const* Client::downloadMan() const
{
if (auto h = m_host.lock())
return &(h->downloadMan());
return nullptr;
}
bool Client::isSyncing() const
{
if (auto h = m_host.lock())
return h->isSyncing();
return false;
}
void Client::doneWorking()
{

2
libethereum/Client.h

@ -285,7 +285,7 @@ private:
State m_preMine; ///< The present state of the client.
State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added).
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
std::vector<Miner> m_miners;
mutable boost::shared_mutex x_miners;

5
libethereum/EthereumHost.cpp

@ -86,6 +86,11 @@ void EthereumHost::noteNeedsSyncing(EthereumPeer* _who)
void EthereumHost::changeSyncer(EthereumPeer* _syncer)
{
if (_syncer)
clog(NetAllDetail) << "Changing syncer to" << _syncer->session()->socketId();
else
clog(NetAllDetail) << "Clearing syncer.";
m_syncer = _syncer;
if (isSyncing())
{

3
libethereum/EthereumPeer.cpp

@ -142,7 +142,6 @@ void EthereumPeer::transition(Asking _a, bool _force)
host()->m_man.resetToChain(m_syncingNeededBlocks);
host()->m_latestBlockSent = m_syncingLatestHash;
}
else
{
@ -156,7 +155,7 @@ void EthereumPeer::transition(Asking _a, bool _force)
if (m_asking == Asking::Nothing || m_asking == Asking::Hashes || m_asking == Asking::Blocks)
{
// Looks like it's the best yet for total difficulty. Set to download.
setAsking(Asking::Blocks, true); // will kick off other peers to help if available.
setAsking(Asking::Blocks, isSyncing()); // will kick off other peers to help if available.
auto blocks = m_sub.nextFetch(c_maxBlocksAsk);
if (blocks.size())
{

2
libevm/VM.h

@ -41,7 +41,7 @@ struct BreakPointHit: virtual VMException {};
struct BadInstruction: virtual VMException {};
struct BadJumpDestination: virtual VMException {};
struct OutOfGas: virtual VMException {};
class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
class StackTooSmall: virtual public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash.
// Currently we just pull out the right (low-order in BE) 160-bits.

2
libp2p/Common.h

@ -127,5 +127,7 @@ struct PeerInfo
std::map<std::string, std::string> notes;
};
using PeerInfos = std::vector<PeerInfo>;
}
}

125
libp2p/Host.cpp

@ -61,8 +61,9 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool
Worker("p2p"),
m_clientVersion(_clientVersion),
m_netPrefs(_n),
m_acceptor(m_ioService),
m_socket(m_ioService),
m_ioService(new ba::io_service),
m_acceptor(*m_ioService),
m_socket(*m_ioService),
m_key(KeyPair::create())
{
populateAddresses();
@ -73,11 +74,15 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool
Host::~Host()
{
stop();
quit();
}
void Host::start()
{
// if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
if (!m_ioService)
return;
if (isWorking())
stop();
@ -105,14 +110,6 @@ void Host::start()
}
}
determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp);
ensureAccepting();
if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id()))
noteNode(id(), m_public, Origin::Perfect, false);
clog(NetNote) << "Id:" << id().abridged();
for (auto const& h: m_capabilities)
h.second->onStarting();
@ -137,7 +134,18 @@ void Host::stop()
m_socket.close();
disconnectPeers();
if (!!m_ioService)
{
m_ioService->stop();
m_ioService->reset();
}
}
void Host::quit()
{
stop();
m_ioService.reset();
// m_acceptor & m_socket are DANGEROUS now.
}
unsigned Host::protocolVersion() const
@ -168,6 +176,10 @@ void Host::registerPeer(std::shared_ptr<Session> _s, CapDescs const& _caps)
void Host::disconnectPeers()
{
// if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
if (!m_ioService)
return;
for (unsigned n = 0;; n = 0)
{
{
@ -181,7 +193,7 @@ void Host::disconnectPeers()
}
if (!n)
break;
m_ioService.poll();
m_ioService->poll();
this_thread::sleep_for(chrono::milliseconds(100));
}
@ -204,6 +216,10 @@ void Host::seal(bytes& _b)
void Host::determinePublic(string const& _publicAddress, bool _upnp)
{
// if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
if (!m_ioService)
return;
if (_upnp)
try
{
@ -211,7 +227,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
}
catch (NoUPnPDevice) {} // let m_upnp continue as null - we handle it properly.
bi::tcp::resolver r(m_ioService);
bi::tcp::resolver r(*m_ioService);
if (m_upnp && m_upnp->isValid() && m_peerAddresses.size())
{
clog(NetNote) << "External addr:" << m_upnp->externalIP();
@ -249,6 +265,10 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
void Host::populateAddresses()
{
// if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
if (!m_ioService)
return;
#ifdef _WIN32
WSAData wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
@ -289,7 +309,7 @@ void Host::populateAddresses()
if (getifaddrs(&ifaddr) == -1)
BOOST_THROW_EXCEPTION(NoNetworking());
bi::tcp::resolver r(m_ioService);
bi::tcp::resolver r(*m_ioService);
for (ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next)
{
@ -349,7 +369,7 @@ shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, boo
if (_a.port() < 30300 && _a.port() > 30303)
cwarn << "Wierd port being recorded!";
if (_a.port() >= 49152)
if (_a.port() >= /*49152*/32768)
{
cwarn << "Private port being recorded - setting to 0";
_a = bi::tcp::endpoint(_a.address(), 0);
@ -422,6 +442,10 @@ Nodes Host::potentialPeers(RangeMask<unsigned> const& _known)
void Host::ensureAccepting()
{
// if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
if (!m_ioService)
return;
if (!m_accepting)
{
clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")";
@ -465,13 +489,17 @@ string Host::pocHost()
void Host::connect(std::string const& _addr, unsigned short _port) noexcept
{
// if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
if (!m_ioService)
return;
for (int i = 0; i < 2; ++i)
{
try
{
if (i == 0)
{
bi::tcp::resolver r(m_ioService);
bi::tcp::resolver r(*m_ioService);
connect(r.resolve({_addr, toString(_port)})->endpoint());
}
else
@ -493,8 +521,12 @@ void Host::connect(std::string const& _addr, unsigned short _port) noexcept
void Host::connect(bi::tcp::endpoint const& _ep)
{
// if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
if (!m_ioService)
return;
clog(NetConnect) << "Attempting single-shot connection to " << _ep;
bi::tcp::socket* s = new bi::tcp::socket(m_ioService);
bi::tcp::socket* s = new bi::tcp::socket(*m_ioService);
s->async_connect(_ep, [=](boost::system::error_code const& ec)
{
if (ec)
@ -509,27 +541,31 @@ void Host::connect(bi::tcp::endpoint const& _ep)
});
}
void Node::connect(Host* _h)
void Host::connect(std::shared_ptr<Node> const& _n)
{
clog(NetConnect) << "Attempting connection to node" << id.abridged() << "@" << address << "from" << _h->id().abridged();
lastAttempted = std::chrono::system_clock::now();
failedAttempts++;
_h->m_ready -= index;
bi::tcp::socket* s = new bi::tcp::socket(_h->m_ioService);
s->async_connect(address, [=](boost::system::error_code const& ec)
// if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
if (!m_ioService)
return;
clog(NetConnect) << "Attempting connection to node" << _n->id.abridged() << "@" << _n->address << "from" << id().abridged();
_n->lastAttempted = std::chrono::system_clock::now();
_n->failedAttempts++;
m_ready -= _n->index;
bi::tcp::socket* s = new bi::tcp::socket(*m_ioService);
s->async_connect(_n->address, [=](boost::system::error_code const& ec)
{
if (ec)
{
clog(NetConnect) << "Connection refused to node" << id.abridged() << "@" << address << "(" << ec.message() << ")";
lastDisconnect = TCPError;
lastAttempted = std::chrono::system_clock::now();
_h->m_ready += index;
clog(NetConnect) << "Connection refused to node" << _n->id.abridged() << "@" << _n->address << "(" << ec.message() << ")";
_n->lastDisconnect = TCPError;
_n->lastAttempted = std::chrono::system_clock::now();
m_ready += _n->index;
}
else
{
clog(NetConnect) << "Connected to" << id.abridged() << "@" << address;
lastConnected = std::chrono::system_clock::now();
auto p = make_shared<Session>(_h, std::move(*s), _h->node(id), true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism.
clog(NetConnect) << "Connected to" << _n->id.abridged() << "@" << _n->address;
_n->lastConnected = std::chrono::system_clock::now();
auto p = make_shared<Session>(this, std::move(*s), node(_n->id), true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism.
p->start();
}
delete s;
@ -594,7 +630,7 @@ void Host::growPeers()
if (ns.size())
for (Node const& i: ns)
{
m_nodes[i.id]->connect(this);
connect(m_nodes[i.id]);
if (!--morePeers)
return;
}
@ -640,8 +676,12 @@ void Host::prunePeers()
i = m_peers.erase(i);
}
std::vector<PeerInfo> Host::peers(bool _updatePing) const
PeerInfos Host::peers(bool _updatePing) const
{
// if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
if (!m_ioService)
return PeerInfos();
RecursiveGuard l(x_peers);
if (_updatePing)
{
@ -656,8 +696,23 @@ std::vector<PeerInfo> Host::peers(bool _updatePing) const
return ret;
}
void Host::startedWorking()
{
determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp);
ensureAccepting();
if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id()))
noteNode(id(), m_public, Origin::Perfect, false);
clog(NetNote) << "Id:" << id().abridged();
}
void Host::doWork()
{
// if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
if (asserts(!!m_ioService))
return;
growPeers();
prunePeers();
@ -679,7 +734,7 @@ void Host::doWork()
pingAll();
}
m_ioService.poll();
m_ioService->poll();
}
void Host::pingAll()
@ -701,7 +756,7 @@ bytes Host::saveNodes() const
{
Node const& n = *(i.second);
// TODO: PoC-7: Figure out why it ever shares these ports.//n.address.port() >= 30300 && n.address.port() <= 30305 &&
if (!n.dead && n.address.port() > 0 && n.address.port() < 49152 && n.id != id() && !isPrivateAddress(n.address.address()))
if (!n.dead && n.address.port() > 0 && n.address.port() < /*49152*/32768 && n.id != id() && !isPrivateAddress(n.address.address()))
{
nodes.appendList(10);
if (n.address.address().is_v4())

13
libp2p/Host.h

@ -97,8 +97,6 @@ struct Node
else
return score < _n.score;
}
void connect(Host* _h);
};
using Nodes = std::vector<Node>;
@ -147,6 +145,7 @@ public:
static std::string pocHost();
void connect(std::string const& _addr, unsigned short _port = 30303) noexcept;
void connect(bi::tcp::endpoint const& _ep);
void connect(std::shared_ptr<Node> const& _n);
/// @returns true iff we have the a peer of the given id.
bool havePeer(NodeId _id) const;
@ -155,7 +154,7 @@ public:
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
/// Get peer information.
std::vector<PeerInfo> peers(bool _updatePing = false) const;
PeerInfos peers(bool _updatePing = false) const;
/// Get number of peers connected; equivalent to, but faster than, peers().size().
size_t peerCount() const { RecursiveGuard l(x_peers); return m_peers.size(); }
@ -174,12 +173,14 @@ public:
Nodes nodes() const { RecursiveGuard l(x_peers); Nodes ret; for (auto const& i: m_nodes) ret.push_back(*i.second); return ret; }
void setNetworkPreferences(NetworkPreferences const& _p) { stop(); m_netPrefs = _p; start(); }
void setNetworkPreferences(NetworkPreferences const& _p) { auto had = isStarted(); if (had) stop(); m_netPrefs = _p; if (had) start(); }
void start();
void stop();
bool isStarted() const { return isWorking(); }
void quit();
NodeId id() const { return m_key.pub(); }
void registerPeer(std::shared_ptr<Session> _s, CapDescs const& _caps);
@ -195,6 +196,8 @@ private:
void growPeers();
void prunePeers();
virtual void startedWorking();
/// Conduct I/O, polling, syncing, whatever.
/// Ideally all time-consuming I/O is done in a background thread or otherwise asynchronously, but you get this call every 100ms or so anyway.
/// This won't touch alter the blockchain.
@ -210,7 +213,7 @@ private:
static const int NetworkStopped = -1; ///< The value meaning we're not actually listening.
int m_listenPort = NetworkStopped; ///< What port are we listening on?
ba::io_service m_ioService; ///< IOService for network stuff.
std::unique_ptr<ba::io_service> m_ioService; ///< IOService for network stuff.
bi::tcp::acceptor m_acceptor; ///< Listening acceptor.
bi::tcp::socket m_socket; ///< Listening socket.

4
libp2p/Session.cpp

@ -335,7 +335,7 @@ bool Session::interpret(RLP const& _r)
if (!ep.port())
goto CONTINUE; // Zero port? Don't think so.
if (ep.port() >= 49152)
if (ep.port() >= /*49152*/32768)
goto CONTINUE; // Private port according to IANA.
// TODO: PoC-7:
@ -582,7 +582,7 @@ void Session::doRead()
// error - bad protocol
clogS(NetWarn) << "Couldn't interpret packet." << RLP(r);
// Just wasting our bandwidth - perhaps reduce rating?
return;
//return;
}
}
memmove(m_incoming.data(), m_incoming.data() + tlen, m_incoming.size() - tlen);

2
libp2p/UPnP.h

@ -25,6 +25,7 @@
#include <set>
#include <string>
#include <memory>
#include <thread>
struct UPNPUrls;
struct IGDdatas;
@ -46,6 +47,7 @@ public:
bool isValid() const { return m_ok; }
private:
std::set<int> m_reg;
bool m_ok;
std::shared_ptr<struct UPNPUrls> m_urls;

90
libqethereum/QEthereum.cpp

@ -57,10 +57,11 @@ QString unpadded(QString _s)
}
QEthereum::QEthereum(QObject* _p, eth::Interface* _c, QList<dev::KeyPair> _accounts):
QObject(_p), m_client(_c), m_accounts(_accounts)
QObject(_p), m_client(_c)
{
// required to prevent crash on osx when performing addto/evaluatejavascript calls
moveToThread(_p->thread());
setAccounts(_accounts);
}
QEthereum::~QEthereum()
@ -82,11 +83,6 @@ void QEthereum::clearWatches()
m_watches.clear();
}
QString QEthereum::secretToAddress(QString _s) const
{
return toQJS(KeyPair(toSecret(_s)).address());
}
eth::Interface* QEthereum::client() const
{
return m_client;
@ -97,27 +93,22 @@ QString QEthereum::lll(QString _s) const
return toQJS(dev::eth::compileLLL(_s.toStdString()));
}
QString QEthereum::sha3(QString _s) const
QString QDev::sha3(QString _s) const
{
return toQJS(dev::sha3(toBytes(_s)));
}
QString QEthereum::sha3(QString _s1, QString _s2) const
QString QDev::sha3(QString _s1, QString _s2) const
{
return toQJS(dev::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32))));
}
QString QEthereum::sha3(QString _s1, QString _s2, QString _s3) const
QString QDev::sha3(QString _s1, QString _s2, QString _s3) const
{
return toQJS(dev::sha3(asBytes(padded(_s1, 32)) + asBytes(padded(_s2, 32)) + asBytes(padded(_s3, 32))));
}
QString QEthereum::sha3old(QString _s) const
{
return toQJS(dev::sha3(asBytes(_s)));
}
QString QEthereum::offset(QString _s, int _i) const
QString QDev::offset(QString _s, int _i) const
{
return toQJS(toU256(_s) + _i);
}
@ -132,33 +123,11 @@ unsigned QEthereum::number() const
return client() ? client()->number() + 1 : 0;
}
QString QEthereum::account() const
{
if (m_accounts.empty())
return toQJS(Address());
return toQJS(m_accounts[0].address());
}
QStringList QEthereum::accounts() const
{
QStringList ret;
for (auto i: m_accounts)
ret.push_back(toQJS(i.address()));
return ret;
}
QString QEthereum::key() const
{
if (m_accounts.empty())
return toQJS(KeyPair().sec());
return toQJS(m_accounts[0].sec());
}
QStringList QEthereum::keys() const
{
QStringList ret;
for (auto i: m_accounts)
ret.push_back(toQJS(i.sec()));
ret.push_back(toQJS(i.first));
return ret;
}
@ -270,7 +239,7 @@ static dev::eth::MessageFilter toMessageFilter(QString _json)
struct TransactionSkeleton
{
Secret from;
Address from;
Address to;
u256 value;
bytes data;
@ -284,7 +253,7 @@ static TransactionSkeleton toTransaction(QString _json)
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
if (f.contains("from"))
ret.from = toSecret(f["from"].toString());
ret.from = toAddress(f["from"].toString());
if (f.contains("to"))
ret.to = toAddress(f["to"].toString());
if (f.contains("value"))
@ -459,6 +428,14 @@ void QEthereum::setMiningImpl(bool _l)
}
}
void QEthereum::setAccounts(QList<dev::KeyPair> const& _l)
{
m_accounts.clear();
for (auto i: _l)
m_accounts[i.address()] = i.secret();
keysChanged();
}
QString QEthereum::doTransactImpl(QString _json)
{
QString ret;
@ -467,18 +444,23 @@ QString QEthereum::doTransactImpl(QString _json)
TransactionSkeleton t = toTransaction(_json);
if (!t.from && m_accounts.size())
{
auto b = m_accounts.first();
auto b = m_accounts.begin()->first;
for (auto a: m_accounts)
if (client()->balanceAt(KeyPair(a).address()) > client()->balanceAt(KeyPair(b).address()))
b = a;
t.from = b.secret();
if (client()->balanceAt(a.first) > client()->balanceAt(b))
b = a.first;
t.from = b;
}
if (!m_accounts.count(t.from))
return QString();
if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo;
if (!t.gas)
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(KeyPair(t.from).address()) / t.gasPrice);
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice);
cwarn << "Silently signing transaction from address" << t.from.abridged() << ": User validation hook goes here.";
if (t.to)
client()->transact(t.from, t.value, t.to, t.data, t.gas, t.gasPrice);
// TODO: insert validification hook here.
client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice);
else
ret = toQJS(client()->transact(t.from, t.value, t.data, t.gas, t.gasPrice));
client()->flushTransactions();
@ -490,15 +472,21 @@ QString QEthereum::doCallImpl(QString _json)
if (!m_client)
return QString();
TransactionSkeleton t = toTransaction(_json);
if (!t.to)
return QString();
if (!t.from && m_accounts.size())
t.from = m_accounts[0].secret();
{
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 QString();
if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo;
if (!t.gas)
t.gas = client()->balanceAt(KeyPair(t.from).address()) / t.gasPrice;
bytes out = client()->call(t.from, t.value, t.to, t.data, t.gas, t.gasPrice);
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice);
bytes out = client()->call(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice);
return asQString(out);
}

134
libqethereum/QEthereum.h

@ -106,6 +106,27 @@ inline QString fromBinary(QString const& _s, unsigned _padding = 32)
return fromBinary(asBytes(_s), _padding);
}
class QDev: public QObject
{
Q_OBJECT
public:
QDev(QObject* _p): QObject(_p) {}
virtual ~QDev() {}
Q_INVOKABLE QString sha3(QString _s) const;
Q_INVOKABLE QString sha3(QString _s1, QString _s2) const;
Q_INVOKABLE QString sha3(QString _s1, QString _s2, QString _s3) const;
Q_INVOKABLE QString offset(QString _s, int _offset) const;
Q_INVOKABLE QString toAscii(QString _s) const { return ::toBinary(_s); }
Q_INVOKABLE QString fromAscii(QString _s) const { return ::fromBinary(_s, 32); }
Q_INVOKABLE QString fromAscii(QString _s, unsigned _padding) const { return ::fromBinary(_s, _padding); }
Q_INVOKABLE QString toDecimal(QString _s) const { return ::toDecimal(_s); }
Q_INVOKABLE double fromFixed(QString _s) const { return ::fromFixed(_s); }
Q_INVOKABLE QString toFixed(double _d) const { return ::toFixed(_d); }
};
class QEthereum: public QObject
{
Q_OBJECT
@ -120,31 +141,12 @@ public:
/// Call when the client() is going to be deleted to make this object useless but safe.
void clientDieing();
void setAccounts(QList<dev::KeyPair> _l) { m_accounts = _l; keysChanged(); }
void setAccounts(QList<dev::KeyPair> const& _l);
Q_INVOKABLE QString ethTest() const { return "Hello world!"; }
Q_INVOKABLE QEthereum* self() { return this; }
Q_INVOKABLE QString secretToAddress(QString _s) const;
Q_INVOKABLE QString lll(QString _s) const;
Q_INVOKABLE QString sha3(QString _s) const;
Q_INVOKABLE QString sha3(QString _s1, QString _s2) const;
Q_INVOKABLE QString sha3(QString _s1, QString _s2, QString _s3) const;
Q_INVOKABLE QString sha3old(QString _s) const;
Q_INVOKABLE QString offset(QString _s, int _offset) const;
Q_INVOKABLE QString pad(QString _s, unsigned _l) const { return padded(_s, _l); }
Q_INVOKABLE QString pad(QString _s, unsigned _l, unsigned _r) const { return padded(_s, _l, _r); }
Q_INVOKABLE QString unpad(QString _s) const { return unpadded(_s); }
Q_INVOKABLE QString toAscii(QString _s) const { return ::toBinary(_s); }
Q_INVOKABLE QString fromAscii(QString _s) const { return ::fromBinary(_s, 32); }
Q_INVOKABLE QString fromAscii(QString _s, unsigned _padding) const { return ::fromBinary(_s, _padding); }
Q_INVOKABLE QString toDecimal(QString _s) const { return ::toDecimal(_s); }
Q_INVOKABLE double fromFixed(QString _s) const { return ::fromFixed(_s); }
Q_INVOKABLE QString toFixed(double _d) const { return ::toFixed(_d); }
// [NEW API] - Use this instead.
Q_INVOKABLE QString/*dev::u256*/ balanceAt(QString/*dev::Address*/ _a, int _block) const;
Q_INVOKABLE double countAt(QString/*dev::Address*/ _a, int _block) const;
@ -176,9 +178,6 @@ public:
unsigned/*dev::u256*/ number() const;
int getDefault() const;
QString/*dev::KeyPair*/ key() const;
QStringList/*list of dev::KeyPair*/ keys() const;
QString/*dev::Address*/ account() const;
QStringList/*list of dev::Address*/ accounts() const;
public slots:
@ -200,14 +199,13 @@ private:
Q_PROPERTY(QString coinbase READ coinbase WRITE setCoinbaseImpl NOTIFY coinbaseChanged)
Q_PROPERTY(bool mining READ isMining WRITE setMiningImpl NOTIFY netChanged)
Q_PROPERTY(QString gasPrice READ gasPrice)
Q_PROPERTY(QString key READ key NOTIFY keysChanged)
Q_PROPERTY(QStringList keys READ keys NOTIFY keysChanged)
Q_PROPERTY(QStringList accounts READ accounts NOTIFY keysChanged)
Q_PROPERTY(int defaultBlock READ getDefault WRITE setDefault)
Q_PROPERTY(unsigned number READ number NOTIFY watchChanged)
dev::eth::Interface* m_client;
std::vector<unsigned> m_watches;
QList<dev::KeyPair> m_accounts;
std::map<dev::Address, dev::KeyPair> m_accounts;
};
class QPeer2Peer : public QObject
@ -272,52 +270,52 @@ private:
};
// TODO: p2p object condition
#define QETH_INSTALL_JS_NAMESPACE(frame, eth, shh, p2p, env) [frame, eth, shh, p2p, env]() \
#define QETH_INSTALL_JS_NAMESPACE(_frame, _env, _dev, _eth, _shh, _p2p) [_frame, _env, _dev, _eth, _shh, _p2p]() \
{ \
frame->disconnect(); \
frame->addToJavaScriptWindowObject("env", env, QWebFrame::QtOwnership); \
if (eth) \
_frame->disconnect(); \
_frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \
_frame->addToJavaScriptWindowObject("dev", _dev, QWebFrame::ScriptOwnership); \
if (_eth) \
{ \
frame->addToJavaScriptWindowObject("eth", eth, QWebFrame::ScriptOwnership); \
frame->addToJavaScriptWindowObject("p2p", p2p, QWebFrame::ScriptOwnership); \
frame->evaluateJavaScript("eth.setCoinbase = function(a, f) { window.setTimeout(function () { eth.coinbase = a; if (f) {f(true);}}, 0); }"); \
frame->evaluateJavaScript("eth.getCoinbase = function(f) { window.setTimeout(function () { if (f) {f(eth.coinbase);}}, 0); }"); \
frame->evaluateJavaScript("eth.listening = {get listening() {return p2p.listening}, set listening(l) {p2p.listening = l}}"); \
frame->evaluateJavaScript("eth.setListening = function(a, f) { window.setTimeout(function () { eth.listening = a; if (f) {f(true);}}, 0); }"); \
frame->evaluateJavaScript("eth.getListening = function(f) { window.setTimeout(function () { if (f) {f(eth.listening);}}, 0); }"); \
frame->evaluateJavaScript("eth.setMining = function(a, f) { window.setTimeout(function () { eth.mining = a; if (f) {f(true);}}, 0); }"); \
frame->evaluateJavaScript("eth.getMining = function(f) { window.setTimeout(function () { if (f) { f(eth.mining);}}, 0); }"); \
frame->evaluateJavaScript("eth.getGasPrice = function(f) { window.setTimeout(function () { if (f) {f(eth.gasPrice);}}, 0); }"); \
frame->evaluateJavaScript("eth.getKey = function(f) { window.setTimeout(function () { if(f) {f(eth.key);}}, 0); }"); \
frame->evaluateJavaScript("eth.getKeys = function(f) { window.setTimeout(function () { if (f) {f(eth.keys);}}, 0); }"); \
frame->evaluateJavaScript("eth.peerCount = {get peerCount() {return p2p.peerCount}}"); \
frame->evaluateJavaScript("eth.getPeerCount = function(f) { window.setTimeout(function () { if (f) {f(eth.peerCount);}}, 0); }"); \
frame->evaluateJavaScript("eth.getDefaultBlock = function(f) { window.setTimeout(function () { if (f) {f(eth.defaultBlock);}}, 0); }"); \
frame->evaluateJavaScript("eth.getNumber = function(f) { window.setTimeout(function () { if (f) {f(eth.number);}}, 0); }"); \
frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessagesImpl(JSON.stringify(a))); }"); \
frame->evaluateJavaScript("eth.getMessages = function(a, f) { window.setTimeout(function () { if (f) { f(JSON.parse(eth.getMessagesImpl(JSON.stringify(a)))); }}, 0);}"); \
frame->evaluateJavaScript("eth.getBalanceAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.balanceAt.apply(null, args)); }},0);}"); \
frame->evaluateJavaScript("eth.getStateAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.stateAt.apply(null, args)); }},0);}"); \
frame->evaluateJavaScript("eth.getCountAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.countAt.apply(null, args)); }},0);}"); \
frame->evaluateJavaScript("eth.getCodeAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.codeAt.apply(null, args)); }},0);}"); \
frame->evaluateJavaScript("eth.transact = function(a) { var ret = eth.doTransactImpl(JSON.stringify(a)); return ret; }"); \
frame->evaluateJavaScript("eth.doTransact = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.transact.apply(null, args)); }},0);}"); \
frame->evaluateJavaScript("eth.call = function(a) { var ret = eth.doCallImpl(JSON.stringify(a)); return ret; }"); \
frame->evaluateJavaScript("eth.doCall = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.call.apply(null, args)); }},0);}"); \
frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlockImpl(JSON.stringify(a))); }"); \
frame->evaluateJavaScript("eth.getBlock = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.block.apply(null, args)); }},0);}"); \
frame->evaluateJavaScript("eth.transaction = function(a, i) { return JSON.parse(eth.getTransactionImpl(JSON.stringify(a), i)); }"); \
frame->evaluateJavaScript("eth.getTransaction = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.transaction.apply(null, args)); }},0);}"); \
frame->evaluateJavaScript("eth.uncle = function(a, i) { return JSON.parse(eth.getUncleImpl(JSON.stringify(a), i)); }"); \
frame->evaluateJavaScript("eth.getUncle = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.uncle.apply(null, args)); }},0);}"); \
frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \
frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \
_frame->addToJavaScriptWindowObject("eth", _eth, QWebFrame::ScriptOwnership); \
_frame->addToJavaScriptWindowObject("p2p", _p2p, QWebFrame::ScriptOwnership); \
_frame->evaluateJavaScript("eth.setCoinbase = function(a, f) { window.setTimeout(function () { eth.coinbase = a; if (f) {f(true);}}, 0); }"); \
_frame->evaluateJavaScript("eth.getCoinbase = function(f) { window.setTimeout(function () { if (f) {f(eth.coinbase);}}, 0); }"); \
_frame->evaluateJavaScript("eth.listening = {get listening() {return p2p.listening}, set listening(l) {p2p.listening = l}}"); \
_frame->evaluateJavaScript("eth.setListening = function(a, f) { window.setTimeout(function () { eth.listening = a; if (f) {f(true);}}, 0); }"); \
_frame->evaluateJavaScript("eth.getListening = function(f) { window.setTimeout(function () { if (f) {f(eth.listening);}}, 0); }"); \
_frame->evaluateJavaScript("eth.setMining = function(a, f) { window.setTimeout(function () { eth.mining = a; if (f) {f(true);}}, 0); }"); \
_frame->evaluateJavaScript("eth.getMining = function(f) { window.setTimeout(function () { if (f) { f(eth.mining);}}, 0); }"); \
_frame->evaluateJavaScript("eth.getGasPrice = function(f) { window.setTimeout(function () { if (f) {f(eth.gasPrice);}}, 0); }"); \
_frame->evaluateJavaScript("eth.getAccounts = function(f) { window.setTimeout(function () { if (f) {f(eth.accounts);}}, 0); }"); \
_frame->evaluateJavaScript("eth.peerCount = {get peerCount() {return p2p.peerCount}}"); \
_frame->evaluateJavaScript("eth.getPeerCount = function(f) { window.setTimeout(function () { if (f) {f(eth.peerCount);}}, 0); }"); \
_frame->evaluateJavaScript("eth.getDefaultBlock = function(f) { window.setTimeout(function () { if (f) {f(eth.defaultBlock);}}, 0); }"); \
_frame->evaluateJavaScript("eth.getNumber = function(f) { window.setTimeout(function () { if (f) {f(eth.number);}}, 0); }"); \
_frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessagesImpl(JSON.stringify(a))); }"); \
_frame->evaluateJavaScript("eth.getMessages = function(a, f) { window.setTimeout(function () { if (f) { f(JSON.parse(eth.getMessagesImpl(JSON.stringify(a)))); }}, 0);}"); \
_frame->evaluateJavaScript("eth.getBalanceAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.balanceAt.apply(null, args)); }},0);}"); \
_frame->evaluateJavaScript("eth.getStateAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.stateAt.apply(null, args)); }},0);}"); \
_frame->evaluateJavaScript("eth.getCountAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.countAt.apply(null, args)); }},0);}"); \
_frame->evaluateJavaScript("eth.getCodeAt = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.codeAt.apply(null, args)); }},0);}"); \
_frame->evaluateJavaScript("eth.transact = function(a) { var ret = eth.doTransactImpl(JSON.stringify(a)); return ret; }"); \
_frame->evaluateJavaScript("eth.doTransact = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.transact.apply(null, args)); }},0);}"); \
_frame->evaluateJavaScript("eth.call = function(a) { var ret = eth.doCallImpl(JSON.stringify(a)); return ret; }"); \
_frame->evaluateJavaScript("eth.doCall = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.call.apply(null, args)); }},0);}"); \
_frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlockImpl(JSON.stringify(a))); }"); \
_frame->evaluateJavaScript("eth.getBlock = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.block.apply(null, args)); }},0);}"); \
_frame->evaluateJavaScript("eth.transaction = function(a, i) { return JSON.parse(eth.getTransactionImpl(JSON.stringify(a), i)); }"); \
_frame->evaluateJavaScript("eth.getTransaction = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.transaction.apply(null, args)); }},0);}"); \
_frame->evaluateJavaScript("eth.uncle = function(a, i) { return JSON.parse(eth.getUncleImpl(JSON.stringify(a), i)); }"); \
_frame->evaluateJavaScript("eth.getUncle = function() { var args = Array.prototype.slice.call(arguments, 0, -1); f = arguments[arguments.length - 1]; window.setTimeout(function () { if (f) { f(eth.uncle.apply(null, args)); }},0);}"); \
_frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \
_frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \
} \
if (shh) \
if (_shh) \
{ \
frame->addToJavaScriptWindowObject("shh", shh, QWebFrame::ScriptOwnership); \
frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \
frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \
_frame->addToJavaScriptWindowObject("shh", _shh, QWebFrame::ScriptOwnership); \
_frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \
_frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \
} \
}

22
libwebthree/WebThree.cpp

@ -51,6 +51,28 @@ WebThreeDirect::WebThreeDirect(std::string const& _clientVersion, std::string co
WebThreeDirect::~WebThreeDirect()
{
// Utterly horrible right now - WebThree owns everything (good), but:
// m_net (Host) owns the eth::EthereumHost via a shared_ptr.
// The eth::EthereumHost depends on eth::Client (it maintains a reference to the BlockChain field of Client).
// eth::Client (owned by us via a unique_ptr) uses eth::EthereumHost (via a weak_ptr).
// Really need to work out a clean way of organising ownership and guaranteeing startup/shutdown is perfect.
// Have to call quit here to get the Host to kill its io_service otherwise we end up with left-over reads,
// still referencing Sessions getting deleted *after* m_ethereum is reset, causing bad things to happen, since
// the guarantee is that m_ethereum is only reset *after* all sessions have ended (sessions are allowed to
// use bits of data owned by m_ethereum).
m_net.quit();
m_ethereum.reset();
}
void WebThreeDirect::setNetworkPreferences(p2p::NetworkPreferences const& _n)
{
auto had = haveNetwork();
if (had)
stopNetwork();
m_net.setNetworkPreferences(_n);
if (had)
startNetwork();
}
std::vector<PeerInfo> WebThreeDirect::peers()

8
libwebthree/WebThree.h

@ -107,7 +107,7 @@ public:
bool haveNetwork() const { return m_net.isStarted(); }
void setNetworkPreferences(p2p::NetworkPreferences const& _n) { auto had = haveNetwork(); if (had) stopNetwork(); m_net.setNetworkPreferences(_n); if (had) startNetwork(); }
void setNetworkPreferences(p2p::NetworkPreferences const& _n);
p2p::NodeId id() const { return m_net.id(); }
@ -126,10 +126,10 @@ public:
private:
std::string m_clientVersion; ///< Our end-application client's name/version.
std::unique_ptr<eth::Client> m_ethereum; ///< Main interface for Ethereum ("eth") protocol.
std::weak_ptr<shh::WhisperHost> m_whisper; ///< Main interface for Whisper ("shh") protocol.
p2p::Host m_net; ///< Should run in background and send us events when blocks found and allow us to send blocks as required.
std::unique_ptr<eth::Client> m_ethereum; ///< Main interface for Ethereum ("eth") protocol.
std::weak_ptr<shh::WhisperHost> m_whisper; ///< Main interface for Whisper ("shh") protocol.
};

7
test/CMakeLists.txt

@ -1,6 +1,7 @@
cmake_policy(SET CMP0015 NEW)
aux_source_directory(. SRC_LIST)
list(REMOVE_ITEM SRC_LIST "./createRandomTest.cpp")
include_directories(..)
link_directories(../libethcore)
@ -8,6 +9,7 @@ link_directories(../libethereum)
file(GLOB HEADERS "*.h")
add_executable(testeth ${SRC_LIST} ${HEADERS})
add_executable(createRandomTest createRandomTest.cpp vm.cpp)
target_link_libraries(testeth ethereum)
target_link_libraries(testeth ethcore)
@ -20,6 +22,11 @@ if(JSONRPC_LS)
target_link_libraries(testeth ethrpc)
endif()
target_link_libraries(createRandomTest ethereum)
target_link_libraries(createRandomTest ethcore)
target_link_libraries(createRandomTest boost_chrono)
target_link_libraries(createRandomTest boost_unit_test_framework)
if ("${TARGET_PLATFORM}" STREQUAL "w64")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
target_link_libraries(testeth boost_system-mt-s)

152
test/createRandomTest.cpp

@ -0,0 +1,152 @@
/*
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 createRandomTest.cpp
* @author Christoph Jentzsch <jentzsch.simulationsoftware@gmail.com>
* @date 2014
* Creating a random virtual machine test.
*/
#include <string>
#include <iostream>
#include <chrono>
#include <boost/random.hpp>
#include <boost/filesystem/path.hpp>
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <json_spirit/json_spirit.h>
#include <json_spirit/json_spirit_reader_template.h>
#include <json_spirit/json_spirit_writer_template.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h>
#include <libevmface/Instruction.h>
#include "vm.h"
using namespace std;
using namespace json_spirit;
using namespace dev;
void doMyTests(json_spirit::mValue& v);
int main(int argc, char *argv[])
{
if (argc != 2)
{
cout << "usage: createRandomTest <filename>\n";
return 0;
}
// create random code
boost::random::mt19937 gen;
auto now = chrono::steady_clock::now().time_since_epoch();
auto timeSinceEpoch = chrono::duration_cast<chrono::nanoseconds>(now).count();
gen.seed(static_cast<unsigned int>(timeSinceEpoch));
boost::random::uniform_int_distribution<> lengthOfCodeDist(2, 16);
boost::random::uniform_int_distribution<> opcodeDist(0, 255);
boost::random::variate_generator<boost::mt19937&,
boost::random::uniform_int_distribution<> > randGen(gen, opcodeDist);
int lengthOfCode = lengthOfCodeDist(gen);
string randomCode;
for (int i = 0; i < lengthOfCode; ++i)
randomCode += toHex(toCompactBigEndian(randGen()));
// read template test file
mValue v;
boost::filesystem::path p(__FILE__);
boost::filesystem::path dir = p.parent_path();
string s = asString(contents(dir.string() + "/randomTestFiller.json"));
read_string(s, v);
// insert new random code
v.get_obj().find("randomVMtest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode;
// execute code in vm
doMyTests(v);
// write new test
string filename = argv[1];
writeFile(filename, asBytes(json_spirit::write_string(v, true)));
return 0;
}
void doMyTests(json_spirit::mValue& v)
{
for (auto& i: v.get_obj())
{
mObject& o = i.second.get_obj();
assert(o.count("env") > 0);
assert(o.count("pre") > 0);
assert(o.count("exec") > 0);
eth::VM vm;
test::FakeExtVM fev;
fev.importEnv(o["env"].get_obj());
fev.importState(o["pre"].get_obj());
o["pre"] = mValue(fev.exportState());
fev.importExec(o["exec"].get_obj());
if (!fev.code)
{
fev.thisTxCode = get<3>(fev.addresses.at(fev.myAddress));
fev.code = &fev.thisTxCode;
}
vm.reset(fev.gas);
bytes output;
try
{
output = vm.go(fev).toBytes();
}
catch (Exception const& _e)
{
cnote << "VM did throw an exception: " << diagnostic_information(_e);
}
catch (std::exception const& _e)
{
cnote << "VM did throw an exception: " << _e.what();
}
// delete null entries in storage for the sake of comparison
for (auto &a: fev.addresses)
{
vector<u256> keystoDelete;
for (auto &s: get<2>(a.second))
{
if (s.second == 0)
keystoDelete.push_back(s.first);
}
for (auto const key: keystoDelete )
{
get<2>(a.second).erase(key);
}
}
o["env"] = mValue(fev.exportEnv());
o["exec"] = mValue(fev.exportExec());
o["post"] = mValue(fev.exportState());
o["callcreates"] = fev.exportCallCreates();
o["out"] = "0x" + toHex(output);
fev.push(o, "gas", vm.gas());
}
}

29
test/randomTestFiller.json

@ -0,0 +1,29 @@
{
"randomVMtest": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "random",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
}
}

63
test/vm.cpp

@ -22,6 +22,7 @@
#include "vm.h"
#include <libdevcore/CommonIO.h>
#include <boost/filesystem/path.hpp>
#define FILL_TESTS
@ -97,7 +98,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
{
cnote << "not able to call to : " << myAddress << "\n";
cnote << "in FakeExtVM you can only make a call to " << na << "\n";
BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(myAddress));
BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(toString(myAddress)));
return false;
}
}
@ -123,7 +124,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
{
cnote << "not able to call to : " << (_codeAddressOverride ? _codeAddressOverride : _receiveAddress) << "\n";
cnote << "in FakeExtVM you can only make a call to " << na << "\n";
BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress));
BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(toString(_codeAddressOverride ? _codeAddressOverride : _receiveAddress)));
return false;
}
}
@ -251,12 +252,13 @@ mObject FakeExtVM::exportEnv()
void FakeExtVM::importEnv(mObject& _o)
{
BOOST_REQUIRE(_o.count("previousHash") > 0);
BOOST_REQUIRE(_o.count("currentGasLimit") > 0);
BOOST_REQUIRE(_o.count("currentDifficulty") > 0);
BOOST_REQUIRE(_o.count("currentTimestamp") > 0);
BOOST_REQUIRE(_o.count("currentCoinbase") > 0);
BOOST_REQUIRE(_o.count("currentNumber") > 0);
// cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest)
assert(_o.count("previousHash") > 0);
assert(_o.count("currentGasLimit") > 0);
assert(_o.count("currentDifficulty") > 0);
assert(_o.count("currentTimestamp") > 0);
assert(_o.count("currentCoinbase") > 0);
assert(_o.count("currentNumber") > 0);
previousBlock.hash = h256(_o["previousHash"].get_str());
currentBlock.number = toInt(_o["currentNumber"]);
@ -293,10 +295,11 @@ void FakeExtVM::importState(mObject& _object)
for (auto const& i: _object)
{
mObject o = i.second.get_obj();
BOOST_REQUIRE(o.count("balance") > 0);
BOOST_REQUIRE(o.count("nonce") > 0);
BOOST_REQUIRE(o.count("storage") > 0);
BOOST_REQUIRE(o.count("code") > 0);
// cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest)
assert(o.count("balance") > 0);
assert(o.count("nonce") > 0);
assert(o.count("storage") > 0);
assert(o.count("code") > 0);
auto& a = addresses[Address(i.first)];
get<0>(a) = toInt(o["balance"]);
@ -334,13 +337,14 @@ mObject FakeExtVM::exportExec()
void FakeExtVM::importExec(mObject& _o)
{
BOOST_REQUIRE(_o.count("address")> 0);
BOOST_REQUIRE(_o.count("caller") > 0);
BOOST_REQUIRE(_o.count("origin") > 0);
BOOST_REQUIRE(_o.count("value") > 0);
BOOST_REQUIRE(_o.count("data") > 0);
BOOST_REQUIRE(_o.count("gasPrice") > 0);
BOOST_REQUIRE(_o.count("gas") > 0);
// cant use BOOST_REQUIRE, because this function is used outside boost test (createRandomTest)
assert(_o.count("address")> 0);
assert(_o.count("caller") > 0);
assert(_o.count("origin") > 0);
assert(_o.count("value") > 0);
assert(_o.count("data") > 0);
assert(_o.count("gasPrice") > 0);
assert(_o.count("gas") > 0);
myAddress = Address(_o["address"].get_str());
caller = Address(_o["caller"].get_str());
@ -611,16 +615,29 @@ void doTests(json_spirit::mValue& v, bool _fillin)
void executeTests(const string& _name)
{
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
string testPath;
if (ptestPath == NULL)
{
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests/vmtests";
}
else
testPath = ptestPath;
#ifdef FILL_TESTS
try
{
cnote << "Populating VM tests...";
json_spirit::mValue v;
string s = asString(contents("../../../cpp-ethereum/test/" + _name + "Filler.json"));
boost::filesystem::path p(__FILE__);
boost::filesystem::path dir = p.parent_path();
string s = asString(contents(dir.string() + "/" + _name + "Filler.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + "Filler.json is empty.");
json_spirit::read_string(s, v);
dev::test::doTests(v, true);
writeFile("../../../tests/vmtests/" + _name + ".json", asBytes(json_spirit::write_string(v, true)));
writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true)));
}
catch (Exception const& _e)
{
@ -636,8 +653,8 @@ void executeTests(const string& _name)
{
cnote << "Testing VM..." << _name;
json_spirit::mValue v;
string s = asString(contents("../../../tests/vmtests/" + _name + ".json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + ".json is empty. Have you cloned the 'tests' repo branch develop?");
string s = asString(contents(testPath + "/" + _name + ".json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
json_spirit::read_string(s, v);
dev::test::doTests(v, false);
}

85
test/vmArithmeticTestFiller.json

@ -281,6 +281,91 @@
}
},
"mul4": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (* 0x8000000000000000000000000000000000000000000000000000000000000000 115792089237316195423570985008687907853269984665640564039457584007913129639935) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mul5": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (* 0x8000000000000000000000000000000000000000000000000000000000000000 0x8000000000000000000000000000000000000000000000000000000000000000) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mul6": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ [[ 0 ]] (* 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"sub0": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

83
test/vmIOandFlowOperationsTestFiller.json

@ -530,6 +530,61 @@
"gas" : "10000"
}
},
"jump0_jumpdest0": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "0x602360085860015d600257",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"jump0_jumpdest1": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "0x602360075860015d600257",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"jumpi0": {
"env" : {
@ -559,6 +614,34 @@
}
},
"jumpi1_jumpdest": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "0x60236001600a5960015d600257",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"jumpi1": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

100
test/vmSystemOperationsTestFiller.json

@ -129,7 +129,7 @@
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -255,6 +255,42 @@
}
},
"callcodeToReturn1": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLCODE 500 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 0 2 ) }",
"storage": {}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x6001600157603760005560026000f2",
"nonce" : "0",
"storage" : {
}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "100000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000000000000"
}
},
"CallToNameRegistratorOutOfGas": {
"env" : {
@ -274,7 +310,7 @@
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -310,7 +346,7 @@
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -346,7 +382,7 @@
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -382,7 +418,7 @@
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -419,7 +455,7 @@
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -455,7 +491,7 @@
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -525,7 +561,7 @@
},
"cd1722f3947def4cf144679da39c4c32bdc35681" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -561,7 +597,7 @@
},
"cd1722f3947def4cf144679da39c4c32bdc35681" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -597,7 +633,7 @@
},
"cd1722f3947def4cf144679da39c4c32bdc35681" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -723,7 +759,7 @@
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -759,7 +795,43 @@
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "100000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000000000000"
}
},
"callcodeToNameRegistrator0": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) (MSTORE 32 0xaaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa ) [[ 0 ]] (CALLCODE 1000000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 23 0 64 64 0) }",
"storage": {}
},
"945304eb96065b2a98b57a48a06ae28d285a71b5" : {
"balance" : "23",
"code" : "0x600035560f600a59005d60203560003557",
"nonce" : "0",
"storage" : {
}
@ -790,7 +862,7 @@
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : 0,
"code" : "0x600035560f6009590060203560003557",
"code" : "0x600035560f600a59005d60203560003557",
"storage": {}
}
},
@ -841,7 +913,7 @@
}
},
"ABAcalls0": {
"ABAcalls1": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",

4
third/MainWin.cpp

@ -105,16 +105,18 @@ Main::Main(QWidget *parent) :
connect(ui->webView, &QWebView::loadStarted, [this]()
{
// NOTE: no need to delete as QETH_INSTALL_JS_NAMESPACE adopts it.
m_dev = new QDev(this);
m_ethereum = new QEthereum(this, ethereum(), owned());
m_whisper = new QWhisper(this, whisper());
m_p2p = new QPeer2Peer(this, peer2peer());
QWebFrame* f = ui->webView->page()->mainFrame();
f->disconnect(SIGNAL(javaScriptWindowObjectCleared()));
auto qdev = m_dev;
auto qeth = m_ethereum;
auto qshh = m_whisper;
auto qp2p = m_p2p;
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, qeth, qshh, qp2p, this));
connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh, qp2p));
});
connect(ui->webView, &QWebView::loadFinished, [=]()

1
third/MainWin.h

@ -133,6 +133,7 @@ private:
QNetworkAccessManager m_webCtrl;
QDev* m_dev = nullptr;
QEthereum* m_ethereum = nullptr;
QWhisper* m_whisper = nullptr;
QPeer2Peer* m_p2p = nullptr;

Loading…
Cancel
Save