Browse Source

Merge branch 'develop' of https://github.com/ethereum/cpp-ethereum into mix_editor

cl-refactor
arkpar 10 years ago
parent
commit
2e3970cd93
  1. 2
      alethzero/MainWin.cpp
  2. 2
      alethzero/MainWin.h
  3. 40
      alethzero/OurWebThreeStubServer.cpp
  4. 4
      alethzero/OurWebThreeStubServer.h
  5. 4
      eth/main.cpp
  6. 2
      evmjit
  7. 6
      libdevcore/Common.h
  8. 4
      libdevcrypto/CryptoPP.cpp
  9. 2
      libethcore/CommonEth.cpp
  10. 11
      libethcore/Exceptions.cpp
  11. 2
      libethereum/BlockChain.cpp
  12. 4
      libethereum/BlockChain.h
  13. 8
      libethereum/EthereumPeer.cpp
  14. 2
      libethereum/Executive.cpp
  15. 2
      libethereum/Executive.h
  16. 8
      libethereum/Precompiled.cpp
  17. 7
      libethereum/State.cpp
  18. 4
      libethereum/State.h
  19. 2
      libethereum/TransactionReceipt.cpp
  20. 3
      libethereum/TransactionReceipt.h
  21. 20
      libevm/VM.h
  22. 4
      libevmcore/Instruction.cpp
  23. 2
      libevmcore/Instruction.h
  24. 46
      libp2p/Host.cpp
  25. 6
      libp2p/Host.h
  26. 2
      libp2p/Network.cpp
  27. 11
      libp2p/Network.h
  28. 467
      libp2p/NodeTable.cpp
  29. 349
      libp2p/NodeTable.h
  30. 2
      libp2p/Session.cpp
  31. 4
      libp2p/Session.h
  32. 54
      libp2p/UDP.cpp
  33. 265
      libp2p/UDP.h
  34. 2
      libserpent/opcodes.cpp
  35. 6
      libsolidity/ExpressionCompiler.cpp
  36. 21
      libsolidity/Scanner.cpp
  37. 1
      libsolidity/Scanner.h
  38. 2
      libsolidity/SourceReferenceFormatter.h
  39. 81
      libweb3jsonrpc/WebThreeStubServer.cpp
  40. 6
      libweb3jsonrpc/WebThreeStubServer.h
  41. 4
      mix/AppContext.cpp
  42. 2
      mix/AppContext.h
  43. 18
      mix/AssemblyDebuggerControl.cpp
  44. 2
      mix/AssemblyDebuggerModel.cpp
  45. 4
      mix/CodeHighlighter.cpp
  46. 22
      mix/CodeModel.cpp
  47. 10
      mix/CodeModel.h
  48. 3
      mix/MixApplication.h
  49. 2
      mix/main.cpp
  50. 7
      test/SolidityScanner.cpp
  51. 4
      test/boostTest.cpp
  52. 21
      test/kademlia.cpp
  53. 214
      test/net.cpp
  54. 55
      test/network.cpp
  55. 4
      test/stSystemOperationsTestFiller.json
  56. 65
      test/trie.cpp
  57. 2392
      test/vmArithmeticTestFiller.json

2
alethzero/MainWin.cpp

@ -1475,7 +1475,7 @@ void Main::populateDebugger(dev::bytesConstRef _r)
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);
m_currentExecution->finalize(onOp);
m_currentExecution->finalize();
initDebugger();
updateDebugger();
}

2
alethzero/MainWin.h

@ -78,6 +78,8 @@ public:
dev::eth::Client* ethereum() const { return m_webThree->ethereum(); }
std::shared_ptr<dev::shh::WhisperHost> whisper() const { return m_webThree->whisper(); }
std::string lookupNatSpec(dev::h256 const& _contractCode) const { (void)_contractCode; return ""; } // TODO: actually implement with leveldb & a UI.
QList<dev::KeyPair> owned() const { return m_myIdentities + m_myKeys; }
public slots:

40
alethzero/OurWebThreeStubServer.cpp

@ -20,12 +20,16 @@
*/
#include "OurWebThreeStubServer.h"
#include <QMessageBox>
#include <libwebthree/WebThree.h>
#include "MainWin.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts):
WebThreeStubServer(_conn, _web3, _accounts)
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3)
{}
std::string OurWebThreeStubServer::shh_newIdentity()
@ -34,3 +38,37 @@ std::string OurWebThreeStubServer::shh_newIdentity()
emit onNewId(QString::fromStdString(toJS(kp.sec())));
return toJS(kp.pub());
}
bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t) const
{
return true;
// To get the balance of the sender
cnote << "Sender has ETH: " << m_web3->ethereum()->postState().balance(_t.from);
Main* main; // don't know this yet, should be a member and set at construction time by Main, who will construct us.
h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to);
if (contractCodeHash == EmptySHA3)
{
// recipient has no code - nothing special about this transaction.
// TODO: show basic message for value transfer.
return true; // or whatever.
}
std::string natspecJson = main->lookupNatSpec(contractCodeHash);
if (natspecJson.empty())
{
// TODO: HUGE warning - we don't know what this will do!
return false; // or whatever.
}
// otherwise it's a transaction to contract for which we have the natspec:
// determine the actual message (embellish with real data) and ask user.
// QMessageBox::question();
return true;
}

4
alethzero/OurWebThreeStubServer.h

@ -32,7 +32,11 @@ public:
OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::vector<dev::KeyPair> const& _accounts);
virtual std::string shh_newIdentity() override;
virtual bool authenticate(dev::TransactionSkeleton const& _t) const;
signals:
void onNewId(QString _s);
private:
dev::WebThreeDirect* m_web3;
};

4
eth/main.cpp

@ -145,6 +145,8 @@ string credits(bool _interactive = false)
void version()
{
cout << "eth version " << dev::Version << endl;
cout << "Network protocol version: " << dev::eth::c_protocolVersion << endl;
cout << "Client database version: " << dev::eth::c_databaseVersion << endl;
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl;
exit(0);
}
@ -672,7 +674,7 @@ int main(int argc, char** argv)
f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl;
};
e.go(oof);
e.finalize(oof);
e.finalize();
}
catch(Exception const& _e)
{

2
evmjit

@ -1 +1 @@
Subproject commit 66d5a2b5cdf1361dcf0205b191dd12be090ed224
Subproject commit 3df5a125fa0baa579528abce80402118cad803fd

6
libdevcore/Common.h

@ -36,7 +36,12 @@
#include <map>
#include <vector>
#include <set>
#pragma warning(push)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <boost/multiprecision/cpp_int.hpp>
#pragma warning(pop)
#pragma GCC diagnostic pop
#include "vector_ref.h"
#include "debugbreak.h"
@ -64,6 +69,7 @@ using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backe
using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using u160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using s160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using u512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 512, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using u256s = std::vector<u256>;
using u160s = std::vector<u160>;
using u256Set = std::set<u256>;

4
libdevcrypto/CryptoPP.cpp

@ -108,7 +108,7 @@ Signature Secp256k1::sign(Secret const& _key, h256 const& _hash)
Integer kInv = k.InverseMod(m_q);
Integer z(_hash.asBytes().data(), 32);
Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + z)) % m_q;
Integer s = (kInv * (Integer(_key.asBytes().data(), 32) * r + z)) % m_q;
if (r == 0 || s == 0)
BOOST_THROW_EXCEPTION(InvalidState());
@ -144,7 +144,7 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message)
Integer s(_signature.data()+32, 32);
// cryptopp encodes sign of y as 0x02/0x03 instead of 0/1 or 27/28
byte encodedpoint[33];
encodedpoint[0] = _signature[64]|2;
encodedpoint[0] = _signature[64] | 2;
memcpy(&encodedpoint[1], _signature.data(), 32);
ECP::Element x;

2
libethcore/CommonEth.cpp

@ -32,7 +32,7 @@ namespace dev
namespace eth
{
const unsigned c_protocolVersion = 49;
const unsigned c_protocolVersion = 51;
const unsigned c_databaseVersion = 5;
static const vector<pair<u256, string>> g_units =

11
libethcore/Exceptions.cpp

@ -20,13 +20,22 @@
*/
#include "Exceptions.h"
#include <boost/thread.hpp>
#include <libdevcore/CommonIO.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
#define ETH_RETURN_STRING(S) static string s_what; s_what = S; return s_what.c_str();
#if ALL_COMPILERS_ARE_CPP11_COMPLIANT
#define ETH_RETURN_STRING(S) thread_local static string s_what; s_what = S; return s_what.c_str();
#else
#define ETH_RETURN_STRING(S) \
static boost::thread_specific_ptr<string> s_what; \
if (!s_what.get()) \
s_what.reset(new string); \
*s_what = S; return s_what->c_str();
#endif
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() + ")"); }

2
libethereum/BlockChain.cpp

@ -71,7 +71,7 @@ std::map<Address, Account> const& dev::eth::genesisState()
return s_ret;
}
BlockInfo* BlockChain::s_genesis = nullptr;
std::unique_ptr<BlockInfo> BlockChain::s_genesis;
boost::shared_mutex BlockChain::x_genesis;
ldb::Slice dev::eth::toSlice(h256 _h, unsigned _sub)

4
libethereum/BlockChain.h

@ -132,7 +132,7 @@ public:
h256Set allUnclesFrom(h256 _parent) const;
/// @returns the genesis block header.
static BlockInfo const& genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); (s_genesis = new BlockInfo)->populate(&gb); } return *s_genesis; }
static BlockInfo const& genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); s_genesis.reset(new BlockInfo); s_genesis->populate(&gb); } return *s_genesis; }
/// @returns the genesis block as its RLP-encoded byte array.
/// @note This is slow as it's constructed anew each call. Consider genesis() instead.
@ -211,7 +211,7 @@ private:
/// Static genesis info and its lock.
static boost::shared_mutex x_genesis;
static BlockInfo* s_genesis;
static std::unique_ptr<BlockInfo> s_genesis;
};
std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc);

8
libethereum/EthereumPeer.cpp

@ -317,14 +317,6 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
disable("Blacklisted client version.");
else if (host()->isBanned(session()->id()))
disable("Peer banned for previous bad behaviour.");
else
{
// Grab transactions off them.
RLPStream s;
prep(s, GetTransactionsPacket);
sealAndSend(s);
transition(Asking::Nothing);
}
break;
}
case GetTransactionsPacket: break; // DEPRECATED.

2
libethereum/Executive.cpp

@ -220,7 +220,7 @@ bool Executive::go(OnOpFunc const& _onOp)
return true;
}
void Executive::finalize(OnOpFunc const&)
void Executive::finalize()
{
// SSTORE refunds...
// must be done before the miner gets the fees.

2
libethereum/Executive.h

@ -64,7 +64,7 @@ public:
bool setup(bytesConstRef _transaction);
/// Finalise a transaction previously set up with setup().
/// @warning Only valid after setup(), and possibly go().
void finalize(OnOpFunc const& _onOp = OnOpFunc());
void finalize();
/// @returns the transaction from setup().
/// @warning Only valid after setup().
Transaction const& t() const { return m_t; }

8
libethereum/Precompiled.cpp

@ -75,11 +75,17 @@ static bytes ripemd160Code(bytesConstRef _in)
return ret;
}
static bytes identityCode(bytesConstRef _in)
{
return _in.toBytes();
}
static const std::map<unsigned, PrecompiledAddress> c_precompiled =
{
{ 1, { [](bytesConstRef) -> bigint { return (bigint)500; }, ecrecoverCode }},
{ 2, { [](bytesConstRef i) -> bigint { return (bigint)50 + (i.size() + 31) / 32 * 50; }, sha256Code }},
{ 3, { [](bytesConstRef i) -> bigint { return (bigint)50 + (i.size() + 31) / 32 * 50; }, ripemd160Code }}
{ 3, { [](bytesConstRef i) -> bigint { return (bigint)50 + (i.size() + 31) / 32 * 50; }, ripemd160Code }},
{ 4, { [](bytesConstRef i) -> bigint { return (bigint)1 + (i.size() + 31) / 32 * 1; }, identityCode }}
};
std::map<unsigned, PrecompiledAddress> const& dev::eth::precompiled()

7
libethereum/State.cpp

@ -958,6 +958,13 @@ bytes const& State::code(Address _contract) const
return m_cache[_contract].code();
}
h256 State::codeHash(Address _contract) const
{
if (!addressHasCode(_contract))
return EmptySHA3;
return m_cache[_contract].codeHash();
}
bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
{
for (int e = 0; e < (_enforceRefs ? 2 : 1); ++e)

4
libethereum/State.h

@ -201,6 +201,10 @@ public:
/// @returns bytes() if no account exists at that address.
bytes const& code(Address _contract) const;
/// Get the code hash of an account.
/// @returns EmptySHA3 if no account exists at that address or if there is no code associated with the address.
h256 codeHash(Address _contract) const;
/// Note that the given address is sending a transaction and thus increment the associated ticker.
void noteSending(Address _id);

2
libethereum/TransactionReceipt.cpp

@ -50,7 +50,7 @@ void TransactionReceipt::streamRLP(RLPStream& _s) const
l.streamRLP(_s);
}
std::ostream& dev::operator<<(std::ostream& _out, TransactionReceipt const& _r)
std::ostream& dev::eth::operator<<(std::ostream& _out, TransactionReceipt const& _r)
{
_out << "Root: " << _r.stateRoot() << std::endl;
_out << "Gas used: " << _r.gasUsed() << std::endl;

3
libethereum/TransactionReceipt.h

@ -57,8 +57,7 @@ private:
using TransactionReceipts = std::vector<TransactionReceipt>;
}
std::ostream& operator<<(std::ostream& _out, eth::TransactionReceipt const& _r);
}
}

20
libevm/VM.h

@ -196,8 +196,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
require(7);
runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1];
newTempSize = std::max(memNeed(m_stack[m_stack.size() - 6], m_stack[m_stack.size() - 7]), memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]));
if (_ext.depth == 1024)
BOOST_THROW_EXCEPTION(OutOfGas());
break;
case Instruction::CREATE:
@ -207,8 +205,6 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
u256 inSize = m_stack[m_stack.size() - 3];
newTempSize = (bigint)inOff + inSize;
runGas = c_createGas;
if (_ext.depth == 1024)
BOOST_THROW_EXCEPTION(OutOfGas());
break;
}
case Instruction::EXP:
@ -219,9 +215,8 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
break;
}
case Instruction::PREVHASH:
if (c_protocolVersion > 49)
require(1);
case Instruction::BLOCKHASH:
require(1);
break;
case Instruction::PC:
@ -563,11 +558,8 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
case Instruction::GASPRICE:
m_stack.push_back(_ext.gasPrice);
break;
case Instruction::PREVHASH:
if (c_protocolVersion > 49)
m_stack.back() = (u256)_ext.prevhash(m_stack.back());
else
m_stack.push_back(_ext.previousBlock.hash);
case Instruction::BLOCKHASH:
m_stack.back() = (u256)_ext.prevhash(m_stack.back());
break;
case Instruction::COINBASE:
m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress);
@ -784,7 +776,7 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
unsigned initSize = (unsigned)m_stack.back();
m_stack.pop_back();
if (_ext.balance(_ext.myAddress) >= endowment)
if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024)
{
_ext.subBalance(endowment);
m_stack.push_back((u160)_ext.create(endowment, m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp));
@ -812,7 +804,7 @@ inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _st
unsigned outSize = (unsigned)m_stack.back();
m_stack.pop_back();
if (_ext.balance(_ext.myAddress) >= value)
if (_ext.balance(_ext.myAddress) >= value && _ext.depth < 1024)
{
_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, {}, receiveAddress));

4
libevmcore/Instruction.cpp

@ -67,7 +67,7 @@ const std::map<std::string, Instruction> dev::eth::c_instructions =
{ "GASPRICE", Instruction::GASPRICE },
{ "EXTCODESIZE", Instruction::EXTCODESIZE },
{ "EXTCODECOPY", Instruction::EXTCODECOPY },
{ "PREVHASH", Instruction::PREVHASH },
{ "BLOCKHASH", Instruction::BLOCKHASH },
{ "COINBASE", Instruction::COINBASE },
{ "TIMESTAMP", Instruction::TIMESTAMP },
{ "NUMBER", Instruction::NUMBER },
@ -200,7 +200,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::GASPRICE, { "GASPRICE", 0, 0, 1, false } },
{ Instruction::EXTCODESIZE, { "EXTCODESIZE", 0, 1, 1, false } },
{ Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true } },
{ Instruction::PREVHASH, { "PREVHASH", 0, 0, 1, false } },
{ Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false } },
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1, false } },
{ Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false } },
{ Instruction::NUMBER, { "NUMBER", 0, 0, 1, false } },

2
libevmcore/Instruction.h

@ -73,7 +73,7 @@ enum class Instruction: uint8_t
EXTCODESIZE, ///< get external code size (from another contract)
EXTCODECOPY, ///< copy external code (from another contract)
PREVHASH = 0x40, ///< get hash of most recent complete block
BLOCKHASH = 0x40, ///< get hash of most recent complete block
COINBASE, ///< get the block's coinbase address
TIMESTAMP, ///< get the block's timestamp
NUMBER, ///< get the block's number

46
libp2p/Host.cpp

@ -43,7 +43,7 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool
m_netPrefs(_n),
m_ifAddresses(Network::getInterfaceAddresses()),
m_ioService(2),
m_acceptorV4(m_ioService),
m_tcp4Acceptor(m_ioService),
m_key(KeyPair::create())
{
for (auto address: m_ifAddresses)
@ -95,9 +95,9 @@ void Host::doneWorking()
m_ioService.reset();
// shutdown acceptor
m_acceptorV4.cancel();
if (m_acceptorV4.is_open())
m_acceptorV4.close();
m_tcp4Acceptor.cancel();
if (m_tcp4Acceptor.is_open())
m_tcp4Acceptor.close();
// There maybe an incoming connection which started but hasn't finished.
// Wait for acceptor to end itself instead of assuming it's complete.
@ -272,15 +272,15 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
// if user supplied address is a public address then we use it
// if user supplied address is private, and localnetworking is enabled, we use it
bi::address reqpublicaddr(bi::address(_publicAddress.empty() ? bi::address() : bi::address::from_string(_publicAddress)));
bi::tcp::endpoint reqpublic(reqpublicaddr, m_listenPort);
bool isprivate = isPrivateAddress(reqpublicaddr);
bool ispublic = !isprivate && !isLocalHostAddress(reqpublicaddr);
if (!reqpublicaddr.is_unspecified() && (ispublic || (isprivate && m_netPrefs.localNetworking)))
bi::address reqPublicAddr(bi::address(_publicAddress.empty() ? bi::address() : bi::address::from_string(_publicAddress)));
bi::tcp::endpoint reqPublic(reqPublicAddr, m_listenPort);
bool isprivate = isPrivateAddress(reqPublicAddr);
bool ispublic = !isprivate && !isLocalHostAddress(reqPublicAddr);
if (!reqPublicAddr.is_unspecified() && (ispublic || (isprivate && m_netPrefs.localNetworking)))
{
if (!m_peerAddresses.count(reqpublicaddr))
m_peerAddresses.insert(reqpublicaddr);
m_public = reqpublic;
if (!m_peerAddresses.count(reqPublicAddr))
m_peerAddresses.insert(reqPublicAddr);
m_tcpPublic = reqPublic;
return;
}
@ -288,7 +288,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
for (auto addr: m_peerAddresses)
if (addr.is_v4() && !isPrivateAddress(addr))
{
m_public = bi::tcp::endpoint(*m_peerAddresses.begin(), m_listenPort);
m_tcpPublic = bi::tcp::endpoint(*m_peerAddresses.begin(), m_listenPort);
return;
}
@ -301,23 +301,23 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
{
if (!m_peerAddresses.count(upnpep.address()))
m_peerAddresses.insert(upnpep.address());
m_public = upnpep;
m_tcpPublic = upnpep;
return;
}
}
// or if no address provided, use private ipv4 address if local networking is enabled
if (reqpublicaddr.is_unspecified())
if (reqPublicAddr.is_unspecified())
if (m_netPrefs.localNetworking)
for (auto addr: m_peerAddresses)
if (addr.is_v4() && isPrivateAddress(addr))
{
m_public = bi::tcp::endpoint(addr, m_listenPort);
m_tcpPublic = bi::tcp::endpoint(addr, m_listenPort);
return;
}
// otherwise address is unspecified
m_public = bi::tcp::endpoint(bi::address(), m_listenPort);
m_tcpPublic = bi::tcp::endpoint(bi::address(), m_listenPort);
}
void Host::runAcceptor()
@ -326,10 +326,10 @@ void Host::runAcceptor()
if (m_run && !m_accepting)
{
clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")";
clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_tcpPublic << ")";
m_accepting = true;
m_socket.reset(new bi::tcp::socket(m_ioService));
m_acceptorV4.async_accept(*m_socket, [=](boost::system::error_code ec)
m_tcp4Acceptor.async_accept(*m_socket, [=](boost::system::error_code ec)
{
bool success = false;
if (!ec)
@ -656,7 +656,7 @@ void Host::startedWorking()
}
// try to open acceptor (todo: ipv6)
m_listenPort = Network::listen4(m_acceptorV4, m_netPrefs.listenPort);
m_listenPort = Network::tcp4Listen(m_tcp4Acceptor, m_netPrefs.listenPort);
// start capability threads
for (auto const& h: m_capabilities)
@ -674,8 +674,8 @@ void Host::startedWorking()
// if m_public address is valid then add us to node list
// todo: abstract empty() and emplace logic
if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id()))
noteNode(id(), m_public, Origin::Perfect, false);
if (!m_tcpPublic.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id()))
noteNode(id(), m_tcpPublic, Origin::Perfect, false);
clog(NetNote) << "Id:" << id().abridged();
@ -739,7 +739,7 @@ void Host::restoreNodes(bytesConstRef _b)
{
auto oldId = id();
m_key = KeyPair(r[1].toHash<Secret>());
noteNode(id(), m_public, Origin::Perfect, false, oldId);
noteNode(id(), m_tcpPublic, Origin::Perfect, false, oldId);
for (auto i: r[2])
{

6
libp2p/Host.h

@ -152,7 +152,7 @@ public:
void pingAll();
/// Get the port we're listening on currently.
unsigned short listenPort() const { return m_public.port(); }
unsigned short listenPort() const { return m_tcpPublic.port(); }
/// Serialise the set of known peers.
bytes saveNodes() const;
@ -219,7 +219,7 @@ private:
int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized.
ba::io_service m_ioService; ///< IOService for network stuff.
bi::tcp::acceptor m_acceptorV4; ///< Listening acceptor.
bi::tcp::acceptor m_tcp4Acceptor; ///< Listening acceptor.
std::unique_ptr<bi::tcp::socket> m_socket; ///< Listening socket.
std::unique_ptr<boost::asio::deadline_timer> m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms.
@ -229,7 +229,7 @@ private:
std::set<Node*> m_pendingNodeConns; /// Used only by connect(Node&) to limit concurrently connecting to same node. See connect(shared_ptr<Node>const&).
Mutex x_pendingNodeConns;
bi::tcp::endpoint m_public; ///< Our public listening endpoint.
bi::tcp::endpoint m_tcpPublic; ///< Our public listening endpoint.
KeyPair m_key; ///< Our unique ID.
bool m_hadNewNodes = false;

2
libp2p/Network.cpp

@ -111,7 +111,7 @@ std::vector<bi::address> Network::getInterfaceAddresses()
return std::move(addresses);
}
int Network::listen4(bi::tcp::acceptor& _acceptor, unsigned short _listenPort)
int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort)
{
int retport = -1;
for (unsigned i = 0; i < 2; ++i)

11
libp2p/Network.h

@ -22,13 +22,18 @@
#pragma once
#include <memory>
#include <vector>
#include <deque>
#include <array>
#include <libdevcore/RLP.h>
#include <libdevcore/Guards.h>
#include "Common.h"
namespace ba = boost::asio;
namespace bi = ba::ip;
namespace dev
{
namespace p2p
{
@ -53,8 +58,8 @@ public:
static std::vector<bi::address> getInterfaceAddresses();
/// Try to bind and listen on _listenPort, else attempt net-allocated port.
static int listen4(bi::tcp::acceptor& _acceptor, unsigned short _listenPort);
static int tcp4Listen(bi::tcp::acceptor& _acceptor, unsigned short _listenPort);
/// Return public endpoint of upnp interface. If successful o_upnpifaddr will be a private interface address and endpoint will contain public address and port.
static bi::tcp::endpoint traverseNAT(std::vector<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr);
};

467
libp2p/NodeTable.cpp

@ -0,0 +1,467 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file NodeTable.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*/
#include "NodeTable.h"
using namespace std;
using namespace dev;
using namespace dev::p2p;
NodeTable::NodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _listenPort):
m_node(Node(_alias.pub(), bi::udp::endpoint())),
m_secret(_alias.sec()),
m_socket(new NodeSocket(_io, *this, _listenPort)),
m_socketPtr(m_socket.get()),
m_io(_io),
m_bucketRefreshTimer(m_io),
m_evictionCheckTimer(m_io)
{
for (unsigned i = 0; i < s_bins; i++)
{
m_state[i].distance = i;
m_state[i].modified = chrono::steady_clock::now() - chrono::seconds(1);
}
m_socketPtr->connect();
doRefreshBuckets(boost::system::error_code());
}
NodeTable::~NodeTable()
{
m_evictionCheckTimer.cancel();
m_bucketRefreshTimer.cancel();
m_socketPtr->disconnect();
}
void NodeTable::join()
{
doFindNode(m_node.id);
}
list<NodeId> NodeTable::nodes() const
{
list<NodeId> nodes;
Guard l(x_nodes);
for (auto& i: m_nodes)
nodes.push_back(i.second->id);
return move(nodes);
}
list<NodeTable::NodeEntry> NodeTable::state() const
{
list<NodeEntry> ret;
Guard l(x_state);
for (auto s: m_state)
for (auto n: s.nodes)
ret.push_back(*n.lock());
return move(ret);
}
NodeTable::NodeEntry NodeTable::operator[](NodeId _id)
{
Guard l(x_nodes);
return *m_nodes[_id];
}
void NodeTable::requestNeighbours(NodeEntry const& _node, NodeId _target) const
{
FindNode p(_node.endpoint.udp, _target);
p.sign(m_secret);
m_socketPtr->send(p);
}
void NodeTable::doFindNode(NodeId _node, unsigned _round, shared_ptr<set<shared_ptr<NodeEntry>>> _tried)
{
if (!m_socketPtr->isOpen() || _round == s_maxSteps)
return;
if (_round == s_maxSteps)
{
clog(NodeTableNote) << "Terminating doFindNode after " << _round << " rounds.";
return;
}
else if(!_round && !_tried)
// initialized _tried on first round
_tried.reset(new set<shared_ptr<NodeEntry>>());
auto nearest = findNearest(_node);
list<shared_ptr<NodeEntry>> tried;
for (unsigned i = 0; i < nearest.size() && tried.size() < s_alpha; i++)
if (!_tried->count(nearest[i]))
{
auto r = nearest[i];
tried.push_back(r);
FindNode p(r->endpoint.udp, _node);
p.sign(m_secret);
m_socketPtr->send(p);
}
if (tried.empty())
{
clog(NodeTableNote) << "Terminating doFindNode after " << _round << " rounds.";
return;
}
while (!tried.empty())
{
_tried->insert(tried.front());
tried.pop_front();
}
auto self(shared_from_this());
m_evictionCheckTimer.expires_from_now(boost::posix_time::milliseconds(c_reqTimeout.count()));
m_evictionCheckTimer.async_wait([this, self, _node, _round, _tried](boost::system::error_code const& _ec)
{
if (_ec)
return;
doFindNode(_node, _round + 1, _tried);
});
}
vector<shared_ptr<NodeTable::NodeEntry>> NodeTable::findNearest(NodeId _target)
{
// send s_alpha FindNode packets to nodes we know, closest to target
static unsigned lastBin = s_bins - 1;
unsigned head = dist(m_node.id, _target);
unsigned tail = head == 0 ? lastBin : (head - 1) % s_bins;
map<unsigned, list<shared_ptr<NodeEntry>>> found;
unsigned count = 0;
// if d is 0, then we roll look forward, if last, we reverse, else, spread from d
if (head > 1 && tail != lastBin)
while (head != tail && head < s_bins && count < s_bucketSize)
{
Guard l(x_state);
for (auto n: m_state[head].nodes)
if (auto p = n.lock())
{
if (count < s_bucketSize)
found[dist(_target, p->id)].push_back(p);
else
break;
}
if (count < s_bucketSize && tail)
for (auto n: m_state[tail].nodes)
if (auto p = n.lock())
{
if (count < s_bucketSize)
found[dist(_target, p->id)].push_back(p);
else
break;
}
head++;
if (tail)
tail--;
}
else if (head < 2)
while (head < s_bins && count < s_bucketSize)
{
Guard l(x_state);
for (auto n: m_state[head].nodes)
if (auto p = n.lock())
{
if (count < s_bucketSize)
found[dist(_target, p->id)].push_back(p);
else
break;
}
head++;
}
else
while (tail > 0 && count < s_bucketSize)
{
Guard l(x_state);
for (auto n: m_state[tail].nodes)
if (auto p = n.lock())
{
if (count < s_bucketSize)
found[dist(_target, p->id)].push_back(p);
else
break;
}
tail--;
}
vector<shared_ptr<NodeEntry>> ret;
for (auto& nodes: found)
for (auto n: nodes.second)
ret.push_back(n);
return move(ret);
}
void NodeTable::ping(bi::udp::endpoint _to) const
{
PingNode p(_to, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port());
p.sign(m_secret);
m_socketPtr->send(p);
}
void NodeTable::ping(NodeEntry* _n) const
{
if (_n)
ping(_n->endpoint.udp);
}
void NodeTable::evict(shared_ptr<NodeEntry> _leastSeen, shared_ptr<NodeEntry> _new)
{
if (!m_socketPtr->isOpen())
return;
Guard l(x_evictions);
m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id));
if (m_evictions.size() == 1)
doCheckEvictions(boost::system::error_code());
m_evictions.push_back(EvictionTimeout(make_pair(_leastSeen->id,chrono::steady_clock::now()), _new->id));
ping(_leastSeen.get());
}
void NodeTable::noteNode(Public const& _pubk, bi::udp::endpoint const& _endpoint)
{
// Don't add ourself
if (_pubk == m_node.address())
return;
shared_ptr<NodeEntry> node;
{
Guard l(x_nodes);
auto n = m_nodes.find(_pubk);
if (n == m_nodes.end())
{
node.reset(new NodeEntry(m_node, _pubk, _endpoint));
m_nodes[_pubk] = node;
// clog(NodeTableMessageSummary) << "Adding node to cache: " << _pubk;
}
else
{
node = n->second;
// clog(NodeTableMessageSummary) << "Found node in cache: " << _pubk;
}
}
// todo: why is this necessary?
if (!!node)
noteNode(node);
}
void NodeTable::noteNode(shared_ptr<NodeEntry> _n)
{
shared_ptr<NodeEntry> contested;
{
NodeBucket& s = bucket(_n.get());
Guard l(x_state);
s.nodes.remove_if([&_n](weak_ptr<NodeEntry> n)
{
if (n.lock() == _n)
return true;
return false;
});
if (s.nodes.size() >= s_bucketSize)
{
contested = s.nodes.front().lock();
if (!contested)
{
s.nodes.pop_front();
s.nodes.push_back(_n);
}
}
else
s.nodes.push_back(_n);
}
if (contested)
evict(contested, _n);
}
void NodeTable::dropNode(shared_ptr<NodeEntry> _n)
{
NodeBucket &s = bucket(_n.get());
{
Guard l(x_state);
s.nodes.remove_if([&_n](weak_ptr<NodeEntry> n) { return n.lock() == _n; });
}
Guard l(x_nodes);
m_nodes.erase(_n->id);
}
NodeTable::NodeBucket& NodeTable::bucket(NodeEntry const* _n)
{
return m_state[_n->distance - 1];
}
void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet)
{
// h256 + Signature + RLP (smallest possible packet is empty neighbours packet which is 3 bytes)
if (_packet.size() < h256::size + Signature::size + 3)
{
clog(NodeTableMessageSummary) << "Invalid Message size from " << _from.address().to_string() << ":" << _from.port();
return;
}
bytesConstRef signedBytes(_packet.cropped(h256::size, _packet.size() - h256::size));
h256 hashSigned(sha3(signedBytes));
if (!_packet.cropped(0, h256::size).contentsEqual(hashSigned.asBytes()))
{
clog(NodeTableMessageSummary) << "Invalid Message hash from " << _from.address().to_string() << ":" << _from.port();
return;
}
bytesConstRef rlpBytes(signedBytes.cropped(Signature::size, signedBytes.size() - Signature::size));
RLP rlp(rlpBytes);
unsigned itemCount = rlp.itemCount();
bytesConstRef sigBytes(_packet.cropped(h256::size, Signature::size));
Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(rlpBytes)));
if (!nodeid)
{
clog(NodeTableMessageSummary) << "Invalid Message signature from " << _from.address().to_string() << ":" << _from.port();
return;
}
noteNode(nodeid, _from);
try {
switch (itemCount)
{
case 1:
{
// clog(NodeTableMessageSummary) << "Received Pong from " << _from.address().to_string() << ":" << _from.port();
Pong in = Pong::fromBytesConstRef(_from, rlpBytes);
// whenever a pong is received, first check if it's in m_evictions
break;
}
case 2:
if (rlp[0].isList())
{
Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes);
// clog(NodeTableMessageSummary) << "Received " << in.nodes.size() << " Neighbours from " << _from.address().to_string() << ":" << _from.port();
for (auto n: in.nodes)
noteNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port));
}
else
{
// clog(NodeTableMessageSummary) << "Received FindNode from " << _from.address().to_string() << ":" << _from.port();
FindNode in = FindNode::fromBytesConstRef(_from, rlpBytes);
vector<shared_ptr<NodeTable::NodeEntry>> nearest = findNearest(in.target);
static unsigned const nlimit = (m_socketPtr->maxDatagramSize - 11) / 86;
for (unsigned offset = 0; offset < nearest.size(); offset += nlimit)
{
Neighbours out(_from, nearest, offset, nlimit);
out.sign(m_secret);
m_socketPtr->send(out);
}
}
break;
case 3:
{
// clog(NodeTableMessageSummary) << "Received PingNode from " << _from.address().to_string() << ":" << _from.port();
PingNode in = PingNode::fromBytesConstRef(_from, rlpBytes);
Pong p(_from);
p.replyTo = sha3(rlpBytes);
p.sign(m_secret);
m_socketPtr->send(p);
break;
}
default:
clog(NodeTableMessageSummary) << "Invalid Message received from " << _from.address().to_string() << ":" << _from.port();
return;
}
}
catch (...)
{
clog(NodeTableWarn) << "Exception processing message from " << _from.address().to_string() << ":" << _from.port();
}
}
void NodeTable::doCheckEvictions(boost::system::error_code const& _ec)
{
if (_ec || !m_socketPtr->isOpen())
return;
auto self(shared_from_this());
m_evictionCheckTimer.expires_from_now(c_evictionCheckInterval);
m_evictionCheckTimer.async_wait([this, self](boost::system::error_code const& _ec)
{
if (_ec)
return;
bool evictionsRemain = false;
list<shared_ptr<NodeEntry>> drop;
{
Guard le(x_evictions);
Guard ln(x_nodes);
for (auto& e: m_evictions)
if (chrono::steady_clock::now() - e.first.second > c_reqTimeout)
if (auto n = m_nodes[e.second])
drop.push_back(n);
evictionsRemain = m_evictions.size() - drop.size() > 0;
}
drop.unique();
for (auto n: drop)
dropNode(n);
if (evictionsRemain)
doCheckEvictions(boost::system::error_code());
});
}
void NodeTable::doRefreshBuckets(boost::system::error_code const& _ec)
{
if (_ec)
return;
clog(NodeTableNote) << "refreshing buckets";
bool connected = m_socketPtr->isOpen();
bool refreshed = false;
if (connected)
{
Guard l(x_state);
for (auto& d: m_state)
if (chrono::steady_clock::now() - d.modified > c_bucketRefresh)
while (!d.nodes.empty())
{
auto n = d.nodes.front();
if (auto p = n.lock())
{
refreshed = true;
ping(p.get());
break;
}
d.nodes.pop_front();
}
}
unsigned nextRefresh = connected ? (refreshed ? 200 : c_bucketRefresh.count()*1000) : 10000;
auto runcb = [this](boost::system::error_code const& error) -> void { doRefreshBuckets(error); };
m_bucketRefreshTimer.expires_from_now(boost::posix_time::milliseconds(nextRefresh));
m_bucketRefreshTimer.async_wait(runcb);
}

349
libp2p/NodeTable.h

@ -0,0 +1,349 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file NodeTable.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*/
#pragma once
#include <algorithm>
#include <boost/integer/static_log2.hpp>
#include <libdevcrypto/Common.h>
#include <libp2p/UDP.h>
namespace dev
{
namespace p2p
{
/**
* NodeTable using S/Kademlia system for node discovery and preference.
* untouched buckets are refreshed if they have not been touched within an hour
*
* Thread-safety is ensured by modifying NodeEntry details via
* shared_ptr replacement instead of mutating values.
*
* [Integration]
* @todo deadline-timer which maintains tcp/peer connections
* @todo restore nodes: affects refreshbuckets
* @todo TCP endpoints
* @todo makeRequired: don't try to evict node if node isRequired.
* @todo makeRequired: exclude bucket from refresh if we have node as peer.
*
* [Optimization]
* @todo encapsulate doFindNode into NetworkAlgorithm (task)
* @todo Pong to include ip:port where ping was received
* @todo expiration and sha3(id) 'to' for messages which are replies (prevents replay)
* @todo std::shared_ptr<PingNode> m_cachedPingPacket;
* @todo std::shared_ptr<FindNeighbours> m_cachedFindSelfPacket;
* @todo store root node in table?
*
* [Networking]
* @todo TCP endpoints
* @todo eth/upnp/natpmp/stun/ice/etc for public-discovery
* @todo firewall
*
* [Protocol]
* @todo post-eviction pong
* @todo optimize knowledge at opposite edges; eg, s_bitsPerStep lookups. (Can be done via pointers to NodeBucket)
* @todo ^ s_bitsPerStep = 5; // Denoted by b in [Kademlia]. Bits by which address space is divided.
* @todo optimize (use tree for state and/or custom compare for cache)
* @todo reputation (aka universal siblings lists)
*/
class NodeTable: UDPSocketEvents, public std::enable_shared_from_this<NodeTable>
{
friend struct Neighbours;
using NodeSocket = UDPSocket<NodeTable, 1280>;
using TimePoint = std::chrono::steady_clock::time_point;
using EvictionTimeout = std::pair<std::pair<NodeId,TimePoint>,NodeId>; ///< First NodeId may be evicted and replaced with second NodeId.
struct NodeDefaultEndpoint
{
NodeDefaultEndpoint(bi::udp::endpoint _udp): udp(_udp) {}
bi::udp::endpoint udp;
};
struct Node
{
Node(Public _pubk, NodeDefaultEndpoint _udp): id(_pubk), endpoint(_udp) {}
Node(Public _pubk, bi::udp::endpoint _udp): Node(_pubk, NodeDefaultEndpoint(_udp)) {}
virtual NodeId const& address() const { return id; }
virtual Public const& publicKey() const { return id; }
NodeId id;
NodeDefaultEndpoint endpoint;
};
/**
* NodeEntry
* @todo Type of id will become template parameter.
*/
struct NodeEntry: public Node
{
NodeEntry(Node _src, Public _pubk, NodeDefaultEndpoint _gw): Node(_pubk, _gw), distance(dist(_src.id,_pubk)) {}
NodeEntry(Node _src, Public _pubk, bi::udp::endpoint _udp): Node(_pubk, NodeDefaultEndpoint(_udp)), distance(dist(_src.id,_pubk)) {}
const unsigned distance; ///< Node's distance from _src (see constructor).
};
struct NodeBucket
{
unsigned distance;
TimePoint modified;
std::list<std::weak_ptr<NodeEntry>> nodes;
};
public:
NodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _port = 30300);
~NodeTable();
/// Constants for Kademlia, mostly derived from address space.
static unsigned const s_addressByteSize = sizeof(NodeId); ///< Size of address type in bytes.
static unsigned const s_bits = 8 * s_addressByteSize; ///< Denoted by n in [Kademlia].
static unsigned const s_bins = s_bits - 1; ///< Size of m_state (excludes root, which is us).
static unsigned const s_maxSteps = boost::static_log2<s_bits>::value; ///< Max iterations of discovery. (doFindNode)
/// Chosen constants
static unsigned const s_bucketSize = 16; ///< Denoted by k in [Kademlia]. Number of nodes stored in each bucket.
static unsigned const s_alpha = 3; ///< Denoted by \alpha in [Kademlia]. Number of concurrent FindNode requests.
/// Intervals
boost::posix_time::milliseconds const c_evictionCheckInterval = boost::posix_time::milliseconds(75); ///< Interval at which eviction timeouts are checked.
std::chrono::milliseconds const c_reqTimeout = std::chrono::milliseconds(300); ///< How long to wait for requests (evict, find iterations).
std::chrono::seconds const c_bucketRefresh = std::chrono::seconds(3600); ///< Refresh interval prevents bucket from becoming stale. [Kademlia]
static unsigned dist(NodeId const& _a, NodeId const& _b) { u512 d = _a ^ _b; unsigned ret; for (ret = 0; d >>= 1; ++ret) {}; return ret; }
void join();
NodeEntry root() const { return NodeEntry(m_node, m_node.publicKey(), m_node.endpoint.udp); }
std::list<NodeId> nodes() const;
std::list<NodeEntry> state() const;
NodeEntry operator[](NodeId _id);
protected:
/// Repeatedly sends s_alpha concurrent requests to nodes nearest to target, for nodes nearest to target, up to s_maxSteps rounds.
void doFindNode(NodeId _node, unsigned _round = 0, std::shared_ptr<std::set<std::shared_ptr<NodeEntry>>> _tried = std::shared_ptr<std::set<std::shared_ptr<NodeEntry>>>());
/// Returns nodes nearest to target.
std::vector<std::shared_ptr<NodeEntry>> findNearest(NodeId _target);
void ping(bi::udp::endpoint _to) const;
void ping(NodeEntry* _n) const;
void evict(std::shared_ptr<NodeEntry> _leastSeen, std::shared_ptr<NodeEntry> _new);
void noteNode(Public const& _pubk, bi::udp::endpoint const& _endpoint);
void noteNode(std::shared_ptr<NodeEntry> _n);
void dropNode(std::shared_ptr<NodeEntry> _n);
NodeBucket& bucket(NodeEntry const* _n);
/// General Network Events
void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet);
void onDisconnected(UDPSocketFace*) {};
/// Tasks
void doCheckEvictions(boost::system::error_code const& _ec);
void doRefreshBuckets(boost::system::error_code const& _ec);
#ifndef BOOST_AUTO_TEST_SUITE
private:
#else
protected:
#endif
/// Sends FindNeighbor packet. See doFindNode.
void requestNeighbours(NodeEntry const& _node, NodeId _target) const;
Node m_node; ///< This node.
Secret m_secret; ///< This nodes secret key.
mutable Mutex x_nodes; ///< Mutable for thread-safe copy in nodes() const.
std::map<NodeId, std::shared_ptr<NodeEntry>> m_nodes; ///< NodeId -> Node table (most common lookup path)
mutable Mutex x_state;
std::array<NodeBucket, s_bins> m_state; ///< State table of binned nodes.
Mutex x_evictions;
std::deque<EvictionTimeout> m_evictions; ///< Eviction timeouts.
std::shared_ptr<NodeSocket> m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr.
NodeSocket* m_socketPtr; ///< Set to m_socket.get().
ba::io_service& m_io; ///< Used by bucket refresh timer.
boost::asio::deadline_timer m_bucketRefreshTimer; ///< Timer which schedules and enacts bucket refresh.
boost::asio::deadline_timer m_evictionCheckTimer; ///< Timer for handling node evictions.
};
inline std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable)
{
_out << _nodeTable.root().address() << "\t" << "0\t" << _nodeTable.root().endpoint.udp.address() << ":" << _nodeTable.root().endpoint.udp.port() << std::endl;
auto s = _nodeTable.state();
for (auto n: s)
_out << n.address() << "\t" << n.distance << "\t" << n.endpoint.udp.address() << ":" << n.endpoint.udp.port() << std::endl;
return _out;
}
/**
* Ping packet: Check if node is alive.
* PingNode is cached and regenerated after expiration - t, where t is timeout.
*
* RLP Encoded Items: 3
* Minimum Encoded Size: 18 bytes
* Maximum Encoded Size: bytes // todo after u128 addresses
*
* signature: Signature of message.
* ipAddress: Our IP address.
* port: Our port.
* expiration: Triggers regeneration of packet. May also provide control over synchronization.
*
* Ping is used to implement evict. When a new node is seen for
* a given bucket which is full, the least-responsive node is pinged.
* If the pinged node doesn't respond then it is removed and the new
* node is inserted.
*
* @todo uint128_t for ip address (<->integer ipv4/6, asio-address, asio-endpoint)
*
*/
struct PingNode: RLPXDatagram<PingNode>
{
PingNode(bi::udp::endpoint _ep): RLPXDatagram<PingNode>(_ep) {}
PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram<PingNode>(_ep), ipAddress(_src), port(_srcPort), expiration(futureFromEpoch(_expiration)) {}
std::string ipAddress;
unsigned port;
unsigned expiration;
void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << expiration; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); ipAddress = r[0].toString(); port = r[1].toInt<unsigned>(); expiration = r[2].toInt<unsigned>(); }
};
/**
* Pong packet: response to ping
*
* RLP Encoded Items: 1
* Minimum Encoded Size: 33 bytes
* Maximum Encoded Size: 33 bytes
*
* @todo expiration
* @todo value of replyTo
* @todo create from PingNode (reqs RLPXDatagram verify flag)
*/
struct Pong: RLPXDatagram<Pong>
{
Pong(bi::udp::endpoint _ep): RLPXDatagram<Pong>(_ep) {}
h256 replyTo; // hash of rlp of PingNode
unsigned expiration;
void streamRLP(RLPStream& _s) const { _s.appendList(1); _s << replyTo; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); replyTo = (h256)r[0]; }
};
/**
* FindNode Packet: Request k-nodes, closest to the target.
* FindNode is cached and regenerated after expiration - t, where t is timeout.
* FindNode implicitly results in finding neighbours of a given node.
*
* RLP Encoded Items: 2
* Minimum Encoded Size: 21 bytes
* Maximum Encoded Size: 30 bytes
*
* target: NodeId of node. The responding node will send back nodes closest to the target.
* expiration: Triggers regeneration of packet. May also provide control over synchronization.
*
*/
struct FindNode: RLPXDatagram<FindNode>
{
FindNode(bi::udp::endpoint _ep): RLPXDatagram<FindNode>(_ep) {}
FindNode(bi::udp::endpoint _ep, NodeId _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram<FindNode>(_ep), target(_target), expiration(futureFromEpoch(_expiration)) {}
h512 target;
unsigned expiration;
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s << target << expiration; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); target = r[0].toHash<h512>(); expiration = r[1].toInt<unsigned>(); }
};
/**
* Node Packet: Multiple node packets are sent in response to FindNode.
*
* RLP Encoded Items: 2 (first item is list)
* Minimum Encoded Size: 10 bytes
*
* @todo nonce: Should be replaced with expiration.
*/
struct Neighbours: RLPXDatagram<Neighbours>
{
struct Node
{
Node() = default;
Node(RLP const& _r) { interpretRLP(_r); }
std::string ipAddress;
unsigned port;
NodeId node;
void streamRLP(RLPStream& _s) const { _s.appendList(3); _s << ipAddress << port << node; }
void interpretRLP(RLP const& _r) { ipAddress = _r[0].toString(); port = _r[1].toInt<unsigned>(); node = h512(_r[2].toBytes()); }
};
Neighbours(bi::udp::endpoint _ep): RLPXDatagram<Neighbours>(_ep) {}
Neighbours(bi::udp::endpoint _to, std::vector<std::shared_ptr<NodeTable::NodeEntry>> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram<Neighbours>(_to)
{
auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size();
for (auto i = _offset; i < limit; i++)
{
Node node;
node.ipAddress = _nearest[i]->endpoint.udp.address().to_string();
node.port = _nearest[i]->endpoint.udp.port();
node.node = _nearest[i]->publicKey();
nodes.push_back(node);
}
}
std::list<Node> nodes;
unsigned expiration = 1;
void streamRLP(RLPStream& _s) const { _s.appendList(2); _s.appendList(nodes.size()); for (auto& n: nodes) n.streamRLP(_s); _s << expiration; }
void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); for (auto n: r[0]) nodes.push_back(Node(n)); expiration = r[1].toInt<unsigned>(); }
};
struct NodeTableWarn: public LogChannel { static const char* name() { return "!P!"; } static const int verbosity = 0; };
struct NodeTableNote: public LogChannel { static const char* name() { return "*P*"; } static const int verbosity = 1; };
struct NodeTableMessageSummary: public LogChannel { static const char* name() { return "-P-"; } static const int verbosity = 2; };
struct NodeTableConnect: public LogChannel { static const char* name() { return "+P+"; } static const int verbosity = 10; };
struct NodeTableMessageDetail: public LogChannel { static const char* name() { return "=P="; } static const int verbosity = 5; };
struct NodeTableTriviaSummary: public LogChannel { static const char* name() { return "-P-"; } static const int verbosity = 10; };
struct NodeTableTriviaDetail: public LogChannel { static const char* name() { return "=P="; } static const int verbosity = 11; };
struct NodeTableAllDetail: public LogChannel { static const char* name() { return "=P="; } static const int verbosity = 13; };
struct NodeTableEgress: public LogChannel { static const char* name() { return ">>P"; } static const int verbosity = 14; };
struct NodeTableIngress: public LogChannel { static const char* name() { return "<<P"; } static const int verbosity = 15; };
}
}

2
libp2p/Session.cpp

@ -522,7 +522,7 @@ void Session::start()
<< m_server->protocolVersion()
<< m_server->m_clientVersion
<< m_server->caps()
<< m_server->m_public.port()
<< m_server->m_tcpPublic.port()
<< m_server->id();
sealAndSend(s);
ping();

4
libp2p/Session.h

@ -107,8 +107,8 @@ private:
mutable bi::tcp::socket m_socket; ///< Socket for the peer's connection. Mutable to ask for native_handle().
Mutex x_writeQueue; ///< Mutex for the write queue.
std::deque<bytes> m_writeQueue; ///< The write queue.
std::array<byte, 65536> m_data; ///< Data buffer for the write queue.
bytes m_incoming; ///< The incoming read queue of bytes.
std::array<byte, 65536> m_data; ///< Buffer for ingress packet data.
bytes m_incoming; ///< Read buffer for ingress bytes.
PeerInfo m_info; ///< Dynamic information about this peer.

54
libp2p/UDP.cpp

@ -0,0 +1,54 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file UDP.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*/
#include "UDP.h"
using namespace dev;
using namespace dev::p2p;
h256 RLPXDatagramFace::sign(Secret const& _k)
{
RLPStream rlpstream;
streamRLP(rlpstream);
bytes rlpBytes(rlpstream.out());
bytesConstRef rlp(&rlpBytes);
h256 hash(dev::sha3(rlp));
Signature sig = dev::sign(_k, hash);
data.resize(h256::size + Signature::size + rlp.size());
bytesConstRef packetHash(&data[0], h256::size);
bytesConstRef signedPayload(&data[h256::size], Signature::size + rlp.size());
bytesConstRef payloadSig(&data[h256::size], Signature::size);
bytesConstRef payload(&data[h256::size + Signature::size], rlp.size());
sig.ref().copyTo(payloadSig);
rlp.copyTo(payload);
dev::sha3(signedPayload).ref().copyTo(packetHash);
return std::move(hash);
};
Public RLPXDatagramFace::authenticate(bytesConstRef _sig, bytesConstRef _rlp)
{
Signature const& sig = *(Signature const*)_sig.data();
return std::move(dev::recover(sig, sha3(_rlp)));
};

265
libp2p/UDP.h

@ -0,0 +1,265 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file UDP.h
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*/
#pragma once
#include <atomic>
#include <memory>
#include <vector>
#include <deque>
#include <array>
#include <libdevcore/Guards.h>
#include <libdevcrypto/Common.h>
#include <libdevcrypto/SHA3.h>
#include <libdevcore/RLP.h>
#include "Common.h"
namespace ba = boost::asio;
namespace bi = ba::ip;
namespace dev
{
namespace p2p
{
/**
* UDP Datagram
* @todo make data protected/functional
*/
class UDPDatagram
{
public:
UDPDatagram(bi::udp::endpoint const& _ep): locus(_ep) {}
UDPDatagram(bi::udp::endpoint const& _ep, bytes _data): data(_data), locus(_ep) {}
bi::udp::endpoint const& endpoint() const { return locus; }
bytes data;
protected:
bi::udp::endpoint locus;
};
/**
* @brief RLPX Datagram which can be signed.
* @todo compact templates
* @todo make data private/functional (see UDPDatagram)
*/
struct RLPXDatagramFace: public UDPDatagram
{
static uint64_t futureFromEpoch(std::chrono::milliseconds _ms) { return std::chrono::duration_cast<std::chrono::milliseconds>((std::chrono::system_clock::now() + _ms).time_since_epoch()).count(); }
static uint64_t futureFromEpoch(std::chrono::seconds _sec) { return std::chrono::duration_cast<std::chrono::milliseconds>((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); }
static Public authenticate(bytesConstRef _sig, bytesConstRef _rlp);
RLPXDatagramFace(bi::udp::endpoint const& _ep): UDPDatagram(_ep) {}
virtual h256 sign(Secret const& _from);
virtual void streamRLP(RLPStream&) const =0;
virtual void interpretRLP(bytesConstRef _bytes) =0;
};
template <class T>
struct RLPXDatagram: public RLPXDatagramFace
{
RLPXDatagram(bi::udp::endpoint const& _ep): RLPXDatagramFace(_ep) {}
static T fromBytesConstRef(bi::udp::endpoint const& _ep, bytesConstRef _bytes) { T t(_ep); t.interpretRLP(_bytes); return std::move(t); }
};
/**
* @brief Interface which UDPSocket will implement.
*/
struct UDPSocketFace
{
virtual bool send(UDPDatagram const& _msg) = 0;
virtual void disconnect() = 0;
};
/**
* @brief Interface which a UDPSocket's owner must implement.
*/
struct UDPSocketEvents
{
virtual void onDisconnected(UDPSocketFace*) {};
virtual void onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packetData) = 0;
};
/**
* @brief UDP Interface
* Handler must implement UDPSocketEvents.
*
* @todo multiple endpoints (we cannot advertise 0.0.0.0)
* @todo decouple deque from UDPDatagram and add ref() to datagram for fire&forget
*/
template <typename Handler, unsigned MaxDatagramSize>
class UDPSocket: UDPSocketFace, public std::enable_shared_from_this<UDPSocket<Handler, MaxDatagramSize>>
{
public:
enum { maxDatagramSize = MaxDatagramSize };
static_assert(maxDatagramSize < 65507, "UDP datagrams cannot be larger than 65507 bytes");
UDPSocket(ba::io_service& _io, UDPSocketEvents& _host, unsigned _port): m_host(_host), m_endpoint(bi::udp::v4(), _port), m_socket(_io) { m_started.store(false); m_closed.store(true); };
virtual ~UDPSocket() { disconnect(); }
/// Socket will begin listening for and delivering packets
void connect();
/// Send datagram.
bool send(UDPDatagram const& _datagram);
/// Returns if socket is open.
bool isOpen() { return !m_closed; }
/// Disconnect socket.
void disconnect() { disconnectWithError(boost::asio::error::connection_reset); }
protected:
void doRead();
void doWrite();
void disconnectWithError(boost::system::error_code _ec);
std::atomic<bool> m_started; ///< Atomically ensure connection is started once. Start cannot occur unless m_started is false. Managed by start and disconnectWithError.
std::atomic<bool> m_closed; ///< Connection availability.
UDPSocketEvents& m_host; ///< Interface which owns this socket.
bi::udp::endpoint m_endpoint; ///< Endpoint which we listen to.
Mutex x_sendQ;
std::deque<UDPDatagram> m_sendQ; ///< Queue for egress data.
std::array<byte, maxDatagramSize> m_recvData; ///< Buffer for ingress data.
bi::udp::endpoint m_recvEndpoint; ///< Endpoint data was received from.
bi::udp::socket m_socket; ///< Boost asio udp socket.
Mutex x_socketError; ///< Mutex for error which can be set from host or IO thread.
boost::system::error_code m_socketError; ///< Set when shut down due to error.
};
template <typename Handler, unsigned MaxDatagramSize>
void UDPSocket<Handler, MaxDatagramSize>::connect()
{
bool expect = false;
if (!m_started.compare_exchange_strong(expect, true))
return;
m_socket.open(bi::udp::v4());
m_socket.bind(m_endpoint);
// clear write queue so reconnect doesn't send stale messages
Guard l(x_sendQ);
m_sendQ.clear();
m_closed = false;
doRead();
}
template <typename Handler, unsigned MaxDatagramSize>
bool UDPSocket<Handler, MaxDatagramSize>::send(UDPDatagram const& _datagram)
{
if (m_closed)
return false;
Guard l(x_sendQ);
m_sendQ.push_back(_datagram);
if (m_sendQ.size() == 1)
doWrite();
return true;
}
template <typename Handler, unsigned MaxDatagramSize>
void UDPSocket<Handler, MaxDatagramSize>::doRead()
{
if (m_closed)
return;
auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this());
m_socket.async_receive_from(boost::asio::buffer(m_recvData), m_recvEndpoint, [this, self](boost::system::error_code _ec, size_t _len)
{
if (_ec)
return disconnectWithError(_ec);
assert(_len);
m_host.onReceived(this, m_recvEndpoint, bytesConstRef(m_recvData.data(), _len));
doRead();
});
}
template <typename Handler, unsigned MaxDatagramSize>
void UDPSocket<Handler, MaxDatagramSize>::doWrite()
{
if (m_closed)
return;
const UDPDatagram& datagram = m_sendQ[0];
auto self(UDPSocket<Handler, MaxDatagramSize>::shared_from_this());
m_socket.async_send_to(boost::asio::buffer(datagram.data), datagram.endpoint(), [this, self](boost::system::error_code _ec, std::size_t)
{
if (_ec)
return disconnectWithError(_ec);
else
{
Guard l(x_sendQ);
m_sendQ.pop_front();
if (m_sendQ.empty())
return;
}
doWrite();
});
}
template <typename Handler, unsigned MaxDatagramSize>
void UDPSocket<Handler, MaxDatagramSize>::disconnectWithError(boost::system::error_code _ec)
{
// If !started and already stopped, shutdown has already occured. (EOF or Operation canceled)
if (!m_started && m_closed && !m_socket.is_open() /* todo: veirfy this logic*/)
return;
assert(_ec);
{
// disconnect-operation following prior non-zero errors are ignored
Guard l(x_socketError);
if (m_socketError != boost::system::error_code())
return;
m_socketError = _ec;
}
// TODO: (if non-zero error) schedule high-priority writes
// prevent concurrent disconnect
bool expected = true;
if (!m_started.compare_exchange_strong(expected, false))
return;
// set m_closed to true to prevent undeliverable egress messages
bool wasClosed = m_closed;
m_closed = true;
// close sockets
boost::system::error_code ec;
m_socket.shutdown(bi::udp::socket::shutdown_both, ec);
m_socket.close();
// socket never started if it never left stopped-state (pre-handshake)
if (wasClosed)
return;
m_host.onDisconnected(this);
}
}
}

2
libserpent/opcodes.cpp

@ -44,7 +44,7 @@ Mapping mapping[] = {
Mapping("GASPRICE", 0x3a, 0, 1),
Mapping("EXTCODESIZE", 0x3b, 1, 1),
Mapping("EXTCODECOPY", 0x3c, 4, 0),
Mapping("PREVHASH", 0x40, 0, 1),
Mapping("BLOCKHASH", 0x40, 1, 1),
Mapping("COINBASE", 0x41, 0, 1),
Mapping("TIMESTAMP", 0x42, 0, 1),
Mapping("NUMBER", 0x43, 0, 1),

6
libsolidity/ExpressionCompiler.cpp

@ -344,9 +344,9 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
m_context << eth::Instruction::COINBASE;
else if (member == "timestamp")
m_context << eth::Instruction::TIMESTAMP;
else if (member == "prevhash")
m_context << eth::Instruction::PREVHASH;
else if (member == "difficulty")
/* else if (member == "blockhash")
m_context << eth::Instruction::BLOCKHASH;
*/ else if (member == "difficulty")
m_context << eth::Instruction::DIFFICULTY;
else if (member == "number")
m_context << eth::Instruction::NUMBER;

21
libsolidity/Scanner.cpp

@ -285,8 +285,6 @@ Token::Value Scanner::scanMultiLineDocComment()
bool endFound = false;
bool charsAdded = false;
advance(); //consume the last '*' at /**
skipWhitespaceExceptLF();
while (!isSourcePastEndOfInput())
{
//handle newlines in multline comments
@ -354,11 +352,20 @@ Token::Value Scanner::scanSlash()
return Token::WHITESPACE;
else if (m_char == '*')
{
Token::Value comment;
m_nextSkippedComment.location.start = firstSlashPosition;
comment = scanMultiLineDocComment();
m_nextSkippedComment.location.end = getSourcePos();
m_nextSkippedComment.token = comment;
advance(); //consume the last '*' at /**
skipWhitespaceExceptLF();
// special case of a closed normal multiline comment
if (!m_source.isPastEndOfInput() && m_source.get(0) == '/')
advance(); //skip the closing slash
else // we actually have a multiline documentation comment
{
Token::Value comment;
m_nextSkippedComment.location.start = firstSlashPosition;
comment = scanMultiLineDocComment();
m_nextSkippedComment.location.end = getSourcePos();
m_nextSkippedComment.token = comment;
}
return Token::WHITESPACE;
}
else

1
libsolidity/Scanner.h

@ -119,6 +119,7 @@ public:
{
return m_currentToken.token;
}
Location getCurrentLocation() const { return m_currentToken.location; }
std::string const& getCurrentLiteral() const { return m_currentToken.literal; }
///@}

2
libsolidity/SourceReferenceFormatter.h

@ -28,7 +28,7 @@
namespace dev
{
class Exception; // forward
struct Exception; // forward
namespace solidity
{

81
libweb3jsonrpc/WebThreeStubServer.cpp

@ -266,21 +266,16 @@ std::string WebThreeStubServer::shh_addToGroup(std::string const& _group, std::s
std::string WebThreeStubServer::eth_balanceAt(string const& _address)
{
int block = 0;
return toJS(client()->balanceAt(jsToAddress(_address), block));
return toJS(client()->balanceAt(jsToAddress(_address), client()->getDefault()));
}
Json::Value WebThreeStubServer::eth_blockByHash(std::string const& _hash)
{
if (!client())
return "";
return toJson(client()->blockInfo(jsToFixed<32>(_hash)));
}
Json::Value WebThreeStubServer::eth_blockByNumber(int const& _number)
{
if (!client())
return "";
return toJson(client()->blockInfo(client()->hashFromNumber(_number)));
}
@ -332,8 +327,6 @@ static TransactionSkeleton toTransaction(Json::Value const& _json)
std::string WebThreeStubServer::eth_call(Json::Value const& _json)
{
std::string ret;
if (!client())
return ret;
TransactionSkeleton t = toTransaction(_json);
if (!t.from && m_accounts.size())
{
@ -355,31 +348,27 @@ std::string WebThreeStubServer::eth_call(Json::Value const& _json)
bool WebThreeStubServer::eth_changed(int const& _id)
{
if (!client())
return false;
return client()->checkWatch(_id);
}
std::string WebThreeStubServer::eth_codeAt(string const& _address)
{
int block = 0;
return client() ? jsFromBinary(client()->codeAt(jsToAddress(_address), block)) : "";
return jsFromBinary(client()->codeAt(jsToAddress(_address), client()->getDefault()));
}
std::string WebThreeStubServer::eth_coinbase()
{
return client() ? toJS(client()->address()) : "";
return toJS(client()->address());
}
double WebThreeStubServer::eth_countAt(string const& _address)
{
int block = 0;
return client() ? (double)(uint64_t)client()->countAt(jsToAddress(_address), block) : 0;
return (double)(uint64_t)client()->countAt(jsToAddress(_address), client()->getDefault());
}
int WebThreeStubServer::eth_defaultBlock()
{
return client() ? client()->getDefault() : 0;
return client()->getDefault();
}
std::string WebThreeStubServer::eth_gasPrice()
@ -397,15 +386,11 @@ std::string WebThreeStubServer::db_get(std::string const& _name, std::string con
Json::Value WebThreeStubServer::eth_filterLogs(int const& _id)
{
if (!client())
return Json::Value(Json::arrayValue);
return toJson(client()->logs(_id));
}
Json::Value WebThreeStubServer::eth_logs(Json::Value const& _json)
{
if (!client())
return Json::Value(Json::arrayValue);
return toJson(client()->logs(toLogFilter(_json)));
}
@ -429,15 +414,12 @@ bool WebThreeStubServer::eth_listening()
bool WebThreeStubServer::eth_mining()
{
return client() ? client()->isMining() : false;
return client()->isMining();
}
int WebThreeStubServer::eth_newFilter(Json::Value const& _json)
{
unsigned ret = -1;
if (!client())
return ret;
// ret = client()->installWatch(toMessageFilter(_json));
ret = client()->installWatch(toLogFilter(_json));
return ret;
}
@ -445,8 +427,6 @@ int WebThreeStubServer::eth_newFilter(Json::Value const& _json)
int WebThreeStubServer::eth_newFilterString(std::string const& _filter)
{
unsigned ret = -1;
if (!client())
return ret;
if (_filter.compare("chain") == 0)
ret = client()->installWatch(dev::eth::ChainChangedFilter);
else if (_filter.compare("pending") == 0)
@ -528,7 +508,7 @@ std::string WebThreeStubServer::eth_solidity(std::string const& _code)
int WebThreeStubServer::eth_number()
{
return client() ? client()->number() + 1 : 0;
return client()->number() + 1;
}
int WebThreeStubServer::eth_peerCount()
@ -538,7 +518,6 @@ int WebThreeStubServer::eth_peerCount()
bool WebThreeStubServer::shh_post(Json::Value const& _json)
{
// cnote << this << m_ids;
shh::Message m = toMessage(_json);
Secret from;
@ -571,16 +550,12 @@ bool WebThreeStubServer::db_putString(std::string const& _name, std::string cons
bool WebThreeStubServer::eth_setCoinbase(std::string const& _address)
{
if (!client())
return false;
client()->setAddress(jsToAddress(_address));
return true;
}
bool WebThreeStubServer::eth_setDefaultBlock(int const& _block)
{
if (!client())
return false;
client()->setDefault(_block);
return true;
}
@ -596,9 +571,6 @@ bool WebThreeStubServer::eth_setListening(bool const& _listening)
bool WebThreeStubServer::eth_setMining(bool const& _mining)
{
if (!client())
return false;
if (_mining)
client()->startMining();
else
@ -646,22 +618,17 @@ bool WebThreeStubServer::shh_uninstallFilter(int const& _id)
std::string WebThreeStubServer::eth_stateAt(string const& _address, string const& _storage)
{
int block = 0;
return client() ? toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), block)) : "";
return toJS(client()->stateAt(jsToAddress(_address), jsToU256(_storage), client()->getDefault()));
}
Json::Value WebThreeStubServer::eth_storageAt(string const& _address)
{
if (!client())
return Json::Value(Json::objectValue);
return toJson(client()->storageAt(jsToAddress(_address)));
}
std::string WebThreeStubServer::eth_transact(Json::Value const& _json)
{
std::string ret;
if (!client())
return ret;
TransactionSkeleton t = toTransaction(_json);
if (!t.from && m_accounts.size())
{
@ -677,48 +644,46 @@ std::string WebThreeStubServer::eth_transact(Json::Value const& _json)
t.gasPrice = 10 * dev::eth::szabo;
if (!t.gas)
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice);
cwarn << "Silently signing transaction from address" << t.from.abridged() << ": User validation hook goes here.";
if (t.to)
// TODO: from qethereum, insert validification hook here.
client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice);
else
ret = toJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice));
client()->flushTransactions();
if (authenticate(t))
{
if (t.to)
// TODO: from qethereum, insert validification hook here.
client()->transact(m_accounts[t.from].secret(), t.value, t.to, t.data, t.gas, t.gasPrice);
else
ret = toJS(client()->transact(m_accounts[t.from].secret(), t.value, t.data, t.gas, t.gasPrice));
client()->flushTransactions();
}
return ret;
}
bool WebThreeStubServer::authenticate(TransactionSkeleton const& _t) const
{
cwarn << "Silently signing transaction from address" << _t.from.abridged() << ": User validation hook goes here.";
return true;
}
Json::Value WebThreeStubServer::eth_transactionByHash(std::string const& _hash, int const& _i)
{
if (!client())
return "";
return toJson(client()->transaction(jsToFixed<32>(_hash), _i));
}
Json::Value WebThreeStubServer::eth_transactionByNumber(int const& _number, int const& _i)
{
if (!client())
return "";
return toJson(client()->transaction(client()->hashFromNumber(_number), _i));
}
Json::Value WebThreeStubServer::eth_uncleByHash(std::string const& _hash, int const& _i)
{
if (!client())
return "";
return toJson(client()->uncle(jsToFixed<32>(_hash), _i));
}
Json::Value WebThreeStubServer::eth_uncleByNumber(int const& _number, int const& _i)
{
if (!client())
return "";
return toJson(client()->uncle(client()->hashFromNumber(_number), _i));
}
bool WebThreeStubServer::eth_uninstallFilter(int const& _id)
{
if (!client())
return false;
client()->uninstallWatch(_id);
return true;
}

6
libweb3jsonrpc/WebThreeStubServer.h

@ -42,6 +42,7 @@ namespace dev
{
class WebThreeDirect;
class KeyPair;
class TransactionSkeleton;
namespace eth
{
class Interface;
@ -119,12 +120,15 @@ public:
void setIdentities(std::vector<dev::KeyPair> const& _ids);
std::map<dev::Public, dev::Secret> const& ids() const { return m_ids; }
protected:
virtual bool authenticate(dev::TransactionSkeleton const& _t) const;
private:
dev::eth::Interface* client() const;
std::shared_ptr<dev::shh::Interface> face() const;
dev::WebThreeDirect& m_web3;
std::map<dev::Address, dev::KeyPair> m_accounts;
ldb::ReadOptions m_readOptions;
ldb::WriteOptions m_writeOptions;
ldb::DB* m_db;

4
mix/AppContext.cpp

@ -60,7 +60,7 @@ void AppContext::loadProject()
if (!path.isEmpty())
{
QFile file(path);
if(file.open(QIODevice::ReadOnly | QIODevice::Text))
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream stream(&file);
QString json = stream.readAll();
@ -95,7 +95,7 @@ void AppContext::saveProject(QString const& _json)
{
dirPath.mkpath(dirPath.path());
QFile file(path);
if(file.open(QIODevice::WriteOnly | QIODevice::Text))
if (file.open(QIODevice::WriteOnly | QIODevice::Text))
{
QTextStream stream(&file);
stream << _json;

2
mix/AppContext.h

@ -51,7 +51,7 @@ class CodeModel;
* @brief Provides access to application scope variable.
*/
class AppContext : public QObject
class AppContext: public QObject
{
Q_OBJECT

18
mix/AssemblyDebuggerControl.cpp

@ -92,7 +92,7 @@ void AssemblyDebuggerControl::debugState(QVariantMap _state)
std::vector<TransactionSettings> transactionSequence;
for (auto const& t : transactions)
for (auto const& t: transactions)
{
QVariantMap transaction = t.toMap();
@ -132,14 +132,14 @@ void AssemblyDebuggerControl::executeSequence(std::vector<TransactionSettings> c
QFunctionDefinition* f;
ContractCallDataEncoder c;
//encode data for all transactions
for (auto const& t : _sequence)
for (auto const& t: _sequence)
{
f = nullptr;
for (int k = 0; k < contractDef->functionsList().size(); k++)
for (int tf = 0; tf < contractDef->functionsList().size(); tf++)
{
if (contractDef->functionsList().at(k)->name() == t.functionId)
if (contractDef->functionsList().at(tf)->name() == t.functionId)
{
f = contractDef->functionsList().at(k);
f = contractDef->functionsList().at(tf);
break;
}
}
@ -147,9 +147,9 @@ void AssemblyDebuggerControl::executeSequence(std::vector<TransactionSettings> c
throw std::runtime_error("function " + t.functionId.toStdString() + " not found");
c.encode(f->index());
for (int k = 0; k < f->parametersList().size(); k++)
for (int p = 0; p < f->parametersList().size(); p++)
{
QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(k);
QVariableDeclaration* var = (QVariableDeclaration*)f->parametersList().at(p);
u256 value = 0;
auto v = t.parameterValues.find(var->name());
if (v != t.parameterValues.cend())
@ -171,7 +171,7 @@ void AssemblyDebuggerControl::executeSequence(std::vector<TransactionSettings> c
//we need to wrap states in a QObject before sending to QML.
QList<QObject*> wStates;
for(int i = 0; i < debuggingContent.machineStates.size(); i++)
for (int i = 0; i < debuggingContent.machineStates.size(); i++)
{
QPointer<DebuggingStateWrapper> s(new DebuggingStateWrapper(debuggingContent.executionCode, debuggingContent.executionData.toBytes()));
s->setState(debuggingContent.machineStates.at(i));
@ -182,7 +182,7 @@ void AssemblyDebuggerControl::executeSequence(std::vector<TransactionSettings> c
emit dataAvailable(debuggingContent.returnParameters, wStates, code);
emit runComplete();
}
catch(boost::exception const& e)
catch(boost::exception const&)
{
emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information()));
}

2
mix/AssemblyDebuggerModel.cpp

@ -73,7 +73,7 @@ DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const&
};
execution.go(onOp);
execution.finalize(onOp);
execution.finalize();
m_executiveState.completeMine();
DebuggingContent d;

4
mix/CodeHighlighter.cpp

@ -36,7 +36,7 @@ using namespace dev::mix;
CodeHighlighterSettings::CodeHighlighterSettings()
{
backgroundColor = QColor(0x00, 0x2b, 0x36);
foregroundColor = QColor (0xee, 0xe8, 0xd5);
foregroundColor = QColor(0xee, 0xe8, 0xd5);
formats[Keyword].setForeground(QColor(0x93, 0xa1, 0xa1));
formats[Comment].setForeground(QColor(0x85, 0x99, 0x00));
formats[StringLiteral].setForeground(QColor(0xdc, 0x32, 0x2f));
@ -49,7 +49,7 @@ CodeHighlighterSettings::CodeHighlighterSettings()
namespace
{
using namespace dev::solidity;
class HighlightVisitor : public ASTConstVisitor
class HighlightVisitor: public ASTConstVisitor
{
public:
HighlightVisitor(CodeHighlighter::Formats* _formats) { m_formats = _formats; }

22
mix/CodeModel.cpp

@ -41,14 +41,17 @@ void BackgroundWorker::queueCodeChange(int _jobId, QString const& _content)
}
CompilationResult::CompilationResult():
QObject(nullptr), m_successfull(false),
QObject(nullptr),
m_successful(false),
m_codeHash(qHash(QString())),
m_contract(new QContractDefinition()),
m_codeHighlighter(new CodeHighlighter())
{}
CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler):
QObject(nullptr), m_successfull(true), m_codeHash(qHash(QString()))
QObject(nullptr),
m_successful(true),
m_codeHash(qHash(QString()))
{
if (!_compiler.getContractNames().empty())
{
@ -61,7 +64,9 @@ CompilationResult::CompilationResult(const solidity::CompilerStack& _compiler):
}
CompilationResult::CompilationResult(CompilationResult const& _prev, QString const& _compilerMessage):
QObject(nullptr), m_successfull(false), m_codeHash(qHash(QString())),
QObject(nullptr),
m_successful(false),
m_codeHash(qHash(QString())),
m_contract(_prev.m_contract),
m_compilerMessage(_compilerMessage),
m_bytes(_prev.m_bytes),
@ -69,8 +74,13 @@ CompilationResult::CompilationResult(CompilationResult const& _prev, QString con
m_codeHighlighter(_prev.m_codeHighlighter)
{}
CodeModel::CodeModel(QObject* _parent) : QObject(_parent),
m_compiling(false), m_result(new CompilationResult()), m_codeHighlighterSettings(new CodeHighlighterSettings()), m_backgroundWorker(this), m_backgroundJobId(0)
CodeModel::CodeModel(QObject* _parent):
QObject(_parent),
m_compiling(false),
m_result(new CompilationResult()),
m_codeHighlighterSettings(new CodeHighlighterSettings()),
m_backgroundWorker(this),
m_backgroundJobId(0)
{
m_backgroundWorker.moveToThread(&m_backgroundThread);
connect(this, &CodeModel::scheduleCompilationJob, &m_backgroundWorker, &BackgroundWorker::queueCodeChange, Qt::QueuedConnection);
@ -97,7 +107,7 @@ void CodeModel::stop()
m_backgroundThread.wait();
}
void CodeModel::registerCodeChange(const QString &_code)
void CodeModel::registerCodeChange(QString const& _code)
{
// launch the background thread
uint hash = qHash(_code);

10
mix/CodeModel.h

@ -61,7 +61,7 @@ private:
};
///Compilation result model. Contains all the compiled contract data required by UI
class CompilationResult : public QObject
class CompilationResult: public QObject
{
Q_OBJECT
Q_PROPERTY(QContractDefinition* contract READ contract)
@ -79,7 +79,7 @@ public:
/// @returns contract definition
std::shared_ptr<QContractDefinition> sharedContract() { return m_contract; }
/// Indicates if the compilation was successfull
bool successfull() const { return m_successfull; }
bool successfull() const { return m_successful; }
/// @returns compiler error message in case of unsuccessfull compilation
QString compilerMessage() const { return m_compilerMessage; }
/// @returns contract bytecode
@ -90,7 +90,7 @@ public:
std::shared_ptr<CodeHighlighter> codeHighlighter() { return m_codeHighlighter; }
private:
bool m_successfull;
bool m_successful;
uint m_codeHash;
std::shared_ptr<QContractDefinition> m_contract;
QString m_compilerMessage; ///< @todo: use some structure here
@ -102,7 +102,7 @@ private:
};
/// Background code compiler
class CodeModel : public QObject
class CodeModel: public QObject
{
Q_OBJECT
@ -139,7 +139,7 @@ signals:
void compilationCompleteInternal(CompilationResult* _newResult);
private slots:
void onCompilationComplete(CompilationResult*_newResult);
void onCompilationComplete(CompilationResult* _newResult);
public slots:
/// Update code model on source code change

3
mix/MixApplication.h

@ -43,7 +43,8 @@ public:
MixApplication(int _argc, char* _argv[]);
virtual ~MixApplication();
AppContext* context() { return m_appContext.get(); }
QQmlApplicationEngine* engine( ) { return m_engine.get(); }
QQmlApplicationEngine* engine() { return m_engine.get(); }
private:
std::unique_ptr<QQmlApplicationEngine> m_engine;
std::unique_ptr<AppContext> m_appContext;

2
mix/main.cpp

@ -23,7 +23,7 @@
#include "MixApplication.h"
using namespace dev::mix;
int main(int _argc, char *_argv[])
int main(int _argc, char* _argv[])
{
MixApplication app(_argc, _argv);
return app.exec();

7
test/SolidityScanner.cpp

@ -227,6 +227,13 @@ BOOST_AUTO_TEST_CASE(documentation_comment_before_eos)
BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), "");
}
BOOST_AUTO_TEST_CASE(empty_multiline_comment)
{
Scanner scanner(CharStream("/**/"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::EOS);
BOOST_CHECK_EQUAL(scanner.getCurrentCommentLiteral(), "");
}
BOOST_AUTO_TEST_CASE(empty_multiline_documentation_comment_before_eos)
{
Scanner scanner(CharStream("/***/"));

4
test/boostTest.cpp

@ -21,4 +21,8 @@
*/
#define BOOST_TEST_MODULE EthereumTests
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <boost/test/included/unit_test.hpp>
#pragma warning(pop)
#pragma GCC diagnostic pop

21
test/kademlia.cpp

@ -0,0 +1,21 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file kademlia.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*/

214
test/net.cpp

@ -0,0 +1,214 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file net.cpp
* @author Alex Leverington <nessence@gmail.com>
* @date 2014
*/
#include <boost/test/unit_test.hpp>
#include <libdevcore/Worker.h>
#include <libdevcrypto/Common.h>
#include <libp2p/UDP.h>
#include <libp2p/NodeTable.h>
using namespace std;
using namespace dev;
using namespace dev::p2p;
namespace ba = boost::asio;
namespace bi = ba::ip;
BOOST_AUTO_TEST_SUITE(p2p)
/**
* Only used for testing. Not useful beyond tests.
*/
class TestHost: public Worker
{
public:
TestHost(): Worker("test",0), m_io() {};
virtual ~TestHost() { m_io.stop(); stopWorking(); }
void start() { startWorking(); }
void doWork() { m_io.run(); }
void doneWorking() { m_io.reset(); m_io.poll(); m_io.reset(); }
protected:
ba::io_service m_io;
};
struct TestNodeTable: public NodeTable
{
/// Constructor
TestNodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _port = 30300): NodeTable(_io, _alias, _port) {}
static std::vector<std::pair<KeyPair,unsigned>> createTestNodes(unsigned _count)
{
std::vector<std::pair<KeyPair,unsigned>> ret;
asserts(_count < 1000);
static uint16_t s_basePort = 30500;
ret.clear();
for (unsigned i = 0; i < _count; i++)
{
KeyPair k = KeyPair::create();
ret.push_back(make_pair(k,s_basePort+i));
}
return std::move(ret);
}
void pingTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes)
{
bi::address ourIp = bi::address::from_string("127.0.0.1");
for (auto& n: _testNodes)
{
ping(bi::udp::endpoint(ourIp, n.second));
this_thread::sleep_for(chrono::milliseconds(2));
}
}
void populateTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes, size_t _count = 0)
{
if (!_count)
_count = _testNodes.size();
bi::address ourIp = bi::address::from_string("127.0.0.1");
for (auto& n: _testNodes)
if (_count--)
noteNode(n.first.pub(), bi::udp::endpoint(ourIp, n.second));
else
break;
}
void reset()
{
Guard l(x_state);
for (auto& n: m_state) n.nodes.clear();
}
};
/**
* Only used for testing. Not useful beyond tests.
*/
struct TestNodeTableHost: public TestHost
{
TestNodeTableHost(unsigned _count = 8): m_alias(KeyPair::create()), nodeTable(new TestNodeTable(m_io, m_alias)), testNodes(TestNodeTable::createTestNodes(_count)) {};
~TestNodeTableHost() { m_io.stop(); stopWorking(); }
void setup() { for (auto n: testNodes) nodeTables.push_back(make_shared<TestNodeTable>(m_io,n.first,n.second)); }
void pingAll() { for (auto& t: nodeTables) t->pingTestNodes(testNodes); }
void populateAll(size_t _count = 0) { for (auto& t: nodeTables) t->populateTestNodes(testNodes, _count); }
void populate(size_t _count = 0) { nodeTable->populateTestNodes(testNodes, _count); }
KeyPair m_alias;
shared_ptr<TestNodeTable> nodeTable;
std::vector<std::pair<KeyPair,unsigned>> testNodes; // keypair and port
std::vector<shared_ptr<TestNodeTable>> nodeTables;
};
class TestUDPSocket: UDPSocketEvents, public TestHost
{
public:
TestUDPSocket(): m_socket(new UDPSocket<TestUDPSocket, 1024>(m_io, *this, 30300)) {}
void onDisconnected(UDPSocketFace*) {};
void onReceived(UDPSocketFace*, bi::udp::endpoint const&, bytesConstRef _packet) { if (_packet.toString() == "AAAA") success = true; }
shared_ptr<UDPSocket<TestUDPSocket, 1024>> m_socket;
bool success = false;
};
BOOST_AUTO_TEST_CASE(test_neighbours_packet)
{
KeyPair k = KeyPair::create();
std::vector<std::pair<KeyPair,unsigned>> testNodes(TestNodeTable::createTestNodes(16));
bi::udp::endpoint to(boost::asio::ip::address::from_string("127.0.0.1"), 30000);
Neighbours out(to);
for (auto n: testNodes)
{
Neighbours::Node node;
node.ipAddress = boost::asio::ip::address::from_string("127.0.0.1").to_string();
node.port = n.second;
node.node = n.first.pub();
out.nodes.push_back(node);
}
out.sign(k.sec());
bytesConstRef packet(out.data.data(), out.data.size());
bytesConstRef rlpBytes(packet.cropped(97, packet.size() - 97));
Neighbours in = Neighbours::fromBytesConstRef(to, rlpBytes);
int count = 0;
for (auto n: in.nodes)
{
BOOST_REQUIRE_EQUAL(testNodes[count].second, n.port);
BOOST_REQUIRE_EQUAL(testNodes[count].first.pub(), n.node);
BOOST_REQUIRE_EQUAL(sha3(testNodes[count].first.pub()), sha3(n.node));
count++;
}
}
BOOST_AUTO_TEST_CASE(test_findnode_neighbours)
{
// Executing findNode should result in a list which is serialized
// into Neighbours packet. Neighbours packet should then be deserialized
// into the same list of nearest nodes.
}
BOOST_AUTO_TEST_CASE(test_windows_template)
{
bi::udp::endpoint ep;
PingNode p(ep);
}
BOOST_AUTO_TEST_CASE(kademlia)
{
// Not yet a 'real' test.
TestNodeTableHost node(8);
node.start();
node.nodeTable->join(); // ideally, joining with empty node table logs warning we can check for
node.setup();
node.populate();
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
node.populateAll();
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
node.nodeTable->reset();
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
node.populate(1);
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
node.nodeTable->join();
this_thread::sleep_for(chrono::milliseconds(2000));
clog << "NodeTable:\n" << *node.nodeTable.get() << endl;
}
BOOST_AUTO_TEST_CASE(test_udp_once)
{
UDPDatagram d(bi::udp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 30300), bytes({65,65,65,65}));
TestUDPSocket a; a.m_socket->connect(); a.start();
a.m_socket->send(d);
this_thread::sleep_for(chrono::seconds(1));
BOOST_REQUIRE_EQUAL(true, a.success);
}
BOOST_AUTO_TEST_SUITE_END()

55
test/network.cpp

@ -1,55 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file network.cpp
* @author Marko Simovic <markobarko@gmail.com>
* @date 2014
* Basic networking tests
*/
#include <boost/test/unit_test.hpp>
#include <boost/filesystem/operations.hpp>
#include <libethereum/Client.h>
#include <libethereum/BlockChain.h>
#include <libethereum/EthereumHost.h>
#include "TestHelper.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
// Disabled since tests shouldn't block (not the worst offender, but timeout should be reduced anyway).
/*
BOOST_AUTO_TEST_CASE(listen_port_busy)
{
short port = 20000;
//make use of the port ahead of our client
ba::io_service ioService;
bi::tcp::endpoint endPoint(bi::tcp::v4(), port);
bi::tcp::acceptor acceptor(ioService, endPoint);
acceptor.listen(10);
//prepare client and try to listen on same, used, port
Client c1("TestClient1", KeyPair::create().address(),
(boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()).string());
c1.startNetwork(port);
BOOST_REQUIRE(c1.haveNetwork());
BOOST_REQUIRE(c1.peerServer()->listenPort() != 0);
BOOST_REQUIRE(c1.peerServer()->listenPort() != port);
}
*/

4
test/stSystemOperationsTestFiller.json

@ -740,7 +740,7 @@
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365223",
"gasLimit" : "365243",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
@ -774,7 +774,7 @@
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "365224",
"gasLimit" : "365244",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",

65
test/trie.cpp

@ -50,7 +50,7 @@ static unsigned fac(unsigned _i)
BOOST_AUTO_TEST_SUITE(TrieTests)
BOOST_AUTO_TEST_CASE(trie_tests)
BOOST_AUTO_TEST_CASE(trie_test_anyorder)
{
string testPath = test::getTestPath();
@ -92,6 +92,69 @@ BOOST_AUTO_TEST_CASE(trie_tests)
}
}
BOOST_AUTO_TEST_CASE(trie_tests_ordered)
{
string testPath = test::getTestPath();
testPath += "/TrieTests";
cnote << "Testing Trie...";
js::mValue v;
string s = asString(contents(testPath + "/trietest.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'trietest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v);
for (auto& i: v.get_obj())
{
cnote << i.first;
js::mObject& o = i.second.get_obj();
vector<pair<string, string>> ss;
vector<string> keysToBeDeleted;
for (auto& i: o["in"].get_array())
{
vector<string> values;
for (auto& s: i.get_array())
{
if (s.type() == json_spirit::str_type)
values.push_back(s.get_str());
else if (s.type() == json_spirit::null_type)
{
// mark entry for deletion
values.push_back("");
if (!values[0].find("0x"))
values[0] = asString(fromHex(values[0].substr(2)));
keysToBeDeleted.push_back(values[0]);
}
else
BOOST_FAIL("Bad type (expected string)");
}
BOOST_REQUIRE(values.size() == 2);
ss.push_back(make_pair(values[0], values[1]));
if (!ss.back().first.find("0x"))
ss.back().first = asString(fromHex(ss.back().first.substr(2)));
if (!ss.back().second.find("0x"))
ss.back().second = asString(fromHex(ss.back().second.substr(2)));
}
MemoryDB m;
GenericTrieDB<MemoryDB> t(&m);
t.init();
BOOST_REQUIRE(t.check(true));
for (auto const& k: ss)
{
if (find(keysToBeDeleted.begin(), keysToBeDeleted.end(), k.first) != keysToBeDeleted.end() && k.second.empty())
t.remove(k.first);
else
t.insert(k.first, k.second);
BOOST_REQUIRE(t.check(true));
}
BOOST_REQUIRE(!o["root"].is_null());
BOOST_CHECK_EQUAL(o["root"].get_str(), "0x" + toHex(t.root().asArray()));
}
}
inline h256 stringMapHash256(StringMap const& _s)
{
return hash256(_s);

2392
test/vmArithmeticTestFiller.json

File diff suppressed because it is too large
Loading…
Cancel
Save