Browse Source

Merge branch 'develop' into develop-evmcc

cl-refactor
Paweł Bylica 10 years ago
parent
commit
aa716d4600
  1. 1
      exp/main.cpp
  2. 2
      libdevcore/Common.cpp
  3. 2
      libdevcore/CommonIO.cpp
  4. 12
      libdevcore/CommonIO.h
  5. 1
      libdevcore/Exceptions.h
  6. 2
      libdevcore/RLP.h
  7. 16
      libdevcrypto/SHA3.cpp
  8. 6
      libdevcrypto/SHA3.h
  9. 2
      libethcore/CommonEth.cpp
  10. 35
      libethcore/Exceptions.cpp
  11. 35
      libethcore/Exceptions.h
  12. 1
      libethcore/_libethcore.cpp
  13. 13
      libethereum/BlockQueue.cpp
  14. 17
      libethereum/BlockQueue.h
  15. 23
      libethereum/Client.cpp
  16. 68
      libethereum/Client.h
  17. 18
      libethereum/CommonNet.h
  18. 4
      libethereum/DownloadMan.cpp
  19. 4
      libethereum/DownloadMan.h
  20. 220
      libethereum/EthereumHost.cpp
  21. 35
      libethereum/EthereumHost.h
  22. 455
      libethereum/EthereumPeer.cpp
  23. 82
      libethereum/EthereumPeer.h
  24. 6
      libethereum/Executive.cpp
  25. 18
      libethereum/ExtVM.h
  26. 9
      libethereum/Interface.h
  27. 8
      libethereum/Miner.cpp
  28. 2
      libethereum/Miner.h
  29. 68
      libethereum/State.cpp
  30. 12
      libethereum/State.h
  31. 11
      libevm/ExtVMFace.h
  32. 42
      libevm/VM.h
  33. 9
      libevmface/Instruction.cpp
  34. 4
      libevmface/Instruction.h
  35. 5
      liblll/Assembly.cpp
  36. 1
      liblll/CodeFragment.cpp
  37. 17
      libp2p/Capability.cpp
  38. 15
      libp2p/Capability.h
  39. 13
      libp2p/Common.cpp
  40. 10
      libp2p/Common.h
  41. 14
      libp2p/Host.cpp
  42. 13
      libp2p/Host.h
  43. 2
      libp2p/HostCapability.cpp
  44. 12
      libp2p/HostCapability.h
  45. 75
      libp2p/Session.cpp
  46. 7
      libp2p/Session.h
  47. 1
      libp2p/UPnP.cpp
  48. 87
      libqethereum/QEthereum.cpp
  49. 20
      libqethereum/QEthereum.h
  50. 5
      libwhisper/Common.h
  51. 3
      libwhisper/Interface.cpp
  52. 1
      libwhisper/Message.cpp
  53. 3
      libwhisper/WhisperHost.cpp
  54. 17
      libwhisper/WhisperPeer.cpp
  55. 6
      libwhisper/WhisperPeer.h
  56. 3
      test/hexPrefix.cpp
  57. 1
      test/rlp.cpp
  58. 1
      test/trie.cpp
  59. 7
      test/vm.cpp
  60. 7
      third/MainWin.cpp
  61. 6
      windows/LibEthereum.vcxproj
  62. 3
      windows/LibEthereum.vcxproj.filters

1
exp/main.cpp

@ -24,6 +24,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/RLP.h>
#include <libdevcore/CommonIO.h>
#include <libp2p/All.h>
#include <libdevcore/RangeMask.h>
#include <libethereum/DownloadMan.h>

2
libdevcore/Common.cpp

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

2
libdevcore/CommonIO.cpp

@ -19,7 +19,7 @@
* @date 2014
*/
#include "Common.h"
#include "CommonIO.h"
#include <fstream>
#include "Exceptions.h"

12
libdevcore/CommonIO.h

@ -55,6 +55,18 @@ std::string memDump(bytes const& _b, unsigned _w = 8, bool _html = false);
template <class S, class T> struct StreamOut { static S& bypass(S& _out, T const& _t) { _out << _t; return _out; } };
template <class S> struct StreamOut<S, uint8_t> { static S& bypass(S& _out, uint8_t const& _t) { _out << (int)_t; return _out; } };
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::vector<T> const& _e);
template <class T, unsigned Z> inline std::ostream& operator<<(std::ostream& _out, std::array<T, Z> const& _e);
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::pair<T, U> const& _e);
template <class T> inline std::ostream& operator<<(std::ostream& _out, std::list<T> const& _e);
template <class T1, class T2, class T3> inline std::ostream& operator<<(std::ostream& _out, std::tuple<T1, T2, T3> const& _e);
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::map<T, U> const& _e);
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::unordered_map<T, U> const& _e);
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::set<T, U> const& _e);
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::unordered_set<T, U> const& _e);
template <class T, class U> inline std::ostream& operator<<(std::ostream& _out, std::multimap<T, U> const& _e);
template <class _S, class _T> _S& operator<<(_S& _out, std::shared_ptr<_T> const& _p);
template <class S, class T>
inline S& streamout(S& _out, std::vector<T> const& _e)
{

1
libdevcore/Exceptions.h

@ -25,7 +25,6 @@
#include <boost/exception/all.hpp>
#include <boost/throw_exception.hpp>
#include <libdevcrypto/Common.h>
#include "CommonIO.h"
#include "CommonData.h"
#include "FixedHash.h"

2
libdevcore/RLP.h

@ -289,7 +289,7 @@ public:
private:
/// Disable construction from rvalue
explicit RLP(bytes const&& _d) {}
explicit RLP(bytes const&&) {}
/// Single-byte data payload.
bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; }

16
libdevcrypto/SHA3.cpp

@ -58,6 +58,22 @@ void sha3(bytesConstRef _input, bytesRef _output)
ctx.Final(_output.data());
}
void ripemd160(bytesConstRef _input, bytesRef _output)
{
CryptoPP::RIPEMD160 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
void sha256(bytesConstRef _input, bytesRef _output)
{
CryptoPP::SHA256 ctx;
ctx.Update((byte*)_input.data(), _input.size());
assert(_output.size() >= 32);
ctx.Final(_output.data());
}
bytes sha3Bytes(bytesConstRef _input)
{
bytes ret(32);

6
libdevcrypto/SHA3.h

@ -60,7 +60,13 @@ inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input))
extern h256 EmptySHA3;
// Other crypto convenience routines
bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef());
void sha256(bytesConstRef _input, bytesRef _output);
void ripemd160(bytesConstRef _input, bytesRef _output);
}
}

2
libethcore/CommonEth.cpp

@ -34,7 +34,7 @@ namespace dev
namespace eth
{
const unsigned c_protocolVersion = 33;
const unsigned c_protocolVersion = 34;
const unsigned c_databaseVersion = 2;
static const vector<pair<u256, string>> g_units =

35
libethcore/Exceptions.cpp

@ -0,0 +1,35 @@
/*
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 Exceptions.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Exceptions.h"
#include <libdevcore/CommonIO.h>
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(); }

35
libethcore/Exceptions.h

@ -1,3 +1,24 @@
/*
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 Exceptions.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <libdevcore/Exceptions.h>
@ -23,23 +44,23 @@ struct FeeTooSmall: virtual dev::Exception {};
struct TooMuchGasUsed: virtual dev::Exception {};
struct ExtraDataTooBig: virtual dev::Exception {};
struct InvalidSignature: virtual dev::Exception {};
class InvalidBlockFormat: public dev::Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual const char* what() const noexcept { return ("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")").c_str(); } };
class InvalidBlockFormat: public dev::Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual const char* what() const noexcept; };
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 { return ("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")").c_str(); } };
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 { return ("Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref())).c_str(); } };
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; };
struct InvalidTransaction: virtual dev::Exception {};
struct InvalidDifficulty: virtual dev::Exception {};
class InvalidGasLimit: public dev::Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0): provided(_provided), valid(_valid) {} u256 provided; u256 valid; virtual const char* what() const noexcept { return ("Invalid gas limit (provided: " + toString(provided) + " valid:" + toString(valid) + ")").c_str(); } };
class InvalidMinGasPrice: public dev::Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual const char* what() const noexcept { return ("Invalid minimum gas price (provided: " + toString(provided) + " limit:" + toString(limit) + ")").c_str(); } };
class InvalidGasLimit: public dev::Exception { public: InvalidGasLimit(u256 _provided = 0, u256 _valid = 0): provided(_provided), valid(_valid) {} u256 provided; u256 valid; virtual const char* what() const noexcept; };
class InvalidMinGasPrice: public dev::Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual const char* what() const noexcept; };
struct InvalidTransactionGasUsed: virtual dev::Exception {};
struct InvalidTransactionStateRoot: virtual dev::Exception {};
struct InvalidTimestamp: virtual dev::Exception {};
class InvalidNonce: public dev::Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual const char* what() const noexcept { return ("Invalid nonce (r: " + toString(required) + " c:" + toString(candidate) + ")").c_str(); } };
class InvalidBlockNonce: public dev::Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; virtual const char* what() const noexcept { return ("Invalid nonce (h: " + toString(h) + " n:" + toString(n) + " d:" + toString(d) + ")").c_str(); } };
class InvalidNonce: public dev::Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual const char* what() const noexcept; };
class InvalidBlockNonce: public dev::Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; virtual const char* what() const noexcept; };
struct InvalidParentHash: virtual dev::Exception {};
struct InvalidNumber: virtual dev::Exception {};
struct InvalidContractAddress: virtual dev::Exception {};

1
libethcore/_libethcore.cpp

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

13
libethereum/BlockQueue.cpp

@ -29,7 +29,7 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
{
// Check if we already know this block.
h256 h = BlockInfo::headerHash(_block);
@ -42,7 +42,7 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
{
// Already know about this one.
cblockq << "Already known.";
return false;
return ImportResult::AlreadyKnown;
}
// VERIFY: populates from the block and checks the block is internally coherent.
@ -60,6 +60,7 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
{
cwarn << "Ignoring malformed block: " << diagnostic_information(_e);
return false;
return ImportResult::Malformed;
}
#endif
@ -67,7 +68,7 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
if (_bc.details(h))
{
cblockq << "Already known in chain.";
return false;
return ImportResult::AlreadyInChain;
}
UpgradeGuard ul(l);
@ -77,6 +78,7 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
{
m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes()));
cblockq << "OK - queued for future.";
return ImportResult::FutureTime;
}
else
{
@ -87,6 +89,8 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
cblockq << "OK - queued as unknown parent:" << bi.parentHash.abridged();
m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
m_unknownSet.insert(h);
return ImportResult::UnknownParent;
}
else
{
@ -96,10 +100,9 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
m_readySet.insert(h);
noteReadyWithoutWriteGuard(h);
return ImportResult::Success;
}
}
return true;
}
void BlockQueue::tick(BlockChain const& _bc)

17
libethereum/BlockQueue.h

@ -37,6 +37,16 @@ class BlockChain;
struct BlockQueueChannel: public LogChannel { static const char* name() { return "[]Q"; } static const int verbosity = 4; };
#define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>()
enum class ImportResult
{
Success = 0,
UnknownParent,
FutureTime,
AlreadyInChain,
AlreadyKnown,
Malformed
};
/**
* @brief A queue of blocks. Sits between network or other I/O and the BlockChain.
* Sorts them ready for blockchain insertion (with the BlockChain::sync() method).
@ -46,7 +56,7 @@ class BlockQueue
{
public:
/// Import a block into the queue.
bool import(bytesConstRef _tx, BlockChain const& _bc);
ImportResult import(bytesConstRef _tx, BlockChain const& _bc);
/// Notes that time has moved on and some blocks that used to be "in the future" may no be valid.
void tick(BlockChain const& _bc);
@ -67,6 +77,9 @@ public:
/// Clear everything.
void clear() { WriteGuard l(m_lock); m_readySet.clear(); m_drainingSet.clear(); m_ready.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); }
/// Return first block with an unknown parent.
h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); }
private:
void noteReadyWithoutWriteGuard(h256 _b);
void notePresentWithoutWriteGuard(bytesConstRef _block);
@ -77,7 +90,7 @@ private:
std::vector<bytes> m_ready; ///< List of blocks, in correct order, ready for chain-import.
std::set<h256> m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain.
std::multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For transactions that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
std::multimap<unsigned, bytes> m_future; ///< Set of blocks that are not yet valid.
std::multimap<unsigned, bytes> m_future; ///< Set of blocks that are not yet valid.
};
}

23
libethereum/Client.cpp

@ -232,12 +232,9 @@ void Client::appendFromNewBlock(h256 _block, h256Set& o_changed) const
void Client::setForceMining(bool _enable)
{
m_forceMining = _enable;
if (!m_host.lock())
{
ReadGuard l(x_miners);
for (auto& m: m_miners)
m.noteStateChange();
}
ReadGuard l(x_miners);
for (auto& m: m_miners)
m.noteStateChange();
}
void Client::setMiningThreads(unsigned _threads)
@ -550,6 +547,20 @@ bytes Client::codeAt(Address _a, int _block) const
return asOf(_block).code(_a);
}
Transaction Client::transaction(h256 _blockHash, unsigned _i) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
return Transaction(b[1][_i].data());
}
BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const
{
auto bl = m_bc.block(_blockHash);
RLP b(bl);
return BlockInfo::fromHeader(b[2][_i].data());
}
PastMessages Client::messages(MessageFilter const& _f) const
{
PastMessages ret;

68
libethereum/Client.h

@ -119,23 +119,23 @@ public:
explicit Client(p2p::Host* _host, std::string const& _dbPath = std::string(), bool _forceClean = false, u256 _networkId = 0);
/// Destructor.
~Client();
virtual ~Client();
/// Submits the given message-call transaction.
void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
virtual void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
/// Submits a new contract-creation transaction.
/// @returns the new contract's address (assuming it all goes through).
Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
virtual Address transact(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
/// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly.
void inject(bytesConstRef _rlp);
virtual void inject(bytesConstRef _rlp);
/// Blocks until all pending transactions have been processed.
void flushTransactions();
virtual void flushTransactions();
/// Makes the given call. Nothing is recorded into the state.
bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
virtual bytes call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
// Informational stuff
@ -147,20 +147,20 @@ public:
using Interface::codeAt;
using Interface::storageAt;
u256 balanceAt(Address _a, int _block) const;
u256 countAt(Address _a, int _block) const;
u256 stateAt(Address _a, u256 _l, int _block) const;
bytes codeAt(Address _a, int _block) const;
std::map<u256, u256> storageAt(Address _a, int _block) const;
virtual u256 balanceAt(Address _a, int _block) const;
virtual u256 countAt(Address _a, int _block) const;
virtual u256 stateAt(Address _a, u256 _l, int _block) const;
virtual bytes codeAt(Address _a, int _block) const;
virtual std::map<u256, u256> storageAt(Address _a, int _block) const;
unsigned installWatch(MessageFilter const& _filter);
unsigned installWatch(h256 _filterId);
void uninstallWatch(unsigned _watchId);
bool peekWatch(unsigned _watchId) const { std::lock_guard<std::mutex> l(m_filterLock); try { return m_watches.at(_watchId).changes != 0; } catch (...) { return false; } }
bool checkWatch(unsigned _watchId) { std::lock_guard<std::mutex> l(m_filterLock); bool ret = false; try { ret = m_watches.at(_watchId).changes != 0; m_watches.at(_watchId).changes = 0; } catch (...) {} return ret; }
virtual unsigned installWatch(MessageFilter const& _filter);
virtual unsigned installWatch(h256 _filterId);
virtual void uninstallWatch(unsigned _watchId);
virtual bool peekWatch(unsigned _watchId) const { std::lock_guard<std::mutex> l(m_filterLock); try { return m_watches.at(_watchId).changes != 0; } catch (...) { return false; } }
virtual bool checkWatch(unsigned _watchId) { std::lock_guard<std::mutex> l(m_filterLock); bool ret = false; try { ret = m_watches.at(_watchId).changes != 0; m_watches.at(_watchId).changes = 0; } catch (...) {} return ret; }
PastMessages messages(unsigned _watchId) const { try { std::lock_guard<std::mutex> l(m_filterLock); return messages(m_filters.at(m_watches.at(_watchId).id).filter); } catch (...) { return PastMessages(); } }
PastMessages messages(MessageFilter const& _filter) const;
virtual PastMessages messages(unsigned _watchId) const { try { std::lock_guard<std::mutex> l(m_filterLock); return messages(m_filters.at(m_watches.at(_watchId).id).filter); } catch (...) { return PastMessages(); } }
virtual PastMessages messages(MessageFilter const& _filter) const;
// [EXTRA API]:
@ -169,19 +169,25 @@ public:
/// Get a map containing each of the pending transactions.
/// @TODO: Remove in favour of transactions().
Transactions pending() const { return m_postMine.pending(); }
virtual Transactions pending() const { return m_postMine.pending(); }
virtual h256 hashFromNumber(unsigned _number) const { return m_bc.numberHash(_number); }
virtual BlockInfo blockInfo(h256 _hash) const { return BlockInfo(m_bc.block(_hash)); }
virtual BlockDetails blockDetails(h256 _hash) const { return m_bc.details(_hash); }
virtual Transaction transaction(h256 _blockHash, unsigned _i) const;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const;
/// Differences between transactions.
using Interface::diff;
StateDiff diff(unsigned _txi, h256 _block) const;
StateDiff diff(unsigned _txi, int _block) const;
virtual StateDiff diff(unsigned _txi, h256 _block) const;
virtual StateDiff diff(unsigned _txi, int _block) const;
/// Get a list of all active addresses.
using Interface::addresses;
std::vector<Address> addresses(int _block) const;
virtual std::vector<Address> addresses(int _block) const;
/// Get the remaining gas limit in this block.
u256 gasLimitRemaining() const { return m_postMine.gasLimitRemaining(); }
virtual u256 gasLimitRemaining() const { return m_postMine.gasLimitRemaining(); }
// [PRIVATE API - only relevant for base clients, not available in general]
@ -210,23 +216,23 @@ public:
void setTurboMining(bool _enable = true) { m_turboMining = _enable; }
/// Set the coinbase address.
void setAddress(Address _us) { m_preMine.setAddress(_us); }
virtual void setAddress(Address _us) { m_preMine.setAddress(_us); }
/// Get the coinbase address.
Address address() const { return m_preMine.address(); }
virtual Address address() const { return m_preMine.address(); }
/// Stops mining and sets the number of mining threads (0 for automatic).
void setMiningThreads(unsigned _threads = 0);
virtual void setMiningThreads(unsigned _threads = 0);
/// Get the effective number of mining threads.
unsigned miningThreads() const { ReadGuard l(x_miners); return m_miners.size(); }
virtual unsigned miningThreads() const { ReadGuard l(x_miners); return m_miners.size(); }
/// Start mining.
/// NOT thread-safe - call it & stopMining only from a single thread
void startMining() { startWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); }
virtual void startMining() { startWorking(); ReadGuard l(x_miners); for (auto& m: m_miners) m.start(); }
/// Stop mining.
/// NOT thread-safe
void stopMining() { ReadGuard l(x_miners); for (auto& m: m_miners) m.stop(); }
virtual void stopMining() { ReadGuard l(x_miners); for (auto& m: m_miners) m.stop(); }
/// Are we mining now?
bool isMining() { ReadGuard l(x_miners); return m_miners.size() && m_miners[0].isRunning(); }
virtual bool isMining() { ReadGuard l(x_miners); return m_miners.size() && m_miners[0].isRunning(); }
/// Check the progress of the mining.
MineProgress miningProgress() const;
virtual MineProgress miningProgress() const;
/// Get and clear the mining history.
std::list<MineInfo> miningHistory();

18
libethereum/CommonNet.h

@ -50,25 +50,33 @@ class TransactionQueue;
class EthereumHost;
class EthereumPeer;
enum EthereumPacket
enum
{
StatusPacket = 0x10,
StatusPacket = 0,
GetTransactionsPacket,
TransactionsPacket,
GetBlockHashesPacket,
BlockHashesPacket,
GetBlocksPacket,
BlocksPacket,
NewBlockPacket,
PacketCount
};
enum class Grabbing
enum class Asking
{
State,
Hashes,
Chain,
ChainHelper,
Blocks,
Nothing
};
enum class Syncing
{
Waiting,
Executing,
Done
};
}
}

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

220
libethereum/EthereumHost.cpp

@ -52,10 +52,10 @@ EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQu
EthereumHost::~EthereumHost()
{
for (auto const& i: peers())
i->cap<EthereumPeer>()->giveUpOnFetch();
i->cap<EthereumPeer>()->abortSync();
}
bool EthereumHost::ensureInitialised(TransactionQueue& _tq)
bool EthereumHost::ensureInitialised()
{
if (!m_latestBlockSent)
{
@ -63,155 +63,109 @@ bool EthereumHost::ensureInitialised(TransactionQueue& _tq)
m_latestBlockSent = m_chain.currentHash();
clog(NetNote) << "Initialising: latest=" << m_latestBlockSent.abridged();
for (auto const& i: _tq.transactions())
for (auto const& i: m_tq.transactions())
m_transactionsSent.insert(i.first);
return true;
}
return false;
}
void EthereumHost::noteHavePeerState(EthereumPeer* _who)
void EthereumHost::noteNeedsSyncing(EthereumPeer* _who)
{
clog(NetAllDetail) << "Have peer state.";
// TODO: FIX: BUG: Better state management!
// if already downloading hash-chain, ignore.
if (m_grabbing != Grabbing::Nothing)
if (isSyncing())
{
for (auto const& i: peers())
if (i->cap<EthereumPeer>()->m_grabbing == m_grabbing || m_grabbing == Grabbing::State)
{
clog(NetAllDetail) << "Already downloading chain. Just set to help out.";
_who->ensureGettingChain();
return;
}
m_grabbing = Grabbing::Nothing;
clog(NetAllDetail) << "Sync in progress: Just set to help out.";
if (m_syncer->m_asking == Asking::Blocks)
_who->transition(Asking::Blocks);
}
// otherwise check to see if we should be downloading...
_who->tryGrabbingHashChain();
}
void EthereumHost::updateGrabbing(Grabbing _g)
{
m_grabbing = _g;
if (_g == Grabbing::Nothing)
readyForSync();
else if (_g == Grabbing::Chain)
for (auto j: peers())
j->cap<EthereumPeer>()->ensureGettingChain();
else
// otherwise check to see if we should be downloading...
_who->attemptSync();
}
void EthereumHost::noteHaveChain(EthereumPeer* _from)
void EthereumHost::changeSyncer(EthereumPeer* _syncer)
{
auto td = _from->m_totalDifficulty;
if (_from->m_neededBlocks.empty())
m_syncer = _syncer;
if (isSyncing())
{
_from->setGrabbing(Grabbing::Nothing);
updateGrabbing(Grabbing::Nothing);
return;
if (_syncer->m_asking == Asking::Blocks)
for (auto j: peers())
if (j->cap<EthereumPeer>().get() != _syncer && j->cap<EthereumPeer>()->m_asking == Asking::Nothing)
j->cap<EthereumPeer>()->transition(Asking::Blocks);
}
clog(NetNote) << "Hash-chain COMPLETE:" << _from->m_totalDifficulty << "vs" << m_chain.details().totalDifficulty << ";" << _from->m_neededBlocks.size() << " blocks, ends" << _from->m_neededBlocks.back().abridged();
if (td < m_chain.details().totalDifficulty || (td == m_chain.details().totalDifficulty && m_chain.currentHash() == _from->m_latestHash))
else
{
clog(NetNote) << "Difficulty of hashchain not HIGHER. Ignoring.";
_from->setGrabbing(Grabbing::Nothing);
updateGrabbing(Grabbing::Nothing);
return;
}
clog(NetNote) << "Difficulty of hashchain HIGHER. Replacing fetch queue [latest now" << _from->m_latestHash.abridged() << ", was" << m_latestBlockSent.abridged() << "]";
// Looks like it's the best yet for total difficulty. Set to download.
m_man.resetToChain(_from->m_neededBlocks);
m_latestBlockSent = _from->m_latestHash;
_from->setGrabbing(Grabbing::Chain);
updateGrabbing(Grabbing::Chain);
}
void EthereumHost::readyForSync()
{
// start grabbing next hash chain if there is one.
for (auto j: peers())
{
j->cap<EthereumPeer>()->tryGrabbingHashChain();
if (j->cap<EthereumPeer>()->m_grabbing == Grabbing::Hashes)
// start grabbing next hash chain if there is one.
for (auto j: peers())
{
m_grabbing = Grabbing::Hashes;
return;
j->cap<EthereumPeer>()->attemptSync();
if (isSyncing())
return;
}
clog(NetNote) << "No more peers to sync with.";
}
clog(NetNote) << "No more peers to sync with.";
}
void EthereumHost::noteDoneBlocks(EthereumPeer* _who)
void EthereumHost::noteDoneBlocks(EthereumPeer* _who, bool _clemency)
{
if (m_man.isComplete())
{
// Done our chain-get.
clog(NetNote) << "Chain download complete.";
updateGrabbing(Grabbing::Nothing);
// 1/100th for each useful block hash.
_who->addRating(m_man.chain().size() / 100);
m_man.reset();
}
if (_who->m_grabbing == Grabbing::Chain)
else if (_who->isSyncing())
{
// Done our chain-get.
clog(NetNote) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished.";
// TODO: note that peer is BADBADBAD!
updateGrabbing(Grabbing::Nothing);
if (_clemency)
clog(NetNote) << "Chain download failed. Aborted while incomplete.";
else
{
// Done our chain-get.
clog(NetNote) << "Chain download failed. Peer with blocks didn't have them all. This peer is bad and should be punished.";
m_banned.insert(_who->session()->id()); // We know who you are!
_who->disable("Peer sent hashes but was unable to provide the blocks.");
}
m_man.reset();
}
}
bool EthereumHost::noteBlock(h256 _hash, bytesConstRef _data)
void EthereumHost::reset()
{
if (!m_chain.details(_hash))
{
lock_guard<recursive_mutex> l(m_incomingLock);
m_incomingBlocks.push_back(_data.toBytes());
return true;
}
return false;
if (m_syncer)
m_syncer->abortSync();
m_man.resetToChain(h256s());
m_latestBlockSent = h256();
m_transactionsSent.clear();
}
void EthereumHost::doWork()
{
bool netChange = ensureInitialised(m_tq);
bool netChange = ensureInitialised();
auto h = m_chain.currentHash();
maintainTransactions(m_tq, h);
maintainBlocks(m_bq, h);
maintainTransactions(h);
maintainBlocks(h);
// return netChange;
// TODO: Figure out what to do with netChange.
(void)netChange;
}
void EthereumHost::maintainTransactions(TransactionQueue& _tq, h256 _currentHash)
void EthereumHost::maintainTransactions(h256 _currentHash)
{
bool resendAll = (m_grabbing == Grabbing::Nothing && m_chain.isKnown(m_latestBlockSent) && _currentHash != m_latestBlockSent);
{
lock_guard<recursive_mutex> l(m_incomingLock);
for (auto it = m_incomingTransactions.begin(); it != m_incomingTransactions.end(); ++it)
if (_tq.import(&*it))
{}//ret = true; // just putting a transaction in the queue isn't enough to change the state - it might have an invalid nonce...
else
m_transactionsSent.insert(sha3(*it)); // if we already had the transaction, then don't bother sending it on.
m_incomingTransactions.clear();
}
bool resendAll = (!isSyncing() && m_chain.isKnown(m_latestBlockSent) && _currentHash != m_latestBlockSent);
// Send any new transactions.
for (auto const& p: peers())
{
auto ep = p->cap<EthereumPeer>();
if (ep)
if (auto ep = p->cap<EthereumPeer>())
{
bytes b;
unsigned n = 0;
for (auto const& i: _tq.transactions())
for (auto const& i: m_tq.transactions())
if ((!m_transactionsSent.count(i.first) && !ep->m_knownTransactions.count(i.first)) || ep->m_requireTransactions || resendAll)
{
b += i.second;
@ -220,75 +174,39 @@ void EthereumHost::maintainTransactions(TransactionQueue& _tq, h256 _currentHash
}
ep->clearKnownTransactions();
if (n)
if (n || ep->m_requireTransactions)
{
RLPStream ts;
EthereumPeer::prep(ts);
ts.appendList(n + 1) << TransactionsPacket;
ts.appendRaw(b, n).swapOut(b);
seal(b);
ep->send(&b);
ep->prep(ts, TransactionsPacket, n).appendRaw(b, n);
ep->sealAndSend(ts);
}
ep->m_requireTransactions = false;
}
}
}
void EthereumHost::reset()
{
m_grabbing = Grabbing::Nothing;
m_man.resetToChain(h256s());
m_incomingTransactions.clear();
m_incomingBlocks.clear();
m_latestBlockSent = h256();
m_transactionsSent.clear();
}
void EthereumHost::maintainBlocks(BlockQueue& _bq, h256 _currentHash)
void EthereumHost::maintainBlocks(h256 _currentHash)
{
// Import new blocks
{
lock_guard<recursive_mutex> l(m_incomingLock);
for (auto it = m_incomingBlocks.rbegin(); it != m_incomingBlocks.rend(); ++it)
if (_bq.import(&*it, m_chain))
{}
else{} // TODO: don't forward it.
m_incomingBlocks.clear();
}
// If we've finished our initial sync send any new blocks.
if (m_grabbing == Grabbing::Nothing && m_chain.isKnown(m_latestBlockSent) && m_chain.details(m_latestBlockSent).totalDifficulty < m_chain.details(_currentHash).totalDifficulty)
if (!isSyncing() && m_chain.isKnown(m_latestBlockSent) && m_chain.details(m_latestBlockSent).totalDifficulty < m_chain.details(_currentHash).totalDifficulty)
{
RLPStream ts;
EthereumPeer::prep(ts);
// TODO: clean up
h256s hs;
hs.push_back(_currentHash);
bytes bs;
unsigned c = 0;
for (auto h: m_chain.treeRoute(m_latestBlockSent, _currentHash, nullptr, false, true))
{
for (auto h: hs)
bs += m_chain.block(h);
++c;
}
clog(NetMessageSummary) << "Sending" << c << "new blocks (current is" << _currentHash << ", was" << m_latestBlockSent << ")";
if (c > 1000)
{
cwarn << "Gaa this would be an awful lot of new blocks. Not bothering";
return;
}
ts.appendList(1 + c).append(BlocksPacket).appendRaw(bs, c);
bytes b;
ts.swapOut(b);
seal(b);
clog(NetMessageSummary) << "Sending" << hs.size() << "new blocks (current is" << _currentHash << ", was" << m_latestBlockSent << ")";
for (auto j: peers())
{
auto p = j->cap<EthereumPeer>();
RLPStream ts;
p->prep(ts, NewBlockPacket, hs.size()).appendRaw(bs, hs.size());
Guard l(p->x_knownBlocks);
if (!p->m_knownBlocks.count(_currentHash))
p->send(&b);
p->sealAndSend(ts);
p->m_knownBlocks.clear();
}
m_latestBlockSent = _currentHash;

35
libethereum/EthereumHost.h

@ -70,26 +70,22 @@ public:
void reset();
DownloadMan const& downloadMan() const { return m_man; }
bool isSyncing() const { return m_grabbing == Grabbing::Chain; }
bool isSyncing() const { return !!m_syncer; }
bool isBanned(h512 _id) const { return !!m_banned.count(_id); }
private:
void noteHavePeerState(EthereumPeer* _who);
/// Session wants to pass us a block that we might not have.
/// @returns true if we didn't have it.
bool noteBlock(h256 _hash, bytesConstRef _data);
/// Session has finished getting the chain of hashes.
void noteHaveChain(EthereumPeer* _who);
/// Session is tell us that we may need (re-)syncing with the peer.
void noteNeedsSyncing(EthereumPeer* _who);
/// Called when the peer can no longer provide us with any needed blocks.
void noteDoneBlocks(EthereumPeer* _who);
void noteDoneBlocks(EthereumPeer* _who, bool _clemency);
/// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network.
void doWork();
/// Called by peer to add incoming transactions.
void addIncomingTransaction(bytes const& _bytes) { std::lock_guard<std::recursive_mutex> l(m_incomingLock); m_incomingTransactions.push_back(_bytes); }
void maintainTransactions(TransactionQueue& _tq, h256 _currentBlock);
void maintainBlocks(BlockQueue& _bq, h256 _currentBlock);
void maintainTransactions(h256 _currentBlock);
void maintainBlocks(h256 _currentBlock);
/// Get a bunch of needed blocks.
/// Removes them from our list of needed blocks.
@ -100,13 +96,12 @@ private:
bool isInitialised() const { return m_latestBlockSent; }
/// Initialises the network peer-state, doing the stuff that needs to be once-only. @returns true if it really was first.
bool ensureInitialised(TransactionQueue& _tq);
bool ensureInitialised();
virtual void onStarting() { startWorking(); }
virtual void onStopping() { stopWorking(); }
void readyForSync();
void updateGrabbing(Grabbing _g);
void changeSyncer(EthereumPeer* _ignore);
BlockChain const& m_chain;
TransactionQueue& m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
@ -114,16 +109,14 @@ private:
u256 m_networkId;
Grabbing m_grabbing = Grabbing::Nothing; // TODO: needs to be thread-safe & switch to just having a peer id.
mutable std::recursive_mutex m_incomingLock;
std::vector<bytes> m_incomingTransactions;
std::vector<bytes> m_incomingBlocks;
EthereumPeer* m_syncer = nullptr; // TODO: switch to weak_ptr
DownloadMan m_man;
h256 m_latestBlockSent;
h256Set m_transactionsSent;
std::set<h512> m_banned;
};
}

455
libethereum/EthereumPeer.cpp

@ -27,24 +27,34 @@
#include <libp2p/Session.h>
#include "BlockChain.h"
#include "EthereumHost.h"
#include "TransactionQueue.h"
#include "BlockQueue.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace p2p;
#if defined(clogS)
#undef clogS
#endif
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "
EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h):
Capability(_s, _h),
EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i):
Capability(_s, _h, _i),
m_sub(host()->m_man)
{
setGrabbing(Grabbing::State);
sendStatus();
transition(Asking::State);
}
EthereumPeer::~EthereumPeer()
{
giveUpOnFetch();
abortSync();
}
void EthereumPeer::abortSync()
{
if (isSyncing())
transition(Asking::Nothing, true);
}
EthereumHost* EthereumPeer::host() const
@ -52,36 +62,207 @@ EthereumHost* EthereumPeer::host() const
return static_cast<EthereumHost*>(Capability::hostCapability());
}
void EthereumPeer::sendStatus()
/*
* Possible asking/syncing states for two peers:
*/
string toString(Asking _a)
{
switch (_a)
{
case Asking::Blocks: return "Blocks";
case Asking::Hashes: return "Hashes";
case Asking::Nothing: return "Nothing";
case Asking::State: return "State";
}
return "?";
}
void EthereumPeer::transition(Asking _a, bool _force)
{
clogS(NetMessageSummary) << "Transition!" << ::toString(_a) << "from" << ::toString(m_asking) << ", " << (isSyncing() ? "syncing" : "holding") << (needsSyncing() ? "& needed" : "");
RLPStream s;
prep(s);
s.appendList(6) << StatusPacket
<< host()->protocolVersion()
<< host()->networkId()
<< host()->m_chain.details().totalDifficulty
<< host()->m_chain.currentHash()
<< host()->m_chain.genesisHash();
sealAndSend(s);
if (_a == Asking::State)
{
if (m_asking == Asking::Nothing)
{
setAsking(Asking::State, false);
prep(s, StatusPacket, 5)
<< host()->protocolVersion()
<< host()->networkId()
<< host()->m_chain.details().totalDifficulty
<< host()->m_chain.currentHash()
<< host()->m_chain.genesisHash();
sealAndSend(s);
return;
}
}
else if (_a == Asking::Hashes)
{
if (m_asking == Asking::State || m_asking == Asking::Nothing)
{
if (isSyncing())
clogS(NetWarn) << "Bad state: not asking for Hashes, yet syncing!";
m_syncingLatestHash = m_latestHash;
m_syncingTotalDifficulty = m_totalDifficulty;
resetNeedsSyncing();
setAsking(_a, true);
prep(s, GetBlockHashesPacket, 2) << m_syncingLatestHash << c_maxHashesAsk;
m_syncingNeededBlocks = h256s(1, m_syncingLatestHash);
sealAndSend(s);
return;
}
else if (m_asking == Asking::Hashes)
{
if (!isSyncing())
clogS(NetWarn) << "Bad state: asking for Hashes yet not syncing!";
setAsking(_a, true);
prep(s, GetBlockHashesPacket, 2) << m_syncingNeededBlocks.back() << c_maxHashesAsk;
sealAndSend(s);
return;
}
}
else if (_a == Asking::Blocks)
{
if (m_asking == Asking::Hashes)
{
if (!isSyncing())
clogS(NetWarn) << "Bad state: asking for Hashes yet not syncing!";
if (shouldGrabBlocks())
{
clog(NetNote) << "Difficulty of hashchain HIGHER. Grabbing" << m_syncingNeededBlocks.size() << "blocks [latest now" << m_syncingLatestHash.abridged() << ", was" << host()->m_latestBlockSent.abridged() << "]";
host()->m_man.resetToChain(m_syncingNeededBlocks);
host()->m_latestBlockSent = m_syncingLatestHash;
}
else
{
clog(NetNote) << "Difficulty of hashchain not HIGHER. Ignoring.";
m_syncingLatestHash = h256();
setAsking(Asking::Nothing, false);
return;
}
}
// run through into...
if (m_asking == Asking::Nothing || m_asking == Asking::Hashes || m_asking == Asking::Blocks)
{
// Looks like it's the best yet for total difficulty. Set to download.
setAsking(Asking::Blocks, true); // will kick off other peers to help if available.
auto blocks = m_sub.nextFetch(c_maxBlocksAsk);
if (blocks.size())
{
prep(s, GetBlocksPacket, blocks.size());
for (auto const& i: blocks)
s << i;
sealAndSend(s);
}
else
transition(Asking::Nothing);
return;
}
}
else if (_a == Asking::Nothing)
{
if (m_asking == Asking::Blocks)
{
clogS(NetNote) << "Finishing blocks fetch...";
// a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry.
if (isSyncing())
host()->noteDoneBlocks(this, _force);
// NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
m_sub.doneFetch();
setAsking(Asking::Nothing, false);
}
else if (m_asking == Asking::Hashes)
{
clogS(NetNote) << "Finishing hashes fetch...";
setAsking(Asking::Nothing, false);
}
else if (m_asking == Asking::State)
{
setAsking(Asking::Nothing, false);
// Just got the state - should check to see if we can be of help downloading the chain if any.
// Otherwise, should put ourselves up for sync.
setNeedsSyncing(m_latestHash, m_totalDifficulty);
}
// Otherwise it's fine. We don't care if it's Nothing->Nothing.
return;
}
clogS(NetWarn) << "Invalid state transition:" << ::toString(_a) << "from" << ::toString(m_asking) << ", " << (isSyncing() ? "syncing" : "holding") << (needsSyncing() ? "& needed" : "");
}
void EthereumPeer::startInitialSync()
void EthereumPeer::setAsking(Asking _a, bool _isSyncing)
{
// Grab transactions off them.
bool changedAsking = (m_asking != _a);
m_asking = _a;
if (_isSyncing != (host()->m_syncer == this) || (_isSyncing && changedAsking))
host()->changeSyncer(_isSyncing ? this : nullptr);
if (!_isSyncing)
{
RLPStream s;
prep(s).appendList(1);
s << GetTransactionsPacket;
sealAndSend(s);
m_syncingLatestHash = h256();
m_syncingTotalDifficulty = 0;
m_syncingNeededBlocks.clear();
}
host()->noteHavePeerState(this);
session()->addNote("ask", _a == Asking::Nothing ? "nothing" : _a == Asking::State ? "state" : _a == Asking::Hashes ? "hashes" : _a == Asking::Blocks ? "blocks" : "?");
session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : ""));
}
void EthereumPeer::setNeedsSyncing(h256 _latestHash, u256 _td)
{
m_latestHash = _latestHash;
m_totalDifficulty = _td;
if (m_latestHash)
host()->noteNeedsSyncing(this);
session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : ""));
}
bool EthereumPeer::isSyncing() const
{
return host()->m_syncer == this;
}
bool EthereumPeer::shouldGrabBlocks() const
{
auto td = m_syncingTotalDifficulty;
auto lh = m_syncingLatestHash;
auto ctd = host()->m_chain.details().totalDifficulty;
if (m_syncingNeededBlocks.empty())
return false;
clog(NetNote) << "Should grab blocks? " << td << "vs" << ctd << ";" << m_syncingNeededBlocks.size() << " blocks, ends" << m_syncingNeededBlocks.back().abridged();
if (td < ctd || (td == ctd && host()->m_chain.currentHash() == lh))
return false;
return true;
}
void EthereumPeer::tryGrabbingHashChain()
void EthereumPeer::attemptSync()
{
if (m_asking != Asking::Nothing)
{
clogS(NetAllDetail) << "Can't synced with this peer - outstanding asks.";
return;
}
// if already done this, then ignore.
if (m_grabbing != Grabbing::State)
if (!needsSyncing())
{
clogS(NetAllDetail) << "Already synced with this peer.";
return;
@ -95,47 +276,26 @@ void EthereumPeer::tryGrabbingHashChain()
if (td >= m_totalDifficulty)
{
clogS(NetAllDetail) << "No. Our chain is better.";
setGrabbing(Grabbing::Nothing);
return; // All good - we have the better chain.
resetNeedsSyncing();
transition(Asking::Nothing);
}
// Our chain isn't better - grab theirs.
else
{
clogS(NetAllDetail) << "Yes. Their chain is better.";
host()->updateGrabbing(Grabbing::Hashes);
setGrabbing(Grabbing::Hashes);
RLPStream s;
prep(s).appendList(3);
s << GetBlockHashesPacket << m_latestHash << c_maxHashesAsk;
m_neededBlocks = h256s(1, m_latestHash);
sealAndSend(s);
transition(Asking::Hashes);
}
}
void EthereumPeer::giveUpOnFetch()
bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
{
clogS(NetNote) << "Finishing fetch...";
// a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry.
if (m_grabbing == Grabbing::Chain || m_grabbing == Grabbing::ChainHelper)
{
host()->noteDoneBlocks(this);
setGrabbing(Grabbing::Nothing);
}
// NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
m_sub.doneFetch();
}
bool EthereumPeer::interpret(RLP const& _r)
{
switch (_r[0].toInt<unsigned>())
switch (_id)
{
case StatusPacket:
{
m_protocolVersion = _r[1].toInt<unsigned>();
m_networkId = _r[2].toInt<u256>();
// a bit dirty as we're misusing these to communicate the values to transition, but harmless.
m_totalDifficulty = _r[3].toInt<u256>();
m_latestHash = _r[4].toHash<h256>();
auto genesisHash = _r[5].toHash<h256>();
@ -148,10 +308,18 @@ bool EthereumPeer::interpret(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.");
else
startInitialSync();
{
// Grab transactions off them.
RLPStream s;
prep(s, GetTransactionsPacket);
sealAndSend(s);
transition(Asking::Nothing);
}
break;
}
case GetTransactionsPacket:
@ -163,13 +331,14 @@ bool EthereumPeer::interpret(RLP const& _r)
{
clogS(NetMessageSummary) << "Transactions (" << dec << (_r.itemCount() - 1) << "entries)";
addRating(_r.itemCount() - 1);
lock_guard<recursive_mutex> l(host()->m_incomingLock);
Guard l(x_knownTransactions);
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
host()->addIncomingTransaction(_r[i].data().toBytes());
lock_guard<mutex> l(x_knownTransactions);
m_knownTransactions.insert(sha3(_r[i].data()));
auto h = sha3(_r[i].data());
m_knownTransactions.insert(h);
if (!host()->m_tq.import(_r[i].data()))
// if we already had the transaction, then don't bother sending it on.
host()->m_transactionsSent.insert(h);
}
break;
}
@ -182,7 +351,7 @@ bool EthereumPeer::interpret(RLP const& _r)
unsigned c = min<unsigned>(host()->m_chain.number(later), limit);
RLPStream s;
prep(s).appendList(1 + c).append(BlockHashesPacket);
prep(s, BlockHashesPacket, c);
h256 p = host()->m_chain.details(later).parent;
for (unsigned i = 0; i < c && p; ++i, p = host()->m_chain.details(p).parent)
s << p;
@ -193,14 +362,14 @@ bool EthereumPeer::interpret(RLP const& _r)
{
clogS(NetMessageSummary) << "BlockHashes (" << dec << (_r.itemCount() - 1) << "entries)" << (_r.itemCount() - 1 ? "" : ": NoMoreHashes");
if (m_grabbing != Grabbing::Hashes)
if (m_asking != Asking::Hashes)
{
cwarn << "Peer giving us hashes when we didn't ask for them.";
break;
}
if (_r.itemCount() == 1)
{
host()->noteHaveChain(this);
transition(Asking::Blocks);
return true;
}
for (unsigned i = 1; i < _r.itemCount(); ++i)
@ -208,17 +377,14 @@ bool EthereumPeer::interpret(RLP const& _r)
auto h = _r[i].toHash<h256>();
if (host()->m_chain.isKnown(h))
{
host()->noteHaveChain(this);
transition(Asking::Blocks);
return true;
}
else
m_neededBlocks.push_back(h);
m_syncingNeededBlocks.push_back(h);
}
// run through - ask for more.
RLPStream s;
prep(s).appendList(3);
s << GetBlockHashesPacket << m_neededBlocks.back() << c_maxHashesAsk;
sealAndSend(s);
transition(Asking::Hashes);
break;
}
case GetBlocksPacket:
@ -237,57 +403,107 @@ bool EthereumPeer::interpret(RLP const& _r)
}
}
RLPStream s;
sealAndSend(prep(s).appendList(n + 1).append(BlocksPacket).appendRaw(rlp, n));
prep(s, BlocksPacket, n).appendRaw(rlp, n);
sealAndSend(s);
break;
}
case BlocksPacket:
{
clogS(NetMessageSummary) << "Blocks (" << dec << (_r.itemCount() - 1) << "entries)" << (_r.itemCount() - 1 ? "" : ": NoMoreBlocks");
if (m_asking != Asking::Blocks)
clogS(NetWarn) << "Unexpected Blocks received!";
if (_r.itemCount() == 1)
{
// Couldn't get any from last batch - probably got to this peer's latest block - just give up.
if (m_grabbing == Grabbing::Chain || m_grabbing == Grabbing::ChainHelper)
giveUpOnFetch();
// Got to this peer's latest block - just give up.
transition(Asking::Nothing);
break;
}
unsigned used = 0;
unsigned success = 0;
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 (host()->noteBlock(h, _r[i].data()))
used++;
Guard l(x_knownBlocks);
m_knownBlocks.insert(h);
}
addRating(used);
unsigned knownParents = 0;
unsigned unknownParents = 0;
if (g_logVerbosity >= NetMessageSummary::verbosity)
{
unsigned ic = _r.itemCount();
for (unsigned i = 1; i < ic; ++i)
if (m_sub.noteBlock(h))
{
auto h = BlockInfo::headerHash(_r[i].data());
BlockInfo bi(_r[i].data());
Guard l(x_knownBlocks);
if (!host()->m_chain.details(bi.parentHash) && !m_knownBlocks.count(bi.parentHash))
{
unknownParents++;
clogS(NetAllDetail) << "Unknown parent" << bi.parentHash.abridged() << "of block" << h.abridged();
}
else
addRating(10);
switch (host()->m_bq.import(_r[i].data(), host()->m_chain))
{
knownParents++;
clogS(NetAllDetail) << "Known parent" << bi.parentHash.abridged() << "of block" << h.abridged();
case ImportResult::Success:
success++;
break;
case ImportResult::Malformed:
disable("Malformed block received.");
return true;
case ImportResult::FutureTime:
future++;
break;
case ImportResult::AlreadyInChain:
case ImportResult::AlreadyKnown:
got++;
break;
case ImportResult::UnknownParent:
unknown++;
break;
}
}
else
{
addRating(0); // -1?
repeated++;
}
}
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);
break;
}
case NewBlockPacket:
{
auto h = BlockInfo::headerHash(_r[1].data());
clogS(NetMessageSummary) << "NewBlock: " << h.abridged();
if (_r.itemCount() != 3)
disable("NewBlock without 2 data fields.");
else
{
switch (host()->m_bq.import(_r[1].data(), host()->m_chain))
{
case ImportResult::Success:
addRating(100);
break;
case ImportResult::FutureTime:
//TODO: Rating dependent on how far in future it is.
break;
case ImportResult::Malformed:
disable("Malformed block received.");
break;
case ImportResult::AlreadyInChain:
case ImportResult::AlreadyKnown:
break;
case ImportResult::UnknownParent:
clogS(NetMessageSummary) << "Received block with no known parent. Resyncing...";
setNeedsSyncing(h, _r[2].toInt<u256>());
break;
}
Guard l(x_knownBlocks);
m_knownBlocks.insert(h);
}
clogS(NetMessageSummary) << dec << knownParents << "known parents," << unknownParents << "unknown," << used << "used.";
if (m_grabbing == Grabbing::Chain || m_grabbing == Grabbing::ChainHelper)
continueGettingChain();
break;
}
default:
@ -295,42 +511,3 @@ bool EthereumPeer::interpret(RLP const& _r)
}
return true;
}
void EthereumPeer::ensureGettingChain()
{
if (m_grabbing == Grabbing::ChainHelper)
return; // Already asked & waiting for some.
// Switch to ChainHelper otherwise, unless we're already the Chain grabber.
if (m_grabbing != Grabbing::Chain)
setGrabbing(Grabbing::ChainHelper);
continueGettingChain();
}
void EthereumPeer::continueGettingChain()
{
// If we're getting the hashes already, then we shouldn't be asking for the chain.
if (m_grabbing == Grabbing::Hashes)
return;
auto blocks = m_sub.nextFetch(c_maxBlocksAsk);
if (blocks.size())
{
RLPStream s;
prep(s);
s.appendList(blocks.size() + 1) << GetBlocksPacket;
for (auto const& i: blocks)
s << i;
sealAndSend(s);
}
else
giveUpOnFetch();
}
void EthereumPeer::setGrabbing(Grabbing _g)
{
m_grabbing = _g;
session()->addNote("grab", _g == Grabbing::Nothing ? "nothing" : _g == Grabbing::State ? "state" : _g == Grabbing::Hashes ? "hashes" : _g == Grabbing::Chain ? "chain" : _g == Grabbing::ChainHelper ? "chainhelper" : "?");
}

82
libethereum/EthereumPeer.h

@ -42,54 +42,98 @@ namespace eth
/**
* @brief The EthereumPeer class
* @todo Document fully.
* @todo make state transitions thread-safe.
*/
class EthereumPeer: public p2p::Capability
{
friend class EthereumHost;
public:
EthereumPeer(p2p::Session* _s, p2p::HostCapabilityFace* _h);
/// Basic constructor.
EthereumPeer(p2p::Session* _s, p2p::HostCapabilityFace* _h, unsigned _i);
/// Basic destructor.
virtual ~EthereumPeer();
/// What is our name?
static std::string name() { return "eth"; }
/// What is our version?
static u256 version() { return c_protocolVersion; }
/// How many message types do we have?
static unsigned messageCount() { return PacketCount; }
/// What is the ethereum subprotocol host object.
EthereumHost* host() const;
private:
virtual bool interpret(RLP const& _r);
using p2p::Capability::sealAndSend;
void sendStatus();
void startInitialSync();
/// Interpret an incoming message.
virtual bool interpret(unsigned _id, RLP const& _r);
void tryGrabbingHashChain();
/// Transition state in a particular direction.
void transition(Asking _wantState, bool _force = false);
/// Ensure that we are waiting for a bunch of blocks from our peer.
void ensureGettingChain();
/// Ensure that we are waiting for a bunch of blocks from our peer.
void continueGettingChain();
/// Attempt to begin syncing with this peer; first check the peer has a more difficlult chain to download, then start asking for hashes, then move to blocks.
void attemptSync();
void giveUpOnFetch();
/// Abort the sync operation.
void abortSync();
/// Clear all known transactions.
void clearKnownTransactions() { std::lock_guard<std::mutex> l(x_knownTransactions); m_knownTransactions.clear(); }
void setGrabbing(Grabbing _g);
/// Update our asking state.
void setAsking(Asking _g, bool _isSyncing);
/// Update our syncing requirements state.
void setNeedsSyncing(h256 _latestHash, u256 _td);
void resetNeedsSyncing() { setNeedsSyncing(h256(), 0); }
/// Do we presently need syncing with this peer?
bool needsSyncing() const { return !!m_latestHash; }
/// Are we presently syncing with this peer?
bool isSyncing() const;
/// Check whether the session should bother grabbing the peer's blocks.
bool shouldGrabBlocks() const;
/// Peer's protocol version.
unsigned m_protocolVersion;
/// Peer's network id.
u256 m_networkId;
Grabbing m_grabbing;
/// What, if anything, we last asked the other peer for.
Asking m_asking = Asking::Nothing;
h256 m_latestHash; ///< Peer's latest block's hash.
/// Whether this peer is in the process of syncing or not. Only one peer can be syncing at once.
bool m_isSyncing = false;
/// These are determined through either a Status message or from NewBlock.
h256 m_latestHash; ///< Peer's latest block's hash that we know about or default null value if no need to sync.
u256 m_totalDifficulty; ///< Peer's latest block's total difficulty.
h256s m_neededBlocks; ///< The blocks that we should download from this peer.
/// Once a sync is started on this peer, they are cleared and moved into m_syncing*.
/// This is built as we ask for hashes. Once no more hashes are given, we present this to the
/// host who initialises the DownloadMan and m_sub becomes active for us to begin asking for blocks.
h256s m_syncingNeededBlocks; ///< The blocks that we should download from this peer.
h256 m_syncingLatestHash; ///< Peer's latest block's hash, as of the current sync.
u256 m_syncingTotalDifficulty; ///< Peer's latest block's total difficulty, as of the current sync.
/// Once we're asking for blocks, this becomes in use.
DownloadSub m_sub;
/// Have we received a GetTransactions packet that we haven't yet answered?
bool m_requireTransactions;
Mutex x_knownBlocks;
std::set<h256> m_knownBlocks;
std::set<h256> m_knownTransactions;
std::mutex x_knownTransactions;
h256Set m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them).
Mutex x_knownTransactions;
h256Set m_knownTransactions; ///< Transactions that the peer already knows of.
DownloadSub m_sub;
};
}

6
libethereum/Executive.cpp

@ -20,6 +20,7 @@
*/
#include <boost/timer.hpp>
#include <libdevcore/CommonIO.h>
#include <libevm/VM.h>
#include "Executive.h"
#include "State.h"
@ -217,15 +218,12 @@ u256 Executive::gas() const
return m_vm ? m_vm->gas() : m_endGas;
}
void Executive::finalize(OnOpFunc const& _onOp)
void Executive::finalize(OnOpFunc const&)
{
if (m_t.isCreation() && m_newAddress && m_out.size())
// non-reverted creation - put code in place.
m_s.m_cache[m_newAddress].setCode(m_out);
if (m_ext)
m_endGas += m_ext->doPosts(_onOp);
// cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")";
m_s.addBalance(m_sender, m_endGas * m_t.gasPrice);

18
libethereum/ExtVM.h

@ -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, &posts, 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, level + 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, &posts, 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, level + 1);
if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back();
return ret;
@ -98,20 +98,6 @@ public:
/// @TODO check call site for the parent manifest being discarded.
void revert() { if (m_ms) *m_ms = Manifest(); m_s.m_cache = m_origCache; }
/// Execute any posts we have left.
u256 doPosts(OnOpFunc const& _onOp = OnOpFunc())
{
u256 ret;
while (posts.size())
{
Post& p = posts.front();
call(p.to, p.value, &p.data, &p.gas, bytesRef(), _onOp, p.from);
ret += p.gas;
posts.pop_front();
}
return ret;
}
State& state() const { return m_s; }
/// @note not a part of the main API; just for use by tracing/debug stuff.

9
libethereum/Interface.h

@ -29,6 +29,7 @@
#include "MessageFilter.h"
#include "Transaction.h"
#include "AccountDiff.h"
#include "BlockDetails.h"
#include "Miner.h"
namespace dev
@ -95,7 +96,13 @@ public:
virtual bool peekWatch(unsigned _watchId) const = 0;
virtual bool checkWatch(unsigned _watchId) = 0;
// TODO: Block query API.
// [BLOCK QUERY API]
virtual h256 hashFromNumber(unsigned _number) const = 0;
virtual BlockInfo blockInfo(h256 _hash) const = 0;
virtual BlockDetails blockDetails(h256 _hash) const = 0;
virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0;
virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0;
// [EXTRA API]:

8
libethereum/Miner.cpp

@ -21,6 +21,8 @@
*/
#include "Miner.h"
#include <libdevcore/CommonIO.h>
#include "State.h"
using namespace std;
using namespace dev;
@ -32,6 +34,12 @@ Miner::Miner(MinerHost* _host, unsigned _id):
{
}
void Miner::setup(MinerHost* _host, unsigned _id)
{
m_host = _host;
setName("miner-" + toString(_id));
}
void Miner::doWork()
{
// Do some mining.

2
libethereum/Miner.h

@ -94,7 +94,7 @@ public:
~Miner() { stop(); }
/// Setup its basics.
void setup(MinerHost* _host, unsigned _id = 0) { m_host = _host; setName("miner-" + toString(_id)); }
void setup(MinerHost* _host, unsigned _id = 0);
/// Start mining.
void start() { startWorking(); }

68
libethereum/State.cpp

@ -25,6 +25,7 @@
#include <time.h>
#include <random>
#include <secp256k1/secp256k1.h>
#include <libdevcore/CommonIO.h>
#include <libevmface/Instruction.h>
#include <libethcore/Exceptions.h>
#include <libethcore/Dagger.h>
@ -40,6 +41,50 @@ using namespace dev::eth;
static const u256 c_blockReward = 1500 * finney;
void ecrecoverCode(bytesConstRef _in, bytesRef _out)
{
struct inType
{
h256 hash;
h256 v;
h256 r;
h256 s;
} in;
h256 ret;
memcpy(&in, _in.data(), min(_in.size(), sizeof(in)));
byte pubkey[65];
int pubkeylen = 65;
secp256k1_start();
if (secp256k1_ecdsa_recover_compact(in.hash.data(), 32, in.r.data(), pubkey, &pubkeylen, 0, (int)(u256)in.v - 27))
ret = dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64));
memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret)));
}
void sha256Code(bytesConstRef _in, bytesRef _out)
{
h256 ret;
sha256(_in, bytesRef(ret.data(), 32));
memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret)));
}
void ripemd160Code(bytesConstRef _in, bytesRef _out)
{
h256 ret;
ripemd160(_in, bytesRef(ret.data(), 32));
memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret)));
}
const std::map<unsigned, PrecompiledAddress> State::c_precompiled =
{
{ 1, { 500, ecrecoverCode }},
{ 2, { 100, sha256Code }},
{ 3, { 100, ripemd160Code }}
};
OverlayDB State::openDB(std::string _path, bool _killExisting)
{
if (_path.empty())
@ -1060,7 +1105,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
return e.gasUsed();
}
bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, std::set<Address>* o_suicides, PostList* o_posts, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, std::set<Address>* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
{
if (!_originAddress)
_originAddress = _senderAddress;
@ -1076,7 +1121,16 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
o_ms->input = _data.toBytes();
}
if (addressHasCode(_codeAddress))
auto it = !(_codeAddress & ~h160(0xffffffff)) ? c_precompiled.find((unsigned)(u160)_codeAddress) : c_precompiled.end();
if (it != c_precompiled.end())
{
if (*_gas >= it->second.gas)
{
*_gas -= it->second.gas;
it->second.exec(_data, _out);
}
}
else if (addressHasCode(_codeAddress))
{
VM vm(*_gas);
ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), o_ms, _level);
@ -1089,9 +1143,6 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
if (o_suicides)
for (auto i: evm.suicides)
o_suicides->insert(i);
if (o_posts)
for (auto i: evm.posts)
o_posts->push_back(i);
if (o_ms)
o_ms->output = out.toBytes();
}
@ -1124,7 +1175,7 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
return true;
}
h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set<Address>* o_suicides, PostList* o_posts, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
h160 State::create(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;
@ -1138,8 +1189,6 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
}
Address newAddress = right160(sha3(rlpList(_sender, transactionsFrom(_sender) - 1)));
while (addressInUse(newAddress))
newAddress = (u160)newAddress + 1;
// Set up new account...
m_cache[newAddress] = AddressState(0, balance(newAddress) + _endowment, h256(), h256());
@ -1158,9 +1207,6 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
if (o_suicides)
for (auto i: evm.suicides)
o_suicides->insert(i);
if (o_posts)
for (auto i: evm.posts)
o_posts->push_back(i);
}
catch (OutOfGas const& /*_e*/)
{

12
libethereum/State.h

@ -69,6 +69,12 @@ struct TransactionReceipt
Manifest changes;
};
struct PrecompiledAddress
{
unsigned gas;
std::function<void(bytesConstRef, bytesRef)> exec;
};
/**
* @brief Model of the current state of the ledger.
* Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block).
@ -277,12 +283,12 @@ private:
// We assume all instrinsic fees are paid up before this point.
/// Execute a contract-creation transaction.
h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, PostList* o_posts = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
/// Execute a call.
/// @a _gas points to the amount of gas to use for the call, and will lower it accordingly.
/// @returns false if the call ran out of gas before completion. true otherwise.
bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, PostList* o_posts = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent();
@ -321,6 +327,8 @@ private:
static std::string c_defaultPath;
static const std::map<unsigned, PrecompiledAddress> c_precompiled;
friend std::ostream& operator<<(std::ostream& _out, State const& _s);
};

11
libevm/ExtVMFace.h

@ -21,6 +21,8 @@
#pragma once
#include <list>
#include <functional>
#include <libdevcore/Common.h>
#include <libevmface/Instruction.h>
#include <libethcore/CommonEth.h>
@ -40,8 +42,6 @@ struct Post
u256 gas;
};
using PostList = std::list<Post>;
using OnOpFunc = std::function<void(uint64_t /*steps*/, Instruction /*instr*/, bigint /*newMemSize*/, bigint /*gasCost*/, void/*VM*/*, void/*ExtVM*/ const*)>;
/**
@ -86,15 +86,9 @@ public:
/// Make a new message call.
bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; }
/// Post a new message call.
void post(Address _to, u256 _value, bytesConstRef _data, u256 _gas) { posts.push_back(Post({myAddress, _to, _value, _data.toBytes(), _gas})); }
/// Revert any changes made (by any of the other calls).
void revert() {}
/// Execute any posts that may exist, including those that are incurred as a result of earlier posts.
void doPosts() {}
Address myAddress; ///< Address associated with executing code (a contract, or contract-to-be).
Address caller; ///< Address which sent the message (either equal to origin or a contract).
Address origin; ///< Original transactor.
@ -105,7 +99,6 @@ public:
BlockInfo previousBlock; ///< The previous block's information.
BlockInfo currentBlock; ///< The current block's information.
std::set<Address> suicides; ///< Any accounts that have suicided.
std::list<Post> posts; ///< Any posts that have been made.
};
}

42
libevm/VM.h

@ -39,6 +39,7 @@ struct VMException: virtual Exception {};
struct StepsDone: virtual VMException {};
struct BreakPointHit: virtual VMException {};
struct BadInstruction: virtual VMException {};
struct BadJumpDestination: virtual VMException {};
struct OutOfGas: virtual VMException {};
class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; };
@ -171,18 +172,12 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
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]));
break;
case Instruction::CALLSTATELESS:
case Instruction::CALLCODE:
require(7);
runGas = 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]));
break;
case Instruction::POST:
require(5);
runGas = c_callGas + m_stack[m_stack.size() - 1];
newTempSize = memNeed(m_stack[m_stack.size() - 4], m_stack[m_stack.size() - 5]);
break;
case Instruction::CREATE:
{
require(3);
@ -572,12 +567,18 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::JUMP:
require(1);
nextPC = m_stack.back();
if ((Instruction)_ext.getCode(nextPC) != Instruction::JUMPDEST)
BOOST_THROW_EXCEPTION(BadJumpDestination());
m_stack.pop_back();
break;
case Instruction::JUMPI:
require(2);
if (m_stack[m_stack.size() - 2])
{
nextPC = m_stack.back();
if ((Instruction)_ext.getCode(nextPC) != Instruction::JUMPDEST)
BOOST_THROW_EXCEPTION(BadJumpDestination());
}
m_stack.pop_back();
m_stack.pop_back();
break;
@ -590,6 +591,8 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::GAS:
m_stack.push_back(m_gas);
break;
case Instruction::JUMPDEST:
break;
case Instruction::CREATE:
{
require(3);
@ -611,7 +614,7 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;
}
case Instruction::CALL:
case Instruction::CALLSTATELESS:
case Instruction::CALLCODE:
{
require(7);
@ -662,29 +665,6 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
}
case Instruction::STOP:
return bytesConstRef();
case Instruction::POST:
{
require(5);
u256 gas = m_stack.back();
m_stack.pop_back();
u160 receiveAddress = asAddress(m_stack.back());
m_stack.pop_back();
u256 value = m_stack.back();
m_stack.pop_back();
unsigned inOff = (unsigned)m_stack.back();
m_stack.pop_back();
unsigned inSize = (unsigned)m_stack.back();
m_stack.pop_back();
if (_ext.balance(_ext.myAddress) >= value)
{
_ext.subBalance(value);
_ext.post(receiveAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), gas);
}
break;
}
default:
BOOST_THROW_EXCEPTION(BadInstruction());
}

9
libevmface/Instruction.cpp

@ -22,6 +22,7 @@
#include "Instruction.h"
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h>
using namespace std;
using namespace dev;
@ -82,6 +83,7 @@ const std::map<std::string, Instruction> dev::eth::c_instructions =
{ "PC", Instruction::PC },
{ "MSIZE", Instruction::MSIZE },
{ "GAS", Instruction::GAS },
{ "JUMPDEST", Instruction::JUMPDEST },
{ "PUSH1", Instruction::PUSH1 },
{ "PUSH2", Instruction::PUSH2 },
{ "PUSH3", Instruction::PUSH3 },
@ -148,9 +150,8 @@ const std::map<std::string, Instruction> dev::eth::c_instructions =
{ "SWAP16", Instruction::SWAP16 },
{ "CREATE", Instruction::CREATE },
{ "CALL", Instruction::CALL },
{ "CALLSTATELESS", Instruction::CALLSTATELESS },
{ "CALLCODE", Instruction::CALLCODE },
{ "RETURN", Instruction::RETURN },
{ "POST", Instruction::POST },
{ "SUICIDE", Instruction::SUICIDE }
};
@ -209,6 +210,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::PC, { "PC", 0, 0, 1 } },
{ Instruction::MSIZE, { "MSIZE", 0, 0, 1 } },
{ Instruction::GAS, { "GAS", 0, 0, 1 } },
{ Instruction::JUMPDEST, { "JUMPDEST", 0, 1, 0 } },
{ Instruction::PUSH1, { "PUSH1", 1, 0, 1 } },
{ Instruction::PUSH2, { "PUSH2", 2, 0, 1 } },
{ Instruction::PUSH3, { "PUSH3", 3, 0, 1 } },
@ -275,9 +277,8 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::SWAP16, { "SWAP16", 0, 17, 17 } },
{ Instruction::CREATE, { "CREATE", 0, 3, 1 } },
{ Instruction::CALL, { "CALL", 0, 7, 1 } },
{ Instruction::CALLSTATELESS, { "CALLSTATELESS",0, 7, 1 } },
{ Instruction::CALLCODE, { "CALLCODE", 0, 7, 1 } },
{ Instruction::RETURN, { "RETURN", 0, 2, 0 } },
{ Instruction::POST, { "POST", 0, 5, 0 } },
{ Instruction::SUICIDE, { "SUICIDE", 0, 1, 0} }
};

4
libevmface/Instruction.h

@ -92,6 +92,7 @@ enum class Instruction: uint8_t
PC, ///< get the program counter
MSIZE, ///< get the size of active memory
GAS, ///< get the amount of available gas
JUMPDEST, ///< set a potential jump destination
PUSH1 = 0x60, ///< place 1 byte item on stack
PUSH2, ///< place 2 byte item on stack
@ -163,8 +164,7 @@ enum class Instruction: uint8_t
CREATE = 0xf0, ///< create a new account with associated code
CALL, ///< message-call into an account
RETURN, ///< halt execution returning output data
POST, ///< asynchronous call without output (adds a message to the post queue)
CALLSTATELESS,
CALLCODE,
SUICIDE = 0xff ///< halt execution and register account for later deletion
};

5
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() << "]";
@ -172,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;
@ -414,6 +414,7 @@ bytes Assembly::assemble() const
}
case Tag:
tagPos[(unsigned)i.m_data] = ret.size();
ret.push_back((byte)Instruction::JUMPDEST);
break;
default:;
}

1
liblll/CodeFragment.cpp

@ -24,6 +24,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/spirit/include/support_utree.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/CommonIO.h>
#include <libevmface/Instruction.h>
#include "CompilerState.h"
#include "Parser.h"

17
libp2p/Capability.cpp

@ -21,20 +21,31 @@
#include "Capability.h"
#include <libdevcore/Log.h>
#include "Session.h"
using namespace std;
using namespace dev;
using namespace dev::p2p;
#if defined(clogS)
#undef clogS
#endif
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "
Capability::Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_host(_h), m_idOffset(_idOffset)
{
clogS(NetConnect) << "New session for capability" << m_host->name() << "; idOffset:" << m_idOffset;
}
void Capability::disable(std::string const& _problem)
{
clog(NetConnect) << "Disabling capability '" << m_host->name() << "'. Reason:" << _problem;
clogS(NetConnect) << "Disabling capability '" << m_host->name() << "'. Reason:" << _problem;
m_enabled = false;
}
RLPStream& Capability::prep(RLPStream& _s)
RLPStream& Capability::prep(RLPStream& _s, unsigned _id, unsigned _args)
{
return Session::prep(_s);
return Session::prep(_s).appendList(_args + 1).append(_id + m_idOffset);
}
void Capability::sealAndSend(RLPStream& _s)

15
libp2p/Capability.h

@ -34,21 +34,23 @@ class Capability
friend class Session;
public:
Capability(Session* _s, HostCapabilityFace* _h): m_session(_s), m_host(_h) {}
Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset);
virtual ~Capability() {}
/// Must return the capability name.
static std::string name() { return ""; }
// Implement these in the derived class.
/* static std::string name() { return ""; }
static u256 version() { return 0; }
static unsigned messageCount() { return 0; }
*/
Session* session() const { return m_session; }
HostCapabilityFace* hostCapability() const { return m_host; }
protected:
virtual bool interpret(RLP const&) = 0;
virtual bool interpret(unsigned _id, RLP const&) = 0;
void disable(std::string const& _problem);
static RLPStream& prep(RLPStream& _s);
RLPStream& prep(RLPStream& _s, unsigned _id, unsigned _args = 0);
void sealAndSend(RLPStream& _s);
void sendDestroy(bytes& _msg);
void send(bytesConstRef _msg);
@ -59,6 +61,7 @@ private:
Session* m_session;
HostCapabilityFace* m_host;
bool m_enabled = true;
unsigned m_idOffset;
};
}

13
libp2p/Common.cpp

@ -27,8 +27,7 @@ using namespace dev::p2p;
// Helper function to determine if an address falls within one of the reserved ranges
// For V4:
// Class A "10.*", Class B "172.[16->31].*", Class C "192.168.*"
// Not implemented yet for V6
bool p2p::isPrivateAddress(bi::address _addressToCheck)
bool p2p::isPrivateAddress(bi::address const& _addressToCheck)
{
if (_addressToCheck.is_v4())
{
@ -41,6 +40,16 @@ bool p2p::isPrivateAddress(bi::address _addressToCheck)
if (bytesToCheck[0] == 192 && bytesToCheck[1] == 168)
return true;
}
else if (_addressToCheck.is_v6())
{
bi::address_v6 v6Address = _addressToCheck.to_v6();
bi::address_v6::bytes_type bytesToCheck = v6Address.to_bytes();
if (bytesToCheck[0] == 0xfd && bytesToCheck[1] == 0)
return true;
if (!bytesToCheck[0] && !bytesToCheck[1] && !bytesToCheck[2] && !bytesToCheck[3] && !bytesToCheck[4] && !bytesToCheck[5] && !bytesToCheck[6] && !bytesToCheck[7]
&& !bytesToCheck[8] && !bytesToCheck[9] && !bytesToCheck[10] && !bytesToCheck[11] && !bytesToCheck[12] && !bytesToCheck[13] && !bytesToCheck[14] && (bytesToCheck[15] == 0 || bytesToCheck[15] == 1))
return true;
}
return false;
}

10
libp2p/Common.h

@ -24,6 +24,8 @@
#pragma once
#include <string>
#include <set>
#include <vector>
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <chrono>
@ -42,7 +44,7 @@ class RLPStream;
namespace p2p
{
bool isPrivateAddress(bi::address _addressToCheck);
bool isPrivateAddress(bi::address const& _addressToCheck);
class UPnP;
class Capability;
@ -88,13 +90,17 @@ enum DisconnectReason
/// @returns the string form of the given disconnection reason.
std::string reasonOf(DisconnectReason _r);
typedef std::pair<std::string, u256> CapDesc;
typedef std::set<CapDesc> CapDescSet;
typedef std::vector<CapDesc> CapDescs;
struct PeerInfo
{
std::string clientVersion;
std::string host;
unsigned short port;
std::chrono::steady_clock::duration lastPing;
std::set<std::string> caps;
std::set<CapDesc> caps;
unsigned socket;
std::map<std::string, std::string> notes;
};

14
libp2p/Host.cpp

@ -36,8 +36,10 @@
#include <thread>
#include <boost/algorithm/string.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libethcore/Exceptions.h>
#include "Session.h"
#include "Common.h"
#include "Capability.h"
#include "UPnP.h"
using namespace std;
@ -142,18 +144,22 @@ void Host::stop()
unsigned Host::protocolVersion() const
{
return 0;
return 1;
}
void Host::registerPeer(std::shared_ptr<Session> _s, vector<string> const& _caps)
void Host::registerPeer(std::shared_ptr<Session> _s, CapDescs const& _caps)
{
{
Guard l(x_peers);
m_peers[_s->m_id] = _s;
}
unsigned o = (unsigned)UserPacket;
for (auto const& i: _caps)
if (haveCapability(i))
_s->m_capabilities[i] = shared_ptr<Capability>(m_capabilities[i]->newPeerCapability(_s.get()));
{
_s->m_capabilities[i] = shared_ptr<Capability>(m_capabilities[i]->newPeerCapability(_s.get(), o));
o += m_capabilities[i]->messageCount();
}
}
void Host::disconnectPeers()
@ -457,7 +463,7 @@ void Host::growPeers()
{
RLPStream s;
bytes b;
(Session::prep(s).appendList(1) << GetPeersPacket).swapOut(b);
Session::prep(s, GetPeersPacket).swapOut(b);
seal(b);
for (auto const& i: m_peers)
if (auto p = i.second.lock())

13
libp2p/Host.h

@ -31,6 +31,7 @@
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include "HostCapability.h"
#include "Common.h"
namespace ba = boost::asio;
namespace bi = boost::asio::ip;
@ -75,11 +76,11 @@ public:
unsigned protocolVersion() const;
/// Register a peer-capability; all new peer connections will have this capability.
template <class T> std::shared_ptr<T> registerCapability(T* _t) { _t->m_host = this; auto ret = std::shared_ptr<T>(_t); m_capabilities[T::staticName()] = ret; return ret; }
template <class T> std::shared_ptr<T> registerCapability(T* _t) { _t->m_host = this; auto ret = std::shared_ptr<T>(_t); m_capabilities[std::make_pair(T::staticName(), T::staticVersion())] = ret; return ret; }
bool haveCapability(std::string const& _name) const { return m_capabilities.count(_name) != 0; }
std::vector<std::string> caps() const { std::vector<std::string> ret; for (auto const& i: m_capabilities) ret.push_back(i.first); return ret; }
template <class T> std::shared_ptr<T> cap() const { try { return std::static_pointer_cast<T>(m_capabilities.at(T::staticName())); } catch (...) { return nullptr; } }
bool haveCapability(CapDesc const& _name) const { return m_capabilities.count(_name) != 0; }
CapDescs caps() const { CapDescs ret; for (auto const& i: m_capabilities) ret.push_back(i.first); return ret; }
template <class T> std::shared_ptr<T> cap() const { try { return std::static_pointer_cast<T>(m_capabilities.at(std::make_pair(T::staticName(), T::staticVersion()))); } catch (...) { return nullptr; } }
/// Connect to a peer explicitly.
static std::string pocHost();
@ -118,7 +119,7 @@ public:
h512 id() const { return m_id; }
void registerPeer(std::shared_ptr<Session> _s, std::vector<std::string> const& _caps);
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.
@ -166,7 +167,7 @@ private:
std::vector<bi::address_v4> m_addresses;
std::vector<bi::address_v4> m_peerAddresses;
std::map<std::string, std::shared_ptr<HostCapabilityFace>> m_capabilities;
std::map<CapDesc, std::shared_ptr<HostCapabilityFace>> m_capabilities;
bool m_accepting = false;
};

2
libp2p/HostCapability.cpp

@ -38,7 +38,7 @@ std::vector<std::shared_ptr<Session> > HostCapabilityFace::peers() const
std::vector<std::shared_ptr<Session> > ret;
for (auto const& i: m_host->m_peers)
if (std::shared_ptr<Session> p = i.second.lock())
if (p->m_capabilities.count(name()))
if (p->m_capabilities.count(capDesc()))
ret.push_back(p);
return ret;
}

12
libp2p/HostCapability.h

@ -36,6 +36,7 @@ class HostCapabilityFace
friend class Host;
template <class T> friend class HostCapability;
friend class Capability;
friend class Session;
public:
HostCapabilityFace() {}
@ -47,7 +48,10 @@ public:
protected:
virtual std::string name() const = 0;
virtual Capability* newPeerCapability(Session* _s) = 0;
virtual u256 version() const = 0;
CapDesc capDesc() const { return std::make_pair(name(), version()); }
virtual unsigned messageCount() const = 0;
virtual Capability* newPeerCapability(Session* _s, unsigned _idOffset) = 0;
virtual void onStarting() {}
virtual void onStopping() {}
@ -66,10 +70,14 @@ public:
virtual ~HostCapability() {}
static std::string staticName() { return PeerCap::name(); }
static u256 staticVersion() { return PeerCap::version(); }
static unsigned staticMessageCount() { return PeerCap::messageCount(); }
protected:
virtual std::string name() const { return PeerCap::name(); }
virtual Capability* newPeerCapability(Session* _s) { return new PeerCap(_s, this); }
virtual u256 version() const { return PeerCap::version(); }
virtual unsigned messageCount() const { return PeerCap::messageCount(); }
virtual Capability* newPeerCapability(Session* _s, unsigned _idOffset) { return new PeerCap(_s, this, _idOffset); }
};
}

75
libp2p/Session.cpp

@ -23,6 +23,7 @@
#include <chrono>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libethcore/Exceptions.h>
#include "Host.h"
#include "Capability.h"
@ -30,6 +31,9 @@ using namespace std;
using namespace dev;
using namespace dev::p2p;
#if defined(clogS)
#undef clogS
#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):
@ -40,7 +44,7 @@ Session::Session(Host* _s, bi::tcp::socket _socket, bi::address _peerAddress, un
{
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), set<string>(), 0, map<string, string>()});
m_info = PeerInfo({"?", _peerAddress.to_string(), m_listenPort, std::chrono::steady_clock::duration(0), CapDescSet(), 0, map<string, string>()});
}
Session::~Session()
@ -72,22 +76,28 @@ bi::tcp::endpoint Session::endpoint() const
bool Session::interpret(RLP const& _r)
{
clogS(NetRight) << _r;
switch (_r[0].toInt<unsigned>())
switch ((PacketType)_r[0].toInt<unsigned>())
{
case HelloPacket:
{
m_protocolVersion = _r[1].toInt<unsigned>();
auto clientVersion = _r[2].toString();
auto caps = _r[3].toVector<string>();
auto caps = _r[3].toVector<CapDesc>();
m_listenPort = _r[4].toInt<unsigned short>();
m_id = _r[5].toHash<h512>();
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << m_id.abridged() << showbase << hex << caps << dec << m_listenPort;
// clang error (previously: ... << hex << caps ...)
// "'operator<<' should be declared prior to the call site or in an associated namespace of one of its arguments"
stringstream capslog;
for (auto cap: caps)
capslog << "(" << hex << cap.first << "," << hex << cap.second << ")";
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << m_id.abridged() << showbase << capslog.str() << dec << m_listenPort;
if (m_server->havePeer(m_id))
{
// Already connected.
cwarn << "Already have peer id" << m_id.abridged();// << "at" << l->endpoint() << "rather than" << endpoint();
clogS(NetWarn) << "Already have peer id" << m_id.abridged();// << "at" << l->endpoint() << "rather than" << endpoint();
disconnect(DuplicatePeer);
return false;
}
@ -102,7 +112,7 @@ bool Session::interpret(RLP const& _r)
return false;
}
try
{ m_info = PeerInfo({clientVersion, m_socket.remote_endpoint().address().to_string(), m_listenPort, std::chrono::steady_clock::duration(), _r[3].toSet<string>(), (unsigned)m_socket.native_handle(), map<string, string>() }); }
{ 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 (...)
{
disconnect(BadProtocol);
@ -130,7 +140,7 @@ bool Session::interpret(RLP const& _r)
{
clogS(NetTriviaSummary) << "Ping";
RLPStream s;
sealAndSend(prep(s).appendList(1) << PongPacket);
sealAndSend(prep(s, PongPacket));
break;
}
case PongPacket:
@ -142,12 +152,14 @@ bool Session::interpret(RLP const& _r)
clogS(NetTriviaSummary) << "GetPeers";
auto peers = m_server->potentialPeers();
RLPStream s;
prep(s).appendList(peers.size() + 1);
s << PeersPacket;
prep(s, PeersPacket, peers.size());
for (auto i: peers)
{
clogS(NetTriviaDetail) << "Sending peer " << i.first.abridged() << i.second;
s.appendList(3) << bytesConstRef(i.second.address().to_v4().to_bytes().data(), 4) << i.second.port() << i.first;
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);
break;
@ -156,7 +168,16 @@ bool Session::interpret(RLP const& _r)
clogS(NetTriviaSummary) << "Peers (" << dec << (_r.itemCount() - 1) << " entries)";
for (unsigned i = 1; i < _r.itemCount(); ++i)
{
bi::address_v4 peerAddress(_r[i][0].toHash<FixedHash<4>>().asArray());
bi::address peerAddress;
if (_r[i][0].size() == 16)
peerAddress = bi::address_v6(_r[i][0].toHash<FixedHash<16>>().asArray());
else if (_r[i][0].size() == 4)
peerAddress = bi::address_v4(_r[i][0].toHash<FixedHash<4>>().asArray());
else
{
disconnect(BadProtocol);
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);
@ -185,25 +206,33 @@ bool Session::interpret(RLP const& _r)
}
break;
default:
{
auto id = _r[0].toInt<unsigned>();
for (auto const& i: m_capabilities)
if (i.second->m_enabled && i.second->interpret(_r))
if (i.second->m_enabled && id >= i.second->m_idOffset && id - i.second->m_idOffset < i.second->hostCapability()->messageCount() && i.second->interpret(id - i.second->m_idOffset, _r))
return true;
return false;
}
}
return true;
}
void Session::ping()
{
RLPStream s;
sealAndSend(prep(s).appendList(1) << PingPacket);
sealAndSend(prep(s, PingPacket));
m_ping = std::chrono::steady_clock::now();
}
void Session::getPeers()
{
RLPStream s;
sealAndSend(prep(s).appendList(1) << GetPeersPacket);
sealAndSend(prep(s, GetPeersPacket));
}
RLPStream& Session::prep(RLPStream& _s, PacketType _id, unsigned _args)
{
return prep(_s).appendList(_args + 1).append((unsigned)_id);
}
RLPStream& Session::prep(RLPStream& _s)
@ -240,7 +269,7 @@ void Session::sendDestroy(bytes& _msg)
if (!checkPacket(bytesConstRef(&_msg)))
{
cwarn << "INVALID PACKET CONSTRUCTED!";
clogS(NetWarn) << "INVALID PACKET CONSTRUCTED!";
}
bytes buffer = bytes(std::move(_msg));
@ -253,7 +282,7 @@ void Session::send(bytesConstRef _msg)
if (!checkPacket(_msg))
{
cwarn << "INVALID PACKET CONSTRUCTED!";
clogS(NetWarn) << "INVALID PACKET CONSTRUCTED!";
}
bytes buffer = bytes(_msg.toBytes());
@ -288,7 +317,7 @@ void Session::write()
// must check queue, as write callback can occur following dropped()
if (ec)
{
cwarn << "Error sending: " << ec.message();
clogS(NetWarn) << "Error sending: " << ec.message();
dropped();
return;
}
@ -323,8 +352,7 @@ void Session::disconnect(int _reason)
if (m_disconnect == chrono::steady_clock::time_point::max())
{
RLPStream s;
prep(s);
s.appendList(2) << DisconnectPacket << _reason;
prep(s, DisconnectPacket, 1) << _reason;
sealAndSend(s);
m_disconnect = chrono::steady_clock::now();
}
@ -336,8 +364,7 @@ void Session::disconnect(int _reason)
void Session::start()
{
RLPStream s;
prep(s);
s.appendList(6) << HelloPacket
prep(s, HelloPacket, 5)
<< m_server->protocolVersion()
<< m_server->m_clientVersion
<< m_server->caps()
@ -363,7 +390,7 @@ void Session::doRead()
if (ec && ec.category() != boost::asio::error::get_misc_category() && ec.value() != boost::asio::error::eof)
{
// got here with length of 1241...
cwarn << "Error reading: " << ec.message();
clogS(NetWarn) << "Error reading: " << ec.message();
dropped();
}
else if (ec && length == 0)
@ -380,7 +407,7 @@ void Session::doRead()
{
if (m_incoming[0] != 0x22 || m_incoming[1] != 0x40 || m_incoming[2] != 0x08 || m_incoming[3] != 0x91)
{
cwarn << "INVALID SYNCHRONISATION TOKEN; expected = 22400891; received = " << toHex(bytesConstRef(m_incoming.data(), 4));
clogS(NetWarn) << "INVALID SYNCHRONISATION TOKEN; expected = 22400891; received = " << toHex(bytesConstRef(m_incoming.data(), 4));
disconnect(BadProtocol);
return;
}
@ -396,7 +423,7 @@ void Session::doRead()
if (!checkPacket(data))
{
cerr << "Received " << len << ": " << toHex(bytesConstRef(m_incoming.data() + 8, len)) << endl;
cwarn << "INVALID MESSAGE RECEIVED";
clogS(NetWarn) << "INVALID MESSAGE RECEIVED";
disconnect(BadProtocol);
return;
}

7
libp2p/Session.h

@ -27,6 +27,7 @@
#include <set>
#include <memory>
#include <utility>
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include "Common.h"
@ -62,8 +63,9 @@ public:
bi::tcp::endpoint endpoint() const; ///< for other peers to connect to.
template <class PeerCap>
std::shared_ptr<PeerCap> cap() const { try { return std::static_pointer_cast<PeerCap>(m_capabilities.at(PeerCap::name())); } catch (...) { return nullptr; } }
std::shared_ptr<PeerCap> cap() const { try { return std::static_pointer_cast<PeerCap>(m_capabilities.at(std::make_pair(PeerCap::name(), PeerCap::version()))); } catch (...) { return nullptr; } }
static RLPStream& prep(RLPStream& _s, PacketType _t, unsigned _args = 0);
static RLPStream& prep(RLPStream& _s);
void sealAndSend(RLPStream& _s);
void sendDestroy(bytes& _msg);
@ -108,7 +110,8 @@ private:
unsigned m_rating;
std::map<std::string, std::shared_ptr<Capability>> m_capabilities;
std::map<CapDesc, std::shared_ptr<Capability>> m_capabilities;
std::set<h512> m_knownPeers;
bool m_willBeDeleted = false; ///< True if we already posted a deleter on the strand.
};

1
libp2p/UPnP.cpp

@ -31,6 +31,7 @@
#endif
#include <libdevcore/Exceptions.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/Log.h>
using namespace std;
using namespace dev;

87
libqethereum/QEthereum.cpp

@ -336,6 +336,93 @@ static QString toJson(dev::eth::PastMessages const& _pms)
return QString::fromUtf8(QJsonDocument(jsonArray).toJson());
}
static QString toJson(dev::eth::BlockInfo const& _bi, dev::eth::BlockDetails const& _bd)
{
QJsonObject v;
v["hash"] = toQJS(_bi.hash);
v["parentHash"] = toQJS(_bi.parentHash);
v["sha3Uncles"] = toQJS(_bi.sha3Uncles);
v["miner"] = toQJS(_bi.coinbaseAddress);
v["stateRoot"] = toQJS(_bi.stateRoot);
v["transactionsRoot"] = toQJS(_bi.transactionsRoot);
v["difficulty"] = toQJS(_bi.difficulty);
v["number"] = (int)_bi.number;
v["minGasPrice"] = toQJS(_bi.minGasPrice);
v["gasLimit"] = (int)_bi.gasLimit;
v["gasUsed"] = (int)_bi.gasUsed;
v["timestamp"] = (int)_bi.timestamp;
v["extraData"] = ::fromBinary(_bi.extraData);
v["nonce"] = toQJS(_bi.nonce);
QJsonArray children;
for (auto c: _bd.children)
children.append(toQJS(c));
v["children"] = children;
v["totalDifficulty"] = toQJS(_bd.totalDifficulty);
v["bloom"] = toQJS(_bd.bloom);
return QString::fromUtf8(QJsonDocument(v).toJson());
}
static QString toJson(dev::eth::BlockInfo const& _bi)
{
QJsonObject v;
v["hash"] = toQJS(_bi.hash);
v["parentHash"] = toQJS(_bi.parentHash);
v["sha3Uncles"] = toQJS(_bi.sha3Uncles);
v["miner"] = toQJS(_bi.coinbaseAddress);
v["stateRoot"] = toQJS(_bi.stateRoot);
v["transactionsRoot"] = toQJS(_bi.transactionsRoot);
v["difficulty"] = toQJS(_bi.difficulty);
v["number"] = (int)_bi.number;
v["minGasPrice"] = toQJS(_bi.minGasPrice);
v["gasLimit"] = (int)_bi.gasLimit;
v["gasUsed"] = (int)_bi.gasUsed;
v["timestamp"] = (int)_bi.timestamp;
v["extraData"] = ::fromBinary(_bi.extraData);
v["nonce"] = toQJS(_bi.nonce);
return QString::fromUtf8(QJsonDocument(v).toJson());
}
static QString toJson(dev::eth::Transaction const& _bi)
{
QJsonObject v;
v["hash"] = toQJS(_bi.sha3());
v["input"] = ::fromBinary(_bi.data);
v["to"] = toQJS(_bi.receiveAddress);
v["from"] = toQJS(_bi.sender());
v["gas"] = (int)_bi.gas;
v["gasPrice"] = toQJS(_bi.gasPrice);
v["nonce"] = toQJS(_bi.nonce);
v["value"] = toQJS(_bi.value);
return QString::fromUtf8(QJsonDocument(v).toJson());
}
QString QEthereum::getUncle(QString _numberOrHash, int _i) const
{
auto n = toU256(_numberOrHash);
auto h = n < m_client->number() ? m_client->hashFromNumber((unsigned)n) : ::toFixed<32>(_numberOrHash);
return m_client ? toJson(m_client->uncle(h, _i)) : "";
}
QString QEthereum::getTransaction(QString _numberOrHash, int _i) const
{
auto n = toU256(_numberOrHash);
auto h = n < m_client->number() ? m_client->hashFromNumber((unsigned)n) : ::toFixed<32>(_numberOrHash);
return m_client ? toJson(m_client->transaction(h, _i)) : "";
}
QString QEthereum::getBlock(QString _numberOrHash) const
{
auto n = toU256(_numberOrHash);
auto h = n < m_client->number() ? m_client->hashFromNumber((unsigned)n) : ::toFixed<32>(_numberOrHash);
return m_client ? toJson(m_client->blockInfo(h), m_client->blockDetails(h)) : "";
}
QString QEthereum::getMessages(QString _json) const
{
return m_client ? toJson(m_client->messages(toMessageFilter(_json))) : "";

20
libqethereum/QEthereum.h

@ -148,6 +148,10 @@ public:
Q_INVOKABLE QString/*dev::u256*/ stateAt(QString/*dev::Address*/ _a, QString/*dev::u256*/ _p) const;
Q_INVOKABLE QString/*dev::u256*/ codeAt(QString/*dev::Address*/ _a) const;
Q_INVOKABLE QString/*json*/ getBlock(QString _numberOrHash/*unsigned if < number(), hash otherwise*/) const;
Q_INVOKABLE QString/*json*/ getTransaction(QString _numberOrHash/*unsigned if < number(), hash otherwise*/, int _index) const;
Q_INVOKABLE QString/*json*/ getUncle(QString _numberOrHash/*unsigned if < number(), hash otherwise*/, int _index) const;
Q_INVOKABLE QString/*json*/ getMessages(QString _attribs/*json*/) const;
Q_INVOKABLE QString doCreate(QString _secret, QString _amount, QString _init, QString _gas, QString _gasPrice);
@ -255,20 +259,12 @@ private:
frame->addToJavaScriptWindowObject("shh", eth, QWebFrame::ScriptOwnership); \
frame->evaluateJavaScript("eth.makeWatch = function(a) { var ww = eth.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { eth.killWatch(w); }; ret.changed = function(f) { eth.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(eth.watchMessages(this.w)) }; return ret; }"); \
frame->evaluateJavaScript("eth.watch = function(a) { return eth.makeWatch(JSON.stringify(a)) }"); \
frame->evaluateJavaScript("eth.watchChain = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.watch('chain') INSTEAD.'); return eth.makeWatch('chain') }"); \
frame->evaluateJavaScript("eth.watchPending = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.watch('pending') INSTEAD.'); return eth.makeWatch('pending') }"); \
frame->evaluateJavaScript("eth.create = function(s, v, c, g, p, f) { env.warn('THIS CALL IS DEPRECATED. USE eth.transact INSTEAD.'); var v = eth.doCreate(s, v, c, g, p); if (f) f(v) }"); \
frame->evaluateJavaScript("eth.transact = function(a_s, f_v, t, d, g, p, f) { if (t == null) { var r = eth.doTransact(JSON.stringify(a_s)); if (f_v) f_v(r); } else { env.warn('THIS FORM OF THIS CALL IS DEPRECATED.'); eth.doTransact(a_s, f_v, t, d, g, p); if (f) f() } }"); \
frame->evaluateJavaScript("eth.transact = function(a, f) { var r = eth.doTransact(JSON.stringify(a)); if (f) f(r); }"); \
frame->evaluateJavaScript("eth.call = function(a, f) { var ret = eth.doCallJson(JSON.stringify(a)); if (f) f(ret); return ret; }"); \
frame->evaluateJavaScript("eth.messages = function(a) { return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \
frame->evaluateJavaScript("eth.transactions = function(a) { env.warn('THIS CALL IS DEPRECATED. USE eth.messages INSTEAD.'); return JSON.parse(eth.getMessages(JSON.stringify(a))); }"); \
frame->evaluateJavaScript("String.prototype.pad = function(l, r) { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.pad(this, l, r) }"); \
frame->evaluateJavaScript("String.prototype.bin = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.toAscii(this) }"); \
frame->evaluateJavaScript("String.prototype.unbin = function(l) { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.fromAscii(this) }"); \
frame->evaluateJavaScript("String.prototype.unpad = function(l) { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.unpad(this) }"); \
frame->evaluateJavaScript("String.prototype.dec = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.toDecimal(this) }"); \
frame->evaluateJavaScript("String.prototype.fix = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.toFixed(this) }"); \
frame->evaluateJavaScript("String.prototype.sha3 = function() { env.warn('THIS CALL IS DEPRECATED. USE eth.* INSTEAD.'); return eth.sha3old(this) }"); \
frame->evaluateJavaScript("eth.block = function(a) { return JSON.parse(eth.getBlock(a)); }"); \
frame->evaluateJavaScript("eth.transaction = function(a) { return JSON.parse(eth.getTransaction(a)); }"); \
frame->evaluateJavaScript("eth.uncle = function(a) { return JSON.parse(eth.getUncle(a)); }"); \
frame->evaluateJavaScript("shh.makeWatch = function(a) { var ww = shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { shh.killWatch(w); }; ret.changed = function(f) { shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(shh.watchMessages(this.w)) }; return ret; }"); \
frame->evaluateJavaScript("shh.watch = function(a) { return shh.makeWatch(JSON.stringify(a)) }"); \
}

5
libwhisper/Common.h

@ -51,10 +51,11 @@ class Whisper;
enum WhisperPacket
{
StatusPacket = 0x20,
StatusPacket = 0,
MessagesPacket,
AddFilterPacket,
RemoveFilterPacket
RemoveFilterPacket,
PacketCount
};
}

3
libwhisper/Interface.cpp

@ -29,6 +29,9 @@ using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;
#if defined(clogS)
#undef clogS
#endif
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "
bool MessageFilter::matches(Message const& _m) const

1
libwhisper/Message.cpp

@ -25,4 +25,3 @@ using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "

3
libwhisper/WhisperHost.cpp

@ -28,6 +28,9 @@ using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;
#if defined(clogS)
#undef clogS
#endif
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "
WhisperHost::WhisperHost()

17
libwhisper/WhisperPeer.cpp

@ -28,13 +28,16 @@ using namespace std;
using namespace dev;
using namespace dev::p2p;
using namespace dev::shh;
#if defined(clogS)
#undef clogS
#endif
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] "
WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h): Capability(_s, _h)
WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h, unsigned _i): Capability(_s, _h, _i)
{
RLPStream s;
prep(s);
sealAndSend(s.appendList(2) << StatusPacket << host()->protocolVersion());
sealAndSend(prep(s, StatusPacket, 1) << host()->protocolVersion());
}
WhisperPeer::~WhisperPeer()
@ -46,9 +49,9 @@ WhisperHost* WhisperPeer::host() const
return static_cast<WhisperHost*>(Capability::hostCapability());
}
bool WhisperPeer::interpret(RLP const& _r)
bool WhisperPeer::interpret(unsigned _id, RLP const& _r)
{
switch (_r[0].toInt<unsigned>())
switch (_id)
{
case StatusPacket:
{
@ -95,9 +98,7 @@ void WhisperPeer::sendMessages()
if (n)
{
RLPStream s;
prep(s);
s.appendList(n + 1) << MessagesPacket;
s.appendRaw(amalg.out(), n);
prep(s, MessagesPacket, n).appendRaw(amalg.out(), n);
sealAndSend(s);
}
else

6
libwhisper/WhisperPeer.h

@ -49,15 +49,17 @@ class WhisperPeer: public Capability
friend class WhisperHost;
public:
WhisperPeer(Session* _s, HostCapabilityFace* _h);
WhisperPeer(Session* _s, HostCapabilityFace* _h, unsigned _i);
virtual ~WhisperPeer();
static std::string name() { return "shh"; }
static u256 version() { return 1; }
static unsigned messageCount() { return PacketCount; }
WhisperHost* host() const;
private:
virtual bool interpret(RLP const&);
virtual bool interpret(unsigned _id, RLP const&);
void sendMessages();

3
test/hexPrefix.cpp

@ -22,8 +22,9 @@
#include <fstream>
#include "JsonSpiritHeaders.h"
#include <libdevcrypto/TrieCommon.h>
#include <libdevcore/Log.h>
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/TrieCommon.h>
#include <boost/test/unit_test.hpp>
using namespace std;

1
test/rlp.cpp

@ -25,6 +25,7 @@
#include <libdevcore/Log.h>
#include <libdevcore/RLP.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <boost/test/unit_test.hpp>
#include <algorithm>
#include "JsonSpiritHeaders.h"

1
test/trie.cpp

@ -23,6 +23,7 @@
#include <fstream>
#include <random>
#include "JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h>
#include <libdevcrypto/TrieDB.h>
#include "TrieHash.h"
#include "MemTrie.h"

7
test/vm.cpp

@ -21,6 +21,7 @@
*/
#include "vm.h"
#include <libdevcore/CommonIO.h>
#define FILL_TESTS
@ -44,7 +45,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &posts, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
if (!m_ms.internal.back().from)
m_ms.internal.pop_back();
@ -82,7 +83,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
{
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, &posts, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
auto na = m_s.create(myAddress, 0, gasPrice, _gas, 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))
@ -95,7 +96,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
}
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, &posts, &(m_ms.internal.back()), OnOpFunc(), 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);
if (!m_ms.internal.back().from)
m_ms.internal.pop_back();
if (!ret)

7
third/MainWin.cpp

@ -84,9 +84,10 @@ Main::Main(QWidget *parent) :
ui->setupUi(this);
cerr << "State root: " << BlockChain::genesis().stateRoot << endl;
cerr << "Block Hash: " << sha3(BlockChain::createGenesisBlock()) << endl;
cerr << "Block RLP: " << RLP(BlockChain::createGenesisBlock()) << endl;
cerr << "Block Hex: " << toHex(BlockChain::createGenesisBlock()) << endl;
auto gb = BlockChain::createGenesisBlock();
cerr << "Block Hash: " << sha3(gb) << endl;
cerr << "Block RLP: " << RLP(gb) << endl;
cerr << "Block Hex: " << toHex(gb) << endl;
cerr << "Network protocol version: " << dev::eth::c_protocolVersion << endl;
cerr << "Client database version: " << dev::eth::c_databaseVersion << endl;

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

Loading…
Cancel
Save