Browse Source

Merge remote-tracking branch 'upstream/develop' into addTests

cl-refactor
CJentzsch 10 years ago
parent
commit
b9c38b42ab
  1. 9
      CMakeLists.txt
  2. 24
      alethzero/DappLoader.cpp
  3. 9
      alethzero/Main.ui
  4. 23
      alethzero/MainWin.cpp
  5. 4
      cmake/EthDependencies.cmake
  6. 2
      libdevcore/Common.cpp
  7. 3
      libethcore/Common.h
  8. 68
      libethereum/BlockChain.cpp
  9. 10
      libethereum/BlockChain.h
  10. 44
      libethereum/BlockQueue.cpp
  11. 14
      libethereum/BlockQueue.h
  12. 26
      libethereum/Client.cpp
  13. 2
      libethereum/Client.h
  14. 1
      libethereum/ClientBase.h
  15. 19
      libethereum/EthereumHost.cpp
  16. 13
      libethereum/EthereumPeer.cpp
  17. 5
      libethereum/EthereumPeer.h
  18. 2
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  19. 2
      mix/CMakeLists.txt
  20. 6
      mix/ClientModel.cpp
  21. 3
      mix/ClientModel.h
  22. 5
      mix/ContractCallDataEncoder.cpp
  23. 8
      mix/ContractCallDataEncoder.h
  24. 1
      mix/FileIo.cpp
  25. 5
      mix/MixApplication.cpp
  26. 84
      mix/Web3Server.cpp
  27. 2
      mix/Web3Server.h
  28. 23
      mix/qml/DeploymentDialog.qml
  29. 4
      mix/qml/LogsPane.qml
  30. 2
      mix/qml/ProjectModel.qml
  31. 6
      mix/qml/StatusPane.qml
  32. 1
      mix/qml/WebPreview.qml
  33. 42
      mix/qml/js/ProjectModel.js
  34. 16
      mix/qml/js/QEtherHelper.js

9
CMakeLists.txt

@ -190,12 +190,13 @@ else ()
set(SOLIDITY OFF)
endif()
if (SERPENT)
set(SERPENT ON)
set(SERPENT ${DECENT_PLATFORM})
else ()
set(SERPENT OFF)
endif()
if (GUI)
set(GUI ON)
set(JSONRPC ON)
else ()
set(GUI OFF)
endif ()
@ -215,7 +216,7 @@ else ()
set(ETHASHCL OFF)
endif()
if (NCURSES)
set(NCURSES ON)
set(NCURSES ${DECENT_PLATFORM})
else ()
set(NCURSES OFF)
endif ()
@ -229,7 +230,7 @@ if (BUNDLE STREQUAL "minimal")
set(TOOLS ON)
set(TESTS OFF)
elseif (BUNDLE STREQUAL "full")
set(SERPENT ON)
set(SERPENT ${DECENT_PLATFORM})
set(SOLIDITY ON)
set(USENPM ON)
set(GUI ON)
@ -238,7 +239,7 @@ elseif (BUNDLE STREQUAL "full")
set(TESTS ON)
set(FATDB ON)
elseif (BUNDLE STREQUAL "tests")
set(SERPENT ON)
set(SERPENT ${DECENT_PLATFORM})
set(SOLIDITY ON)
set(USENPM OFF)
set(GUI OFF)

24
alethzero/DappLoader.cpp

@ -193,10 +193,26 @@ Manifest DappLoader::loadManifest(std::string const& _manifest)
void DappLoader::loadDapp(QString const& _uri)
{
DappLocation location = resolveAppUri(_uri);
QUrl uri(location.contentUri);
QNetworkRequest request(uri);
m_uriHashes[uri] = location.contentHash;
QUrl uri(_uri);
QUrl contentUri;
h256 hash;
if (uri.path().endsWith(".dapp") && uri.query().startsWith("hash="))
{
contentUri = uri;
QString query = uri.query();
query.remove("hash=");
if (!query.startsWith("0x"))
query.insert(0, "0x");
hash = jsToFixed<32>(query.toStdString());
}
else
{
DappLocation location = resolveAppUri(_uri);
contentUri = location.contentUri;
hash = location.contentHash;
}
QNetworkRequest request(contentUri);
m_uriHashes[uri] = hash;
m_net.get(request);
}

9
alethzero/Main.ui

@ -45,6 +45,13 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="chainStatus">
<property name="text">
<string>#0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="balance">
<property name="text">
@ -118,7 +125,7 @@
<x>0</x>
<y>0</y>
<width>1617</width>
<height>22</height>
<height>24</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">

23
alethzero/MainWin.cpp

@ -161,8 +161,11 @@ Main::Main(QWidget *parent) :
statusBar()->addPermanentWidget(ui->balance);
statusBar()->addPermanentWidget(ui->peerCount);
statusBar()->addPermanentWidget(ui->mineStatus);
statusBar()->addPermanentWidget(ui->chainStatus);
statusBar()->addPermanentWidget(ui->blockCount);
ui->blockCount->setText(QString("PV%2 D%3 H%4 v%5").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(c_ethashVersion).arg(dev::Version));
connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved()));
QSettings s("ethereum", "alethzero");
@ -301,16 +304,25 @@ unsigned Main::installWatch(dev::h256 _tf, WatchHandler const& _f)
void Main::uninstallWatch(unsigned _w)
{
cdebug << "!!! Main: uninstalling watch" << _w;
ethereum()->uninstallWatch(_w);
m_handlers.erase(_w);
}
void Main::installWatches()
{
auto newBlockId = installWatch(ChainChangedFilter, [=](LocalisedLogEntries const&){
onNewBlock();
});
auto newPendingId = installWatch(PendingChangedFilter, [=](LocalisedLogEntries const&){
onNewPending();
});
cdebug << "newBlock watch ID: " << newBlockId;
cdebug << "newPending watch ID: " << newPendingId;
installWatch(LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installNameRegWatch(); });
installWatch(LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installCurrenciesWatch(); });
installWatch(PendingChangedFilter, [=](LocalisedLogEntries const&){ onNewPending(); });
installWatch(ChainChangedFilter, [=](LocalisedLogEntries const&){ onNewBlock(); });
}
Address Main::getNameReg() const
@ -900,7 +912,7 @@ void Main::on_urlEdit_returnPressed()
{
QString s = ui->urlEdit->text();
QUrl url(s);
if (url.scheme().isEmpty() || url.scheme() == "eth")
if (url.scheme().isEmpty() || url.scheme() == "eth" || url.path().endsWith(".dapp"))
{
try
{
@ -1089,9 +1101,9 @@ void Main::refreshAccounts()
void Main::refreshBlockCount()
{
cwatch << "refreshBlockCount()";
auto d = ethereum()->blockChain().details();
ui->blockCount->setText(QString("%4 #%1 PV%2 D%3 H%5").arg(d.number).arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(c_ethashVersion));
BlockQueueStatus b = ethereum()->blockQueueStatus();
ui->chainStatus->setText(QString("%3 ready %4 future %5 unknown %6 bad %1 #%2").arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.ready).arg(b.future).arg(b.unknown).arg(b.bad));
}
void Main::on_turboMining_triggered()
@ -1270,6 +1282,7 @@ void Main::timerEvent(QTimerEvent*)
refreshNetwork();
refreshWhispers();
refreshCache();
refreshBlockCount();
poll();
}
else

4
cmake/EthDependencies.cmake

@ -101,7 +101,7 @@ find_program(ETH_JSON_RPC_STUB jsonrpcstub)
message(" - jsonrpcstub location : ${ETH_JSON_RPC_STUB}")
# do not compile GUI
if (NOT HEADLESS)
if (GUI)
# we need json rpc to build alethzero
if (NOT JSON_RPC_CPP_FOUND)
@ -153,7 +153,7 @@ if (NOT HEADLESS)
endif()
endif()
endif() #HEADLESS
endif() #GUI
# use multithreaded boost libraries, with -mt suffix
set(Boost_USE_MULTITHREADED ON)

2
libdevcore/Common.cpp

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

3
libethcore/Common.h

@ -92,7 +92,8 @@ enum class ImportResult
FutureTime,
AlreadyInChain,
AlreadyKnown,
Malformed
Malformed,
BadChain
};
}

68
libethereum/BlockChain.cpp

@ -306,39 +306,49 @@ LastHashes BlockChain::lastHashes(unsigned _n) const
return m_lastLastHashes;
}
pair<h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max)
tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max)
{
_bq.tick(*this);
vector<bytes> blocks;
_bq.drain(blocks, _max);
h256s ret;
h256s fresh;
h256s dead;
h256s badBlocks;
for (auto const& block: blocks)
{
try
{
for (auto h: import(block, _stateDB))
ret.push_back(h);
auto r = import(block, _stateDB);
bool isOld = true;
for (auto const& h: r.first)
if (h == r.second)
isOld = false;
else if (isOld)
dead.push_back(h);
else
fresh.push_back(h);
}
catch (UnknownParent)
{
cwarn << "Unknown parent of block!!!" << BlockInfo::headerHash(block).abridged() << boost::current_exception_diagnostic_information();
_bq.import(&block, *this);
cwarn << "ODD: Import queue contains block with unknown parent." << boost::current_exception_diagnostic_information();
// NOTE: don't reimport since the queue should guarantee everything in the right order.
// Can't continue - chain bad.
badBlocks.push_back(BlockInfo::headerHash(block));
}
catch (Exception const& _e)
{
cwarn << "Unexpected exception!" << diagnostic_information(_e);
_bq.import(&block, *this);
cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << diagnostic_information(_e);
// NOTE: don't reimport since the queue should guarantee everything in the right order.
// Can't continue - chain bad.
badBlocks.push_back(BlockInfo::headerHash(block));
}
catch (...)
{}
}
bool yetMore = _bq.doneDrain();
return make_pair(ret, yetMore);
return make_tuple(fresh, dead, _bq.doneDrain(badBlocks));
}
h256s BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _force) noexcept
pair<h256s, h256> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _force) noexcept
{
try
{
@ -347,11 +357,11 @@ h256s BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB,
catch (...)
{
cwarn << "Unexpected exception! Could not import block!" << boost::current_exception_diagnostic_information();
return h256s();
return make_pair(h256s(), h256());
}
}
h256s BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force)
pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force)
{
//@tidy This is a behemoth of a method - could do to be split into a few smaller ones.
@ -532,14 +542,14 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force)
);
// cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children.";
h256s ret;
h256s route;
h256 common;
// This might be the new best block...
h256 last = currentHash();
if (td > details(last).totalDifficulty)
{
h256 common;
unsigned commonIndex;
tie(ret, common, commonIndex) = treeRoute(last, newHash);
tie(route, common, commonIndex) = treeRoute(last, newHash);
{
WriteGuard l(x_lastBlockHash);
m_lastBlockHash = newHash;
@ -554,7 +564,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force)
clearBlockBlooms(number(common) + 1, number(last) + 1);
// Go through ret backwards until hash != last.parent and update m_transactionAddresses, m_blockHashes
for (auto i = ret.rbegin(); i != ret.rend() && *i != common; ++i)
for (auto i = route.rbegin(); i != route.rend() && *i != common; ++i)
{
auto b = block(*i);
BlockInfo bi(b);
@ -606,7 +616,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force)
m_extrasDB->Put(m_writeOptions, toSlice(h, ExtraTransactionAddress), (ldb::Slice)dev::ref(m_transactionAddresses[h].rlp()));
}
clog(BlockChainNote) << " Imported and best" << td << ". Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(ret);
clog(BlockChainNote) << " Imported and best" << td << ". Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(route);
noteCanonChanged();
StructuredLogger::chainNewHead(
@ -631,7 +641,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force)
cnote << "checkBest:" << checkBest;
#endif
return ret;
return make_pair(route, common);
}
void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end)
@ -704,21 +714,21 @@ tuple<h256s, h256, unsigned> BlockChain::treeRoute(h256 const& _from, h256 const
tn--;
// cdebug << "to:" << tn << _to.abridged();
}
while (from != to)
for (;; from = details(from).parent, to = details(to).parent)
{
if (!from)
assert(from);
if (!to)
assert(to);
from = details(from).parent;
to = details(to).parent;
if (_pre && (from != to || _common))
ret.push_back(from);
if (_post && (from != to || (!_pre && _common)))
back.push_back(to);
fn--;
tn--;
// cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged();
// cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged();
if (from == to)
break;
if (!from)
assert(from);
if (!to)
assert(to);
}
ret.reserve(ret.size() + back.size());
unsigned i = ret.size() - (int)(_common && !ret.empty() && !back.empty());

10
libethereum/BlockChain.h

@ -100,15 +100,15 @@ public:
void process();
/// Sync the chain with any incoming blocks. All blocks should, if processed in order
std::pair<h256s, bool> sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max);
std::tuple<h256s, h256s, bool> sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max);
/// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB.
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
h256s attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _force = false) noexcept;
std::pair<h256s, h256> attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _force = false) noexcept;
/// Import block into disk-backed DB
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
h256s import(bytes const& _block, OverlayDB const& _stateDB, bool _force = false);
std::pair<h256s, h256> import(bytes const& _block, OverlayDB const& _stateDB, bool _force = false);
/// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 const& _hash) const;
@ -178,6 +178,10 @@ public:
bytes transaction(h256 const& _blockHash, unsigned _i) const { bytes b = block(_blockHash); return RLP(b)[1][_i].data().toBytes(); }
bytes transaction(unsigned _i) const { return transaction(currentHash(), _i); }
/// Get all transactions from a block.
std::vector<bytes> transactions(h256 const& _blockHash) const { bytes b = block(_blockHash); std::vector<bytes> ret; for (auto const& i: RLP(b)[1]) ret.push_back(i.data().toBytes()); return ret; }
std::vector<bytes> transactions() const { return transactions(currentHash()); }
/// Get a number for the given hash (or the most recent mined if none given). Thread-safe.
unsigned number(h256 const& _hash) const { return details(_hash).number; }
unsigned number() const { return number(currentHash()); }

44
libethereum/BlockQueue.cpp

@ -38,7 +38,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
UpgradableGuard l(m_lock);
if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h))
if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h) || m_knownBad.count(h))
{
// Already know about this one.
cblockq << "Already known.";
@ -48,20 +48,17 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
// VERIFY: populates from the block and checks the block is internally coherent.
BlockInfo bi;
#if ETH_CATCH
try
#endif
{
// TODO: quick verify
bi.populate(_block);
bi.verifyInternals(_block);
}
#if ETH_CATCH
catch (Exception const& _e)
{
cwarn << "Ignoring malformed block: " << diagnostic_information(_e);
return ImportResult::Malformed;
}
#endif
// Check block doesn't already exist first!
if (_bc.details(h))
@ -82,7 +79,13 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
else
{
// We now know it.
if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash))
if (m_knownBad.count(bi.parentHash))
{
m_knownBad.insert(bi.hash());
// bad parent; this is bad too, note it as such
return ImportResult::BadChain;
}
else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash))
{
// We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on.
cblockq << "OK - queued as unknown parent:" << bi.parentHash.abridged();
@ -104,6 +107,35 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
}
}
namespace dev {
template <class T, class U> std::set<T>& operator+=(std::set<T>& _a, U const& _b)
{
for (auto const& i: _b)
_a.insert(i);
return _a;
} }
bool BlockQueue::doneDrain(h256s const& _bad)
{
WriteGuard l(m_lock);
m_drainingSet.clear();
if (_bad.size())
{
vector<bytes> old;
swap(m_ready, old);
for (auto& b: old)
{
BlockInfo bi(b);
if (m_knownBad.count(bi.parentHash))
m_knownBad.insert(bi.hash());
else
m_ready.push_back(std::move(b));
}
}
m_knownBad += _bad;
return !m_readySet.empty();
}
void BlockQueue::tick(BlockChain const& _bc)
{
unsigned t = time(0);

14
libethereum/BlockQueue.h

@ -38,6 +38,14 @@ class BlockChain;
struct BlockQueueChannel: public LogChannel { static const char* name() { return "[]Q"; } static const int verbosity = 4; };
#define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>()
struct BlockQueueStatus
{
size_t ready;
size_t future;
size_t unknown;
size_t bad;
};
/**
* @brief A queue of blocks. Sits between network or other I/O and the BlockChain.
* Sorts them ready for blockchain insertion (with the BlockChain::sync() method).
@ -58,7 +66,7 @@ public:
/// Must be called after a drain() call. Notes that the drained blocks have been imported into the blockchain, so we can forget about them.
/// @returns true iff there are additional blocks ready to be processed.
bool doneDrain() { WriteGuard l(m_lock); m_drainingSet.clear(); return !m_readySet.empty(); }
bool doneDrain(h256s const& _knownBad = h256s());
/// Notify the queue that the chain has changed and a new block has attained 'ready' status (i.e. is in the chain).
void noteReady(h256 _b) { WriteGuard l(m_lock); noteReadyWithoutWriteGuard(_b); }
@ -72,6 +80,9 @@ public:
/// Return first block with an unknown parent.
h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); }
/// Get some infomration on the current status.
BlockQueueStatus status() const { ReadGuard l(m_lock); return BlockQueueStatus{m_ready.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; }
private:
void noteReadyWithoutWriteGuard(h256 _b);
void notePresentWithoutWriteGuard(bytesConstRef _block);
@ -83,6 +94,7 @@ private:
std::set<h256> m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain.
std::multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For transactions that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
std::multimap<unsigned, bytes> m_future; ///< Set of blocks that are not yet valid.
std::set<h256> m_knownBad; ///< Set of blocks that we know will never be valid.
};
}

26
libethereum/Client.cpp

@ -453,6 +453,7 @@ void Client::doWork()
// TODO: enable a short-circuit option since we mined it. will need to get the end state from the miner.
auto lm = dynamic_cast<LocalMiner*>(&m);
h256s hs;
h256 c;
if (false && lm && !m_verifyOwnBlocks)
{
// TODO: implement
@ -463,12 +464,13 @@ void Client::doWork()
{
cwork << "CHAIN <== postSTATE";
WriteGuard l(x_stateDB);
hs = m_bc.attemptImport(m.blockData(), m_stateDB);
tie(hs, c) = m_bc.attemptImport(m.blockData(), m_stateDB);
}
if (hs.size())
{
for (auto const& h: hs)
appendFromNewBlock(h, changeds);
if (h != c)
appendFromNewBlock(h, changeds);
changeds.insert(ChainChangedFilter);
}
for (auto& m: m_localMiners)
@ -498,18 +500,28 @@ void Client::doWork()
cwork << "BQ ==> CHAIN ==> STATE";
OverlayDB db = m_stateDB;
x_stateDB.unlock();
h256s newBlocks;
h256s fresh;
h256s dead;
bool sgw;
tie(newBlocks, sgw) = m_bc.sync(m_bq, db, 100); // TODO: remove transactions from m_tq nicely rather than relying on out of date nonce later on.
tie(fresh, dead, sgw) = m_bc.sync(m_bq, db, 100);
// TODO: remove transactions from m_tq nicely rather than relying on out of date nonce later on.
for (auto const& h: dead)
for (auto const& t: m_bc.transactions(h))
m_tq.import(t);
for (auto const& h: fresh)
for (auto const& th: m_bc.transactionHashes(h))
m_tq.drop(th);
stillGotWork = stillGotWork | sgw;
if (newBlocks.size())
if (!fresh.empty())
{
for (auto i: newBlocks)
for (auto i: fresh)
appendFromNewBlock(i, changeds);
changeds.insert(ChainChangedFilter);
}
x_stateDB.lock();
if (newBlocks.size())
if (fresh.size())
m_stateDB = db;
cwork << "preSTATE <== CHAIN";

2
libethereum/Client.h

@ -168,6 +168,8 @@ public:
dev::eth::State postState() const { ReadGuard l(x_stateDB); return m_postMine; }
/// Get the object representing the current canonical blockchain.
CanonBlockChain const& blockChain() const { return m_bc; }
/// Get some information on the block queue.
BlockQueueStatus blockQueueStatus() const { return m_bq.status(); }
// Mining stuff:

1
libethereum/ClientBase.h

@ -108,6 +108,7 @@ public:
virtual LocalisedLogEntries peekWatch(unsigned _watchId) const override;
virtual LocalisedLogEntries checkWatch(unsigned _watchId) override;
// TODO: switch all the _blockHash arguments to also accept _blockNumber
virtual h256 hashFromNumber(unsigned _number) const override;
virtual eth::BlockInfo blockInfo(h256 _hash) const override;
virtual eth::BlockDetails blockDetails(h256 _hash) const override;

19
libethereum/EthereumHost.cpp

@ -162,6 +162,11 @@ void EthereumHost::doWork()
maintainTransactions();
maintainBlocks(h);
}
for (auto p: peerSessions())
if (shared_ptr<EthereumPeer> const& ep = p.first->cap<EthereumPeer>())
ep->tick();
// return netChange;
// TODO: Figure out what to do with netChange.
(void)netChange;
@ -201,16 +206,22 @@ void EthereumHost::maintainBlocks(h256 _currentHash)
{
clog(NetMessageSummary) << "Sending a new block (current is" << _currentHash << ", was" << m_latestBlockSent << ")";
for (auto j: peerSessions())
std::vector<std::shared_ptr<EthereumPeer>> dispersal;
for (auto const& j: peerSessions())
if (!j.first->cap<EthereumPeer>()->m_knownBlocks.count(_currentHash))
dispersal.push_back(j.first->cap<EthereumPeer>());
for (unsigned i = (dispersal.size() + 3) / 4; i--;)
{
auto p = j.first->cap<EthereumPeer>().get();
unsigned n = rand() % dispersal.size();
auto p = std::move(dispersal[n]);
dispersal.erase(dispersal.begin() + n);
RLPStream ts;
p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(), 1).append(m_chain.details().totalDifficulty);
Guard l(p->x_knownBlocks);
if (!p->m_knownBlocks.count(_currentHash))
p->sealAndSend(ts);
p->sealAndSend(ts);
p->m_knownBlocks.clear();
}
m_latestBlockSent = _currentHash;

13
libethereum/EthereumPeer.cpp

@ -220,6 +220,8 @@ void EthereumPeer::setAsking(Asking _a, bool _isSyncing)
m_syncingNeededBlocks.clear();
}
m_lastAsk = chrono::system_clock::now();
session()->addNote("ask", _a == Asking::Nothing ? "nothing" : _a == Asking::State ? "state" : _a == Asking::Hashes ? "hashes" : _a == Asking::Blocks ? "blocks" : "?");
session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : ""));
}
@ -235,6 +237,13 @@ void EthereumPeer::setNeedsSyncing(h256 _latestHash, u256 _td)
session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : ""));
}
void EthereumPeer::tick()
{
if (chrono::system_clock::now() - m_lastAsk > chrono::seconds(10) && m_asking != Asking::Nothing)
// timeout
session()->disconnect(PingTimeout);
}
bool EthereumPeer::isSyncing() const
{
return host()->m_syncer == this;
@ -451,6 +460,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
break;
case ImportResult::Malformed:
case ImportResult::BadChain:
disable("Malformed block received.");
return true;
@ -505,8 +515,9 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
break;
case ImportResult::Malformed:
case ImportResult::BadChain:
disable("Malformed block received.");
break;
return true;
case ImportResult::AlreadyInChain:
case ImportResult::AlreadyKnown:

5
libethereum/EthereumPeer.h

@ -105,6 +105,9 @@ private:
/// Check whether the session should bother grabbing the peer's blocks.
bool shouldGrabBlocks() const;
/// Runs period checks to check up on the peer.
void tick();
/// Peer's protocol version.
unsigned m_protocolVersion;
/// Peer's network id.
@ -112,6 +115,8 @@ private:
/// What, if anything, we last asked the other peer for.
Asking m_asking = Asking::Nothing;
/// When we asked for it. Allows a time out.
std::chrono::system_clock::time_point m_lastAsk;
/// Whether this peer is in the process of syncing or not. Only one peer can be syncing at once.
bool m_isSyncing = false;

2
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -385,7 +385,7 @@ string WebThreeStubServerBase::eth_getBlockTransactionCountByNumber(string const
{
try
{
return toJS(client()->transactionCount(client()->hashFromNumber(toBlockNumber(_blockNumber))));
return toJS(_blockNumber == "pending" ? client()->pending().size() : client()->transactionCount(client()->hashFromNumber(toBlockNumber(_blockNumber))));
}
catch (...)
{

2
mix/CMakeLists.txt

@ -29,7 +29,7 @@ else()
qt5_add_resources(UI_RESOURCES noweb.qrc)
endif()
if (CMAKE_BUILD_TYPE EQUAL "DEBUG")
if (CMAKE_BUILD_TYPE MATCHES Debug)
add_definitions(-DQT_QML_DEBUG)
endif()

6
mix/ClientModel.cpp

@ -139,6 +139,12 @@ QString ClientModel::newAddress()
return QString::fromStdString(toHex(a.secret().ref()));
}
QString ClientModel::encodeAbiString(QString _string)
{
ContractCallDataEncoder encoder;
return QString::fromStdString(toHex(encoder.encodeBytes(_string)));
}
QVariantMap ClientModel::contractAddresses() const
{
QVariantMap res;

3
mix/ClientModel.h

@ -155,7 +155,10 @@ public slots:
Q_INVOKABLE void debugRecord(unsigned _index);
/// Show the debugger for an empty record
Q_INVOKABLE void emptyRecord();
/// Generate new adress
Q_INVOKABLE QString newAddress();
/// Encode a string to ABI parameter. Returns a hex string
Q_INVOKABLE QString encodeAbiString(QString _string);
private slots:
/// Update UI with machine states result. Display a modal dialog.

5
mix/ContractCallDataEncoder.cpp

@ -110,11 +110,6 @@ unsigned ContractCallDataEncoder::encodeSingleItem(QVariant const& _data, Solidi
return dataSize;
}
void ContractCallDataEncoder::push(bytes const& _b)
{
m_encodedData.insert(m_encodedData.end(), _b.begin(), _b.end());
}
bigint ContractCallDataEncoder::decodeInt(dev::bytes const& _rawValue)
{
dev::u256 un = dev::fromBigEndian<dev::u256>(_rawValue);

8
mix/ContractCallDataEncoder.h

@ -52,8 +52,10 @@ public:
QVariant decode(SolidityType const& _type, bytes const& _value);
/// Get all encoded data encoded by encode function.
bytes encodedData();
/// Push the given @a _b to the current param context.
void push(bytes const& _b);
/// Encode a string to ABI bytes
dev::bytes encodeBytes(QString const& _str);
/// Decode bytes from ABI
dev::bytes decodeBytes(dev::bytes const& _rawValue);
private:
unsigned encodeSingleItem(QVariant const& _data, SolidityType const& _type, bytes& _dest);
@ -63,8 +65,6 @@ private:
dev::bytes encodeBool(QString const& _str);
bool decodeBool(dev::bytes const& _rawValue);
QString toString(bool _b);
dev::bytes encodeBytes(QString const& _str);
dev::bytes decodeBytes(dev::bytes const& _rawValue);
QString toString(dev::bytes const& _b);
bool asString(dev::bytes const& _b, QString& _str);

1
mix/FileIo.cpp

@ -196,6 +196,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
QStringList ret;
ret.append(QString::fromStdString(toHex(dappHash.ref())));
ret.append(qFileBytes.toBase64());
ret.append(url.toString());
return ret;
}

5
mix/MixApplication.cpp

@ -36,6 +36,7 @@
#include "Clipboard.h"
#include "HttpServer.h"
extern int qInitResources_js();
using namespace dev::mix;
ApplicationService::ApplicationService()
@ -59,7 +60,6 @@ MixApplication::MixApplication(int& _argc, char* _argv[]):
}
}
void MixApplication::initialize()
{
#if __linux
@ -72,6 +72,9 @@ void MixApplication::initialize()
if (!getenv("OPENSSL_CONF"))
putenv((char*)"OPENSSL_CONF=c:\\");
#endif
#ifdef ETH_HAVE_WEBENGINE
qInitResources_js();
#endif
setOrganizationName(tr("Ethereum"));
setOrganizationDomain(tr("ethereum.org"));

84
mix/Web3Server.cpp

@ -23,13 +23,93 @@
#include <libdevcore/Exceptions.h>
#include <libdevcore/Log.h>
#include <libethereum/Interface.h>
#include <libwebthree/WebThree.h>
#include "Web3Server.h"
using namespace dev::mix;
using namespace dev;
namespace
{
class EmptyNetwork : public dev::WebThreeNetworkFace
{
std::vector<p2p::PeerSessionInfo> peers() override
{
return std::vector<p2p::PeerSessionInfo>();
}
size_t peerCount() const override
{
return 0;
}
void addNode(p2p::NodeId const& _node, bi::tcp::endpoint const& _hostEndpoint) override
{
(void)_node;
(void)_hostEndpoint;
}
void requirePeer(p2p::NodeId const& _node, bi::tcp::endpoint const& _endpoint) override
{
(void)_node;
(void)_endpoint;
}
dev::bytes saveNetwork() override
{
return dev::bytes();
}
void setIdealPeerCount(size_t _n) override
{
(void)_n;
}
bool haveNetwork() const override
{
return false;
}
void setNetworkPreferences(p2p::NetworkPreferences const& _n, bool _dropPeers) override
{
(void)_n;
(void)_dropPeers;
}
p2p::NodeId id() const override
{
return p2p::NodeId();
}
p2p::Peers nodes() const override
{
return p2p::Peers();
}
void startNetwork() override
{
}
void stopNetwork() override
{
}
bool isNetworkStarted() const override
{
return false;
}
};
}
Web3Server::Web3Server(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts, dev::eth::Interface* _client):
WebThreeStubServerBase(_conn, _accounts),
m_client(_client)
m_client(_client),
m_network(new EmptyNetwork())
{
}
Web3Server::~Web3Server()
{
}
@ -40,7 +120,7 @@ std::shared_ptr<dev::shh::Interface> Web3Server::face()
dev::WebThreeNetworkFace* Web3Server::network()
{
BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::WebThreeNetworkFace"));
return m_network.get();
}
std::string Web3Server::get(std::string const& _name, std::string const& _key)

2
mix/Web3Server.h

@ -39,6 +39,7 @@ class Web3Server: public QObject, public dev::WebThreeStubServerBase, public dev
public:
Web3Server(jsonrpc::AbstractServerConnector& _conn, std::vector<dev::KeyPair> const& _accounts, dev::eth::Interface* _client);
virtual ~Web3Server();
signals:
void newTransaction();
@ -60,6 +61,7 @@ private:
private:
dev::eth::Interface* m_client;
std::map<std::string, std::string> m_db;
std::unique_ptr<dev::WebThreeNetworkFace> m_network;
};
}

23
mix/qml/DeploymentDialog.qml

@ -24,7 +24,8 @@ Window {
visible: false
property alias applicationUrlEth: applicationUrlEth.text
property alias applicationUrlHttp: applicationUrlHttp.text
property string urlHintContract: urlHintAddr.text
property alias urlHintContract: urlHintAddr.text
property alias localPackageUrl: localPackageUrl.text
property string packageHash
property string packageBase64
property string eth: registrarAddr.text
@ -131,8 +132,8 @@ Window {
var jsonRpcRequestId = 0;
requests.push({
jsonrpc: "2.0",
method: "eth_countAt",
params: [ currentAccount ],
method: "eth_getTransactionCount",
params: [ currentAccount, "pending" ],
id: jsonRpcRequestId++
});
TransactionHelper.rpcCall(requests, function (httpRequest, response){
@ -299,7 +300,7 @@ Window {
DefaultTextField
{
text: "20000"
text: "1000000"
Layout.preferredWidth: 350
id: gasToUseInput
}
@ -416,6 +417,20 @@ Window {
columns: 2
Layout.fillWidth: true
DefaultLabel
{
Layout.preferredWidth: 355
text: qsTr("Local package URL")
}
DefaultTextField
{
Layout.preferredWidth: 350
id: localPackageUrl
readOnly: true
enabled: rowRegister.isOkToRegister()
}
DefaultLabel
{
Layout.preferredWidth: 355

4
mix/qml/LogsPane.qml

@ -27,10 +27,6 @@ Rectangle
}
}
LogsPaneStyle {
id: logStyle
}
anchors.fill: parent
radius: 10
color: "transparent"

2
mix/qml/ProjectModel.qml

@ -160,7 +160,7 @@ Item {
}
MessageDialog {
id: deployRessourcesDialog
id: deployResourcesDialog
title: qsTr("Project")
standardButtons: StandardButton.Ok
}

6
mix/qml/StatusPane.qml

@ -231,7 +231,11 @@ Rectangle {
top = top.parent
var coordinates = logsContainer.mapToItem(top, 0, 0);
logsContainer.parent = top;
logsContainer.x = status.x + statusContainer.x - LogsPaneStyle.generic.layout.dateWidth - LogsPaneStyle.generic.layout.typeWidth + 70
logsContainer.x = status.x + statusContainer.x - logStyle.generic.layout.dateWidth - logStyle.generic.layout.typeWidth + 70
}
LogsPaneStyle {
id: logStyle
}
LogsPane

1
mix/qml/WebPreview.qml

@ -304,6 +304,7 @@ Item {
id: webView
experimental.settings.localContentCanAccessRemoteUrls: true
onJavaScriptConsoleMessage: {
console.log(sourceID + ":" + lineNumber + ": " + message);
webPreview.javaScriptMessage(level, sourceID, lineNumber, message);
}
onLoadingChanged: {

42
mix/qml/js/ProjectModel.js

@ -367,23 +367,8 @@ function startDeployProject(erasePrevious)
var ctrNames = Object.keys(codeModel.contracts);
var ctrAddresses = {};
setDefaultBlock(0, function() {
deployContracts(0, ctrAddresses, ctrNames, function (){
finalizeDeployment(deploymentId, ctrAddresses);
});
});
}
function setDefaultBlock(val, callBack)
{
var requests = [{
jsonrpc: "2.0",
method: "eth_setDefaultBlock",
params: [val],
id: 0
}];
rpcCall(requests, function (httpCall, response){
callBack();
deployContracts(0, ctrAddresses, ctrNames, function (){
finalizeDeployment(deploymentId, ctrAddresses);
});
}
@ -392,7 +377,7 @@ function deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack)
var code = codeModel.contracts[ctrNames[ctrIndex]].codeHex;
var requests = [{
jsonrpc: "2.0",
method: "eth_transact",
method: "eth_sendTransaction",
params: [ { "from": deploymentDialog.currentAccount, "gas": deploymentDialog.gasToUse, "code": code } ],
id: 0
}];
@ -452,7 +437,8 @@ function finalizeDeployment(deploymentId, addresses) {
"\tinterface: " + codeModel.contracts[c].contractInterface + ",\n" +
"\taddress: \"" + addresses[c] + "\"\n" +
"};\n" +
contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n";
contractAccessor + ".contractClass = web3.eth.contract(" + contractAccessor + ".interface);\n" +
contractAccessor + ".contract = new " + contractAccessor + ".contractClass(" + contractAccessor + ".address);\n";
}
fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs);
deploymentAddresses = addresses;
@ -461,6 +447,7 @@ function finalizeDeployment(deploymentId, addresses) {
var packageRet = fileIo.makePackage(deploymentDir);
deploymentDialog.packageHash = packageRet[0];
deploymentDialog.packageBase64 = packageRet[1];
deploymentDialog.localPackageUrl = packageRet[2] + "?hash=" + packageRet[0];
var applicationUrlEth = deploymentDialog.applicationUrlEth;
@ -468,9 +455,8 @@ function finalizeDeployment(deploymentId, addresses) {
deploymentStepChanged(qsTr("Registering application on the Ethereum network ..."));
checkEthPath(applicationUrlEth, function () {
deploymentComplete();
deployRessourcesDialog.text = qsTr("Register Web Application to finalize deployment.");
deployRessourcesDialog.open();
setDefaultBlock(-1, function() {});
deployResourcesDialog.text = qsTr("Register Web Application to finalize deployment.");
deployResourcesDialog.open();
});
}
@ -567,7 +553,7 @@ function checkRegistration(dappUrl, addr, callBack)
requests.push({
jsonrpc: "2.0",
method: "eth_transact",
method: "eth_sendTransaction",
params: [ { "from": deploymentDialog.currentAccount, "gas": 20000, "code": "0x60056013565b61059e8061001d6000396000f35b33600081905550560060003560e060020a90048063019848921461009a578063449c2090146100af5780635d574e32146100cd5780635fd4b08a146100e1578063618242da146100f65780636be16bed1461010b5780636c4489b414610129578063893d20e8146101585780639607730714610173578063c284bc2a14610187578063e50f599a14610198578063e5811b35146101af578063ec7b9200146101cd57005b6100a560043561031b565b8060005260206000f35b6100ba6004356103a0565b80600160a060020a031660005260206000f35b6100db600435602435610537565b60006000f35b6100ec600435610529565b8060005260206000f35b6101016004356103dd565b8060005260206000f35b6101166004356103bd565b80600160a060020a031660005260206000f35b61013460043561034b565b82600160a060020a031660005281600160a060020a03166020528060405260606000f35b610160610341565b80600160a060020a031660005260206000f35b6101816004356024356102b4565b60006000f35b6101926004356103fd565b60006000f35b6101a96004356024356044356101f2565b60006000f35b6101ba6004356101eb565b80600160a060020a031660005260206000f35b6101d8600435610530565b80600160a060020a031660005260206000f35b6000919050565b600054600160a060020a031633600160a060020a031614610212576102af565b8160026000858152602001908152602001600020819055508061023457610287565b81600160a060020a0316837f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a3826001600084600160a060020a03168152602001908152602001600020819055505b827f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505050565b600054600160a060020a031633600160a060020a0316146102d457610317565b806002600084815260200190815260200160002060010181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b5050565b60006001600083600160a060020a03168152602001908152602001600020549050919050565b6000600054905090565b6000600060006002600085815260200190815260200160002054925060026000858152602001908152602001600020600101549150600260008581526020019081526020016000206002015490509193909250565b600060026000838152602001908152602001600020549050919050565b600060026000838152602001908152602001600020600101549050919050565b600060026000838152602001908152602001600020600201549050919050565b600054600160a060020a031633600160a060020a03161461041d57610526565b80600160006002600085815260200190815260200160002054600160a060020a031681526020019081526020016000205414610458576104d2565b6002600082815260200190815260200160002054600160a060020a0316817f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a36000600160006002600085815260200190815260200160002054600160a060020a03168152602001908152602001600020819055505b6002600082815260200190815260200160002060008101600090556001810160009055600281016000905550807f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b50565b6000919050565b6000919050565b600054600160a060020a031633600160a060020a0316146105575761059a565b806002600084815260200190815260200160002060020181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505056" } ],
id: jsonRpcRequestId++
});
@ -588,7 +574,7 @@ function checkRegistration(dappUrl, addr, callBack)
requests.push({
//setRegister()
jsonrpc: "2.0",
method: "eth_transact",
method: "eth_sendTransaction",
params: [ { "from": deploymentDialog.currentAccount, "gas": 30000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ],
id: jsonRpcRequestId++
});
@ -617,12 +603,12 @@ function registerContentHash(registrar, callBack)
deploymentStepChanged(txt);
console.log(txt);
var requests = [];
var paramTitle = createString(projectModel.projectTitle);
var paramTitle = clientModel.encodeAbiString(projectModel.projectTitle);
requests.push({
//setContent()
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "from": deploymentDialog.currentAccount, "gas": 30000, "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ],
method: "eth_sendTransaction",
params: [ { "from": deploymentDialog.currentAccount, "gas": 30000, "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle + deploymentDialog.packageHash } ],
id: jsonRpcRequestId++
});
rpcCall(requests, function (httpRequest, response) {
@ -638,7 +624,7 @@ function registerToUrlHint()
requests.push({
//urlHint => suggestUrl
jsonrpc: "2.0",
method: "eth_transact",
method: "eth_sendTransaction",
params: [ { "to": '0x' + deploymentDialog.urlHintContract, "gas": 30000, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ],
id: jsonRpcRequestId++
});

16
mix/qml/js/QEtherHelper.js

@ -15,19 +15,3 @@ function createBigInt(_value)
return bigint;
}
function createString(_value)
{
var stringComponent = Qt.createComponent("qrc:/qml/QStringType.qml");
var stringC = stringComponent.createObject();
stringC.setValue(_value);
return stringC;
}
function createHash(_value)
{
var hComponent = Qt.createComponent("qrc:/qml/QHashType.qml");
var hC = hComponent.createObject();
hC.setValue(_value);
return hC;
}

Loading…
Cancel
Save