Browse Source

Merge remote-tracking branch 'ethereum/develop' into solidity

cl-refactor
Christian 10 years ago
parent
commit
f9ac490498
  1. 2
      alethzero/DownloadView.cpp
  2. 34
      alethzero/Main.ui
  3. 56
      alethzero/MainWin.cpp
  4. 1
      alethzero/MainWin.h
  5. 31
      eth/main.cpp
  6. 2
      libdevcore/Common.cpp
  7. 27
      libdevcore/RangeMask.h
  8. 2
      libdevcrypto/MemoryDB.h
  9. 4
      libdevcrypto/TrieDB.h
  10. 17
      libethcore/Exceptions.cpp
  11. 2
      libethcore/Exceptions.h
  12. 1
      libethcore/_libethcore.cpp
  13. 6
      libethereum/BlockChain.cpp
  14. 4
      libethereum/DownloadMan.cpp
  15. 4
      libethereum/DownloadMan.h
  16. 2
      libethereum/EthereumHost.cpp
  17. 4
      libethereum/EthereumHost.h
  18. 24
      libethereum/EthereumPeer.cpp
  19. 2
      libethereum/Executive.cpp
  20. 11
      libethereum/ExtVM.h
  21. 18
      libethereum/State.cpp
  22. 3
      libethereum/State.h
  23. 5
      libevm/ExtVMFace.cpp
  24. 3
      libevm/ExtVMFace.h
  25. 2
      libevm/VM.cpp
  26. 134
      libevm/VM.h
  27. 31
      liblll/Assembly.cpp
  28. 1
      libp2p/CMakeLists.txt
  29. 5
      libp2p/Common.cpp
  30. 26
      libp2p/Common.h
  31. 338
      libp2p/Host.cpp
  32. 131
      libp2p/Host.h
  33. 2
      libp2p/HostCapability.cpp
  34. 259
      libp2p/Session.cpp
  35. 29
      libp2p/Session.h
  36. 8
      libp2p/UPnP.cpp
  37. 8
      libwebthree/WebThree.cpp
  38. 9
      libwebthree/WebThree.h
  39. 1
      libwhisper/Common.h
  40. 188
      test/vm.cpp
  41. 12
      test/vm.h
  42. 155
      test/vmSystemOperationsTestFiller.json
  43. 12
      third/MainWin.cpp
  44. 2
      third/MainWin.h
  45. 2
      windows/LibEthereum.props
  46. 6
      windows/LibEthereum.vcxproj
  47. 3
      windows/LibEthereum.vcxproj.filters
  48. 8
      windows/LibMiniUPnPc.vcxproj

2
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);

34
alethzero/Main.ui

@ -1480,6 +1480,40 @@ font-size: 14pt</string>
</layout>
</widget>
</widget>
<widget class="QDockWidget" name="dockWidget_13">
<property name="features">
<set>QDockWidget::DockWidgetFeatureMask</set>
</property>
<property name="windowTitle">
<string>Nodes</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_13">
<layout class="QHBoxLayout" name="horizontalLayout_10">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QListWidget" name="nodes">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<action name="quit">
<property name="text">
<string>&amp;Quit</string>

56
alethzero/MainWin.cpp

@ -207,6 +207,12 @@ unsigned Main::installWatch(dev::h256 _tf, std::function<void()> 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<chrono::milliseconds>(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<chrono::milliseconds>(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 << "<br/>Bloom: <b>" << details.bloom << "</b>";
s << "<br/>Transactions: <b>" << block[1].itemCount() << "</b> @<b>" << info.transactionsRoot << "</b>";
s << "<br/>Uncles: <b>" << block[2].itemCount() << "</b> @<b>" << info.sha3Uncles << "</b>";
if (info.parentHash)
s << "<br/>Pre: <b>" << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "</b>";
else
s << "<br/>Pre: <i>Nothing is before the Gensesis</i>";
for (auto const& i: block[1])
s << "<br/>" << sha3(i[0].data()).abridged() << ": <b>" << i[1].toHash<h256>() << "</b> [<b>" << i[2].toInt<u256>() << "</b> used]";
s << "<br/>Post: <b>" << info.stateRoot << "</b>";
@ -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
{

1
alethzero/MainWin.h

@ -183,6 +183,7 @@ private:
unsigned installWatch(dev::eth::MessageFilter const& _tf, std::function<void()> const& _f);
unsigned installWatch(dev::h256 _tf, std::function<void()> const& _f);
void uninstallWatch(unsigned _w);
void keysChanged();

31
eth/main.cpp

@ -24,6 +24,7 @@
#include <chrono>
#include <fstream>
#include <iostream>
#include <signal.h>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#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();
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;
}

2
libdevcore/Common.cpp

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

27
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 <class S> RangeMask operator-(S const& _m) const { auto ret = *this; return ret -= _m; }
template <class S> 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<T, T> 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
{

2
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)

4
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 <class DB> void GenericTrieDB<DB>::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)

17
libethcore/Exceptions.cpp

@ -22,14 +22,17 @@
#include "Exceptions.h"
#include <libdevcore/CommonIO.h>
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) + ")"); }

2
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; };

1
libethcore/_libethcore.cpp

@ -3,4 +3,5 @@
#include "BlockInfo.cpp"
#include "CommonEth.cpp"
#include "Dagger.cpp"
#include "Exceptions.cpp"
#endif

6
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);
}
}

4
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;
}

4
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(); }

2
libethereum/EthereumHost.cpp

@ -202,7 +202,7 @@ void EthereumHost::maintainBlocks(h256 _currentHash)
auto p = j->cap<EthereumPeer>();
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))

4
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<h512> m_banned;
std::set<p2p::NodeId> m_banned;
};
}

24
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,21 +425,17 @@ 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:
addRating(1);
success++;
break;
@ -461,8 +457,14 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
break;
}
}
else
{
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:

2
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<VMTraceChannel, false>(true) << o.str();
dev::LogOutputStream<VMTraceChannel, false>(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<VMTraceChannel, false>(false) << " | " << dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << dec << vm.gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32" << " ]";
};
}

11
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<Address, AddressState> m_origCache; ///< The cache of the address states (i.e. the externalities) as-was prior to the execution.

18
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<int>(12, _out.size()));
if (_out.size() > 12)
memcpy(_out.data() + 12, &ret, min(_out.size() - 12, sizeof(ret)));
}
const std::map<unsigned, PrecompiledAddress> State::c_precompiled =
@ -1052,7 +1054,14 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
Manifest ms;
Executive e(*this, &ms);
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<h256>() != 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<u256, u256> mem;
std::set<u256> back;

3
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:

5
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)
{}

3
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<Address> suicides; ///< Any accounts that have suicided.
unsigned depth; ///< Depth of the present call.
};
}

2
libevm/VM.cpp

@ -29,6 +29,4 @@ void VM::reset(u256 _gas)
{
m_gas = _gas;
m_curPC = 0;
m_jumpLatch = false;
m_destinations.clear();
}

134
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 <class Ext> 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 <class Ext> 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 <class Ext> 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 <class Ext> 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 <class Ext> 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 <class Ext> 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)

31
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<unsigned> tagPos(m_usedTags);
map<unsigned, unsigned> tagRef;
map<unsigned, unsigned> pretagRef;
multimap<h256, unsigned> 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;
}

1
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)

5
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.";
}
}

26
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<CapDesc> CapDescs;
struct PeerInfo
{
NodeId id;
std::string clientVersion;
std::string host;
unsigned short port;

338
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<Session> _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<h512, bi::tcp::endpoint> Host::potentialPeers()
shared_ptr<Node> Host::noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId)
{
std::map<h512, bi::tcp::endpoint> 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))
{
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))
if (m_nodes.count(_oldId))
{
ep = m_incomingPeers.at(j->m_id).first;
peerOnNet = (j->m_listenPort != 0 && (!isPrivateAddress(ep.address()) || m_netPrefs.localNetworking));
i = m_nodes[_oldId]->index;
m_nodes.erase(_oldId);
m_nodesList[i] = _id;
}
if (peerOnNet && ep.port() && j->m_id)
ret.insert(make_pair(i.first, ep));
else
{
i = m_nodesList.size();
m_nodesList.push_back(_id);
}
m_nodes[_id] = make_shared<Node>();
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<unsigned> 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<Session>(this, std::move(m_socket), remoteAddress);
auto p = std::make_shared<Session>(this, std::move(m_socket), bi::tcp::endpoint(remoteAddress, 0));
p->start();
}
catch (Exception const& _e)
@ -411,36 +478,51 @@ 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)
else
{
m_freePeers.push_back(i->first);
goto OK;
auto p = make_shared<Session>(this, std::move(*s), _ep);
clog(NetConnect) << "Connected to " << _ep;
p->start();
}
// for-else
clog(NetConnect) << "Giving up.";
OK:;
delete s;
});
}
void Node::connect(Host* _h)
{
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
{
auto p = make_shared<Session>(this, std::move(*s), _ep.address(), _ep.port());
clog(NetConnect) << "Connected to " << _ep;
clog(NetConnect) << "Connected to" << id.abridged() << "@" << address;
failedAttempts = 0;
lastConnected = std::chrono::system_clock::now();
auto p = make_shared<Session>(_h, std::move(*s), _h->node(id), true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism.
p->start();
}
delete s;
});
}
bool Host::havePeer(h512 _id) const
bool Host::havePeer(NodeId _id) const
{
Guard l(x_peers);
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)
{
if (m_freePeers.empty())
{
if (chrono::steady_clock::now() > m_lastPeersRequest + chrono::seconds(10))
{
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();
RecursiveGuard l(x_peers);
int morePeers = (int)m_idealPeerCount - m_peers.size();
if (morePeers > 0)
{
auto toTry = m_ready;
if (!m_netPrefs.localNetworking)
toTry -= m_private;
set<Node> 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)
{
m_nodes[i.id]->connect(this);
if (!--morePeers)
return;
}
if (!m_accepting)
else
{
ensureAccepting();
break;
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<PeerInfo> Host::peers(bool _updatePing) const
{
Guard l(x_peers);
RecursiveGuard l(x_peers);
if (_updatePing)
{
const_cast<Host*>(this)->pingAll();
this_thread::sleep_for(chrono::milliseconds(200));
}
std::vector<PeerInfo> 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;
{
ret.appendList(3) << p->endpoint().address().to_v4().to_bytes() << p->endpoint().port() << p->m_id;
n++;
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()))
{
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<std::chrono::seconds>(n.lastConnected.time_since_epoch()).count()
<< std::chrono::duration_cast<std::chrono::seconds>(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))
RecursiveGuard l(x_peers);
RLP r(_b);
if (r.itemCount() > 0 && r[0].isInt())
switch (r[0].toInt<int>())
{
auto k = (h512)i[2];
if (!m_incomingPeers.count(k))
case 0:
{
m_incomingPeers.insert(make_pair(k, make_pair(bi::tcp::endpoint(bi::address_v4(i[0].toArray<byte, 4>()), i[1].toInt<short>()), 0)));
m_freePeers.push_back(k);
auto oldId = id();
m_key = KeyPair(r[1].toHash<Secret>());
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<byte, 4>()), i[1].toInt<short>());
else
ep = bi::tcp::endpoint(bi::address_v6(i[0].toArray<byte, 16>()), i[1].toInt<short>());
auto id = (NodeId)i[2];
if (!m_nodes.count(id))
{
auto o = (Origin)i[3].toInt<int>();
auto n = noteNode(id, ep, o, true);
n->lastConnected = chrono::system_clock::time_point(chrono::seconds(i[4].toInt<unsigned>()));
n->lastAttempted = chrono::system_clock::time_point(chrono::seconds(i[5].toInt<unsigned>()));
n->failedAttempts = i[6].toInt<unsigned>();
n->lastDisconnect = (DisconnectReason)i[7].toInt<unsigned>();
n->score = (int)i[8].toInt<unsigned>();
n->rating = (int)i[9].toInt<unsigned>();
}
}
}
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<byte, 4>()), i[1].toInt<short>());
else
ep = bi::tcp::endpoint(bi::address_v6(i[0].toArray<byte, 16>()), i[1].toInt<short>());
auto n = noteNode(id, ep, Origin::Self, true);
}
}
}

131
libp2p/Host.h

@ -28,8 +28,11 @@
#include <memory>
#include <utility>
#include <thread>
#include <chrono>
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libdevcore/RangeMask.h>
#include <libdevcrypto/Common.h>
#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::seconds>(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::seconds>(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<Node>;
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<PeerInfo> 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<Session> _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> node(NodeId _id) const { if (m_nodes.count(_id)) return m_nodes.at(_id); return std::shared_ptr<Node>(); }
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<h512, bi::tcp::endpoint> potentialPeers();
std::shared_ptr<Node> noteNode(NodeId _id, bi::tcp::endpoint const& _a, Origin _o, bool _ready, NodeId _oldId = h256());
Nodes potentialPeers(RangeMask<unsigned> 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<NodeId, std::weak_ptr<Session>> 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<NodeId, std::shared_ptr<Node> > m_nodes;
mutable std::mutex x_peers;
mutable std::map<h512, std::weak_ptr<Session>> 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<NodeId> m_nodesList;
std::map<h512, std::pair<bi::tcp::endpoint, unsigned>> m_incomingPeers; // TODO: does this need a lock?
std::vector<h512> m_freePeers;
RangeMask<unsigned> m_ready; ///< Indices into m_nodesList over to which nodes we are not currently connected, connecting or otherwise ignoring.
RangeMask<unsigned> 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<bi::address_v4> m_addresses;
std::vector<bi::address_v4> m_peerAddresses;
// Our addresses.
std::vector<bi::address> m_addresses; ///< Addresses for us.
std::vector<bi::address> m_peerAddresses; ///< Addresses that peers (can) know us by.
std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities;
// Our capabilities.
std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities; ///< Each of the capabilities we support.
bool m_accepting = false;
};

2
libp2p/HostCapability.cpp

@ -34,7 +34,7 @@ void HostCapabilityFace::seal(bytes& _b)
std::vector<std::shared_ptr<Session> > HostCapabilityFace::peers() const
{
Guard l(m_host->x_peers);
RecursiveGuard l(m_host->x_peers);
std::vector<std::shared_ptr<Session> > ret;
for (auto const& i: m_host->m_peers)
if (std::shared_ptr<Session> p = i.second.lock())

259
libp2p/Session.cpp

@ -36,19 +36,35 @@ using namespace dev::p2p;
#endif
#define clogS(X) dev::LogOutputStream<X, true>(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<string, string>()});
m_info = PeerInfo({NodeId(), "?", m_manualEndpoint.address().to_string(), m_manualEndpoint.port(), std::chrono::steady_clock::duration(0), CapDescSet(), 0, map<string, string>()});
}
Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr<Node> 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<string, string>()});
}
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;
}
template <class T> vector<T> randomSelection(vector<T> const& _t, unsigned _n)
{
if (_t.size() <= _n)
return _t;
vector<T> ret = _t;
while (ret.size() > _n)
{
auto i = ret.begin();
advance(i, rand() % ret.size());
ret.erase(i);
}
return ret;
}
return bi::tcp::endpoint();
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<unsigned>(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<unsigned>())
{
case HelloPacket:
{
if (m_node)
m_node->lastDisconnect = NoDisconnect;
m_protocolVersion = _r[1].toInt<unsigned>();
auto clientVersion = _r[2].toString();
auto caps = _r[3].toVector<CapDesc>();
m_listenPort = _r[4].toInt<unsigned short>();
m_id = _r[5].toHash<h512>();
auto listenPort = _r[4].toInt<unsigned short>();
auto id = _r[5].toHash<NodeId>();
// 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 << ")";
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << m_id.abridged() << showbase << hex << caps << dec << m_listenPort;
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << id.abridged() << showbase << capslog.str() << dec << listenPort;
if (m_server->havePeer(m_id))
if (m_server->id() == id)
{
// Already connected.
clogS(NetWarn) << "Already have peer id" << m_id.abridged();// << "at" << l->endpoint() << "rather than" << endpoint();
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_node && m_node->id != id)
{
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_id)
}
if (m_server->havePeer(id))
{
disconnect(InvalidIdentity);
// 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<CapDesc>(), (unsigned)m_socket.native_handle(), map<string, string>() }); }
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<CapDesc>(), (unsigned)m_socket.native_handle(), map<string, string>() });
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<short>());
h512 id = _r[i][2].toHash<h512>();
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<NodeId>();
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();
}

29
libp2p/Session.h

@ -29,6 +29,7 @@
#include <utility>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcore/RangeMask.h>
#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<Session>
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<Node> 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.
@ -98,20 +105,22 @@ private:
mutable bi::tcp::socket m_socket; ///< Mutable to ask for native_handle().
std::array<byte, 65536> 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<Node> 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<CapDesc, std::shared_ptr<Capability>> m_capabilities;
std::set<h512> m_knownPeers;
RangeMask<unsigned> 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.
};

8
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;
}

8
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)

9
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(); }

1
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;

188
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_receiveAddress = toHex(get<3>(addresses[_receiveAddress]) );
string sizeOfCode = toHex(toCompactBigEndian((codeOf_receiveAddress.size()+1)/2));
string codeOf_CodeAddress = _codeAddressOverride ? toHex(get<3>(addresses[_codeAddressOverride])) : toHex(get<3>(addresses[_receiveAddress]) );
string sizeOfCode = toHex(toCompactBigEndian((codeOf_CodeAddress.size()+1)/2));
if (codeOf_receiveAddress.size())
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);
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_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<Address>* 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");
}

12
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<Address>* 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;
};

155
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"
}
}
}

12
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()

2
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;

2
windows/LibEthereum.props

@ -15,7 +15,7 @@
<TreatWarningAsError>true</TreatWarningAsError>
<MinimalRebuild>false</MinimalRebuild>
<AdditionalIncludeDirectories>include/$(ProjectName);$(IntDir);../../cryptopp;..;../libethcore;../libethereum;../libethsupport;$(BoostDir);../../leveldb/include;../secp256k1;../../miniupnp</AdditionalIncludeDirectories>
<PreprocessorDefinitions>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)</PreprocessorDefinitions>
<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)</PreprocessorDefinitions>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WarningLevel>Level3</WarningLevel>

6
windows/LibEthereum.vcxproj

@ -93,6 +93,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\libethcore\Exceptions.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\libethcore\_libethcore.cpp" />
<ClCompile Include="..\libethereum\AccountDiff.cpp" />
<ClCompile Include="..\libethereum\AddressState.cpp" />

3
windows/LibEthereum.vcxproj.filters

@ -190,6 +190,9 @@
<ClCompile Include="..\libwebthree\WebThree.cpp">
<Filter>libwebthree</Filter>
</ClCompile>
<ClCompile Include="..\libethcore\Exceptions.cpp">
<Filter>libethcore</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">

8
windows/LibMiniUPnPc.vcxproj

@ -106,7 +106,7 @@
</PrecompiledHeader>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4100;4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>
@ -123,7 +123,7 @@
</PrecompiledHeader>
<Optimization>Disabled</Optimization>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;MINIUPNP_STATICLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4100;4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>
@ -142,7 +142,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;MINIUPNP_STATICLIB;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4100;4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>
@ -163,7 +163,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;MINIUPNP_STATICLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DisableSpecificWarnings>4100;4244;4245;4267;4389;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>

Loading…
Cancel
Save