diff --git a/alethzero/DownloadView.cpp b/alethzero/DownloadView.cpp
index a6533023c..88a595566 100644
--- a/alethzero/DownloadView.cpp
+++ b/alethzero/DownloadView.cpp
@@ -45,7 +45,7 @@ void DownloadView::paintEvent(QPaintEvent*)
double ratio = (double)rect().width() / rect().height();
if (ratio < 1)
ratio = 1 / ratio;
- double n = min(rect().width(), rect().height()) / ceil(sqrt(m_man->chain().size() / ratio));
+ double n = min(16.0, min(rect().width(), rect().height()) / ceil(sqrt(m_man->chain().size() / ratio)));
// QSizeF area(rect().width() / floor(rect().width() / n), rect().height() / floor(rect().height() / n));
QSizeF area(n, n);
diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index 5e86ee59a..5a6eb6f32 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -1480,6 +1480,40 @@ font-size: 14pt
+
+
+ QDockWidget::DockWidgetFeatureMask
+
+
+ Nodes
+
+
+ 2
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ QFrame::NoFrame
+
+
+
+
+
+
&Quit
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 5455c27ea..f55bf2d9f 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -207,6 +207,12 @@ unsigned Main::installWatch(dev::h256 _tf, std::function const& _f)
return ret;
}
+void Main::uninstallWatch(unsigned _w)
+{
+ ethereum()->uninstallWatch(_w);
+ m_handlers.erase(_w);
+}
+
void Main::installWatches()
{
installWatch(dev::eth::MessageFilter().altered(c_config, 0), [=](){ installNameRegWatch(); });
@@ -217,13 +223,13 @@ void Main::installWatches()
void Main::installNameRegWatch()
{
- ethereum()->uninstallWatch(m_nameRegFilter);
+ uninstallWatch(m_nameRegFilter);
m_nameRegFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 0)), [=](){ onNameRegChange(); });
}
void Main::installCurrenciesWatch()
{
- ethereum()->uninstallWatch(m_currenciesFilter);
+ uninstallWatch(m_currenciesFilter);
m_currenciesFilter = installWatch(dev::eth::MessageFilter().altered((u160)ethereum()->stateAt(c_config, 1)), [=](){ onCurrenciesChange(); });
}
@@ -242,7 +248,7 @@ void Main::installBalancesWatch()
tf.altered(c, (u160)i.address());
}
- ethereum()->uninstallWatch(m_balancesFilter);
+ uninstallWatch(m_balancesFilter);
m_balancesFilter = installWatch(tf, [=](){ onBalancesChange(); });
}
@@ -500,7 +506,7 @@ void Main::writeSettings()
s.setValue("privateChain", m_privateChain);
s.setValue("verbosity", ui->verbosity->value());
- bytes d = m_webThree->savePeers();
+ bytes d = m_webThree->saveNodes();
if (d.size())
m_peers = QByteArray((char*)d.data(), (int)d.size());
s.setValue("peers", m_peers);
@@ -744,11 +750,34 @@ void Main::refreshBalances()
void Main::refreshNetwork()
{
auto ps = web3()->peers();
-
ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)");
ui->peers->clear();
for (PeerInfo const& i: ps)
- ui->peers->addItem(QString("[%7] %3 ms - %1:%2 - %4 %5 %6").arg(i.host.c_str()).arg(i.port).arg(chrono::duration_cast(i.lastPing).count()).arg(i.clientVersion.c_str()).arg(QString::fromStdString(toString(i.caps))).arg(QString::fromStdString(toString(i.notes))).arg(i.socket));
+ ui->peers->addItem(QString("[%8 %7] %3 ms - %1:%2 - %4 %5 %6")
+ .arg(QString::fromStdString(i.host))
+ .arg(i.port)
+ .arg(chrono::duration_cast(i.lastPing).count())
+ .arg(QString::fromStdString(i.clientVersion))
+ .arg(QString::fromStdString(toString(i.caps)))
+ .arg(QString::fromStdString(toString(i.notes)))
+ .arg(i.socket)
+ .arg(QString::fromStdString(i.id.abridged())));
+
+ auto ns = web3()->nodes();
+ ui->nodes->clear();
+ for (p2p::Node const& i: ns)
+ if (!i.dead)
+ ui->nodes->addItem(QString("[%1%3] %2 - ( =%5s | /%4s | %6 | %7x ) - *%8 $%9")
+ .arg(QString::fromStdString(i.id.abridged()))
+ .arg(QString::fromStdString(toString(i.address)))
+ .arg(i.id == web3()->id() ? " self" : i.isOffline() ? " ripe" : " ----")
+ .arg(i.secondsSinceLastAttempted())
+ .arg(i.secondsSinceLastConnected())
+ .arg(QString::fromStdString(reasonOf(i.lastDisconnect)))
+ .arg(i.failedAttempts)
+ .arg(i.rating)
+ .arg((int)i.idOrigin)
+ );
}
void Main::refreshAll()
@@ -866,7 +895,7 @@ void Main::refreshBlockChain()
string filter = ui->blockChainFilter->text().toLower().toStdString();
auto const& bc = ethereum()->blockChain();
unsigned i = (ui->showAll->isChecked() || !filter.empty()) ? (unsigned)-1 : 10;
- for (auto h = bc.currentHash(); h != bc.genesisHash() && bc.details(h) && i; h = bc.details(h).parent, --i)
+ for (auto h = bc.currentHash(); bc.details(h) && i; h = bc.details(h).parent, --i)
{
auto d = bc.details(h);
auto bm = blockMatch(filter, d, h, bc);
@@ -906,6 +935,8 @@ void Main::refreshBlockChain()
}
n++;
}
+ if (h == bc.genesisHash())
+ break;
}
if (!ui->blocks->currentItem())
@@ -1132,7 +1163,10 @@ void Main::on_blocks_currentItemChanged()
s << "
Bloom: " << details.bloom << "";
s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "";
s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "";
- s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "";
+ if (info.parentHash)
+ s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "";
+ else
+ s << "
Pre: Nothing is before the Gensesis";
for (auto const& i: block[1])
s << "
" << sha3(i[0].data()).abridged() << ": " << i[1].toHash() << " [" << i[2].toInt() << " used]";
s << "
Post: " << info.stateRoot << "";
@@ -1257,10 +1291,10 @@ void Main::populateDebugger(dev::bytesConstRef _r)
if (!m_codes.count(lastDataHash))
m_codes[lastDataHash] = ext.data.toBytes();
}
- if (levels.size() < ext.level)
+ if (levels.size() < ext.depth)
levels.push_back(&m_history.back());
else
- levels.resize(ext.level);
+ levels.resize(ext.depth);
m_history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
};
m_currentExecution->go(onOp);
@@ -1539,10 +1573,10 @@ void Main::on_net_triggered()
web3()->setIdealPeerCount(ui->idealPeers->value());
web3()->setNetworkPreferences(netPrefs());
ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : 0);
+ if (m_peers.size()/* && ui->usePast->isChecked()*/)
+ web3()->restoreNodes(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
web3()->startNetwork();
ui->downloadView->setDownloadMan(ethereum()->downloadMan());
- if (m_peers.size() && ui->usePast->isChecked())
- web3()->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
}
else
{
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index c83848cdd..55b8b4e0a 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -183,6 +183,7 @@ private:
unsigned installWatch(dev::eth::MessageFilter const& _tf, std::function const& _f);
unsigned installWatch(dev::h256 _tf, std::function const& _f);
+ void uninstallWatch(unsigned _w);
void keysChanged();
diff --git a/eth/main.cpp b/eth/main.cpp
index 03be8b969..95d1c21fa 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
#if ETH_JSONRPC
@@ -166,6 +167,13 @@ string pretty(h160 _a, dev::eth::State _st)
return ns;
}
+bool g_exit = false;
+
+void sighandler(int)
+{
+ g_exit = true;
+}
+
int main(int argc, char** argv)
{
unsigned short listenPort = 30303;
@@ -316,6 +324,9 @@ int main(int argc, char** argv)
c->setAddress(coinbase);
}
+ auto nodesState = contents(dbPath + "/nodeState.rlp");
+ web3.restoreNodes(&nodesState);
+
cout << "Address: " << endl << toHex(us.address().asArray()) << endl;
web3.startNetwork();
@@ -334,11 +345,15 @@ int main(int argc, char** argv)
}
#endif
+ signal(SIGABRT, &sighandler);
+ signal(SIGTERM, &sighandler);
+ signal(SIGINT, &sighandler);
+
if (interactive)
{
string logbuf;
string l;
- while (true)
+ while (!g_exit)
{
g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << "Press Enter" << flush; };
cout << logbuf << "Press Enter" << flush;
@@ -612,7 +627,14 @@ int main(int argc, char** argv)
Transaction t = state.pending()[index];
state = state.fromPending(index);
bytes r = t.rlp();
- e.setup(&r);
+ try
+ {
+ e.setup(&r);
+ }
+ catch(Exception const& _e)
+ {
+ cwarn << diagnostic_information(_e);
+ }
OnOpFunc oof;
if (format == "pretty")
@@ -627,7 +649,7 @@ int main(int argc, char** argv)
f << " STORAGE" << endl;
for (auto const& i: ext->state().storage(ext->myAddress))
f << showbase << hex << i.first << ": " << i.second << endl;
- f << dec << ext->level << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32";
+ f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32";
};
else if (format == "standard")
oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM)
@@ -757,7 +779,7 @@ int main(int argc, char** argv)
unsigned n =c->blockChain().details().number;
if (mining)
c->startMining();
- while (true)
+ while (!g_exit)
{
if ( c->isMining() &&c->blockChain().details().number - n == mining)
c->stopMining();
@@ -765,9 +787,10 @@ int main(int argc, char** argv)
}
}
else
- while (true)
+ while (!g_exit)
this_thread::sleep_for(chrono::milliseconds(1000));
+ writeFile(dbPath + "/nodeState.rlp", web3.saveNodes());
return 0;
}
diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp
index 8a8687bfa..b67e3e62c 100644
--- a/libdevcore/Common.cpp
+++ b/libdevcore/Common.cpp
@@ -27,7 +27,7 @@ using namespace dev;
namespace dev
{
-char const* Version = "0.7.0";
+char const* Version = "0.7.2";
}
diff --git a/libdevcore/RangeMask.h b/libdevcore/RangeMask.h
index e6a66776c..ac58ec8b1 100644
--- a/libdevcore/RangeMask.h
+++ b/libdevcore/RangeMask.h
@@ -47,6 +47,7 @@ public:
RangeMask(T _begin, T _end): m_all(_begin, _end) {}
RangeMask(Range const& _c): m_all(_c) {}
+ RangeMask unionedWith(RangeMask const& _m) const { return operator+(_m); }
RangeMask operator+(RangeMask const& _m) const { return RangeMask(*this) += _m; }
RangeMask lowest(T _items) const
@@ -57,7 +58,9 @@ public:
return ret;
}
- RangeMask operator~() const
+ RangeMask operator~() const { return inverted(); }
+
+ RangeMask inverted() const
{
RangeMask ret(m_all);
T last = m_all.first;
@@ -72,16 +75,28 @@ public:
return ret;
}
- RangeMask& operator+=(RangeMask const& _m)
+ RangeMask& invert() { return *this = inverted(); }
+
+ template RangeMask operator-(S const& _m) const { auto ret = *this; return ret -= _m; }
+ template RangeMask& operator-=(S const& _m) { return invert().unionWith(_m).invert(); }
+
+ RangeMask& operator+=(RangeMask const& _m) { return unionWith(_m); }
+
+ RangeMask& unionWith(RangeMask const& _m)
{
+ m_all.first = std::min(_m.m_all.first, m_all.first);
+ m_all.second = std::max(_m.m_all.second, m_all.second);
for (auto const& i: _m.m_ranges)
- operator+=(i);
+ unionWith(i);
return *this;
}
- RangeMask& operator+=(UnsignedRange const& _m)
+ RangeMask& operator+=(Range const& _m) { return unionWith(_m); }
+ RangeMask& unionWith(Range const& _m)
{
for (auto i = _m.first; i < _m.second;)
{
+ assert(i >= m_all.first);
+ assert(i < m_all.second);
// for each number, we find the element equal or next lower. this, if any, must contain the value.
auto uit = m_ranges.upper_bound(i);
auto it = uit == m_ranges.begin() ? m_ranges.end() : std::prev(uit);
@@ -130,7 +145,8 @@ public:
return *this;
}
- RangeMask& operator+=(T _i)
+ RangeMask& operator+=(T _m) { return unionWith(_m); }
+ RangeMask& unionWith(T _i)
{
return operator+=(Range(_i, _i + 1));
}
@@ -165,6 +181,7 @@ public:
}
std::pair const& all() const { return m_all; }
+ void extendAll(T _i) { m_all = std::make_pair(std::min(m_all.first, _i), std::max(m_all.second, _i + 1)); }
class const_iterator
{
diff --git a/libdevcrypto/MemoryDB.h b/libdevcrypto/MemoryDB.h
index 59435d3bf..446a947ec 100644
--- a/libdevcrypto/MemoryDB.h
+++ b/libdevcrypto/MemoryDB.h
@@ -32,7 +32,7 @@ namespace dev
namespace eth
{
-struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 12; };
+struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 18; };
#define dbdebug clog(DBChannel)
diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h
index d4583dc9b..3dd76899a 100644
--- a/libdevcrypto/TrieDB.h
+++ b/libdevcrypto/TrieDB.h
@@ -42,7 +42,7 @@ namespace dev
namespace eth
{
-struct TrieDBChannel: public LogChannel { static const char* name() { return "-T-"; } static const int verbosity = 6; };
+struct TrieDBChannel: public LogChannel { static const char* name() { return "-T-"; } static const int verbosity = 17; };
#define tdebug clog(TrieDBChannel)
struct InvalidTrie: virtual dev::Exception {};
@@ -473,7 +473,7 @@ template void GenericTrieDB::insert(bytesConstRef _key, bytesCons
assert(rv.size());
bytes b = mergeAt(RLP(rv), NibbleSlice(_key), _value);
- // mergeAt won't attempt to delete the node is it's less than 32 bytes
+ // mergeAt won't attempt to delete the node if it's less than 32 bytes
// However, we know it's the root node and thus always hashed.
// So, if it's less than 32 (and thus should have been deleted but wasn't) then we delete it here.
if (rv.size() < 32)
diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp
index 2936e9353..c6f35763e 100644
--- a/libethcore/Exceptions.cpp
+++ b/libethcore/Exceptions.cpp
@@ -22,14 +22,17 @@
#include "Exceptions.h"
#include
+using namespace std;
using namespace dev;
using namespace dev::eth;
-const char* InvalidBlockFormat::what() const noexcept { return ("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")").c_str(); }
-const char* UncleInChain::what() const noexcept { return ("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")").c_str(); }
-const char* InvalidTransactionsHash::what() const noexcept { return ("Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref())).c_str(); }
-const char* InvalidGasLimit::what() const noexcept { return ("Invalid gas limit (provided: " + toString(provided) + " valid:" + toString(valid) + ")").c_str(); }
-const char* InvalidMinGasPrice::what() const noexcept { return ("Invalid minimum gas price (provided: " + toString(provided) + " limit:" + toString(limit) + ")").c_str(); }
-const char* InvalidNonce::what() const noexcept { return ("Invalid nonce (r: " + toString(required) + " c:" + toString(candidate) + ")").c_str(); }
-const char* InvalidBlockNonce::what() const noexcept { return ("Invalid nonce (h: " + toString(h) + " n:" + toString(n) + " d:" + toString(d) + ")").c_str(); }
+#define ETH_RETURN_STRING(S) static string s_what; s_what = S; return s_what.c_str();
+
+const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); }
+const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); }
+const char* InvalidTransactionsHash::what() const noexcept { ETH_RETURN_STRING("Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref())); }
+const char* InvalidGasLimit::what() const noexcept { ETH_RETURN_STRING("Invalid gas limit (provided: " + toString(provided) + " valid:" + toString(valid) + ")"); }
+const char* InvalidMinGasPrice::what() const noexcept { ETH_RETURN_STRING("Invalid minimum gas price (provided: " + toString(provided) + " limit:" + toString(limit) + ")"); }
+const char* InvalidNonce::what() const noexcept { ETH_RETURN_STRING("Invalid nonce (r: " + toString(required) + " c:" + toString(candidate) + ")"); }
+const char* InvalidBlockNonce::what() const noexcept { ETH_RETURN_STRING("Invalid nonce (h: " + toString(h) + " n:" + toString(n) + " d:" + toString(d) + ")"); }
diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h
index f9207f795..8a4723696 100644
--- a/libethcore/Exceptions.h
+++ b/libethcore/Exceptions.h
@@ -48,7 +48,7 @@ class InvalidBlockFormat: public dev::Exception { public: InvalidBlockFormat(int
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: 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; };
diff --git a/libethcore/_libethcore.cpp b/libethcore/_libethcore.cpp
index 8a3831584..477034b9e 100644
--- a/libethcore/_libethcore.cpp
+++ b/libethcore/_libethcore.cpp
@@ -3,4 +3,5 @@
#include "BlockInfo.cpp"
#include "CommonEth.cpp"
#include "Dagger.cpp"
+#include "Exceptions.cpp"
#endif
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index 0a66a0979..8e0619a43 100644
--- a/libethereum/BlockChain.cpp
+++ b/libethereum/BlockChain.cpp
@@ -43,7 +43,9 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc)
for (it->SeekToFirst(); it->Valid(); it->Next())
if (it->key().ToString() != "best")
{
- BlockDetails d(RLP(it->value().ToString()));
+ string rlpString = it->value().ToString();
+ RLP r(rlpString);
+ BlockDetails d(r);
_out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parent << (cmp == it->key().ToString() ? " BEST" : "") << std::endl;
}
delete it;
@@ -437,7 +439,7 @@ void BlockChain::checkConsistency()
if (p != h256())
{
auto dp = details(p);
- assert(contains(dp.children, h));
+// assert(contains(dp.children, h)); // WTF?
assert(dp.number == dh.number - 1);
}
}
diff --git a/libethereum/DownloadMan.cpp b/libethereum/DownloadMan.cpp
index 3c8dae58e..be33f5187 100644
--- a/libethereum/DownloadMan.cpp
+++ b/libethereum/DownloadMan.cpp
@@ -66,10 +66,12 @@ h256Set DownloadSub::nextFetch(unsigned _n)
return m_remaining;
}
-void DownloadSub::noteBlock(h256 _hash)
+bool DownloadSub::noteBlock(h256 _hash)
{
Guard l(m_fetch);
if (m_man && m_indices.count(_hash))
m_man->m_blocksGot += m_indices[_hash];
+ bool ret = !!m_remaining.count(_hash);
m_remaining.erase(_hash);
+ return ret;
}
diff --git a/libethereum/DownloadMan.h b/libethereum/DownloadMan.h
index 6f4c4bafb..1902f3db1 100644
--- a/libethereum/DownloadMan.h
+++ b/libethereum/DownloadMan.h
@@ -48,8 +48,8 @@ public:
/// Finished last fetch - grab the next bunch of block hashes to download.
h256Set nextFetch(unsigned _n);
- /// Note that we've received a particular block.
- void noteBlock(h256 _hash);
+ /// Note that we've received a particular block. @returns true if we had asked for it but haven't received it yet.
+ bool noteBlock(h256 _hash);
/// Nothing doing here.
void doneFetch() { resetFetch(); }
diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp
index bc5f11936..8e92fa9e6 100644
--- a/libethereum/EthereumHost.cpp
+++ b/libethereum/EthereumHost.cpp
@@ -202,7 +202,7 @@ void EthereumHost::maintainBlocks(h256 _currentHash)
auto p = j->cap();
RLPStream ts;
- p->prep(ts, BlocksPacket, hs.size()).appendRaw(bs, hs.size());
+ p->prep(ts, NewBlockPacket, hs.size()).appendRaw(bs, hs.size());
Guard l(p->x_knownBlocks);
if (!p->m_knownBlocks.count(_currentHash))
diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h
index a4ccf5383..2add925c6 100644
--- a/libethereum/EthereumHost.h
+++ b/libethereum/EthereumHost.h
@@ -72,7 +72,7 @@ public:
DownloadMan const& downloadMan() const { return m_man; }
bool isSyncing() const { return !!m_syncer; }
- bool isBanned(h512 _id) const { return !!m_banned.count(_id); }
+ bool isBanned(p2p::NodeId _id) const { return !!m_banned.count(_id); }
private:
/// Session is tell us that we may need (re-)syncing with the peer.
@@ -116,7 +116,7 @@ private:
h256 m_latestBlockSent;
h256Set m_transactionsSent;
- std::set m_banned;
+ std::set m_banned;
};
}
diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp
index 21fe5fbba..5817aa434 100644
--- a/libethereum/EthereumPeer.cpp
+++ b/libethereum/EthereumPeer.cpp
@@ -308,7 +308,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
disable("Invalid protocol version.");
else if (m_networkId != host()->networkId())
disable("Invalid network identifier.");
- else if (session()->info().clientVersion.find("/v0.6.9/") != string::npos)
+ else if (session()->info().clientVersion.find("/v0.7.0/") != string::npos)
disable("Blacklisted client version.");
else if (host()->isBanned(session()->id()))
disable("Peer banned for previous bad behaviour.");
@@ -425,44 +425,46 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
unsigned future = 0;
unsigned unknown = 0;
unsigned got = 0;
+ unsigned repeated = 0;
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
auto h = BlockInfo::headerHash(_r[i].data());
- m_sub.noteBlock(h);
-
+ if (m_sub.noteBlock(h))
{
- Guard l(x_knownBlocks);
- m_knownBlocks.insert(h);
+ addRating(10);
+ switch (host()->m_bq.import(_r[i].data(), host()->m_chain))
+ {
+ case ImportResult::Success:
+ success++;
+ break;
+
+ case ImportResult::Malformed:
+ disable("Malformed block received.");
+ return true;
+
+ case ImportResult::FutureTime:
+ future++;
+ break;
+
+ case ImportResult::AlreadyInChain:
+ case ImportResult::AlreadyKnown:
+ got++;
+ break;
+
+ case ImportResult::UnknownParent:
+ unknown++;
+ break;
+ }
}
-
- switch (host()->m_bq.import(_r[i].data(), host()->m_chain))
+ else
{
- case ImportResult::Success:
- addRating(1);
- success++;
- break;
-
- case ImportResult::Malformed:
- disable("Malformed block received.");
- return true;
-
- case ImportResult::FutureTime:
- future++;
- break;
-
- case ImportResult::AlreadyInChain:
- case ImportResult::AlreadyKnown:
- got++;
- break;
-
- case ImportResult::UnknownParent:
- unknown++;
- break;
+ addRating(0); // -1?
+ repeated++;
}
}
- clogS(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known.";
+ clogS(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received.";
if (m_asking == Asking::Blocks)
transition(Asking::Blocks);
@@ -480,8 +482,10 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
switch (host()->m_bq.import(_r[1].data(), host()->m_chain))
{
case ImportResult::Success:
+ addRating(100);
+ break;
case ImportResult::FutureTime:
- addRating(1);
+ //TODO: Rating dependent on how far in future it is.
break;
case ImportResult::Malformed:
diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp
index 61d179ed8..93900b51e 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -158,7 +158,7 @@ OnOpFunc Executive::simpleTrace()
for (auto const& i: ext.state().storage(ext.myAddress))
o << showbase << hex << i.first << ": " << i.second << endl;
dev::LogOutputStream(true) << o.str();
- dev::LogOutputStream(false) << " | " << dec << ext.level << " | " << ext.myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << dec << vm.gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32" << " ]";
+ dev::LogOutputStream(false) << " | " << dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << dec << vm.gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32" << " ]";
};
}
diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h
index 3b4b7161f..612164d13 100644
--- a/libethereum/ExtVM.h
+++ b/libethereum/ExtVM.h
@@ -39,8 +39,8 @@ class ExtVM: public ExtVMFace
{
public:
/// Full constructor.
- ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, Manifest* o_ms, unsigned _level = 0):
- ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code, _s.m_previousBlock, _s.m_currentBlock), level(_level), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms)
+ ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, Manifest* o_ms, unsigned _depth = 0):
+ ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code, _s.m_previousBlock, _s.m_currentBlock, _depth), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms)
{
m_s.ensureCached(_myAddress, true, true);
}
@@ -61,7 +61,7 @@ public:
m_s.noteSending(myAddress);
if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1);
- auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1);
+ auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back();
return ret;
@@ -72,7 +72,7 @@ public:
{
if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1);
- auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1);
+ auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back();
return ret;
@@ -100,9 +100,6 @@ public:
State& state() const { return m_s; }
- /// @note not a part of the main API; just for use by tracing/debug stuff.
- unsigned level = 0;
-
private:
State& m_s; ///< A reference to the base state.
std::map m_origCache; ///< The cache of the address states (i.e. the externalities) as-was prior to the execution.
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 047b9dcd5..105df0172 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -75,7 +75,9 @@ void ripemd160Code(bytesConstRef _in, bytesRef _out)
{
h256 ret;
ripemd160(_in, bytesRef(ret.data(), 32));
- memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret)));
+ memset(_out.data(), 0, std::min(12, _out.size()));
+ if (_out.size() > 12)
+ memcpy(_out.data() + 12, &ret, min(_out.size() - 12, sizeof(ret)));
}
const std::map State::c_precompiled =
@@ -1052,7 +1054,14 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
Manifest ms;
Executive e(*this, &ms);
- e.setup(_rlp);
+ try
+ {
+ e.setup(_rlp);
+ }
+ catch (Exception const & _e)
+ {
+ cwarn << diagnostic_information(_e);
+ }
u256 startGasUsed = gasUsed();
@@ -1284,8 +1293,8 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s)
{
auto it = _s.m_cache.find(i);
AddressState* cache = it != _s.m_cache.end() ? &it->second : nullptr;
- auto rlpString = trie.at(i);
- RLP r(dtr.count(i) ? rlpString : "");
+ string rlpString = dtr.count(i) ? trie.at(i) : "";
+ RLP r(rlpString);
assert(cache || r);
if (cache && !cache->isAlive())
@@ -1298,7 +1307,8 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s)
stringstream contout;
- if ((!cache || cache->codeBearing()) && (!r || r[3].toHash() != EmptySHA3))
+ /// For POC6, 3rd value of account is code and will be empty if code is not present.
+ if ((cache && cache->codeBearing()) || (!cache && r && !r[3].isEmpty()))
{
std::map mem;
std::set back;
diff --git a/libethereum/State.h b/libethereum/State.h
index a28d8155c..c73fc95dc 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -40,7 +40,7 @@
namespace dev
{
-namespace test{ class FakeExtVM;}
+namespace test{ class FakeExtVM; class FakeState;}
namespace eth
{
@@ -84,6 +84,7 @@ class State
{
friend class ExtVM;
friend class test::FakeExtVM;
+ friend class test::FakeState;
friend class Executive;
public:
diff --git a/libevm/ExtVMFace.cpp b/libevm/ExtVMFace.cpp
index 7c938417a..da189d899 100644
--- a/libevm/ExtVMFace.cpp
+++ b/libevm/ExtVMFace.cpp
@@ -25,7 +25,7 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
-ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock):
+ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth):
myAddress(_myAddress),
caller(_caller),
origin(_origin),
@@ -34,6 +34,7 @@ ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256
data(_data),
code(_code),
previousBlock(_previousBlock),
- currentBlock(_currentBlock)
+ currentBlock(_currentBlock),
+ depth(_depth)
{}
diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h
index f78cb82cb..1b0f9eaf5 100644
--- a/libevm/ExtVMFace.h
+++ b/libevm/ExtVMFace.h
@@ -54,7 +54,7 @@ public:
ExtVMFace() {}
/// Full constructor.
- ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock);
+ ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, unsigned _depth);
/// Get the code at the given location in code ROM.
byte getCode(u256 _n) const { return _n < code.size() ? code[(unsigned)_n] : 0; }
@@ -99,6 +99,7 @@ public:
BlockInfo previousBlock; ///< The previous block's information.
BlockInfo currentBlock; ///< The current block's information.
std::set suicides; ///< Any accounts that have suicided.
+ unsigned depth; ///< Depth of the present call.
};
}
diff --git a/libevm/VM.cpp b/libevm/VM.cpp
index 4a3f70d5e..e47237d5a 100644
--- a/libevm/VM.cpp
+++ b/libevm/VM.cpp
@@ -29,6 +29,4 @@ void VM::reset(u256 _gas)
{
m_gas = _gas;
m_curPC = 0;
- m_jumpLatch = false;
- m_destinations.clear();
}
diff --git a/libevm/VM.h b/libevm/VM.h
index 86acd8c26..401e30baf 100644
--- a/libevm/VM.h
+++ b/libevm/VM.h
@@ -84,8 +84,6 @@ private:
u256 m_curPC = 0;
bytes m_temp;
u256s m_stack;
- bool m_jumpLatch = false;
- u256Set m_destinations;
};
}
@@ -190,8 +188,116 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;
}
- default:
+ case Instruction::ADD:
+ case Instruction::MUL:
+ case Instruction::SUB:
+ case Instruction::DIV:
+ case Instruction::SDIV:
+ case Instruction::MOD:
+ case Instruction::SMOD:
+ case Instruction::EXP:
+ case Instruction::NEG:
+ case Instruction::LT:
+ case Instruction::GT:
+ case Instruction::SLT:
+ case Instruction::SGT:
+ case Instruction::EQ:
+ case Instruction::NOT:
+ case Instruction::AND:
+ case Instruction::OR:
+ case Instruction::XOR:
+ case Instruction::BYTE:
+ case Instruction::ADDMOD:
+ case Instruction::MULMOD:
+ case Instruction::ADDRESS:
+ case Instruction::ORIGIN:
+ case Instruction::CALLER:
+ case Instruction::CALLVALUE:
+ case Instruction::CALLDATALOAD:
+ case Instruction::CALLDATASIZE:
+ case Instruction::CODESIZE:
+ case Instruction::EXTCODESIZE:
+ case Instruction::GASPRICE:
+ case Instruction::PREVHASH:
+ case Instruction::COINBASE:
+ case Instruction::TIMESTAMP:
+ case Instruction::NUMBER:
+ case Instruction::DIFFICULTY:
+ case Instruction::GASLIMIT:
+ case Instruction::PUSH1:
+ case Instruction::PUSH2:
+ case Instruction::PUSH3:
+ case Instruction::PUSH4:
+ case Instruction::PUSH5:
+ case Instruction::PUSH6:
+ case Instruction::PUSH7:
+ case Instruction::PUSH8:
+ case Instruction::PUSH9:
+ case Instruction::PUSH10:
+ case Instruction::PUSH11:
+ case Instruction::PUSH12:
+ case Instruction::PUSH13:
+ case Instruction::PUSH14:
+ case Instruction::PUSH15:
+ case Instruction::PUSH16:
+ case Instruction::PUSH17:
+ case Instruction::PUSH18:
+ case Instruction::PUSH19:
+ case Instruction::PUSH20:
+ case Instruction::PUSH21:
+ case Instruction::PUSH22:
+ case Instruction::PUSH23:
+ case Instruction::PUSH24:
+ case Instruction::PUSH25:
+ case Instruction::PUSH26:
+ case Instruction::PUSH27:
+ case Instruction::PUSH28:
+ case Instruction::PUSH29:
+ case Instruction::PUSH30:
+ case Instruction::PUSH31:
+ case Instruction::PUSH32:
+ case Instruction::POP:
+ case Instruction::DUP1:
+ case Instruction::DUP2:
+ case Instruction::DUP3:
+ case Instruction::DUP4:
+ case Instruction::DUP5:
+ case Instruction::DUP6:
+ case Instruction::DUP7:
+ case Instruction::DUP8:
+ case Instruction::DUP9:
+ case Instruction::DUP10:
+ case Instruction::DUP11:
+ case Instruction::DUP12:
+ case Instruction::DUP13:
+ case Instruction::DUP14:
+ case Instruction::DUP15:
+ case Instruction::DUP16:
+ case Instruction::SWAP1:
+ case Instruction::SWAP2:
+ case Instruction::SWAP3:
+ case Instruction::SWAP4:
+ case Instruction::SWAP5:
+ case Instruction::SWAP6:
+ case Instruction::SWAP7:
+ case Instruction::SWAP8:
+ case Instruction::SWAP9:
+ case Instruction::SWAP10:
+ case Instruction::SWAP11:
+ case Instruction::SWAP12:
+ case Instruction::SWAP13:
+ case Instruction::SWAP14:
+ case Instruction::SWAP15:
+ case Instruction::SWAP16:
+ case Instruction::JUMP:
+ case Instruction::JUMPI:
+ case Instruction::PC:
+ case Instruction::MSIZE:
+ case Instruction::GAS:
+ case Instruction::JUMPDEST:
break;
+ default:
+ BOOST_THROW_EXCEPTION(BadInstruction());
}
newTempSize = (newTempSize + 31) / 32 * 32;
@@ -568,19 +674,19 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;
case Instruction::JUMP:
require(1);
- m_jumpLatch = true;
- if (!m_destinations.count(m_stack.back()))
- BOOST_THROW_EXCEPTION(BadJumpDestination());
nextPC = m_stack.back();
+ if (nextPC && (Instruction)_ext.getCode(nextPC - 1) != Instruction::JUMPDEST)
+ BOOST_THROW_EXCEPTION(BadJumpDestination());
m_stack.pop_back();
break;
case Instruction::JUMPI:
require(2);
- m_jumpLatch = true;
- if (!m_destinations.count(m_stack.back()))
- BOOST_THROW_EXCEPTION(BadJumpDestination());
if (m_stack[m_stack.size() - 2])
+ {
nextPC = m_stack.back();
+ if (nextPC && (Instruction)_ext.getCode(nextPC - 1) != Instruction::JUMPDEST)
+ BOOST_THROW_EXCEPTION(BadJumpDestination());
+ }
m_stack.pop_back();
m_stack.pop_back();
break;
@@ -594,10 +700,6 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
m_stack.push_back(m_gas);
break;
case Instruction::JUMPDEST:
- require(1);
- if (!m_jumpLatch)
- m_destinations.insert(m_stack.back());
- m_stack.pop_back();
break;
case Instruction::CREATE:
{
@@ -612,6 +714,8 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
if (_ext.balance(_ext.myAddress) >= endowment)
{
+ if (_ext.depth == 1024)
+ BOOST_THROW_EXCEPTION(OutOfGas());
_ext.subBalance(endowment);
m_stack.push_back((u160)_ext.create(endowment, &m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp));
}
@@ -642,6 +746,8 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
if (_ext.balance(_ext.myAddress) >= value)
{
+ if (_ext.depth == 1024)
+ BOOST_THROW_EXCEPTION(OutOfGas());
_ext.subBalance(value);
m_stack.push_back(_ext.call(inst == Instruction::CALL ? receiveAddress : _ext.myAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), &gas, bytesRef(m_temp.data() + outOff, outSize), _onOp, Address(), receiveAddress));
}
@@ -671,8 +777,6 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
}
case Instruction::STOP:
return bytesConstRef();
- default:
- BOOST_THROW_EXCEPTION(BadInstruction());
}
}
if (_steps == (uint64_t)-1)
diff --git a/liblll/Assembly.cpp b/liblll/Assembly.cpp
index 11ee9122c..c26a9a98e 100644
--- a/liblll/Assembly.cpp
+++ b/liblll/Assembly.cpp
@@ -129,7 +129,7 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i)
_out << " PUSH[tag" << i.data() << "]";
break;
case Tag:
- _out << " tag" << i.data() << ":";
+ _out << " tag" << i.data() << ": JUMPDEST";
break;
case PushData:
_out << " PUSH*[" << hex << (unsigned)i.data() << "]";
@@ -149,17 +149,6 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItemsConstRef _i)
ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const
{
- _out << _prefix << ".pre:" << endl;
- for (AssemblyItem const& i: m_items)
- switch (i.m_type)
- {
- case PushTag:
- _out << _prefix << " PUSH [tag" << i.m_data << "]" << endl;
- _out << _prefix << " JUMPDEST" << endl;
- break;
- default:;
- }
-
_out << _prefix << ".code:" << endl;
for (AssemblyItem const& i: m_items)
switch (i.m_type)
@@ -183,7 +172,7 @@ ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const
_out << _prefix << " PUSH #[$" << h256(i.m_data).abridged() << "]" << endl;
break;
case Tag:
- _out << _prefix << "tag" << i.m_data << ": " << endl;
+ _out << _prefix << "tag" << i.m_data << ": " << endl << _prefix << " JUMPDEST" << endl;
break;
case PushData:
_out << _prefix << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl;
@@ -364,11 +353,9 @@ bytes Assembly::assemble() const
ret.reserve(totalBytes);
vector tagPos(m_usedTags);
map tagRef;
- map pretagRef;
multimap dataRef;
unsigned bytesPerTag = dev::bytesRequired(totalBytes);
byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag;
- bytes preret;
for (auto const& i: m_subs)
m_data[i.first] = i.second.assemble();
@@ -406,11 +393,6 @@ bytes Assembly::assemble() const
ret.push_back(tagPush);
tagRef[ret.size()] = (unsigned)i.m_data;
ret.resize(ret.size() + bytesPerTag);
-
- preret.push_back(tagPush);
- pretagRef[preret.size()] = (unsigned)i.m_data;
- preret.resize(preret.size() + bytesPerTag);
- preret.push_back((byte)Instruction::JUMPDEST);
break;
}
case PushData: case PushSub:
@@ -431,6 +413,7 @@ bytes Assembly::assemble() const
break;
}
case Tag:
+ ret.push_back((byte)Instruction::JUMPDEST);
tagPos[(unsigned)i.m_data] = ret.size();
break;
default:;
@@ -442,12 +425,6 @@ bytes Assembly::assemble() const
toBigEndian(tagPos[i.second], r);
}
- for (auto const& i: pretagRef)
- {
- bytesRef r(preret.data() + i.first, bytesPerTag);
- toBigEndian(tagPos[i.second], r);
- }
-
if (m_data.size())
{
ret.push_back(0);
@@ -466,5 +443,5 @@ bytes Assembly::assemble() const
}
}
}
- return preret + ret;
+ return ret;
}
diff --git a/libp2p/CMakeLists.txt b/libp2p/CMakeLists.txt
index ab852fc57..c3cdc70b9 100644
--- a/libp2p/CMakeLists.txt
+++ b/libp2p/CMakeLists.txt
@@ -17,6 +17,7 @@ file(GLOB HEADERS "*.h")
include_directories(..)
+target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} secp256k1)
if(MINIUPNPC_LS)
diff --git a/libp2p/Common.cpp b/libp2p/Common.cpp
index 540f285c1..8a3b27ef0 100644
--- a/libp2p/Common.cpp
+++ b/libp2p/Common.cpp
@@ -64,7 +64,12 @@ std::string p2p::reasonOf(DisconnectReason _r)
case TooManyPeers: return "Peer had too many connections.";
case DuplicatePeer: return "Peer was already connected.";
case IncompatibleProtocol: return "Peer protocol versions are incompatible.";
+ case NullIdentity: return "Null identity given.";
case ClientQuit: return "Peer is exiting.";
+ case UnexpectedIdentity: return "Unexpected identity given.";
+ case LocalIdentity: return "Connected to ourselves.";
+ case UserReason: return "Subprotocol reason.";
+ case NoDisconnect: return "(No disconnect has happened.)";
default: return "Unknown reason.";
}
}
diff --git a/libp2p/Common.h b/libp2p/Common.h
index 895b76404..04154c9a0 100644
--- a/libp2p/Common.h
+++ b/libp2p/Common.h
@@ -44,6 +44,8 @@ class RLPStream;
namespace p2p
{
+using NodeId = h512;
+
bool isPrivateAddress(bi::address const& _addressToCheck);
class UPnP;
@@ -82,11 +84,30 @@ enum DisconnectReason
TooManyPeers,
DuplicatePeer,
IncompatibleProtocol,
- InvalidIdentity,
+ NullIdentity,
ClientQuit,
- UserReason = 0x10
+ UnexpectedIdentity,
+ LocalIdentity,
+ UserReason = 0x10,
+ NoDisconnect = 0xffff
};
+inline bool isPermanentProblem(DisconnectReason _r)
+{
+ switch (_r)
+ {
+ case DisconnectRequested:
+ case DuplicatePeer:
+ case IncompatibleProtocol:
+ case NullIdentity:
+ case UnexpectedIdentity:
+ case LocalIdentity:
+ return true;
+ default:
+ return false;
+ }
+}
+
/// @returns the string form of the given disconnection reason.
std::string reasonOf(DisconnectReason _r);
@@ -96,6 +117,7 @@ typedef std::vector CapDescs;
struct PeerInfo
{
+ NodeId id;
std::string clientVersion;
std::string host;
unsigned short port;
diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp
index 05fa81f4c..44fa137e5 100644
--- a/libp2p/Host.cpp
+++ b/libp2p/Host.cpp
@@ -63,11 +63,10 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool
m_netPrefs(_n),
m_acceptor(m_ioService),
m_socket(m_ioService),
- m_id(h512::random())
+ m_key(KeyPair::create())
{
populateAddresses();
- m_lastPeersRequest = chrono::steady_clock::time_point::min();
- clog(NetNote) << "Id:" << m_id.abridged();
+ clog(NetNote) << "Id:" << id().abridged();
if (_start)
start();
}
@@ -109,11 +108,10 @@ void Host::start()
determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp);
ensureAccepting();
- m_incomingPeers.clear();
- m_freePeers.clear();
+ if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id()))
+ noteNode(id(), m_public, Origin::Perfect, false);
- m_lastPeersRequest = chrono::steady_clock::time_point::min();
- clog(NetNote) << "Id:" << m_id.abridged();
+ clog(NetNote) << "Id:" << id().abridged();
for (auto const& h: m_capabilities)
h.second->onStarting();
@@ -149,9 +147,15 @@ unsigned Host::protocolVersion() const
void Host::registerPeer(std::shared_ptr _s, CapDescs const& _caps)
{
+ if (!_s->m_node || !_s->m_node->id)
{
- Guard l(x_peers);
- m_peers[_s->m_id] = _s;
+ cwarn << "Attempting to register a peer without node information!";
+ return;
+ }
+
+ {
+ RecursiveGuard l(x_peers);
+ m_peers[_s->m_node->id] = _s;
}
unsigned o = (unsigned)UserPacket;
for (auto const& i: _caps)
@@ -167,7 +171,7 @@ void Host::disconnectPeers()
for (unsigned n = 0;; n = 0)
{
{
- Guard l(x_peers);
+ RecursiveGuard l(x_peers);
for (auto i: m_peers)
if (auto p = i.second.lock())
{
@@ -182,6 +186,7 @@ void Host::disconnectPeers()
}
delete m_upnp;
+ m_upnp = nullptr;
}
void Host::seal(bytes& _b)
@@ -210,7 +215,10 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
if (m_upnp && m_upnp->isValid() && m_peerAddresses.size())
{
clog(NetNote) << "External addr:" << m_upnp->externalIP();
- int p = m_upnp->addRedirect(m_peerAddresses[0].to_string().c_str(), m_listenPort);
+ int p;
+ for (auto const& addr : m_peerAddresses)
+ if ((p = m_upnp->addRedirect(addr.to_string().c_str(), m_listenPort)))
+ break;
if (p)
clog(NetNote) << "Punched through NAT and mapped local port" << m_listenPort << "onto external port" << p << ".";
else
@@ -226,7 +234,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
else
{
m_public = bi::tcp::endpoint(bi::address::from_string(_publicAddress.empty() ? eip : _publicAddress), (unsigned short)p);
- m_addresses.push_back(m_public.address().to_v4());
+ m_addresses.push_back(m_public.address());
}
}
else
@@ -235,7 +243,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
m_public = bi::tcp::endpoint(_publicAddress.size() ? bi::address::from_string(_publicAddress)
: m_peerAddresses.size() ? m_peerAddresses[0]
: bi::address(), m_listenPort);
- m_addresses.push_back(m_public.address().to_v4());
+ m_addresses.push_back(m_public.address());
}
}
@@ -308,33 +316,92 @@ void Host::populateAddresses()
clog(NetNote) << "Couldn't resolve: " << host;
}
}
+ else if (ifa->ifa_addr->sa_family == AF_INET6)
+ {
+ char host[NI_MAXHOST];
+ if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
+ continue;
+ try
+ {
+ auto it = r.resolve({host, "30303"});
+ bi::tcp::endpoint ep = it->endpoint();
+ bi::address ad = ep.address();
+ m_addresses.push_back(ad.to_v6());
+ bool isLocal = std::find(c_rejectAddresses.begin(), c_rejectAddresses.end(), ad) != c_rejectAddresses.end();
+ if (!isLocal)
+ m_peerAddresses.push_back(ad);
+ clog(NetNote) << "Address: " << host << " = " << m_addresses.back() << (isLocal ? " [LOCAL]" : " [PEER]");
+ }
+ catch (...)
+ {
+ clog(NetNote) << "Couldn't resolve: " << host;
+ }
+ }
}
freeifaddrs(ifaddr);
#endif
}
-std::map Host::potentialPeers()
+shared_ptr Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId)
{
- std::map ret;
- if (!m_public.address().is_unspecified())
- ret.insert(make_pair(m_id, m_public));
- Guard l(x_peers);
- for (auto i: m_peers)
- if (auto j = i.second.lock())
+ RecursiveGuard l(x_peers);
+ cnote << "Node:" << _id.abridged() << _a << (_ready ? "ready" : "used") << _oldId.abridged() << (m_nodes.count(_id) ? "[have]" : "[NEW]");
+ if (!_a.port())
+ {
+ cwarn << "PORT IS INVALID!";
+ }
+ unsigned i;
+ if (!m_nodes.count(_id))
+ {
+ if (m_nodes.count(_oldId))
{
- auto ep = j->endpoint();
-// cnote << "Checking potential peer" << j->m_listenPort << j->endpoint() << isPrivateAddress(ep.address()) << ep.port() << j->m_id.abridged();
- // Skip peers with a listen port of zero or are on a private network
- bool peerOnNet = (j->m_listenPort != 0 && (!isPrivateAddress(ep.address()) || m_netPrefs.localNetworking));
- if (!peerOnNet && m_incomingPeers.count(j->m_id))
- {
- ep = m_incomingPeers.at(j->m_id).first;
- peerOnNet = (j->m_listenPort != 0 && (!isPrivateAddress(ep.address()) || m_netPrefs.localNetworking));
- }
- if (peerOnNet && ep.port() && j->m_id)
- ret.insert(make_pair(i.first, ep));
+ i = m_nodes[_oldId]->index;
+ m_nodes.erase(_oldId);
+ m_nodesList[i] = _id;
+ }
+ else
+ {
+ i = m_nodesList.size();
+ m_nodesList.push_back(_id);
}
+ m_nodes[_id] = make_shared();
+ m_nodes[_id]->id = _id;
+ m_nodes[_id]->address = _a;
+ m_nodes[_id]->index = i;
+ m_nodes[_id]->idOrigin = _o;
+ }
+ else
+ {
+ i = m_nodes[_id]->index;
+ m_nodes[_id]->idOrigin = max(m_nodes[_id]->idOrigin, _o);
+ }
+ m_ready.extendAll(i);
+ m_private.extendAll(i);
+ if (_ready)
+ m_ready += i;
+ else
+ m_ready -= i;
+ if (!_a.port() || (isPrivateAddress(_a.address()) && !m_netPrefs.localNetworking))
+ m_private += i;
+ else
+ m_private -= i;
+
+ cnote << m_nodes[_id]->index << ":" << m_ready;
+
+ m_hadNewNodes = true;
+
+ return m_nodes[_id];
+}
+
+Nodes Host::potentialPeers(RangeMask const& _known)
+{
+ RecursiveGuard l(x_peers);
+ Nodes ret;
+
+ auto ns = (m_netPrefs.localNetworking ? _known : (m_private + _known)).inverted();
+ for (auto i: ns)
+ ret.push_back(*m_nodes[m_nodesList[i]]);
return ret;
}
@@ -355,7 +422,7 @@ void Host::ensureAccepting()
} catch (...){}
bi::address remoteAddress = m_socket.remote_endpoint().address();
// Port defaults to 0 - we let the hello tell us which port the peer listens to
- auto p = std::make_shared(this, std::move(m_socket), remoteAddress);
+ auto p = std::make_shared(this, std::move(m_socket), bi::tcp::endpoint(remoteAddress, 0));
p->start();
}
catch (Exception const& _e)
@@ -411,26 +478,15 @@ void Host::connect(std::string const& _addr, unsigned short _port) noexcept
void Host::connect(bi::tcp::endpoint const& _ep)
{
- clog(NetConnect) << "Attempting connection to " << _ep;
+ clog(NetConnect) << "Attempting single-shot connection to " << _ep;
bi::tcp::socket* s = new bi::tcp::socket(m_ioService);
s->async_connect(_ep, [=](boost::system::error_code const& ec)
{
if (ec)
- {
clog(NetConnect) << "Connection refused to " << _ep << " (" << ec.message() << ")";
- for (auto i = m_incomingPeers.begin(); i != m_incomingPeers.end(); ++i)
- if (i->second.first == _ep && i->second.second < 3)
- {
- m_freePeers.push_back(i->first);
- goto OK;
- }
- // for-else
- clog(NetConnect) << "Giving up.";
- OK:;
- }
else
{
- auto p = make_shared(this, std::move(*s), _ep.address(), _ep.port());
+ auto p = make_shared(this, std::move(*s), _ep);
clog(NetConnect) << "Connected to " << _ep;
p->start();
}
@@ -438,9 +494,35 @@ void Host::connect(bi::tcp::endpoint const& _ep)
});
}
-bool Host::havePeer(h512 _id) const
+void Node::connect(Host* _h)
{
- Guard l(x_peers);
+ clog(NetConnect) << "Attempting connection to node" << id.abridged() << "@" << address << "from" << _h->id().abridged();
+ _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 (ec)
+ {
+ clog(NetConnect) << "Connection refused to node" << id.abridged() << "@" << address << "(" << ec.message() << ")";
+ failedAttempts++;
+ lastAttempted = std::chrono::system_clock::now();
+ _h->m_ready += index;
+ }
+ else
+ {
+ clog(NetConnect) << "Connected to" << id.abridged() << "@" << address;
+ failedAttempts = 0;
+ lastConnected = std::chrono::system_clock::now();
+ auto p = make_shared(_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.
+ p->start();
+ }
+ delete s;
+ });
+}
+
+bool Host::havePeer(NodeId _id) const
+{
+ RecursiveGuard l(x_peers);
// Remove dead peers from list.
for (auto i = m_peers.begin(); i != m_peers.end();)
@@ -452,43 +534,55 @@ bool Host::havePeer(h512 _id) const
return !!m_peers.count(_id);
}
+unsigned cumulativeFallback(unsigned _failed)
+{
+ if (_failed < 5)
+ return _failed * 5;
+ else if (_failed < 15)
+ return 25 + (_failed - 5) * 10;
+ else
+ return 25 + 100 + (_failed - 15) * 20;
+}
+
void Host::growPeers()
{
- Guard l(x_peers);
- while (m_peers.size() < m_idealPeerCount)
+ RecursiveGuard l(x_peers);
+ int morePeers = (int)m_idealPeerCount - m_peers.size();
+ if (morePeers > 0)
{
- if (m_freePeers.empty())
- {
- if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10))
+ auto toTry = m_ready;
+ if (!m_netPrefs.localNetworking)
+ toTry -= m_private;
+ set ns;
+ for (auto i: toTry)
+ if (chrono::system_clock::now() > m_nodes[m_nodesList[i]]->lastAttempted + chrono::seconds(cumulativeFallback(m_nodes[m_nodesList[i]]->failedAttempts)))
+ ns.insert(*m_nodes[m_nodesList[i]]);
+
+ if (ns.size())
+ for (Node const& i: ns)
{
- RLPStream s;
- bytes b;
- Session::prep(s, GetPeersPacket).swapOut(b);
- seal(b);
- for (auto const& i: m_peers)
- if (auto p = i.second.lock())
- if (p->isOpen())
- p->send(&b);
- m_lastPeersRequest = chrono::steady_clock::now();
+ m_nodes[i.id]->connect(this);
+ if (!--morePeers)
+ return;
}
-
- if (!m_accepting)
- ensureAccepting();
-
- break;
+ else
+ {
+ ensureAccepting();
+ requestNodes();
}
-
- auto x = time(0) % m_freePeers.size();
- m_incomingPeers[m_freePeers[x]].second++;
- if (!m_peers.count(m_freePeers[x]))
- connect(m_incomingPeers[m_freePeers[x]].first);
- m_freePeers.erase(m_freePeers.begin() + x);
}
}
+void Host::requestNodes()
+{
+ for (auto const& i: m_peers)
+ if (auto p = i.second.lock())
+ p->ensureNodesRequested();
+}
+
void Host::prunePeers()
{
- Guard l(x_peers);
+ RecursiveGuard l(x_peers);
// We'll keep at most twice as many as is ideal, halfing what counts as "too young to kill" until we get there.
for (unsigned old = 15000; m_peers.size() > m_idealPeerCount * 2 && old > 100; old /= 2)
while (m_peers.size() > m_idealPeerCount)
@@ -502,7 +596,7 @@ void Host::prunePeers()
if (/*(m_mode != NodeMode::Host || p->m_caps != 0x01) &&*/ chrono::steady_clock::now() > p->m_connect + chrono::milliseconds(old)) // don't throw off new peers; peer-servers should never kick off other peer-servers.
{
++agedPeers;
- if ((!worst || p->m_rating < worst->m_rating || (p->m_rating == worst->m_rating && p->m_connect > worst->m_connect))) // kill older ones
+ if ((!worst || p->rating() < worst->rating() || (p->rating() == worst->rating() && p->m_connect > worst->m_connect))) // kill older ones
worst = p;
}
if (!worst || agedPeers <= m_idealPeerCount)
@@ -520,10 +614,12 @@ void Host::prunePeers()
std::vector Host::peers(bool _updatePing) const
{
- Guard l(x_peers);
+ RecursiveGuard l(x_peers);
if (_updatePing)
+ {
const_cast(this)->pingAll();
- this_thread::sleep_for(chrono::milliseconds(200));
+ this_thread::sleep_for(chrono::milliseconds(200));
+ }
std::vector ret;
for (auto& i: m_peers)
if (auto j = i.second.lock())
@@ -536,41 +632,105 @@ void Host::doWork()
{
growPeers();
prunePeers();
+
+ if (m_hadNewNodes)
+ {
+ for (auto p: m_peers)
+ if (auto pp = p.second.lock())
+ pp->serviceNodesRequest();
+
+ m_hadNewNodes = false;
+ }
+
m_ioService.poll();
}
void Host::pingAll()
{
- Guard l(x_peers);
+ RecursiveGuard l(x_peers);
for (auto& i: m_peers)
if (auto j = i.second.lock())
j->ping();
}
-bytes Host::savePeers() const
+bytes Host::saveNodes() const
{
- Guard l(x_peers);
- RLPStream ret;
- int n = 0;
- for (auto& i: m_peers)
- if (auto p = i.second.lock())
- if (p->m_socket.is_open() && p->endpoint().port())
+ RLPStream nodes;
+ int count = 0;
+ {
+ RecursiveGuard l(x_peers);
+ for (auto const& i: m_nodes)
+ {
+ Node const& n = *(i.second);
+ if (!n.dead && n.id != id() && !isPrivateAddress(n.address.address()))
{
- ret.appendList(3) << p->endpoint().address().to_v4().to_bytes() << p->endpoint().port() << p->m_id;
- n++;
+ nodes.appendList(10);
+ if (n.address.address().is_v4())
+ nodes << n.address.address().to_v4().to_bytes();
+ else
+ nodes << n.address.address().to_v6().to_bytes();
+ nodes << n.address.port() << n.id << (int)n.idOrigin
+ << std::chrono::duration_cast(n.lastConnected.time_since_epoch()).count()
+ << std::chrono::duration_cast(n.lastAttempted.time_since_epoch()).count()
+ << n.failedAttempts << (unsigned)n.lastDisconnect << n.score << n.rating;
+ count++;
}
- return RLPStream(n).appendRaw(ret.out(), n).out();
+ }
+ }
+ RLPStream ret(3);
+ ret << 0 << m_key.secret();
+ ret.appendList(count).appendRaw(nodes.out(), count);
+ return ret.out();
}
-void Host::restorePeers(bytesConstRef _b)
+void Host::restoreNodes(bytesConstRef _b)
{
- for (auto i: RLP(_b))
- {
- auto k = (h512)i[2];
- if (!m_incomingPeers.count(k))
+ RecursiveGuard l(x_peers);
+ RLP r(_b);
+ if (r.itemCount() > 0 && r[0].isInt())
+ switch (r[0].toInt())
+ {
+ case 0:
{
- m_incomingPeers.insert(make_pair(k, make_pair(bi::tcp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt()), 0)));
- m_freePeers.push_back(k);
+ auto oldId = id();
+ m_key = KeyPair(r[1].toHash());
+ noteNode(id(), m_public, Origin::Perfect, false, oldId);
+
+ for (auto i: r[2])
+ {
+ bi::tcp::endpoint ep;
+ if (i[0].itemCount() == 4)
+ ep = bi::tcp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt());
+ else
+ ep = bi::tcp::endpoint(bi::address_v6(i[0].toArray()), i[1].toInt());
+ auto id = (NodeId)i[2];
+ if (!m_nodes.count(id))
+ {
+ auto o = (Origin)i[3].toInt();
+ auto n = noteNode(id, ep, o, true);
+ n->lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt()));
+ n->lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt()));
+ n->failedAttempts = i[6].toInt();
+ n->lastDisconnect = (DisconnectReason)i[7].toInt();
+ n->score = (int)i[8].toInt();
+ n->rating = (int)i[9].toInt();
+ }
+ }
+ }
+ default:;
+ }
+ else
+ for (auto i: r)
+ {
+ auto id = (NodeId)i[2];
+ if (!m_nodes.count(id))
+ {
+ bi::tcp::endpoint ep;
+ if (i[0].itemCount() == 4)
+ ep = bi::tcp::endpoint(bi::address_v4(i[0].toArray()), i[1].toInt());
+ else
+ ep = bi::tcp::endpoint(bi::address_v6(i[0].toArray()), i[1].toInt());
+ auto n = noteNode(id, ep, Origin::Self, true);
+ }
}
- }
}
diff --git a/libp2p/Host.h b/libp2p/Host.h
index b4ba9c2d4..a7beb8c35 100644
--- a/libp2p/Host.h
+++ b/libp2p/Host.h
@@ -28,8 +28,11 @@
#include
#include
#include
+#include
#include
#include
+#include
+#include
#include "HostCapability.h"
#include "Common.h"
namespace ba = boost::asio;
@@ -43,6 +46,60 @@ class RLPStream;
namespace p2p
{
+class Host;
+
+enum class Origin
+{
+ Unknown,
+ Self,
+ SelfThird,
+ PerfectThird,
+ Perfect,
+};
+
+struct Node
+{
+ NodeId id; ///< Their id/public key.
+ unsigned index; ///< Index into m_nodesList
+ bi::tcp::endpoint address; ///< As reported from the node itself.
+ int score = 0; ///< All time cumulative.
+ int rating = 0; ///< Trending.
+ bool dead = false; ///< If true, we believe this node is permanently dead - forget all about it.
+ std::chrono::system_clock::time_point lastConnected;
+ std::chrono::system_clock::time_point lastAttempted;
+ unsigned failedAttempts = 0;
+ DisconnectReason lastDisconnect = NoDisconnect; ///< Reason for disconnect that happened last.
+
+ Origin idOrigin = Origin::Unknown; ///< How did we get to know this node's id?
+
+ int secondsSinceLastConnected() const { return lastConnected == std::chrono::system_clock::time_point() ? -1 : (int)std::chrono::duration_cast(std::chrono::system_clock::now() - lastConnected).count(); }
+ int secondsSinceLastAttempted() const { return lastAttempted == std::chrono::system_clock::time_point() ? -1 : (int)std::chrono::duration_cast(std::chrono::system_clock::now() - lastAttempted).count(); }
+
+ bool isOffline() const { return lastDisconnect == -1 || lastAttempted > lastConnected; }
+ bool operator<(Node const& _n) const
+ {
+ if (isOffline() != _n.isOffline())
+ return isOffline();
+ else if (isOffline())
+ if (lastAttempted == _n.lastAttempted)
+ return failedAttempts < _n.failedAttempts;
+ else
+ return lastAttempted < _n.lastAttempted;
+ else
+ if (score == _n.score)
+ if (rating == _n.rating)
+ return failedAttempts < _n.failedAttempts;
+ else
+ return rating < _n.rating;
+ else
+ return score < _n.score;
+ }
+
+ void connect(Host* _h);
+};
+
+using Nodes = std::vector;
+
struct NetworkPreferences
{
NetworkPreferences(unsigned short p = 30303, std::string i = std::string(), bool u = true, bool l = false): listenPort(p), publicIP(i), upnp(u), localNetworking(l) {}
@@ -61,6 +118,7 @@ class Host: public Worker
{
friend class Session;
friend class HostCapabilityFace;
+ friend class Node;
public:
/// Start server, listening for connections on the given port.
@@ -88,7 +146,7 @@ public:
void connect(bi::tcp::endpoint const& _ep);
/// @returns true iff we have the a peer of the given id.
- bool havePeer(h512 _id) const;
+ bool havePeer(NodeId _id) const;
/// Set ideal number of peers.
void setIdealPeerCount(unsigned _n) { m_idealPeerCount = _n; }
@@ -97,7 +155,7 @@ public:
std::vector peers(bool _updatePing = false) const;
/// Get number of peers connected; equivalent to, but faster than, peers().size().
- size_t peerCount() const { Guard l(x_peers); return m_peers.size(); }
+ size_t peerCount() const { RecursiveGuard l(x_peers); return m_peers.size(); }
/// Ping the peers, to update the latency information.
void pingAll();
@@ -106,10 +164,12 @@ public:
unsigned short listenPort() const { return m_public.port(); }
/// Serialise the set of known peers.
- bytes savePeers() const;
+ bytes saveNodes() const;
/// Deserialise the data and populate the set of known peers.
- void restorePeers(bytesConstRef _b);
+ void restoreNodes(bytesConstRef _b);
+
+ 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(); }
@@ -117,14 +177,13 @@ public:
void stop();
bool isStarted() const { return isWorking(); }
- h512 id() const { return m_id; }
+ NodeId id() const { return m_key.pub(); }
void registerPeer(std::shared_ptr _s, CapDescs const& _caps);
-private:
- /// Called when the session has provided us with a new peer we can connect to.
- void noteNewPeers() {}
+ std::shared_ptr node(NodeId _id) const { if (m_nodes.count(_id)) return m_nodes.at(_id); return std::shared_ptr(); }
+private:
void seal(bytes& _b);
void populateAddresses();
void determinePublic(std::string const& _publicAddress, bool _upnp);
@@ -138,36 +197,52 @@ private:
/// This won't touch alter the blockchain.
virtual void doWork();
- std::map potentialPeers();
+ std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId = h256());
+ Nodes potentialPeers(RangeMask const& _known);
+
+ void requestNodes();
+
+ std::string m_clientVersion; ///< Our version string.
+
+ NetworkPreferences m_netPrefs; ///< Network settings.
+
+ 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.
+ bi::tcp::acceptor m_acceptor; ///< Listening acceptor.
+ bi::tcp::socket m_socket; ///< Listening socket.
- std::string m_clientVersion;
+ UPnP* m_upnp = nullptr; ///< UPnP helper.
+ bi::tcp::endpoint m_public; ///< Our public listening endpoint.
+ KeyPair m_key; ///< Our unique ID.
- NetworkPreferences m_netPrefs;
+ bool m_hadNewNodes = false;
- static const int NetworkStopped = -1;
- int m_listenPort = NetworkStopped;
+ mutable RecursiveMutex x_peers;
- ba::io_service m_ioService;
- bi::tcp::acceptor m_acceptor;
- bi::tcp::socket m_socket;
+ /// The nodes to which we are currently connected.
+ /// Mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method.
+ mutable std::map> m_peers;
- UPnP* m_upnp = nullptr;
- bi::tcp::endpoint m_public;
- h512 m_id;
+ /// Nodes to which we may connect (or to which we have connected).
+ /// TODO: does this need a lock?
+ std::map > m_nodes;
- mutable std::mutex x_peers;
- mutable std::map> m_peers; // mutable because we flush zombie entries (null-weakptrs) as regular maintenance from a const method.
+ /// A list of node IDs. This contains every index from m_nodes; the order is guaranteed to remain the same.
+ std::vector m_nodesList;
- std::map> m_incomingPeers; // TODO: does this need a lock?
- std::vector m_freePeers;
+ RangeMask m_ready; ///< Indices into m_nodesList over to which nodes we are not currently connected, connecting or otherwise ignoring.
+ RangeMask m_private; ///< Indices into m_nodesList over to which nodes are private.
- std::chrono::steady_clock::time_point m_lastPeersRequest;
- unsigned m_idealPeerCount = 5;
+ unsigned m_idealPeerCount = 5; ///< Ideal number of peers to be connected to.
- std::vector m_addresses;
- std::vector m_peerAddresses;
+ // Our addresses.
+ std::vector m_addresses; ///< Addresses for us.
+ std::vector m_peerAddresses; ///< Addresses that peers (can) know us by.
- std::map> m_capabilities;
+ // Our capabilities.
+ std::map> m_capabilities; ///< Each of the capabilities we support.
bool m_accepting = false;
};
diff --git a/libp2p/HostCapability.cpp b/libp2p/HostCapability.cpp
index 2f295afd0..0728bef2c 100644
--- a/libp2p/HostCapability.cpp
+++ b/libp2p/HostCapability.cpp
@@ -34,7 +34,7 @@ void HostCapabilityFace::seal(bytes& _b)
std::vector > HostCapabilityFace::peers() const
{
- Guard l(m_host->x_peers);
+ RecursiveGuard l(m_host->x_peers);
std::vector > ret;
for (auto const& i: m_host->m_peers)
if (std::shared_ptr p = i.second.lock())
diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp
index 12f48f3c9..3f224a72d 100644
--- a/libp2p/Session.cpp
+++ b/libp2p/Session.cpp
@@ -36,19 +36,35 @@ using namespace dev::p2p;
#endif
#define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << m_socket.native_handle() << "] "
-Session::Session(Host* _s, bi::tcp::socket _socket, bi::address _peerAddress, unsigned short _peerPort):
+Session::Session(Host* _s, bi::tcp::socket _socket, bi::tcp::endpoint const& _manual):
m_server(_s),
m_socket(std::move(_socket)),
- m_listenPort(_peerPort),
- m_rating(0)
+ m_node(nullptr),
+ m_manualEndpoint(_manual)
{
m_disconnect = std::chrono::steady_clock::time_point::max();
m_connect = std::chrono::steady_clock::now();
- m_info = PeerInfo({"?", _peerAddress.to_string(), m_listenPort, std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()});
+
+ m_info = PeerInfo({NodeId(), "?", m_manualEndpoint.address().to_string(), m_manualEndpoint.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()});
+}
+
+Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr const& _n, bool _force):
+ m_server(_s),
+ m_socket(std::move(_socket)),
+ m_node(_n),
+ m_manualEndpoint(_n->address),
+ m_force(_force)
+{
+ m_disconnect = std::chrono::steady_clock::time_point::max();
+ m_connect = std::chrono::steady_clock::now();
+ m_info = PeerInfo({m_node->id, "?", _n->address.address().to_string(), _n->address.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map()});
}
Session::~Session()
{
+ if (id() && (!m_node || (!isPermanentProblem(m_node->lastDisconnect) && !m_node->dead)))
+ m_server->m_ready += m_node->index;
+
// Read-chain finished for one reason or another.
for (auto& i: m_capabilities)
i.second.reset();
@@ -61,57 +77,174 @@ Session::~Session()
catch (...){}
}
+NodeId Session::id() const
+{
+ return m_node ? m_node->id : NodeId();
+}
+
+void Session::addRating(unsigned _r)
+{
+ if (m_node)
+ {
+ m_node->rating += _r;
+ m_node->score += _r;
+ }
+}
+
+int Session::rating() const
+{
+ return m_node->rating;
+}
+
bi::tcp::endpoint Session::endpoint() const
{
- if (m_socket.is_open())
+ if (m_socket.is_open() && m_node)
try
{
- return bi::tcp::endpoint(m_socket.remote_endpoint().address(), m_listenPort);
+ return bi::tcp::endpoint(m_socket.remote_endpoint().address(), m_node->address.port());
}
- catch (...){}
+ catch (...) {}
+
+ if (m_node)
+ return m_node->address;
+
+ return m_manualEndpoint;
+}
- return bi::tcp::endpoint();
+template vector randomSelection(vector const& _t, unsigned _n)
+{
+ if (_t.size() <= _n)
+ return _t;
+ vector ret = _t;
+ while (ret.size() > _n)
+ {
+ auto i = ret.begin();
+ advance(i, rand() % ret.size());
+ ret.erase(i);
+ }
+ return ret;
+}
+
+void Session::ensureNodesRequested()
+{
+ if (isOpen() && !m_weRequestedNodes)
+ {
+ m_weRequestedNodes = true;
+ RLPStream s;
+ sealAndSend(prep(s, GetPeersPacket));
+ }
+}
+
+void Session::serviceNodesRequest()
+{
+ if (!m_theyRequestedNodes)
+ return;
+
+ auto peers = m_server->potentialPeers(m_knownNodes);
+ if (peers.empty())
+ {
+ addNote("peers", "requested");
+ return;
+ }
+
+ // note this should cost them...
+ RLPStream s;
+ prep(s, PeersPacket, min(10, peers.size()));
+ auto rs = randomSelection(peers, 10);
+ for (auto const& i: rs)
+ {
+ clogS(NetTriviaDetail) << "Sending peer " << i.id.abridged() << i.address;
+ if (i.address.address().is_v4())
+ s.appendList(3) << bytesConstRef(i.address.address().to_v4().to_bytes().data(), 4) << i.address.port() << i.id;
+ else// if (i.second.address().is_v6()) - assumed
+ s.appendList(3) << bytesConstRef(i.address.address().to_v6().to_bytes().data(), 16) << i.address.port() << i.id;
+ m_knownNodes.extendAll(i.index);
+ m_knownNodes.unionWith(i.index);
+ }
+ sealAndSend(s);
+ m_theyRequestedNodes = false;
+ addNote("peers", "done");
}
bool Session::interpret(RLP const& _r)
{
clogS(NetRight) << _r;
+ try // Generic try-catch block designed to capture RLP format errors - TODO: give decent diagnostics, make a bit more specific over what is caught.
+ {
+
switch ((PacketType)_r[0].toInt())
{
case HelloPacket:
{
+ if (m_node)
+ m_node->lastDisconnect = NoDisconnect;
+
m_protocolVersion = _r[1].toInt();
auto clientVersion = _r[2].toString();
auto caps = _r[3].toVector();
- m_listenPort = _r[4].toInt();
- m_id = _r[5].toHash();
+ auto listenPort = _r[4].toInt();
+ auto id = _r[5].toHash();
- clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << m_id.abridged() << showbase << hex << caps << dec << m_listenPort;
+ // clang error (previously: ... << hex << caps ...)
+ // "'operator<<' should be declared prior to the call site or in an associated namespace of one of its arguments"
+ stringstream capslog;
+ for (auto cap: caps)
+ capslog << "(" << hex << cap.first << "," << hex << cap.second << ")";
- if (m_server->havePeer(m_id))
+ clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << id.abridged() << showbase << capslog.str() << dec << listenPort;
+
+ if (m_server->id() == id)
{
// Already connected.
- clogS(NetWarn) << "Already have peer id" << m_id.abridged();// << "at" << l->endpoint() << "rather than" << endpoint();
- disconnect(DuplicatePeer);
+ clogS(NetWarn) << "Connected to ourself under a false pretext. We were told this peer was id" << m_info.id.abridged();
+ disconnect(LocalIdentity);
return false;
}
- if (!m_id)
+
+ if (m_node && m_node->id != id)
{
- disconnect(InvalidIdentity);
+ if (m_force || m_node->idOrigin <= Origin::SelfThird)
+ // SECURITY: We're forcing through the new ID, despite having been told
+ clogS(NetWarn) << "Connected to node, but their ID has changed since last time. This could indicate a MitM attack. Allowing anyway...";
+ else
+ {
+ clogS(NetWarn) << "Connected to node, but their ID has changed since last time. This could indicate a MitM attack. Disconnecting.";
+ disconnect(UnexpectedIdentity);
+ return false;
+ }
+
+ if (m_server->havePeer(id))
+ {
+ m_node->dead = true;
+ disconnect(DuplicatePeer);
+ return false;
+ }
+ }
+
+ if (m_server->havePeer(id))
+ {
+ // Already connected.
+ clogS(NetWarn) << "Already connected to a peer with id" << id.abridged();
+ disconnect(DuplicatePeer);
return false;
}
- if (m_protocolVersion != m_server->protocolVersion())
+
+ if (!id)
{
- disconnect(IncompatibleProtocol);
+ disconnect(NullIdentity);
return false;
}
- try
- { m_info = PeerInfo({clientVersion, m_socket.remote_endpoint().address().to_string(), m_listenPort, std::chrono::steady_clock::duration(), _r[3].toSet(), (unsigned)m_socket.native_handle(), map() }); }
- catch (...)
+
+ m_node = m_server->noteNode(id, bi::tcp::endpoint(m_socket.remote_endpoint().address(), listenPort), Origin::Self, false, !m_node || m_node->id == id ? NodeId() : m_node->id);
+ m_knownNodes.extendAll(m_node->index);
+ m_knownNodes.unionWith(m_node->index);
+
+ if (m_protocolVersion != m_server->protocolVersion())
{
- disconnect(BadProtocol);
+ disconnect(IncompatibleProtocol);
return false;
}
+ m_info = PeerInfo({id, clientVersion, m_socket.remote_endpoint().address().to_string(), listenPort, std::chrono::steady_clock::duration(), _r[3].toSet(), (unsigned)m_socket.native_handle(), map() });
m_server->registerPeer(shared_from_this(), caps);
break;
@@ -144,22 +277,13 @@ bool Session::interpret(RLP const& _r)
case GetPeersPacket:
{
clogS(NetTriviaSummary) << "GetPeers";
- auto peers = m_server->potentialPeers();
- RLPStream s;
- prep(s, PeersPacket, peers.size());
- for (auto i: peers)
- {
- clogS(NetTriviaDetail) << "Sending peer " << i.first.abridged() << i.second;
- if (i.second.address().is_v4())
- s.appendList(3) << bytesConstRef(i.second.address().to_v4().to_bytes().data(), 4) << i.second.port() << i.first;
- else// if (i.second.address().is_v6()) - assumed
- s.appendList(3) << bytesConstRef(i.second.address().to_v6().to_bytes().data(), 16) << i.second.port() << i.first;
- }
- sealAndSend(s);
+ m_theyRequestedNodes = true;
+ serviceNodesRequest();
break;
}
case PeersPacket:
clogS(NetTriviaSummary) << "Peers (" << dec << (_r.itemCount() - 1) << " entries)";
+ m_weRequestedNodes = false;
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
bi::address peerAddress;
@@ -173,28 +297,51 @@ bool Session::interpret(RLP const& _r)
return false;
}
auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt());
- h512 id = _r[i][2].toHash();
- clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")" << isPrivateAddress(peerAddress) << m_id.abridged() << isPrivateAddress(endpoint().address()) << m_server->m_incomingPeers.count(id) << (m_server->m_incomingPeers.count(id) ? isPrivateAddress(m_server->m_incomingPeers.at(id).first.address()) : -1);
+ NodeId id = _r[i][2].toHash();
+ clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")" << isPrivateAddress(peerAddress) << this->id().abridged() << isPrivateAddress(endpoint().address()) << m_server->m_nodes.count(id) << (m_server->m_nodes.count(id) ? isPrivateAddress(m_server->m_nodes.at(id)->address.address()) : -1);
if (isPrivateAddress(peerAddress) && !m_server->m_netPrefs.localNetworking)
- goto CONTINUE;
+ goto CONTINUE; // Private address. Ignore.
+
+ if (!id)
+ goto CONTINUE; // Null identity. Ignore.
+
+ if (m_server->id() == id)
+ goto CONTINUE; // Just our info - we already have that.
+
+ if (id == this->id())
+ goto CONTINUE; // Just their info - we already have that.
// check that it's not us or one we already know:
- if (!(m_id == id && isPrivateAddress(endpoint().address()) && (!m_server->m_incomingPeers.count(id) || isPrivateAddress(m_server->m_incomingPeers.at(id).first.address()))) && (!id || m_server->m_id == id || m_server->m_incomingPeers.count(id)))
+ if (m_server->m_nodes.count(id))
+ {
+ // Already got this node.
+ // See if it's any better that ours or not...
+ // This could be the public address of a known node.
+ // SECURITY: remove this in beta - it's only for lazy connections and presents an easy attack vector.
+ if (m_server->m_nodes.count(id) && isPrivateAddress(m_server->m_nodes.at(id)->address.address()))
+ // Update address if the node if we now have a public IP for it.
+ m_server->m_nodes[id]->address = ep;
goto CONTINUE;
+ }
- // check that we're not already connected to addr:
if (!ep.port())
- goto CONTINUE;
+ goto CONTINUE; // Zero port? Don't think so.
+
+ // Avoid our random other addresses that they might end up giving us.
for (auto i: m_server->m_addresses)
if (ep.address() == i && ep.port() == m_server->listenPort())
goto CONTINUE;
- for (auto i: m_server->m_incomingPeers)
- if (i.second.first == ep)
- goto CONTINUE;
- m_server->m_incomingPeers[id] = make_pair(ep, 0);
- m_server->m_freePeers.push_back(id);
- m_server->noteNewPeers();
+
+ // Check that we don't already know about this addr:port combination. If we are, assume the original is best.
+ // SECURITY: Not a valid assumption in general. Should compare ID origins and pick the best or note uncertainty and weight each equally.
+ for (auto const& i: m_server->m_nodes)
+ if (i.second->address == ep)
+ goto CONTINUE; // Same address but a different node.
+
+ // OK passed all our checks. Assume it's good.
+ addRating(1000);
+ m_server->noteNode(id, ep, m_node->idOrigin == Origin::Perfect ? Origin::PerfectThird : Origin::SelfThird, true);
clogS(NetTriviaDetail) << "New peer: " << ep << "(" << id .abridged()<< ")";
CONTINUE:;
}
@@ -208,6 +355,12 @@ bool Session::interpret(RLP const& _r)
return false;
}
}
+ }
+ catch (...)
+ {
+ disconnect(BadProtocol);
+ return false;
+ }
return true;
}
@@ -218,12 +371,6 @@ void Session::ping()
m_ping = std::chrono::steady_clock::now();
}
-void Session::getPeers()
-{
- RLPStream s;
- sealAndSend(prep(s, GetPeersPacket));
-}
-
RLPStream& Session::prep(RLPStream& _s, PacketType _id, unsigned _args)
{
return prep(_s).appendList(_args + 1).append((unsigned)_id);
@@ -338,9 +485,13 @@ void Session::dropped()
catch (...) {}
}
-void Session::disconnect(int _reason)
+void Session::disconnect(DisconnectReason _reason)
{
clogS(NetConnect) << "Disconnecting (reason:" << reasonOf((DisconnectReason)_reason) << ")";
+
+ if (m_node)
+ m_node->lastDisconnect = _reason;
+
if (m_socket.is_open())
{
if (m_disconnect == chrono::steady_clock::time_point::max())
@@ -363,11 +514,9 @@ void Session::start()
<< m_server->m_clientVersion
<< m_server->caps()
<< m_server->m_public.port()
- << m_server->m_id;
+ << m_server->id();
sealAndSend(s);
ping();
- getPeers();
-
doRead();
}
diff --git a/libp2p/Session.h b/libp2p/Session.h
index 1a0ae8730..e76edd8b1 100644
--- a/libp2p/Session.h
+++ b/libp2p/Session.h
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include "Common.h"
namespace dev
@@ -37,6 +38,8 @@ namespace dev
namespace p2p
{
+class Node;
+
/**
* @brief The Session class
* @todo Document fully.
@@ -47,17 +50,18 @@ class Session: public std::enable_shared_from_this
friend class HostCapabilityFace;
public:
- Session(Host* _server, bi::tcp::socket _socket, bi::address _peerAddress, unsigned short _peerPort = 0);
+ Session(Host* _server, bi::tcp::socket _socket, std::shared_ptr const& _n, bool _force = false);
+ Session(Host* _server, bi::tcp::socket _socket, bi::tcp::endpoint const& _manual);
virtual ~Session();
void start();
- void disconnect(int _reason);
+ void disconnect(DisconnectReason _reason);
void ping();
bool isOpen() const { return m_socket.is_open(); }
- h512 id() const { return m_id; }
+ NodeId id() const;
unsigned socketId() const { return m_socket.native_handle(); }
bi::tcp::endpoint endpoint() const; ///< for other peers to connect to.
@@ -71,12 +75,16 @@ public:
void sendDestroy(bytes& _msg);
void send(bytesConstRef _msg);
- void addRating(unsigned _r) { m_rating += _r; }
+ int rating() const;
+ void addRating(unsigned _r);
void addNote(std::string const& _k, std::string const& _v) { m_info.notes[_k] = _v; }
PeerInfo const& info() const { return m_info; }
+ void ensureNodesRequested();
+ void serviceNodesRequest();
+
private:
void dropped();
void doRead();
@@ -84,7 +92,6 @@ private:
void writeImpl(bytes& _buffer);
void write();
- void getPeers();
bool interpret(RLP const& _r);
/// @returns true iff the _msg forms a valid message for sending or receiving on the network.
@@ -95,23 +102,25 @@ private:
std::mutex m_writeLock;
std::deque m_writeQueue;
- mutable bi::tcp::socket m_socket; ///< Mutable to ask for native_handle().
+ mutable bi::tcp::socket m_socket; ///< Mutable to ask for native_handle().
std::array m_data;
PeerInfo m_info;
- h512 m_id;
bytes m_incoming;
unsigned m_protocolVersion;
- unsigned short m_listenPort; ///< Port that the remote client is listening on for connections. Useful for giving to peers.
+ std::shared_ptr m_node;
+ bi::tcp::endpoint m_manualEndpoint;
+ bool m_force = false; /// If true, ignore IDs being different. This could open you up to MitM attacks.
+
+ bool m_theyRequestedNodes = false;
+ bool m_weRequestedNodes = false;
std::chrono::steady_clock::time_point m_ping;
std::chrono::steady_clock::time_point m_connect;
std::chrono::steady_clock::time_point m_disconnect;
- unsigned m_rating;
-
std::map> m_capabilities;
- std::set m_knownPeers;
+ RangeMask m_knownNodes; ///< Nodes we already know about as indices into Host's nodesList. These shouldn't be resent to peer.
bool m_willBeDeleted = false; ///< True if we already posted a deleter on the strand.
};
diff --git a/libp2p/UPnP.cpp b/libp2p/UPnP.cpp
index 211b185bb..42868d67a 100644
--- a/libp2p/UPnP.cpp
+++ b/libp2p/UPnP.cpp
@@ -123,16 +123,18 @@ int UPnP::addRedirect(char const* _addr, int _port)
// Try direct mapping first (port external, port internal).
char port_str[16];
+ char ext_port_str[16];
sprintf(port_str, "%d", _port);
if (!UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, port_str, port_str, _addr, "ethereum", "TCP", NULL, NULL))
return _port;
// Failed - now try (random external, port internal) and cycle up to 10 times.
+ srand(time(NULL));
for (unsigned i = 0; i < 10; ++i)
{
- _port = rand() % 65535 - 1024 + 1024;
- sprintf(port_str, "%d", _port);
- if (!UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, NULL, port_str, _addr, "ethereum", "TCP", NULL, NULL))
+ _port = rand() % (65535 - 1024) + 1024;
+ sprintf(ext_port_str, "%d", _port);
+ if (!UPNP_AddPortMapping(m_urls->controlURL, m_data->first.servicetype, ext_port_str, port_str, _addr, "ethereum", "TCP", NULL, NULL))
return _port;
}
diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp
index 46725de1a..1515a8707 100644
--- a/libwebthree/WebThree.cpp
+++ b/libwebthree/WebThree.cpp
@@ -68,14 +68,14 @@ void WebThreeDirect::setIdealPeerCount(size_t _n)
return m_net.setIdealPeerCount(_n);
}
-bytes WebThreeDirect::savePeers()
+bytes WebThreeDirect::saveNodes()
{
- return m_net.savePeers();
+ return m_net.saveNodes();
}
-void WebThreeDirect::restorePeers(bytesConstRef _saved)
+void WebThreeDirect::restoreNodes(bytesConstRef _saved)
{
- return m_net.restorePeers(_saved);
+ return m_net.restoreNodes(_saved);
}
void WebThreeDirect::connect(std::string const& _seedHost, unsigned short _port)
diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h
index d4f23ca26..32bbe0b31 100644
--- a/libwebthree/WebThree.h
+++ b/libwebthree/WebThree.h
@@ -96,10 +96,10 @@ public:
bool haveNetwork() { return peerCount() != 0; }
/// Save peers
- dev::bytes savePeers();
+ dev::bytes saveNodes();
/// Restore peers
- void restorePeers(bytesConstRef _saved);
+ void restoreNodes(bytesConstRef _saved);
/// Sets the ideal number of peers.
void setIdealPeerCount(size_t _n);
@@ -108,6 +108,11 @@ public:
void setNetworkPreferences(p2p::NetworkPreferences const& _n) { auto had = haveNetwork(); if (had) stopNetwork(); m_net.setNetworkPreferences(_n); if (had) startNetwork(); }
+ p2p::NodeId id() const { return m_net.id(); }
+
+ /// Gets the nodes.
+ p2p::Nodes nodes() const { return m_net.nodes(); }
+
/// Start the network subsystem.
void startNetwork() { m_net.start(); }
diff --git a/libwhisper/Common.h b/libwhisper/Common.h
index 251a089b7..26e8b9da8 100644
--- a/libwhisper/Common.h
+++ b/libwhisper/Common.h
@@ -35,7 +35,6 @@ namespace shh
/* this makes these symbols ambiguous on VS2013
using h256 = dev::h256;
-using h512 = dev::h512;
using h256s = dev::h256s;
using bytes = dev::bytes;
using RLPStream = dev::RLPStream;
diff --git a/test/vm.cpp b/test/vm.cpp
index a90b122e2..cc87866df 100644
--- a/test/vm.cpp
+++ b/test/vm.cpp
@@ -31,8 +31,8 @@ using namespace dev;
using namespace dev::eth;
using namespace dev::test;
-FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock):
- ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock) {}
+FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix.
+ ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytesConstRef(), _previousBlock, _currentBlock, _depth) {}
h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFunc)
{
@@ -41,7 +41,6 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
t.gasPrice = gasPrice;
t.gas = *_gas;
t.data = _init.toBytes();
- callcreates.push_back(t);
m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1);
@@ -56,57 +55,103 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
get<3>(addresses[ret]) = m_s.code(ret);
}
+ t.receiveAddress = ret;
+ callcreates.push_back(t);
return ret;
}
-bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc, Address, Address)
+bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, u256* _gas, bytesRef _out, OnOpFunc, Address _myAddressOverride = Address(), Address _codeAddressOverride = Address())
{
+
+ u256 contractgas = 0xffff;
+
Transaction t;
t.value = _value;
t.gasPrice = gasPrice;
t.gas = *_gas;
t.data = _data.toVector();
t.receiveAddress = _receiveAddress;
+ callcreates.push_back(t);
+
+ string codeOf_CodeAddress = _codeAddressOverride ? toHex(get<3>(addresses[_codeAddressOverride])) : toHex(get<3>(addresses[_receiveAddress]) );
+ string sizeOfCode = toHex(toCompactBigEndian((codeOf_CodeAddress.size()+1)/2));
+
+ string codeOf_SenderAddress = toHex(get<3>(addresses[myAddress]) );
+ string sizeOfSenderCode = toHex(toCompactBigEndian((codeOf_SenderAddress.size()+1)/2));
+
+ if (codeOf_SenderAddress.size())
+ {
+ // create init code that returns given contract code
+ string initStringHex = "{ (CODECOPY 0 (- (CODESIZE) 0x" + sizeOfSenderCode + " ) 0x" + sizeOfSenderCode + ") (RETURN 0 0x" + sizeOfSenderCode +")}";
+ bytes initBytes = compileLLL(initStringHex, true, NULL);
+ initBytes += fromHex(codeOf_SenderAddress);
+ bytesConstRef init(&initBytes);
- string codeOf_receiveAddress = toHex(get<3>(addresses[_receiveAddress]) );
- string sizeOfCode = toHex(toCompactBigEndian((codeOf_receiveAddress.size()+1)/2));
+ if (!m_s.addresses().count(myAddress))
+ {
+ m_ms.internal.resize(m_ms.internal.size() + 1);
+ auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
+ if (!m_ms.internal.back().from)
+ m_ms.internal.pop_back();
+ if (na != myAddress)
+ {
+ 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));
+ return false;
+ }
+ }
+ }
- if (codeOf_receiveAddress.size())
+ if (codeOf_CodeAddress.size())
{
// create init code that returns given contract code
string initStringHex = "{ (CODECOPY 0 (- (CODESIZE) 0x" + sizeOfCode + " ) 0x" + sizeOfCode + ") (RETURN 0 0x" + sizeOfCode +")}";
bytes initBytes = compileLLL(initStringHex, true, NULL);
- initBytes += fromHex(codeOf_receiveAddress);
+ initBytes += fromHex(codeOf_CodeAddress);
bytesConstRef init(&initBytes);
- if (!m_s.addresses().count(_receiveAddress))
+ if (!m_s.addresses().count(_codeAddressOverride ? _codeAddressOverride : _receiveAddress))
{
m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1);
- auto na = m_s.create(myAddress, 0, gasPrice, _gas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
+ auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
if (!m_ms.internal.back().from)
m_ms.internal.pop_back();
- if (!m_s.addresses().count(_receiveAddress))
+
+ if (na != (_codeAddressOverride ? _codeAddressOverride : _receiveAddress))
{
- cnote << "not able to call to : " << _receiveAddress << "\n";
+ 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(_receiveAddress));
+ BOOST_THROW_EXCEPTION(FakeExtVMFailure() << errinfo_comment("Address not callable in FakeExtVM\n") << errinfo_wrongAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress));
return false;
}
}
m_ms.internal.resize(m_ms.internal.size() + 1);
- auto ret = m_s.call(_receiveAddress, Address() ? Address() : _receiveAddress, Address() ? Address() : myAddress, _value, gasPrice, _data, _gas, _out, origin, &suicides, &(m_ms.internal.back()), OnOpFunc(), 1);
+
+ auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &suicides, &(m_ms.internal.back()), OnOpFunc(), 1);
+
if (!m_ms.internal.back().from)
m_ms.internal.pop_back();
+
+ // get correct balances, (also for sucicides in the call function)
+ for (auto const& f: addresses)
+ {
+ if (m_s.addressInUse(f.first))
+ get<0>(addresses[f.first]) = m_s.balance(f.first);
+ }
+
if (!ret)
return false;
- if (get<0>(addresses[myAddress]) >= _value)
- {
- get<1>(addresses[myAddress])++;
- get<0>(addresses[_receiveAddress]) += _value;
+ // do suicides
+ for (auto const& f: suicides)
+ addresses.erase(f);
+ // get storage
+ if ((get<0>(addresses[myAddress]) >= _value) && (suicides.find(_receiveAddress) == suicides.end()))
+ {
for (auto const& j: m_s.storage(_receiveAddress))
{
u256 adr(j.first);
@@ -114,13 +159,10 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
get<2>(addresses[_receiveAddress])[adr] = j.second;
}
}
-
}
else
addresses.erase(_receiveAddress); // for the sake of comparison
- callcreates.push_back(t);
-
return true;
}
@@ -235,30 +277,8 @@ mObject FakeExtVM::exportState()
{
mObject store;
- string curKey;
- u256 li = 0;
- bool isOutOfRange = false;
- mArray curVal;
for (auto const& s: get<2>(a.second))
- {
- if (!li || s.first > li + 8)
- {
- if (li || isOutOfRange)
- store[curKey] = curVal;
- li = s.first;
- curKey = "0x"+toHex(toCompactBigEndian(li));
- curVal = mArray();
- }
- else
- for (; li != s.first; ++li)
- curVal.push_back(0);
- curVal.push_back("0x"+toHex(toCompactBigEndian(s.second)));
- if ( toHex(toCompactBigEndian(li)) == "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
- isOutOfRange = true;
- ++li;
- }
- if (li || isOutOfRange)
- store[curKey] = curVal;
+ store["0x"+toHex(toCompactBigEndian(s.first))] = "0x"+toHex(toCompactBigEndian(s.second));
o["storage"] = store;
}
o["code"] = "0x" + toHex(get<3>(a.second));
@@ -282,15 +302,7 @@ void FakeExtVM::importState(mObject& _object)
get<0>(a) = toInt(o["balance"]);
get<1>(a) = toInt(o["nonce"]);
for (auto const& j: o["storage"].get_obj())
- {
- u256 adr(j.first);
- for (auto const& k: j.second.get_array())
- {
- if ((toInt(k) != 0) || (j.second.get_array().size() == 1))
- get<2>(a)[adr] = toInt(k);
- adr++;
- }
- }
+ get<2>(a)[toInt(j.first)] = toInt(j.second);
if (o["code"].type() == str_type)
if (o["code"].get_str().find_first_of("0x") != 0)
@@ -402,6 +414,71 @@ void FakeExtVM::importCallCreates(mArray& _callcreates)
}
}
+h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
+{
+ if (!_origin)
+ _origin = _sender;
+
+ if (o_ms)
+ {
+ o_ms->from = _sender;
+ o_ms->to = Address();
+ o_ms->value = _endowment;
+ o_ms->input = _code.toBytes();
+ }
+
+ // Set up new account...
+ m_cache[_newAddress] = AddressState(0, balance(_newAddress) + _endowment, h256(), h256());
+
+ // Execute init code.
+ VM vm(*_gas);
+ ExtVM evm(*this, _newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level);
+ bool revert = false;
+ bytesConstRef out;
+
+ try
+ {
+ out = vm.go(evm, _onOp);
+ if (o_ms)
+ o_ms->output = out.toBytes();
+ if (o_suicides)
+ for (auto i: evm.suicides)
+ o_suicides->insert(i);
+ }
+ catch (OutOfGas const& /*_e*/)
+ {
+ clog(StateChat) << "Out of Gas! Reverting.";
+ revert = true;
+ }
+ catch (VMException const& _e)
+ {
+ clog(StateChat) << "VM Exception: " << diagnostic_information(_e);
+ }
+ catch (Exception const& _e)
+ {
+ clog(StateChat) << "Exception in VM: " << diagnostic_information(_e);
+ }
+ catch (std::exception const& _e)
+ {
+ clog(StateChat) << "std::exception in VM: " << _e.what();
+ }
+
+ // TODO: CHECK: IS THIS CORRECT?! (esp. given account created prior to revertion init.)
+
+ // Write state out only in the case of a non-out-of-gas transaction.
+ if (revert)
+ evm.revert();
+
+ // Set code.
+ if (addressInUse(_newAddress))
+ m_cache[_newAddress].setCode(out);
+
+ *_gas = vm.gas();
+
+ return _newAddress;
+}
+
+
namespace dev { namespace test {
@@ -542,7 +619,7 @@ void executeTests(const string& _name)
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/" + _name + ".json", asBytes(json_spirit::write_string(v, true)));
+ writeFile("../../../tests/vmtests/" + _name + ".json", asBytes(json_spirit::write_string(v, true)));
}
catch (Exception const& _e)
{
@@ -558,7 +635,7 @@ void executeTests(const string& _name)
{
cnote << "Testing VM..." << _name;
json_spirit::mValue v;
- string s = asString(contents("../../../tests/" + _name + ".json"));
+ 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?");
json_spirit::read_string(s, v);
dev::test::doTests(v, false);
@@ -620,3 +697,4 @@ BOOST_AUTO_TEST_CASE(vmSystemOperationsTest)
{
dev::test::executeTests("vmSystemOperationsTest");
}
+
diff --git a/test/vm.h b/test/vm.h
index 5bad9d7d4..34e0e855a 100644
--- a/test/vm.h
+++ b/test/vm.h
@@ -40,11 +40,18 @@ namespace dev { namespace test {
struct FakeExtVMFailure : virtual Exception {};
+class FakeState: public eth::State
+{
+public:
+ /// Execute a contract-creation transaction.
+ h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), std::set* o_suicides = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = eth::OnOpFunc(), unsigned _level = 0);
+};
+
class FakeExtVM: public eth::ExtVMFace
{
public:
FakeExtVM() {}
- FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock);
+ FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth = 0);
u256 store(u256 _n) { return std::get<2>(addresses[myAddress])[_n]; }
void setStore(u256 _n, u256 _v) { std::get<2>(addresses[myAddress])[_n] = _v; }
@@ -63,6 +70,7 @@ public:
byte toByte(json_spirit::mValue const& _v);
void push(json_spirit::mObject& o, std::string const& _n, u256 _v);
void push(json_spirit::mArray& a, u256 _v);
+ u256 doPosts();
json_spirit::mObject exportEnv();
void importEnv(json_spirit::mObject& _o);
json_spirit::mObject exportState();
@@ -79,7 +87,7 @@ public:
u256 gas;
private:
- eth::State m_s;
+ FakeState m_s;
eth::Manifest m_ms;
};
diff --git a/test/vmSystemOperationsTestFiller.json b/test/vmSystemOperationsTestFiller.json
index 34235e040..de8a3ad1a 100644
--- a/test/vmSystemOperationsTestFiller.json
+++ b/test/vmSystemOperationsTestFiller.json
@@ -48,7 +48,7 @@
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
- "value" : "1000000000000000000",
+ "value" : "100",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
@@ -76,7 +76,7 @@
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
- "value" : "1000000000000000000",
+ "value" : "100",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
@@ -104,7 +104,7 @@
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
- "value" : "1000000000000000000",
+ "value" : "100",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
@@ -638,7 +638,7 @@
"address" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"origin" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
- "value" : "100000",
+ "value" : "23",
"data" : "0xaa",
"gasPrice" : "100000000000000",
"gas" : "1000"
@@ -668,7 +668,7 @@
"address" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"origin" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
- "value" : "100000",
+ "value" : "23",
"data" : "0xaa",
"gasPrice" : "100000000000000",
"gas" : "1000"
@@ -698,7 +698,7 @@
"address" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"origin" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"caller" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
- "value" : "100000",
+ "value" : "23",
"data" : "0xaa",
"gasPrice" : "100000000000000",
"gas" : "1000"
@@ -777,9 +777,6 @@
}
},
-
-
-
"TestNameRegistrator": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
@@ -806,9 +803,149 @@
"gasPrice" : "100000000000000",
"gas" : "10000"
}
- }
+ },
+ "ABAcalls0": {
+ "env" : {
+ "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
+ "currentNumber" : "0",
+ "currentGasLimit" : "10000000",
+ "currentDifficulty" : "256",
+ "currentTimestamp" : 1,
+ "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
+ },
+ "pre" : {
+ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "1000000000000000000",
+ "nonce" : 0,
+ "code" : "{ [[ (PC) ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) }",
+ "storage": {}
+ },
+ "945304eb96065b2a98b57a48a06ae28d285a71b5" : {
+ "balance" : "23",
+ "code" : " { [[ (PC) ]] (ADD 1 (CALL 500 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 23 0 0 0 0)) } ",
+ "nonce" : "0",
+ "storage" : {
+ }
+ }
+ },
+ "exec" : {
+ "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
+ "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "100000",
+ "data" : "",
+ "gasPrice" : "100000000000000",
+ "gas" : "10000000000000"
+ }
+ },
+ "ABAcalls0": {
+ "env" : {
+ "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
+ "currentNumber" : "0",
+ "currentGasLimit" : "10000000",
+ "currentDifficulty" : "256",
+ "currentTimestamp" : 1,
+ "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
+ },
+ "pre" : {
+ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "1000000000000000000",
+ "nonce" : 0,
+ "code" : "{ [[ (PC) ]] (CALL (- (GAS) 1000) 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) }",
+ "storage": {}
+ },
+ "945304eb96065b2a98b57a48a06ae28d285a71b5" : {
+ "balance" : "23",
+ "code" : " { [[ (PC) ]] (ADD 1 (CALL (- (GAS) 1000) 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 23 0 0 0 0)) } ",
+ "nonce" : "0",
+ "storage" : {
+ }
+ }
+ },
+ "exec" : {
+ "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
+ "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "100000",
+ "data" : "",
+ "gasPrice" : "100000000000000",
+ "gas" : "10000000000000"
+ }
+ },
+
+
+ "ABAcallsSuicide0": {
+ "env" : {
+ "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
+ "currentNumber" : "0",
+ "currentGasLimit" : "10000000",
+ "currentDifficulty" : "256",
+ "currentTimestamp" : 1,
+ "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
+ },
+ "pre" : {
+ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "1000000000000000000",
+ "nonce" : 0,
+ "code" : "{ [[ (PC) ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) (SUICIDE 0x945304eb96065b2a98b57a48a06ae28d285a71b5) }",
+ "storage": {}
+ },
+ "945304eb96065b2a98b57a48a06ae28d285a71b5" : {
+ "balance" : "23",
+ "code" : "{ [[ (PC) ]] (ADD 1 (CALL 500 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 23 0 0 0 0)) } ",
+ "nonce" : "0",
+ "storage" : {
+ }
+ }
+
+ },
+ "exec" : {
+ "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
+ "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "100000",
+ "data" : "",
+ "gasPrice" : "100000000000000",
+ "gas" : "10000000000000"
+ }
+ },
+
+ "ABAcallsSuicide1": {
+ "env" : {
+ "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
+ "currentNumber" : "0",
+ "currentGasLimit" : "10000000",
+ "currentDifficulty" : "256",
+ "currentTimestamp" : 1,
+ "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
+ },
+ "pre" : {
+ "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "1000000000000000000",
+ "nonce" : 0,
+ "code" : "{ [[ (PC) ]] (CALL 1000 0x945304eb96065b2a98b57a48a06ae28d285a71b5 24 0 0 0 0) }",
+ "storage": {}
+ },
+ "945304eb96065b2a98b57a48a06ae28d285a71b5" : {
+ "balance" : "23",
+ "code" : "{ [[ (PC) ]] (ADD 1 (CALL 500 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 23 0 0 0 0)) (SUICIDE 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6) } ",
+ "nonce" : "0",
+ "storage" : {
+ }
+ }
+ },
+ "exec" : {
+ "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
+ "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "100000",
+ "data" : "",
+ "gasPrice" : "100000000000000",
+ "gas" : "10000000000000"
+ }
+ }
}
diff --git a/third/MainWin.cpp b/third/MainWin.cpp
index f86dc0434..399fc8396 100644
--- a/third/MainWin.cpp
+++ b/third/MainWin.cpp
@@ -365,10 +365,10 @@ void Main::writeSettings()
s.setValue("address", b);
s.setValue("url", ui->urlEdit->text());
- bytes d = m_web3->savePeers();
+ bytes d = m_web3->saveNodes();
if (d.size())
- m_peers = QByteArray((char*)d.data(), (int)d.size());
- s.setValue("peers", m_peers);
+ m_nodes = QByteArray((char*)d.data(), (int)d.size());
+ s.setValue("peers", m_nodes);
s.setValue("geometry", saveGeometry());
s.setValue("windowState", saveState());
@@ -397,7 +397,7 @@ void Main::readSettings(bool _skipGeometry)
}
}
ethereum()->setAddress(m_myKeys.back().address());
- m_peers = s.value("peers").toByteArray();
+ m_nodes = s.value("peers").toByteArray();
ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html
on_urlEdit_returnPressed();
}
@@ -571,8 +571,8 @@ void Main::ensureNetwork()
else
if (!m_web3->peerCount())
m_web3->connect(defPeer);
- if (m_peers.size())
- m_web3->restorePeers(bytesConstRef((byte*)m_peers.data(), m_peers.size()));
+ if (m_nodes.size())
+ m_web3->restoreNodes(bytesConstRef((byte*)m_nodes.data(), m_nodes.size()));
}
void Main::on_connect_triggered()
diff --git a/third/MainWin.h b/third/MainWin.h
index 0afab773f..fcb7ab304 100644
--- a/third/MainWin.h
+++ b/third/MainWin.h
@@ -127,7 +127,7 @@ private:
unsigned m_currenciesFilter = (unsigned)-1;
unsigned m_balancesFilter = (unsigned)-1;
- QByteArray m_peers;
+ QByteArray m_nodes;
QStringList m_servers;
QNetworkAccessManager m_webCtrl;
diff --git a/windows/LibEthereum.props b/windows/LibEthereum.props
index 136a8edab..8c0bcac90 100644
--- a/windows/LibEthereum.props
+++ b/windows/LibEthereum.props
@@ -15,7 +15,7 @@
true
false
include/$(ProjectName);$(IntDir);../../cryptopp;..;../libethcore;../libethereum;../libethsupport;$(BoostDir);../../leveldb/include;../secp256k1;../../miniupnp
- ETH_BUILD_PLATFORM=Windows/VS2013;ETH_BUILD_TYPE=$(Configuration)-$(Platform);STATICLIB;LEVELDB_PLATFORM_WINDOWS;USE_NUM_BOOST;USE_FIELD_10X26;USE_FIELD_INV_BUILTIN;_WIN32_WINNT=0x0501;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ ETH_BUILD_PLATFORM=Windows/VS2013;ETH_BUILD_TYPE=$(Configuration)-$(Platform);ETH_MINIUPNPC=1;STATICLIB;LEVELDB_PLATFORM_WINDOWS;USE_NUM_BOOST;USE_FIELD_10X26;USE_FIELD_INV_BUILTIN;_WIN32_WINNT=0x0501;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
true
true
Level3
diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj
index db1362363..8c08091ec 100644
--- a/windows/LibEthereum.vcxproj
+++ b/windows/LibEthereum.vcxproj
@@ -93,6 +93,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters
index 848b8308d..7d743d82d 100644
--- a/windows/LibEthereum.vcxproj.filters
+++ b/windows/LibEthereum.vcxproj.filters
@@ -190,6 +190,9 @@
libwebthree
+
+ libethcore
+
diff --git a/windows/LibMiniUPnPc.vcxproj b/windows/LibMiniUPnPc.vcxproj
index 7e5e44412..07489d0e8 100644
--- a/windows/LibMiniUPnPc.vcxproj
+++ b/windows/LibMiniUPnPc.vcxproj
@@ -106,7 +106,7 @@
Disabled
MultiThreadedDebugDLL
- _CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)
4100;4244;4245;4267;4389;%(DisableSpecificWarnings)
@@ -123,7 +123,7 @@
Disabled
MultiThreadedDebugDLL
- _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;MINIUPNP_STATICLIB;%(PreprocessorDefinitions)
4100;4244;4245;4267;4389;%(DisableSpecificWarnings)
@@ -142,7 +142,7 @@
true
true
MultiThreadedDLL
- _CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)
4100;4244;4245;4267;4389;%(DisableSpecificWarnings)
@@ -163,7 +163,7 @@
true
true
MultiThreadedDLL
- _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;MINIUPNP_STATICLIB;%(PreprocessorDefinitions)
4100;4244;4245;4267;4389;%(DisableSpecificWarnings)