Browse Source

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

cl-refactor
arkpar 10 years ago
parent
commit
0bc96ff44d
  1. 1
      CMakeLists.txt
  2. 8
      alethzero/MainWin.cpp
  3. 183
      eth/main.cpp
  4. 4
      ethminer/CMakeLists.txt
  5. 19
      ethvm/CMakeLists.txt
  6. 200
      ethvm/main.cpp
  7. 4
      libdevcore/Exceptions.h
  8. 2
      libdevcore/FixedHash.h
  9. 2
      libdevcore/Log.cpp
  10. 43
      libdevcore/MemoryDB.cpp
  11. 8
      libdevcore/MemoryDB.h
  12. 6
      libdevcrypto/OverlayDB.cpp
  13. 29
      libethcore/Common.cpp
  14. 2
      libethcore/Common.h
  15. 5
      libethcore/Ethash.cpp
  16. 28
      libethereum/BlockChain.cpp
  17. 28
      libethereum/BlockQueue.cpp
  18. 3
      libethereum/BlockQueue.h
  19. 4
      libethereum/CMakeLists.txt
  20. 30
      libethereum/Client.cpp
  21. 2
      libethereum/Client.h
  22. 27
      libethereum/EthereumHost.cpp
  23. 5
      libethereum/EthereumHost.h
  24. 37
      libethereum/EthereumPeer.cpp
  25. 11
      libethereum/EthereumPeer.h
  26. 22
      libethereum/Executive.cpp
  27. 5
      libethereum/Executive.h
  28. 72
      libethereum/State.cpp
  29. 21
      libethereum/Transaction.cpp
  30. 3
      libethereum/Transaction.h
  31. 12
      libp2p/Capability.cpp
  32. 8
      libp2p/Capability.h
  33. 19
      libp2p/Host.cpp
  34. 40
      libp2p/Host.h
  35. 6
      libp2p/Session.cpp
  36. 2
      libp2p/Session.h
  37. 109
      libsolidity/InterfaceHandler.cpp
  38. 36
      libsolidity/InterfaceHandler.h

1
CMakeLists.txt

@ -421,6 +421,7 @@ if (TOOLS)
add_subdirectory(rlp)
add_subdirectory(abi)
add_subdirectory(ethvm)
add_subdirectory(eth)
if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")

8
alethzero/MainWin.cpp

@ -240,6 +240,10 @@ Main::Main(QWidget *parent) :
#if !ETH_FATDB
removeDockWidget(ui->dockWidget_accounts);
#endif
#if !ETH_EVMJIT
ui->jitvm->setEnabled(false);
ui->jitvm->setChecked(false);
#endif
installWatches();
startTimer(100);
@ -1242,8 +1246,8 @@ void Main::refreshBlockCount()
auto d = ethereum()->blockChain().details();
BlockQueueStatus b = ethereum()->blockQueueStatus();
HashChainStatus h = ethereum()->hashChainStatus();
ui->chainStatus->setText(QString("%9/%10%11 hashes %3 ready %4 verifying %5 unverified %6 future %7 unknown %8 bad %1 #%2")
.arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.verified).arg(b.verifying).arg(b.unverified).arg(b.future).arg(b.unknown).arg(b.bad).arg(h.received).arg(h.estimated ? "~" : "").arg(h.total));
ui->chainStatus->setText(QString("%10/%11%12 hashes %3 importing %4 ready %5 verifying %6 unverified %7 future %8 unknown %9 bad %1 #%2")
.arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.importing).arg(b.verified).arg(b.verifying).arg(b.unverified).arg(b.future).arg(b.unknown).arg(b.bad).arg(h.received).arg(h.estimated ? "~" : "").arg(h.total));
}
void Main::on_turboMining_triggered()

183
eth/main.cpp

@ -84,15 +84,24 @@ void interactiveHelp()
<< " minestop Stops mining." << endl
<< " mineforce <enable> Forces mining, even when there are no transactions." << endl
<< " block Gives the current block height." << endl
<< " blockhashfromnumber <number> Gives the block hash with the givne number." << endl
<< " numberfromblockhash <hash> Gives the block number with the given hash." << endl
<< " blockqueue Gives the current block queue status." << endl
<< " findblock <hash> Searches for the block in the blockchain and blockqueue." << endl
<< " firstunknown Gives the first unknown block from the blockqueue." << endl
<< " retryunknown retries to import all unknown blocks from the blockqueue." << endl
<< " accounts Gives information on all owned accounts (balances, mining beneficiary and default signer)." << endl
<< " newaccount <name> Creates a new account with the given name." << endl
<< " transact Execute a given transaction." << endl
<< " txcreate Execute a given contract creation transaction." << endl
<< " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl
<< " peers List the peers that are connected" << endl
#if ETH_FATDB || !ETH_TRUE
<< " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts on the network." << endl
<< " balanceat <address> Gives the balance of the given account." << endl
<< " codeat <address> Gives the code of the given account." << endl
#endif
<< " setsigningkey <addr> Set the address with which to sign transactions." << endl
<< " setaddress <addr> Set the coinbase (mining payout) address." << endl
@ -971,10 +980,89 @@ int main(int argc, char** argv)
cout << "Current mining beneficiary:" << endl << beneficiary << endl;
cout << "Current signing account:" << endl << signingKey << endl;
}
else if (c && cmd == "blockhashfromnumber")
{
if (iss.peek() != -1)
{
unsigned number;
iss >> number;
cout << " hash of block: " << c->hashFromNumber(number).hex() << endl;
}
}
else if (c && cmd == "numberfromblockhash")
{
if (iss.peek() != -1)
{
string stringHash;
iss >> stringHash;
h256 hash = h256(fromHex(stringHash));
cout << " number of block: " << c->numberFromHash(hash) << endl;
}
}
else if (c && cmd == "block")
{
cout << "Current block: " << c->blockChain().details().number << endl;
}
else if (c && cmd == "blockqueue")
{
cout << "Current blockqueue status: " << endl << c->blockQueueStatus() << endl;
}
else if (c && cmd == "findblock")
{
if (iss.peek() != -1)
{
string stringHash;
iss >> stringHash;
h256 hash = h256(fromHex(stringHash));
// search in blockchain
cout << "search in blockchain... " << endl;
try
{
cout << c->blockInfo(hash) << endl;
}
catch(Exception& _e)
{
cout << "block not in blockchain" << endl;
cout << boost::diagnostic_information(_e) << endl;
}
cout << "search in blockqueue... " << endl;
switch(c->blockQueue().blockStatus(hash))
{
case QueueStatus::Ready:
cout << "Ready" << endl;
break;
case QueueStatus::Importing:
cout << "Importing" << endl;
break;
case QueueStatus::UnknownParent:
cout << "UnknownParent" << endl;
break;
case QueueStatus::Bad:
cout << "Bad" << endl;
break;
case QueueStatus::Unknown:
cout << "Unknown" << endl;
break;
default:
cout << "invalid queueStatus" << endl;
}
}
else
cwarn << "Require parameter: findblock HASH";
}
else if (c && cmd == "firstunknown")
{
cout << "first unknown blockhash: " << c->blockQueue().firstUnknown().hex() << endl;
}
else if (c && cmd == "retryunknown")
{
c->retryUnkonwn();
}
else if (cmd == "peers")
{
for (auto it: web3.peers())
@ -1087,6 +1175,64 @@ int main(int argc, char** argv)
else
cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
}
else if (c && cmd == "txcreate")
{
auto const& bc =c->blockChain();
auto h = bc.currentHash();
auto blockData = bc.block(h);
BlockInfo info(blockData);
if (iss.peek() != -1)
{
u256 amount;
u256 gasPrice;
u256 gas;
string sechex;
string sdata;
iss >> amount >> gasPrice >> gas >> sechex >> sdata;
if (!gasPrice)
gasPrice = gasPricer->bid(priority);
cnote << "Data:";
cnote << sdata;
bytes data = dev::eth::parseData(sdata);
cnote << "Bytes:";
string sbd = asString(data);
bytes bbd = asBytes(sbd);
stringstream ssbd;
ssbd << bbd;
cnote << ssbd.str();
int ssize = sechex.length();
u256 minGas = (u256)Transaction::gasRequired(data, 0);
if (gas < minGas)
cwarn << "Minimum gas amount is" << minGas;
else if (ssize < 40)
{
if (ssize > 0)
cwarn << "Invalid secret length:" << ssize;
}
else
{
try
{
Secret secret = h256(fromHex(sechex));
cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl;
}
catch (BadHexCharacter& _e)
{
cwarn << "invalid hex character, transaction rejected";
cwarn << boost::diagnostic_information(_e);
}
catch (...)
{
cwarn << "transaction rejected";
}
}
}
else
cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET INIT";
}
#if ETH_FATDB
else if (c && cmd == "listcontracts")
{
@ -1110,6 +1256,43 @@ int main(int argc, char** argv)
cout << ss << endl;
}
}
else if (c && cmd == "balanceat")
{
if (iss.peek() != -1)
{
string stringHash;
iss >> stringHash;
Address address = h160(fromHex(stringHash));
cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address)) << endl;
}
}
// TODO implement << operator for std::unorderd_map
// else if (c && cmd == "storageat")
// {
// if (iss.peek() != -1)
// {
// string stringHash;
// iss >> stringHash;
// Address address = h160(fromHex(stringHash));
// cout << "storage at " << stringHash << " is: " << c->storageAt(address) << endl;
// }
// }
else if (c && cmd == "codeat")
{
if (iss.peek() != -1)
{
string stringHash;
iss >> stringHash;
Address address = h160(fromHex(stringHash));
cout << "code at " << stringHash << " is: " << toHex(c->codeAt(address)) << endl;
}
}
#endif
else if (c && cmd == "send")
{

4
ethminer/CMakeLists.txt

@ -22,6 +22,10 @@ target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
if (JSONRPC)
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls(${EXECUTABLE} CURL_DLLS)
endif()
endif()
target_link_libraries(${EXECUTABLE} ethcore)

19
ethvm/CMakeLists.txt

@ -0,0 +1,19 @@
cmake_policy(SET CMP0015 NEW)
set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS})
set(EXECUTABLE ethvm)
add_executable(${EXECUTABLE} ${SRC_LIST})
target_link_libraries(${EXECUTABLE} ethereum)
if (APPLE)
install(TARGETS ${EXECUTABLE} DESTINATION bin)
else()
eth_install_executable(${EXECUTABLE})
endif()

200
ethvm/main.cpp

@ -0,0 +1,200 @@
/*
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 main.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
* EVM Execution tool.
*/
#include <fstream>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <libdevcore/CommonIO.h>
#include <libdevcore/RLP.h>
#include <libdevcore/SHA3.h>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include <libevm/VM.h>
#include <libevm/VMFactory.h>
using namespace std;
using namespace dev;
using namespace eth;
void help()
{
cout
<< "Usage ethvm <options> [trace|stats|output] (<file>|--)" << endl
<< "Transaction options:" << endl
<< " --value <n> Transaction should transfer the <n> wei (default: 0)." << endl
<< " --gas <n> Transaction should be given <n> gas (default: block gas limit)." << endl
<< " --gas-price <n> Transaction's gas price' should be <n> (default: 0)." << endl
<< " --sender <a> Transaction sender should be <a> (default: 0000...0069)." << endl
<< " --origin <a> Transaction origin should be <a> (default: 0000...0069)." << endl
#if ETH_EVMJIT || !ETH_TRUE
<< endl
<< "VM options:" << endl
<< " -J,--jit Enable LLVM VM (default: off)." << endl
<< " --smart Enable smart VM (default: off)." << endl
#endif
<< endl
<< "Options for trace:" << endl
<< " --flat Minimal whitespace in the JSON." << endl
<< " --mnemonics Show instruction mnemonics in the trace (non-standard)." << endl
<< endl
<< "General options:" << endl
<< " -V,--version Show the version and exit." << endl
<< " -h,--help Show this help message and exit." << endl;
exit(0);
}
void version()
{
cout << "ethvm version " << dev::Version << endl;
cout << "By Gav Wood, 2015." << endl;
cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl;
exit(0);
}
enum class Mode
{
Trace,
Statistics,
OutputOnly
};
int main(int argc, char** argv)
{
string incoming = "--";
Mode mode = Mode::Statistics;
State state;
Address sender = Address(69);
Address origin = Address(69);
u256 value = 0;
u256 gas = state.gasLimitRemaining();
u256 gasPrice = 0;
bool styledJson = true;
StandardTrace st;
for (int i = 1; i < argc; ++i)
{
string arg = argv[i];
if (arg == "-h" || arg == "--help")
help();
else if (arg == "-V" || arg == "--version")
version();
#if ETH_EVMJIT
else if (arg == "-J" || arg == "--jit")
VMFactory::setKind(VMKind::JIT);
else if (arg == "--smart")
VMFactory::setKind(VMKind::Smart);
#endif
else if (arg == "--mnemonics")
st.setShowMnemonics();
else if (arg == "--flat")
styledJson = false;
else if (arg == "--value" && i + 1 < argc)
value = u256(argv[++i]);
else if (arg == "--sender" && i + 1 < argc)
sender = Address(argv[++i]);
else if (arg == "--origin" && i + 1 < argc)
origin = Address(argv[++i]);
else if (arg == "--gas" && i + 1 < argc)
gas = u256(argv[++i]);
else if (arg == "--gas-price" && i + 1 < argc)
gasPrice = u256(argv[++i]);
else if (arg == "--value" && i + 1 < argc)
value = u256(argv[++i]);
else if (arg == "--value" && i + 1 < argc)
value = u256(argv[++i]);
else if (arg == "stats")
mode = Mode::Statistics;
else if (arg == "output")
mode = Mode::OutputOnly;
else if (arg == "trace")
mode = Mode::Trace;
else
incoming = arg;
}
bytes code;
if (incoming == "--" || incoming.empty())
for (int i = cin.get(); i != -1; i = cin.get())
code.push_back((char)i);
else
code = contents(incoming);
bytes data = fromHex(boost::trim_copy(asString(code)));
if (data.empty())
data = code;
state.addBalance(sender, value);
Executive executive(state, eth::LastHashes(), 0);
ExecutionResult res;
executive.setResultRecipient(res);
Transaction t = eth::Transaction(value, gasPrice, gas, data, 0);
t.forceSender(sender);
unordered_map<byte, pair<unsigned, bigint>> counts;
unsigned total = 0;
bigint memTotal;
auto onOp = [&](uint64_t step, Instruction inst, bigint m, bigint gasCost, bigint gas, VM* vm, ExtVMFace const* extVM) {
if (mode == Mode::Statistics)
{
counts[(byte)inst].first++;
counts[(byte)inst].second += gasCost;
total++;
if (m > 0)
memTotal = m;
}
else if (mode == Mode::Trace)
st(step, inst, m, gasCost, gas, vm, extVM);
};
executive.initialize(t);
executive.create(sender, value, gasPrice, gas, &data, origin);
boost::timer timer;
executive.go(onOp);
double execTime = timer.elapsed();
executive.finalize();
bytes output = std::move(res.output);
if (mode == Mode::Statistics)
{
cout << "Gas used: " << res.gasUsed << " (+" << t.gasRequired() << " for transaction, -" << res.gasRefunded << " refunded)" << endl;
cout << "Output: " << toHex(output) << endl;
LogEntries logs = executive.logs();
cout << logs.size() << " logs" << (logs.empty() ? "." : ":") << endl;
for (LogEntry const& l: logs)
{
cout << " " << l.address.hex() << ": " << toHex(t.data()) << endl;
for (h256 const& t: l.topics)
cout << " " << t.hex() << endl;
}
cout << total << " operations in " << execTime << " seconds." << endl;
cout << "Maximum memory usage: " << memTotal * 32 << " bytes" << endl;
cout << "Expensive operations:" << endl;
for (auto const& c: {Instruction::SSTORE, Instruction::SLOAD, Instruction::CALL, Instruction::CREATE, Instruction::CALLCODE, Instruction::MSTORE8, Instruction::MSTORE, Instruction::MLOAD, Instruction::SHA3})
if (!!counts[(byte)c].first)
cout << " " << instructionInfo(c).name << " x " << counts[(byte)c].first << " (" << counts[(byte)c].second << " gas)" << endl;
}
else if (mode == Mode::Trace)
cout << st.json(styledJson);
else if (mode == Mode::OutputOnly)
cout << toHex(output);
return 0;
}

4
libdevcore/Exceptions.h

@ -41,11 +41,11 @@ private:
std::string m_message;
};
#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { public: X(): Exception(#X) {} }
#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { const char* what() const noexcept override { return #X; } }
/// Base class for all RLP exceptions.
struct RLPException: virtual Exception { RLPException(std::string _message = std::string()): Exception(_message) {} };
#define DEV_SIMPLE_EXCEPTION_RLP(X) struct X: virtual RLPException { public: X(): RLPException(#X) {} }
#define DEV_SIMPLE_EXCEPTION_RLP(X) struct X: virtual RLPException { const char* what() const noexcept override { return #X; } }
DEV_SIMPLE_EXCEPTION_RLP(BadCast);
DEV_SIMPLE_EXCEPTION_RLP(BadRLP);

2
libdevcore/FixedHash.h

@ -113,7 +113,7 @@ public:
/// @returns an abridged version of the hash as a user-readable hex string.
std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; }
/// @returns an abridged version of the hash as a user-readable hex string.
/// @returns the hash as a user-readable hex string.
std::string hex() const { return toHex(ref()); }
/// @returns a mutable byte vector_ref to the object's data.

2
libdevcore/Log.cpp

@ -40,7 +40,7 @@ mutex x_logOverride;
/// or equal to the currently output verbosity (g_logVerbosity).
static map<type_info const*, bool> s_logOverride;
bool isLogVisible(std::type_info const* _ch, bool _default)
bool isChannelVisible(std::type_info const* _ch, bool _default)
{
Guard l(x_logOverride);
if (s_logOverride.count(_ch))

43
libdevcore/MemoryDB.cpp

@ -32,7 +32,9 @@ const char* DBWarn::name() { return "TDB"; }
std::unordered_map<h256, std::string> MemoryDB::get() const
{
#if DEV_GUARDED_DB
ReadGuard l(x_this);
#endif
std::unordered_map<h256, std::string> ret;
for (auto const& i: m_main)
if (!m_enforceRefs || i.second.second > 0)
@ -44,8 +46,10 @@ MemoryDB& MemoryDB::operator=(MemoryDB const& _c)
{
if (this == &_c)
return *this;
#if DEV_GUARDED_DB
ReadGuard l(_c.x_this);
WriteGuard l2(x_this);
#endif
m_main = _c.m_main;
m_aux = _c.m_aux;
return *this;
@ -53,7 +57,9 @@ MemoryDB& MemoryDB::operator=(MemoryDB const& _c)
std::string MemoryDB::lookup(h256 const& _h) const
{
#if DEV_GUARDED_DB
ReadGuard l(x_this);
#endif
auto it = m_main.find(_h);
if (it != m_main.end())
{
@ -67,7 +73,9 @@ std::string MemoryDB::lookup(h256 const& _h) const
bool MemoryDB::exists(h256 const& _h) const
{
#if DEV_GUARDED_DB
ReadGuard l(x_this);
#endif
auto it = m_main.find(_h);
if (it != m_main.end() && (!m_enforceRefs || it->second.second > 0))
return true;
@ -76,7 +84,9 @@ bool MemoryDB::exists(h256 const& _h) const
void MemoryDB::insert(h256 const& _h, bytesConstRef _v)
{
#if DEV_GUARDED_DB
WriteGuard l(x_this);
#endif
auto it = m_main.find(_h);
if (it != m_main.end())
{
@ -92,7 +102,9 @@ void MemoryDB::insert(h256 const& _h, bytesConstRef _v)
bool MemoryDB::kill(h256 const& _h)
{
#if DEV_GUARDED_DB
ReadGuard l(x_this);
#endif
if (m_main.count(_h))
{
if (m_main[_h].second > 0)
@ -117,9 +129,38 @@ bool MemoryDB::kill(h256 const& _h)
return false;
}
bytes MemoryDB::lookupAux(h256 const& _h) const
{
#if DEV_GUARDED_DB
ReadGuard l(x_this);
#endif
auto it = m_aux.find(_h);
if (it != m_aux.end() && (!m_enforceRefs || it->second.second))
return it->second.first;
return bytes();
}
void MemoryDB::removeAux(h256 const& _h)
{
#if DEV_GUARDED_DB
WriteGuard l(x_this);
#endif
m_aux[_h].second = false;
}
void MemoryDB::insertAux(h256 const& _h, bytesConstRef _v)
{
#if DEV_GUARDED_DB
WriteGuard l(x_this);
#endif
m_aux[_h] = make_pair(_v.toBytes(), true);
}
void MemoryDB::purge()
{
#if DEV_GUARDED_DB
WriteGuard l(x_this);
#endif
for (auto it = m_main.begin(); it != m_main.end(); )
if (it->second.second)
++it;
@ -129,7 +170,9 @@ void MemoryDB::purge()
h256Hash MemoryDB::keys() const
{
#if DEV_GUARDED_DB
ReadGuard l(x_this);
#endif
h256Hash ret;
for (auto const& i: m_main)
if (i.second.second)

8
libdevcore/MemoryDB.h

@ -57,14 +57,16 @@ public:
bool kill(h256 const& _h);
void purge();
bytes lookupAux(h256 const& _h) const { ReadGuard l(x_this); auto it = m_aux.find(_h); if (it != m_aux.end() && (!m_enforceRefs || it->second.second)) return it->second.first; return bytes(); }
void removeAux(h256 const& _h) { WriteGuard l(x_this); m_aux[_h].second = false; }
void insertAux(h256 const& _h, bytesConstRef _v) { WriteGuard l(x_this); m_aux[_h] = make_pair(_v.toBytes(), true); }
bytes lookupAux(h256 const& _h) const;
void removeAux(h256 const& _h);
void insertAux(h256 const& _h, bytesConstRef _v);
h256Hash keys() const;
protected:
#if DEV_GUARDED_DB
mutable SharedMutex x_this;
#endif
std::unordered_map<h256, std::pair<std::string, unsigned>> m_main;
std::unordered_map<h256, std::pair<bytes, bool>> m_aux;

6
libdevcrypto/OverlayDB.cpp

@ -50,7 +50,9 @@ void OverlayDB::commit()
{
ldb::WriteBatch batch;
// cnote << "Committing nodes to disk DB:";
#if DEV_GUARDED_DB
DEV_READ_GUARDED(x_this)
#endif
{
for (auto const& i: m_main)
{
@ -83,7 +85,9 @@ void OverlayDB::commit()
cwarn << "Sleeping for" << (i + 1) << "seconds, then retrying.";
this_thread::sleep_for(chrono::seconds(i + 1));
}
#if DEV_GUARDED_DB
DEV_WRITE_GUARDED(x_this)
#endif
{
m_aux.clear();
m_main.clear();
@ -107,7 +111,9 @@ bytes OverlayDB::lookupAux(h256 const& _h) const
void OverlayDB::rollback()
{
#if DEV_GUARDED_DB
WriteGuard l(x_this);
#endif
m_main.clear();
}

29
libethcore/Common.cpp

@ -112,25 +112,26 @@ std::string formatBalance(bigint const& _b)
static void badBlockInfo(BlockInfo const& _bi, string const& _err)
{
cwarn << EthRedBold << "========================================================================";
cwarn << EthRedBold << "== Software Failure " + _err + string(max<int>(0, 44 - _err.size()), ' ') + " ==";
string const c_line = EthReset EthOnMaroon + string(80, ' ');
string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold;
string const c_space = c_border + string(76, ' ') + c_border;
stringstream ss;
ss << c_line << endl;
ss << c_space << endl;
ss << c_border + " Import Failure " + _err + string(max<int>(0, 53 - _err.size()), ' ') + " " + c_border << endl;
ss << c_space << endl;
string bin = toString(_bi.number);
cwarn << EthRedBold << ("== Guru Meditation #" + string(max<int>(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ==");
cwarn << EthRedBold << "========================================================================";
ss << c_border + (" Guru Meditation #" + string(max<int>(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl;
ss << c_space << endl;
ss << c_line;
cwarn << "\n" + ss.str();
}
void badBlock(bytesConstRef _block, string const& _err)
{
badBlockInfo(BlockInfo(_block, CheckNothing), _err);
cwarn << " Block:" << toHex(_block);
cwarn << " Block RLP:" << RLP(_block);
}
void badBlockHeader(bytesConstRef _header, string const& _err)
{
badBlockInfo(BlockInfo::fromHeader(_header, CheckNothing), _err);
cwarn << " Header:" << toHex(_header);
cwarn << " Header RLP:" << RLP(_header);;
BlockInfo bi;
DEV_IGNORE_EXCEPTIONS(bi = BlockInfo(_block, CheckNothing));
badBlockInfo(bi, _err);
}
}

2
libethcore/Common.h

@ -156,8 +156,6 @@ struct TransactionSkeleton
u256 gasPrice = UndefinedU256;
};
void badBlockHeader(bytesConstRef _header, std::string const& _err);
inline void badBlockHeader(bytes const& _header, std::string const& _err) { badBlockHeader(&_header, _err); }
void badBlock(bytesConstRef _header, std::string const& _err);
inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); }

5
libethcore/Ethash.cpp

@ -335,11 +335,12 @@ void Ethash::GPUMiner::workLoop()
EthashAux::FullType dag;
while (true)
{
if ((dag = EthashAux::full(w.seedHash, false)))
if ((dag = EthashAux::full(w.seedHash, true)))
break;
if (shouldStop())
{
delete m_miner;
m_miner = nullptr;
return;
}
cnote << "Awaiting DAG";
@ -354,6 +355,8 @@ void Ethash::GPUMiner::workLoop()
}
catch (cl::Error const& _e)
{
delete m_miner;
m_miner = nullptr;
cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")";
}
}

28
libethereum/BlockChain.cpp

@ -50,7 +50,7 @@ using namespace dev::eth;
namespace js = json_spirit;
#define ETH_CATCH 1
#define ETH_TIMED_IMPORTS 0
#define ETH_TIMED_IMPORTS 1
#ifdef _WIN32
const char* BlockChainDebug::name() { return EthBlue "8" EthWhite " <>"; }
@ -315,7 +315,10 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
h256s fresh;
h256s dead;
h256s badBlocks;
for (auto const& block: blocks)
for (VerifiedBlock const& block: blocks)
if (!badBlocks.empty())
badBlocks.push_back(block.verified.info.hash());
else
{
try
{
@ -534,11 +537,6 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
}
catch (Exception& ex)
{
clog(BlockChainWarn) << " Malformed block: " << diagnostic_information(ex);
clog(BlockChainWarn) << "Block: " << _block.info.hash();
clog(BlockChainWarn) << _block.info;
clog(BlockChainWarn) << "Block parent: " << _block.info.parentHash;
clog(BlockChainWarn) << BlockInfo(block(_block.info.parentHash));
ex << errinfo_now(time(0));
ex << errinfo_block(_block.block.toBytes());
throw;
@ -641,7 +639,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
m_blocksDB->Write(m_writeOptions, &blocksBatch);
m_extrasDB->Write(m_writeOptions, &extrasBatch);
#if ETH_DEBUG || !ETH_TRUE
#if ETH_PARANOIA || !ETH_TRUE
if (isKnown(_block.info.hash()) && !details(_block.info.hash()))
{
clog(BlockChainDebug) << "Known block just inserted has no details.";
@ -676,12 +674,16 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
#if ETH_TIMED_IMPORTS
checkBest = t.elapsed();
if (total.elapsed() > 1.0)
{
cnote << "SLOW IMPORT:" << _block.info.hash();
cnote << " Import took:" << total.elapsed();
cnote << " preliminaryChecks:" << preliminaryChecks;
cnote << " enactment:" << enactment;
cnote << " collation:" << collation;
cnote << " writing:" << writing;
cnote << " checkBest:" << checkBest;
}
#endif
if (!route.empty())
@ -1074,8 +1076,6 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function<void(Exce
}
catch (Exception& ex)
{
clog(BlockChainNote) << " Malformed block: " << diagnostic_information(ex);
badBlock(_block, ex.what());
ex << errinfo_now(time(0));
ex << errinfo_block(_block);
if (_onBad)
@ -1093,8 +1093,6 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function<void(Exce
}
catch (Exception& ex)
{
clog(BlockChainNote) << " Malformed block header: " << diagnostic_information(ex);
badBlockHeader(uncle.data(), ex.what());
ex << errinfo_uncleIndex(i);
ex << errinfo_now(time(0));
ex << errinfo_block(_block);
@ -1111,10 +1109,10 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function<void(Exce
{
res.transactions.push_back(Transaction(tr.data(), CheckTransaction::Everything));
}
catch (...)
catch (Exception& ex)
{
badBlock(_block, "Invalid transaction");
cwarn << " Transaction Index:" << i;
ex << errinfo_transactionIndex(i);
ex << errinfo_block(_block);
throw;
}
++i;

28
libethereum/BlockQueue.cpp

@ -125,7 +125,7 @@ void BlockQueue::verifierBody()
m_verifying.erase(it);
goto OK1;
}
cwarn << "GAA BlockQueue corrupt: job cancelled but cannot be found in m_verifying queue.";
cwarn << "BlockQueue missing our job: was there a GM?";
OK1:;
continue;
}
@ -133,7 +133,7 @@ void BlockQueue::verifierBody()
bool ready = false;
{
unique_lock<Mutex> l(m_verification);
if (m_verifying.front().verified.info.mixHash == work.first)
if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.first)
{
// we're next!
m_verifying.pop_front();
@ -153,7 +153,7 @@ void BlockQueue::verifierBody()
i = move(res);
goto OK;
}
cwarn << "GAA BlockQueue corrupt: job finished but cannot be found in m_verifying queue.";
cwarn << "BlockQueue missing our job: was there a GM?";
OK:;
}
}
@ -261,23 +261,16 @@ bool BlockQueue::doneDrain(h256s const& _bad)
DEV_INVARIANT_CHECK;
m_drainingSet.clear();
if (_bad.size())
{
vector<VerifiedBlock> old;
// one of them was bad. since they all rely on their parent, all following are bad.
DEV_GUARDED(m_verification)
swap(m_verified, old);
for (auto& b: old)
{
if (m_knownBad.count(b.verified.info.parentHash))
{
m_knownBad.insert(b.verified.info.hash());
m_readySet.erase(b.verified.info.hash());
}
else
DEV_GUARDED(m_verification)
m_verified.push_back(std::move(b));
}
}
m_knownBad += _bad;
m_knownBad += m_readySet;
m_readySet.clear();
m_verified.clear();
m_verifying.clear();
m_unverified.clear();
}
return !m_readySet.empty();
}
@ -435,6 +428,7 @@ void BlockQueue::retryAllUnknown()
std::ostream& dev::eth::operator<<(std::ostream& _out, BlockQueueStatus const& _bqs)
{
_out << "importing: " << _bqs.importing << endl;
_out << "verified: " << _bqs.verified << endl;
_out << "verifying: " << _bqs.verifying << endl;
_out << "unverified: " << _bqs.unverified << endl;

3
libethereum/BlockQueue.h

@ -46,6 +46,7 @@ struct BlockQueueChannel: public LogChannel { static const char* name(); static
struct BlockQueueStatus
{
size_t importing;
size_t verified;
size_t verifying;
size_t unverified;
@ -104,7 +105,7 @@ public:
h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); }
/// Get some infomration on the current status.
BlockQueueStatus status() const { ReadGuard l(m_lock); Guard l2(m_verification); return BlockQueueStatus{m_verified.size(), m_verifying.size(), m_unverified.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; }
BlockQueueStatus status() const { ReadGuard l(m_lock); Guard l2(m_verification); return BlockQueueStatus{m_drainingSet.size(), m_verified.size(), m_verifying.size(), m_unverified.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; }
/// Get some infomration on the given block's status regarding us.
QueueStatus blockStatus(h256 const& _h) const;

4
libethereum/CMakeLists.txt

@ -36,6 +36,10 @@ target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
target_link_libraries(${EXECUTABLE} secp256k1)
if (JSONRPC)
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
eth_copy_dlls(${EXECUTABLE} CURL_DLLS)
endif()
endif()
if (CMAKE_COMPILER_IS_MINGW)

30
libethereum/Client.cpp

@ -90,19 +90,16 @@ void VersionChecker::setOk()
void Client::onBadBlock(Exception& _ex)
{
// BAD BLOCK!!!
bytes const& block = *boost::get_error_info<errinfo_block>(_ex);
if (!&block)
bytes const* block = boost::get_error_info<errinfo_block>(_ex);
if (!block)
{
cwarn << "ODD: onBadBlock called but exception has no block in it.";
return;
}
badBlock(block, _ex.what());
cwarn << boost::diagnostic_information(_ex, true);
badBlock(*block, _ex.what());
#if ETH_JSONRPC || !ETH_TRUE
if (!m_sentinel.empty())
{
Json::Value report;
report["client"] = "cpp";
@ -110,8 +107,7 @@ void Client::onBadBlock(Exception& _ex)
report["protocolVersion"] = c_protocolVersion;
report["databaseVersion"] = c_databaseVersion;
report["errortype"] = _ex.what();
report["block"] = toHex(block);
report["hint"] = Json::Value(Json::objectValue);
report["block"] = toHex(*block);
// add the various hints.
if (unsigned const* uncleIndex = boost::get_error_info<errinfo_uncleIndex>(_ex))
@ -160,7 +156,19 @@ void Client::onBadBlock(Exception& _ex)
DEV_HINT_ERRINFO(comment);
DEV_HINT_ERRINFO(min);
DEV_HINT_ERRINFO(max);
DEV_HINT_ERRINFO(name);
DEV_HINT_ERRINFO(field);
DEV_HINT_ERRINFO(data);
DEV_HINT_ERRINFO_HASH(nonce);
DEV_HINT_ERRINFO(difficulty);
DEV_HINT_ERRINFO(target);
DEV_HINT_ERRINFO_HASH(seedHash);
DEV_HINT_ERRINFO_HASH(mixHash);
if (tuple<h256, h256> const* r = boost::get_error_info<errinfo_ethashResult>(_ex))
{
report["hints"]["ethashResult"]["value"] = get<0>(*r).hex();
report["hints"]["ethashResult"]["mixHash"] = get<1>(*r).hex();
}
DEV_HINT_ERRINFO(required);
DEV_HINT_ERRINFO(got);
DEV_HINT_ERRINFO_HASH(required_LogBloom);
@ -168,6 +176,10 @@ void Client::onBadBlock(Exception& _ex)
DEV_HINT_ERRINFO_HASH(required_h256);
DEV_HINT_ERRINFO_HASH(got_h256);
cwarn << ("Report: \n" + Json::StyledWriter().write(report));
if (!m_sentinel.empty())
{
jsonrpc::HttpClient client(m_sentinel);
Sentinel rpc(client);
try

2
libethereum/Client.h

@ -158,6 +158,8 @@ public:
BlockQueueStatus blockQueueStatus() const { return m_bq.status(); }
/// Get some information on the block queue.
HashChainStatus hashChainStatus() const;
/// Get the block queue.
BlockQueue const& blockQueue() const { return m_bq; }
// Mining stuff:

27
libethereum/EthereumHost.cpp

@ -277,13 +277,6 @@ void EthereumHost::estimatePeerHashes(EthereumPeer* _peer)
_peer->m_expectedHashes = blockCount;
}
void EthereumHost::noteRude(p2p::NodeId const& _id, std::string const& _client)
{
cwarn << "RUDE node/client: " << _id << _client;
m_rudeNodes.insert(_id);
m_rudeClients.insert(_client);
}
void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes)
{
RecursiveGuard l(x_sync);
@ -577,9 +570,10 @@ void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r)
void EthereumHost::onPeerAborting(EthereumPeer* _peer)
{
RecursiveGuard l(x_sync);
if (_peer->isSyncing())
if (_peer->isConversing())
{
_peer->setIdle();
if (_peer->isCriticalSyncing())
_peer->setRude();
continueSync();
}
@ -647,18 +641,23 @@ void EthereumHost::continueSync(EthereumPeer* _peer)
_peer->setIdle();
}
}
else if (m_needSyncBlocks && peerShouldGrabBlocks(_peer)) // Check if this peer can help with downloading blocks
else if (m_needSyncBlocks && peerCanHelp(_peer)) // Check if this peer can help with downloading blocks
_peer->requestBlocks();
else
_peer->setIdle();
}
bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const
bool EthereumHost::peerCanHelp(EthereumPeer* _peer) const
{
// Early exit if this peer has proved unreliable.
if (_peer->isRude())
return false;
(void)_peer;
return true;
}
bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const
{
// this is only good for deciding whether to go ahead and grab a particular peer's hash chain,
// yet it's being used in determining whether to allow a peer help with downloading an existing
// chain of blocks.
auto td = _peer->m_totalDifficulty;
auto lh = m_syncingLatestHash;
auto ctd = m_chain.details().totalDifficulty;
@ -710,6 +709,6 @@ HashChainStatus EthereumHost::status()
RecursiveGuard l(x_sync);
if (m_syncingV61)
return HashChainStatus { static_cast<unsigned>(m_hashMan.chainSize()), static_cast<unsigned>(m_hashMan.gotCount()), false };
return HashChainStatus { m_estimatedHashes, static_cast<unsigned>(m_hashes.size()), true };
return HashChainStatus { m_estimatedHashes - 30000, static_cast<unsigned>(m_hashes.size()), true };
}

5
libethereum/EthereumHost.h

@ -72,8 +72,6 @@ public:
DownloadMan const& downloadMan() const { return m_man; }
bool isSyncing() const { RecursiveGuard l(x_sync); return isSyncing_UNSAFE(); }
bool isBanned(p2p::NodeId const& _id) const { return !!m_banned.count(_id); }
void noteRude(p2p::NodeId const& _id, std::string const& _client);
bool isRude(p2p::NodeId const& _id, std::string const& _client) const { return m_rudeClients.count(_client) && m_rudeNodes.count(_id); }
void noteNewTransactions() { m_newTransactions = true; }
void noteNewBlocks() { m_newBlocks = true; }
@ -126,6 +124,7 @@ private:
void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete);
bool peerShouldGrabBlocks(EthereumPeer* _peer) const;
bool peerShouldGrabChain(EthereumPeer* _peer) const;
bool peerCanHelp(EthereumPeer* _peer) const;
void estimatePeerHashes(EthereumPeer* _peer);
BlockChain const& m_chain;
@ -153,8 +152,6 @@ private:
h256s m_hashes; ///< List of hashes with unknown block numbers. Used for PV60 chain downloading and catching up to a particular unknown
unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only.
bool m_syncingV61 = false; ///< True if recent activity was over pv61+. Used for status reporting only.
std::unordered_set<p2p::NodeId> m_rudeNodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible.
std::unordered_set<std::string> m_rudeClients; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible.
};
}

37
libethereum/EthereumPeer.cpp

@ -25,6 +25,7 @@
#include <libdevcore/Common.h>
#include <libethcore/Exceptions.h>
#include <libp2p/Session.h>
#include <libp2p/Host.h>
#include "BlockChain.h"
#include "EthereumHost.h"
#include "TransactionQueue.h"
@ -40,8 +41,7 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, Cap
m_hashSub(host()->hashDownloadMan()),
m_peerCapabilityVersion(_cap.second)
{
m_isRude = host()->isRude(session()->id(), session()->info().clientVersion);
session()->addNote("manners", m_isRude ? "RUDE" : "nice");
session()->addNote("manners", isRude() ? "RUDE" : "nice");
m_syncHashNumber = host()->chain().number() + 1;
requestStatus();
}
@ -52,16 +52,20 @@ EthereumPeer::~EthereumPeer()
abortSync();
}
void EthereumPeer::abortSync()
bool EthereumPeer::isRude() const
{
host()->onPeerAborting(this);
return repMan().isRude(*session(), name());
}
void EthereumPeer::setRude()
{
m_isRude = true;
host()->noteRude(session()->id(), session()->info().clientVersion);
session()->addNote("manners", m_isRude ? "RUDE" : "nice");
repMan().noteRude(*session(), name());
session()->addNote("manners", "RUDE");
}
void EthereumPeer::abortSync()
{
host()->onPeerAborting(this);
}
EthereumHost* EthereumPeer::host() const
@ -136,7 +140,7 @@ void EthereumPeer::requestHashes(h256 const& _lastHash)
void EthereumPeer::requestBlocks()
{
setAsking(Asking::Blocks);
auto blocks = m_sub.nextFetch(c_maxBlocksAsk);
auto blocks = m_sub.nextFetch(isRude() ? 1 : c_maxBlocksAsk);
if (blocks.size())
{
RLPStream s;
@ -156,7 +160,7 @@ void EthereumPeer::setAsking(Asking _a)
m_lastAsk = chrono::system_clock::now();
session()->addNote("ask", _a == Asking::Nothing ? "nothing" : _a == Asking::State ? "state" : _a == Asking::Hashes ? "hashes" : _a == Asking::Blocks ? "blocks" : "?");
session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : ""));
session()->addNote("sync", string(isCriticalSyncing() ? "ONGOING" : "holding") + (needsSyncing() ? " & needed" : ""));
}
void EthereumPeer::tick()
@ -166,11 +170,16 @@ void EthereumPeer::tick()
session()->disconnect(PingTimeout);
}
bool EthereumPeer::isSyncing() const
bool EthereumPeer::isConversing() const
{
return m_asking != Asking::Nothing;
}
bool EthereumPeer::isCriticalSyncing() const
{
return m_asking == Asking::Hashes || m_asking == Asking::State || (m_asking == Asking::Blocks && m_protocolVersion == 60);
}
bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
{
try
@ -185,10 +194,18 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
m_latestHash = _r[3].toHash<h256>();
m_genesisHash = _r[4].toHash<h256>();
if (m_peerCapabilityVersion == host()->protocolVersion())
{
if (_r.itemCount() != 6)
{
clog(NetImpolite) << "Peer does not support PV61+ status extension.";
m_protocolVersion = EthereumHost::c_oldProtocolVersion;
}
else
{
m_protocolVersion = host()->protocolVersion();
m_latestBlockNumber = _r[5].toInt<u256>();
}
}
clog(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << m_genesisHash << "/" << m_latestBlockNumber << ", TD:" << m_totalDifficulty << "=" << m_latestHash;
setAsking(Asking::Nothing);

11
libethereum/EthereumPeer.h

@ -83,7 +83,7 @@ public:
void requestBlocks();
/// Check if this node is rude.
bool isRude() const { return m_isRude; }
bool isRude() const;
/// Set that it's a rude node.
void setRude();
@ -109,8 +109,11 @@ private:
/// Do we presently need syncing with this peer?
bool needsSyncing() const { return !isRude() && !!m_latestHash; }
/// Are we presently syncing with this peer?
bool isSyncing() const;
/// Are we presently in the process of communicating with this peer?
bool isConversing() const;
/// Are we presently in a critical part of the syncing process with this peer?
bool isCriticalSyncing() const;
/// Runs period checks to check up on the peer.
void tick();
@ -152,8 +155,6 @@ private:
h256Hash m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them).
Mutex x_knownTransactions;
h256Hash m_knownTransactions; ///< Transactions that the peer already knows of.
bool m_isRude; ///< True if this node has been rude in the past.
};
}

22
libethereum/Executive.cpp

@ -46,6 +46,8 @@ bool changesMemory(Instruction _inst)
return
_inst == Instruction::MSTORE ||
_inst == Instruction::MSTORE8 ||
_inst == Instruction::MLOAD ||
_inst == Instruction::CREATE ||
_inst == Instruction::CALL ||
_inst == Instruction::CALLCODE ||
_inst == Instruction::SHA3 ||
@ -71,6 +73,7 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS
stack.append(toHex(toCompactBigEndian(i), 1));
r["stack"] = stack;
bool returned = false;
bool newContext = false;
Instruction lastInst = Instruction::STOP;
@ -84,6 +87,7 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS
else if (m_lastInst.size() == ext.depth + 2)
{
// returned from old context
returned = true;
m_lastInst.pop_back();
lastInst = m_lastInst.back();
}
@ -91,6 +95,7 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS
{
// continuing in previous context
lastInst = m_lastInst.back();
m_lastInst.back() = inst;
}
else
{
@ -101,10 +106,10 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS
if (changesMemory(lastInst) || newContext)
{
Json::Value mem(Json::arrayValue);
for (auto const& i: vm.memory())
mem.append(toHex(toCompactBigEndian(i), 1));
r["memory"] = mem;
if (vm.memory().size() < 1024)
r["memory"] = toHex(vm.memory());
else
r["sha3memory"] = sha3(vm.memory()).hex();
}
if (changesStorage(lastInst) || newContext)
@ -115,21 +120,26 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS
r["storage"] = storage;
}
if (returned)
r["depth"] = ext.depth;
if (newContext)
r["address"] = ext.myAddress.hex();
r["steps"] = (unsigned)_steps;
r["inst"] = (unsigned)inst;
if (m_showMnemonics)
r["instname"] = instructionInfo(inst).name;
r["pc"] = toString(vm.curPC());
r["gas"] = toString(gas);
r["gascost"] = toString(gasCost);
if (!!newMemSize)
r["memexpand"] = toString(newMemSize);
m_trace->append(r);
}
string StandardTrace::json() const
string StandardTrace::json(bool _styled) const
{
return Json::FastWriter().write(*m_trace);
return _styled ? Json::StyledWriter().write(*m_trace) : Json::FastWriter().write(*m_trace);
}
Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level):

5
libethereum/Executive.h

@ -49,9 +49,12 @@ public:
StandardTrace();
void operator()(uint64_t _steps, Instruction _inst, bigint _newMemSize, bigint _gasCost, bigint _gas, VM* _vm, ExtVMFace const* _extVM);
std::string json() const;
void setShowMnemonics() { m_showMnemonics = true; }
std::string json(bool _styled = false) const;
private:
bool m_showMnemonics = false;
std::vector<Instruction> m_lastInst;
std::shared_ptr<Json::Value> m_trace;
};

72
libethereum/State.cpp

@ -607,6 +607,8 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire
u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir)
{
DEV_TIMED_FUNCTION_ABOVE(500);
// m_currentBlock is assumed to be prepopulated and reset.
#if !ETH_RELEASE
assert(m_previousBlock.hash() == _block.info.parentHash);
@ -625,13 +627,17 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
// cnote << "playback begins:" << m_state.root();
// cnote << m_state;
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number);
LastHashes lh;
DEV_TIMED_ABOVE(lastHashes, 500)
lh = _bc.lastHashes((unsigned)m_previousBlock.number);
RLP rlp(_block.block);
vector<bytes> receipts;
// All ok with the block generally. Play back the transactions now...
unsigned i = 0;
DEV_TIMED_ABOVE(txEcec, 500)
for (auto const& tr: _block.transactions)
{
try
@ -641,11 +647,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
}
catch (Exception& ex)
{
badBlock(_block.block, "Invalid transaction: " + toString(toTransactionException(ex)));
cwarn << " Transaction Index:" << i;
LogOverride<ExecutiveWarnChannel> o(true);
DEV_IGNORE_EXCEPTIONS(execute(lh, tr));
ex << errinfo_transactionIndex(i);
throw;
}
@ -656,22 +657,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
++i;
}
auto receiptsRoot = orderedTrieRoot(receipts);
h256 receiptsRoot;
DEV_TIMED_ABOVE(receiptsRoot, 500)
receiptsRoot = orderedTrieRoot(receipts);
if (receiptsRoot != m_currentBlock.receiptsRoot)
{
badBlock(_block.block, "Bad receipts state root");
cwarn << " Received: " << toString(m_currentBlock.receiptsRoot);
cwarn << " Expected: " << toString(receiptsRoot) << " which is:";
for (unsigned j = 0; j < i; ++j)
{
auto b = receipts[j];
cwarn << j << ": ";
cwarn << " RLP: " << RLP(b);
cwarn << " Hex: " << toHex(b);
cwarn << " " << TransactionReceipt(&b);
}
cwarn << " VMTrace:\n" << vmTrace(_block.block, _bc, _ir);
InvalidReceiptsStateRoot ex;
ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot);
ex << errinfo_receipts(receipts);
@ -681,14 +672,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
if (m_currentBlock.logBloom != logBloom())
{
badBlock(_block.block, "Bad log bloom");
cwarn << " Receipt blooms:";
for (unsigned j = 0; j < i; ++j)
{
auto b = receipts[j];
cwarn << " " << j << ":" << TransactionReceipt(&b).bloom().hex();
}
cwarn << " Final bloom:" << m_currentBlock.logBloom.hex();
InvalidLogBloom ex;
ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom);
ex << errinfo_receipts(receipts);
@ -701,15 +684,20 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
// Check uncles & apply their rewards to state.
if (rlp[2].itemCount() > 2)
{
badBlock(_block.block, "Too many uncles");
BOOST_THROW_EXCEPTION(TooManyUncles() << errinfo_max(2) << errinfo_got(rlp[2].itemCount()));
TooManyUncles ex;
ex << errinfo_max(2);
ex << errinfo_got(rlp[2].itemCount());
BOOST_THROW_EXCEPTION(ex);
}
vector<BlockInfo> rewarded;
h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6);
h256Hash excluded;
DEV_TIMED_ABOVE(allKin, 500)
excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6);
excluded.insert(m_currentBlock.hash());
unsigned ii = 0;
DEV_TIMED_ABOVE(uncleCheck, 500)
for (auto const& i: rlp[2])
{
try
@ -717,7 +705,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
auto h = sha3(i.data());
if (excluded.count(h))
{
badBlock(_block.block, "Invalid uncle included");
UncleInChain ex;
ex << errinfo_comment("Uncle in block already mentioned");
ex << errinfo_unclesExcluded(excluded);
@ -726,19 +713,15 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
}
excluded.insert(h);
BlockInfo uncle;
BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h);
BlockInfo uncleParent;
uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h);
if (!_bc.isKnown(uncle.parentHash))
BOOST_THROW_EXCEPTION(UnknownParent());
uncleParent = BlockInfo(_bc.block(uncle.parentHash));
if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7)
{
badBlock(_block.block, "Uncle too old");
cwarn << " Uncle number: " << uncle.number;
cwarn << " Uncle parent number: " << uncleParent.number;
cwarn << " Block number: " << m_currentBlock.number;
UncleTooOld ex;
ex << errinfo_uncleNumber(uncle.number);
ex << errinfo_currentNumber(m_currentBlock.number);
@ -746,10 +729,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
}
else if (uncle.number == m_currentBlock.number)
{
badBlock(_block.block, "Uncle is brother");
cwarn << " Uncle number: " << uncle.number;
cwarn << " Uncle parent number: " << uncleParent.number;
cwarn << " Block number: " << m_currentBlock.number;
UncleIsBrother ex;
ex << errinfo_uncleNumber(uncle.number);
ex << errinfo_currentNumber(m_currentBlock.number);
@ -757,7 +736,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
}
uncle.verifyParent(uncleParent);
// tdIncrease += uncle.difficulty;
rewarded.push_back(uncle);
++ii;
}
@ -768,15 +746,16 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
}
}
DEV_TIMED_ABOVE(applyRewards, 500)
applyRewards(rewarded);
// Commit all cached state changes to the state trie.
DEV_TIMED_ABOVE(commit, 500)
commit();
// Hash the state trie and check against the state_root hash in m_currentBlock.
if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash())
{
badBlock(_block.block, "Bad state root");
m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot));
}
@ -784,7 +763,6 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
if (m_currentBlock.gasUsed != gasUsed())
{
// Rollback the trie.
badBlock(_block.block, "Invalid gas used");
m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed)));
}
@ -1201,6 +1179,8 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
return true;
}
#define ETH_VMTIMER 1
ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp)
{
#if ETH_PARANOIA

21
libethereum/Transaction.cpp

@ -39,27 +39,6 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, ExecutionResult const& _e
return _out;
}
std::string badTransaction(bytesConstRef _tx, string const& _err)
{
stringstream ret;
ret << "========================================================================" << endl;
ret << "== Software Failure " << (_err + string(max<int>(0, 44 - _err.size()), ' ')) << " ==" << endl;
ret << "== Guru Meditation " << sha3(_tx).abridged() << " ==" << endl;
ret << "========================================================================" << endl;
ret << " Transaction: " << toHex(_tx) << endl;
ret << " Transaction RLP: ";
try {
ret << RLP(_tx);
}
catch (Exception& _e)
{
ret << "Invalid: " << _e.what();
}
ret << endl;
return ret.str();
}
TransactionException dev::eth::toTransactionException(Exception const& _e)
{
// Basic Transaction exceptions

3
libethereum/Transaction.h

@ -228,8 +228,5 @@ inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t)
return _out;
}
void badTransaction(bytesConstRef _tx, std::string const& _err);
inline void badTransaction(bytes const& _tx, std::string const& _err) { badTransaction(&_tx, _err); }
}
}

12
libp2p/Capability.cpp

@ -23,18 +23,19 @@
#include <libdevcore/Log.h>
#include "Session.h"
#include "Host.h"
using namespace std;
using namespace dev;
using namespace dev::p2p;
Capability::Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_host(_h), m_idOffset(_idOffset)
Capability::Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_hostCap(_h), m_idOffset(_idOffset)
{
clog(NetConnect) << "New session for capability" << m_host->name() << "; idOffset:" << m_idOffset;
clog(NetConnect) << "New session for capability" << m_hostCap->name() << "; idOffset:" << m_idOffset;
}
void Capability::disable(std::string const& _problem)
{
clog(NetWarn) << "DISABLE: Disabling capability '" << m_host->name() << "'. Reason:" << _problem;
clog(NetWarn) << "DISABLE: Disabling capability '" << m_hostCap->name() << "'. Reason:" << _problem;
m_enabled = false;
}
@ -52,3 +53,8 @@ void Capability::addRating(int _r)
{
m_session->addRating(_r);
}
ReputationManager& Capability::repMan() const
{
return host()->repMan();
}

8
libp2p/Capability.h

@ -29,6 +29,8 @@ namespace dev
namespace p2p
{
class ReputationManager;
class Capability
{
friend class Session;
@ -43,7 +45,9 @@ public:
static unsigned messageCount() { return 0; }
*/
Session* session() const { return m_session; }
HostCapabilityFace* hostCapability() const { return m_host; }
HostCapabilityFace* hostCapability() const { return m_hostCap; }
Host* host() const { return m_hostCap->host(); }
ReputationManager& repMan() const;
protected:
virtual bool interpret(unsigned _id, RLP const&) = 0;
@ -56,7 +60,7 @@ protected:
private:
Session* m_session;
HostCapabilityFace* m_host;
HostCapabilityFace* m_hostCap;
bool m_enabled = true;
unsigned m_idOffset;
};

19
libp2p/Host.cpp

@ -55,6 +55,25 @@ void HostNodeTableHandler::processEvent(NodeId const& _n, NodeTableEventType con
m_host.onNodeTableEvent(_n, _e);
}
ReputationManager::ReputationManager()
{
}
void ReputationManager::noteRude(Session const& _s, std::string const& _sub)
{
m_nodes[make_pair(_s.id(), _s.info().clientVersion)].subs[_sub].isRude = true;
}
bool ReputationManager::isRude(Session const& _s, std::string const& _sub) const
{
auto nit = m_nodes.find(make_pair(_s.id(), _s.info().clientVersion));
if (nit == m_nodes.end())
return false;
auto sit = nit->second.subs.find(_sub);
bool ret = sit == nit->second.subs.end() ? false : sit->second.isRude;
return _sub.empty() ? ret : (ret || isRude(_s));
}
Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bytesConstRef _restoreNetwork):
Worker("p2p", 0),
m_restoreNetwork(_restoreNetwork.toBytes()),

40
libp2p/Host.h

@ -45,6 +45,18 @@
namespace ba = boost::asio;
namespace bi = ba::ip;
namespace std
{
template<> struct hash<pair<dev::p2p::NodeId, string>>
{
size_t operator()(pair<dev::p2p::NodeId, string> const& _value) const
{
size_t ret = hash<dev::p2p::NodeId>()(_value.first);
return ret ^ (hash<string>()(_value.second) + 0x9e3779b9 + (ret << 6) + (ret >> 2));
}
};
}
namespace dev
{
@ -66,6 +78,29 @@ private:
Host& m_host;
};
struct SubReputation
{
bool isRude = false;
int utility = 0;
};
struct Reputation
{
std::unordered_map<std::string, SubReputation> subs;
};
class ReputationManager
{
public:
ReputationManager();
void noteRude(Session const& _s, std::string const& _sub = std::string());
bool isRude(Session const& _s, std::string const& _sub = std::string()) const;
private:
std::unordered_map<std::pair<p2p::NodeId, std::string>, Reputation> m_nodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible.
};
/**
* @brief The Host class
* Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe.
@ -152,6 +187,9 @@ public:
/// @returns if network has been started.
bool isStarted() const { return isWorking(); }
/// @returns our reputation manager.
ReputationManager& repMan() { return m_repMan; }
/// @returns if network is started and interactive.
bool haveNetwork() const { return m_run && !!m_nodeTable; }
@ -255,6 +293,8 @@ private:
std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers.
bool m_accepting = false;
bool m_dropPeers = false;
ReputationManager m_repMan;
};
}

6
libp2p/Session.cpp

@ -70,6 +70,11 @@ Session::~Session()
delete m_io;
}
ReputationManager& Session::repMan() const
{
return m_server->repMan();
}
NodeId Session::id() const
{
return m_peer ? m_peer->id : NodeId();
@ -450,6 +455,7 @@ void Session::doRead()
else if (ec && length < tlen)
{
clog(NetWarn) << "Error reading - Abrupt peer disconnect: " << ec.message();
repMan().noteRude(*this);
drop(TCPError);
return;
}

2
libp2p/Session.h

@ -43,6 +43,7 @@ namespace p2p
{
class Peer;
class ReputationManager;
/**
* @brief The Session class
@ -75,6 +76,7 @@ public:
static RLPStream& prep(RLPStream& _s, PacketType _t, unsigned _args = 0);
void sealAndSend(RLPStream& _s);
ReputationManager& repMan() const;
int rating() const;
void addRating(int _r);

109
libsolidity/InterfaceHandler.cpp

@ -16,8 +16,10 @@ InterfaceHandler::InterfaceHandler()
m_lastTag = DocTagType::None;
}
std::unique_ptr<std::string> InterfaceHandler::getDocumentation(ContractDefinition const& _contractDef,
DocumentationType _type)
unique_ptr<string> InterfaceHandler::getDocumentation(
ContractDefinition const& _contractDef,
DocumentationType _type
)
{
switch(_type)
{
@ -35,7 +37,7 @@ std::unique_ptr<std::string> InterfaceHandler::getDocumentation(ContractDefiniti
return nullptr;
}
std::unique_ptr<std::string> InterfaceHandler::getABIInterface(ContractDefinition const& _contractDef)
unique_ptr<string> InterfaceHandler::getABIInterface(ContractDefinition const& _contractDef)
{
Json::Value abi(Json::arrayValue);
@ -101,7 +103,7 @@ std::unique_ptr<std::string> InterfaceHandler::getABIInterface(ContractDefinitio
event["inputs"] = params;
abi.append(event);
}
return std::unique_ptr<std::string>(new std::string(Json::FastWriter().write(abi)));
return unique_ptr<string>(new string(Json::FastWriter().write(abi)));
}
unique_ptr<string> InterfaceHandler::getABISolidityInterface(ContractDefinition const& _contractDef)
@ -141,7 +143,7 @@ unique_ptr<string> InterfaceHandler::getABISolidityInterface(ContractDefinition
return unique_ptr<string>(new string(ret + "}"));
}
std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefinition const& _contractDef)
unique_ptr<string> InterfaceHandler::getUserDocumentation(ContractDefinition const& _contractDef)
{
Json::Value doc;
Json::Value methods(Json::objectValue);
@ -163,10 +165,10 @@ std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefi
}
doc["methods"] = methods;
return std::unique_ptr<std::string>(new std::string(Json::FastWriter().write(doc)));
return unique_ptr<string>(new string(Json::FastWriter().write(doc)));
}
std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefinition const& _contractDef)
unique_ptr<string> InterfaceHandler::getDevDocumentation(ContractDefinition const& _contractDef)
{
// LTODO: Somewhere in this function warnings for mismatch of param names
// should be thrown
@ -203,7 +205,7 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin
method["author"] = m_author;
Json::Value params(Json::objectValue);
std::vector<std::string> paramNames = it.second->getParameterNames();
vector<string> paramNames = it.second->getParameterNames();
for (auto const& pair: m_params)
{
if (find(paramNames.begin(), paramNames.end(), pair.first) == paramNames.end())
@ -227,7 +229,7 @@ std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefin
}
doc["methods"] = methods;
return std::unique_ptr<std::string>(new std::string(Json::FastWriter().write(doc)));
return unique_ptr<string>(new string(Json::FastWriter().write(doc)));
}
/* -- private -- */
@ -244,48 +246,56 @@ void InterfaceHandler::resetDev()
m_params.clear();
}
static inline std::string::const_iterator skipLineOrEOS(std::string::const_iterator _nlPos,
std::string::const_iterator _end)
static inline string::const_iterator skipLineOrEOS(
string::const_iterator _nlPos,
string::const_iterator _end
)
{
return (_nlPos == _end) ? _end : ++_nlPos;
}
std::string::const_iterator InterfaceHandler::parseDocTagLine(std::string::const_iterator _pos,
std::string::const_iterator _end,
std::string& _tagString,
string::const_iterator InterfaceHandler::parseDocTagLine(
string::const_iterator _pos,
string::const_iterator _end,
string& _tagString,
DocTagType _tagType,
bool _appending)
bool _appending
)
{
auto nlPos = std::find(_pos, _end, '\n');
auto nlPos = find(_pos, _end, '\n');
if (_appending && _pos < _end && *_pos != ' ')
_tagString += " ";
std::copy(_pos, nlPos, back_inserter(_tagString));
copy(_pos, nlPos, back_inserter(_tagString));
m_lastTag = _tagType;
return skipLineOrEOS(nlPos, _end);
}
std::string::const_iterator InterfaceHandler::parseDocTagParam(std::string::const_iterator _pos,
std::string::const_iterator _end)
string::const_iterator InterfaceHandler::parseDocTagParam(
string::const_iterator _pos,
string::const_iterator _end
)
{
// find param name
auto currPos = std::find(_pos, _end, ' ');
auto currPos = find(_pos, _end, ' ');
if (currPos == _end)
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of param name not found" + std::string(_pos, _end)));
BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of param name not found" + string(_pos, _end)));
auto paramName = std::string(_pos, currPos);
auto paramName = string(_pos, currPos);
currPos += 1;
auto nlPos = std::find(currPos, _end, '\n');
auto paramDesc = std::string(currPos, nlPos);
m_params.push_back(std::make_pair(paramName, paramDesc));
auto nlPos = find(currPos, _end, '\n');
auto paramDesc = string(currPos, nlPos);
m_params.push_back(make_pair(paramName, paramDesc));
m_lastTag = DocTagType::Param;
return skipLineOrEOS(nlPos, _end);
}
std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::const_iterator _pos,
std::string::const_iterator _end)
string::const_iterator InterfaceHandler::appendDocTagParam(
string::const_iterator _pos,
string::const_iterator _end
)
{
// Should never be called with an empty vector
solAssert(!m_params.empty(), "Internal: Tried to append to empty parameter");
@ -293,18 +303,20 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con
auto pair = m_params.back();
if (_pos < _end && *_pos != ' ')
pair.second += " ";
auto nlPos = std::find(_pos, _end, '\n');
std::copy(_pos, nlPos, back_inserter(pair.second));
auto nlPos = find(_pos, _end, '\n');
copy(_pos, nlPos, back_inserter(pair.second));
m_params.at(m_params.size() - 1) = pair;
return skipLineOrEOS(nlPos, _end);
}
std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_iterator _pos,
std::string::const_iterator _end,
std::string const& _tag,
CommentOwner _owner)
string::const_iterator InterfaceHandler::parseDocTag(
string::const_iterator _pos,
string::const_iterator _end,
string const& _tag,
CommentOwner _owner
)
{
// LTODO: need to check for @(start of a tag) between here and the end of line
// for all cases. Also somehow automate list of acceptable tags for each
@ -345,9 +357,11 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite
return appendDocTag(_pos, _end, _owner);
}
std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_iterator _pos,
std::string::const_iterator _end,
CommentOwner _owner)
string::const_iterator InterfaceHandler::appendDocTag(
string::const_iterator _pos,
string::const_iterator _end,
CommentOwner _owner
)
{
switch (m_lastTag)
{
@ -379,33 +393,36 @@ std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_it
}
}
static inline std::string::const_iterator getFirstSpaceOrNl(std::string::const_iterator _pos,
std::string::const_iterator _end)
static inline string::const_iterator getFirstSpaceOrNl(
string::const_iterator _pos,
string::const_iterator _end
)
{
auto spacePos = std::find(_pos, _end, ' ');
auto nlPos = std::find(_pos, _end, '\n');
auto spacePos = find(_pos, _end, ' ');
auto nlPos = find(_pos, _end, '\n');
return (spacePos < nlPos) ? spacePos : nlPos;
}
void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _owner)
void InterfaceHandler::parseDocString(string const& _string, CommentOwner _owner)
{
auto currPos = _string.begin();
auto end = _string.end();
while (currPos != end)
{
auto tagPos = std::find(currPos, end, '@');
auto nlPos = std::find(currPos, end, '\n');
auto tagPos = find(currPos, end, '@');
auto nlPos = find(currPos, end, '\n');
if (tagPos != end && tagPos < nlPos)
{
// we found a tag
auto tagNameEndPos = getFirstSpaceOrNl(tagPos, end);
if (tagNameEndPos == end)
BOOST_THROW_EXCEPTION(DocstringParsingError() <<
errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found"));
BOOST_THROW_EXCEPTION(
DocstringParsingError() <<
errinfo_comment("End of tag " + string(tagPos, tagNameEndPos) + "not found"));
currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos), _owner);
currPos = parseDocTag(tagNameEndPos + 1, end, string(tagPos + 1, tagNameEndPos), _owner);
}
else if (m_lastTag != DocTagType::None) // continuation of the previous tag
currPos = appendDocTag(currPos, end, _owner);

36
libsolidity/InterfaceHandler.h

@ -67,8 +67,10 @@ public:
/// types provided by @c DocumentationType
/// @return A unique pointer contained string with the json
/// representation of provided type
std::unique_ptr<std::string> getDocumentation(ContractDefinition const& _contractDef,
DocumentationType _type);
std::unique_ptr<std::string> getDocumentation(
ContractDefinition const& _contractDef,
DocumentationType _type
);
/// Get the ABI Interface of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
@ -90,23 +92,33 @@ private:
void resetUser();
void resetDev();
std::string::const_iterator parseDocTagLine(std::string::const_iterator _pos,
std::string::const_iterator parseDocTagLine(
std::string::const_iterator _pos,
std::string::const_iterator _end,
std::string& _tagString,
DocTagType _tagType,
bool _appending);
std::string::const_iterator parseDocTagParam(std::string::const_iterator _pos,
std::string::const_iterator _end);
std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos,
std::string::const_iterator _end);
bool _appending
);
std::string::const_iterator parseDocTagParam(
std::string::const_iterator _pos,
std::string::const_iterator _end
);
std::string::const_iterator appendDocTagParam(
std::string::const_iterator _pos,
std::string::const_iterator _end
);
void parseDocString(std::string const& _string, CommentOwner _owner);
std::string::const_iterator appendDocTag(std::string::const_iterator _pos,
std::string::const_iterator appendDocTag(
std::string::const_iterator _pos,
std::string::const_iterator _end,
CommentOwner _owner);
std::string::const_iterator parseDocTag(std::string::const_iterator _pos,
CommentOwner _owner
);
std::string::const_iterator parseDocTag(
std::string::const_iterator _pos,
std::string::const_iterator _end,
std::string const& _tag,
CommentOwner _owner);
CommentOwner _owner
);
// internal state
DocTagType m_lastTag;

Loading…
Cancel
Save