Browse Source

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

cl-refactor
Marek Kotewicz 10 years ago
parent
commit
6f5b824bf4
  1. 4
      alethzero/MainWin.cpp
  2. 2
      alethzero/MainWin.h
  3. 6
      alethzero/NatspecHandler.h
  4. 195
      eth/main.cpp
  5. 7
      ethminer/CMakeLists.txt
  6. 7
      ethminer/MinerAux.h
  7. 5
      json_spirit/json_spirit_writer_template.h
  8. 39
      libdevcore/Exceptions.h
  9. 2
      libdevcore/FixedHash.h
  10. 8
      libdevcore/Log.cpp
  11. 3
      libdevcore/Log.h
  12. 8
      libdevcore/RangeMask.h
  13. 4
      libdevcrypto/Common.cpp
  14. 2
      libdevcrypto/CryptoPP.cpp
  15. 2
      libdevcrypto/CryptoPP.h
  16. 4
      libdevcrypto/OverlayDB.cpp
  17. 51
      libethash-cl/ethash_cl_miner.cpp
  18. 5
      libethash-cl/ethash_cl_miner.h
  19. 24
      libethcore/BlockInfo.cpp
  20. 15
      libethcore/Ethash.cpp
  21. 6
      libethcore/Ethash.h
  22. 77
      libethcore/Exceptions.h
  23. 48
      libethereum/BlockChain.cpp
  24. 5
      libethereum/BlockChain.h
  25. 55
      libethereum/BlockQueue.cpp
  26. 4
      libethereum/BlockQueue.h
  27. 7
      libethereum/CMakeLists.txt
  28. 167
      libethereum/Client.cpp
  29. 35
      libethereum/Client.h
  30. 5
      libethereum/ClientBase.cpp
  31. 8
      libethereum/ClientBase.h
  32. 7
      libethereum/CommonNet.h
  33. 7
      libethereum/DownloadMan.cpp
  34. 8
      libethereum/DownloadMan.h
  35. 113
      libethereum/EthereumHost.cpp
  36. 16
      libethereum/EthereumHost.h
  37. 33
      libethereum/EthereumPeer.cpp
  38. 15
      libethereum/EthereumPeer.h
  39. 118
      libethereum/Executive.cpp
  40. 18
      libethereum/Executive.h
  41. 2
      libethereum/Interface.h
  42. 8
      libethereum/Precompiled.cpp
  43. 31
      libethereum/Sentinel.h
  44. 3
      libethereum/Sentinel.json
  45. 157
      libethereum/State.cpp
  46. 28
      libethereum/State.h
  47. 43
      libethereum/Transaction.cpp
  48. 6
      libethereum/Transaction.h
  49. 322
      libevm/VM.cpp
  50. 6
      libevm/VM.h
  51. 1
      libevm/VMFace.h
  52. 2
      libevmasm/Assembly.cpp
  53. 4
      libevmcore/Exceptions.h
  54. 4
      libp2p/Common.h
  55. 4
      libp2p/Host.cpp
  56. 2
      libp2p/Network.cpp
  57. 12
      libp2p/NodeTable.cpp
  58. 4
      libp2p/RLPxFrameIO.cpp
  59. 4
      libp2p/UDP.cpp
  60. 2
      libp2p/UDP.h
  61. 42
      libsolidity/AST.cpp
  62. 2
      libsolidity/AST.h
  63. 2
      libsolidity/CompilerContext.cpp
  64. 2
      libsolidity/LValue.h
  65. 12
      libsolidity/Types.cpp
  66. 4
      libsolidity/Types.h
  67. 2
      libtestutils/FixedClient.h
  68. 2
      libweb3jsonrpc/WebThreeStubServer.h
  69. 8
      libwhisper/WhisperHost.h
  70. 4
      mix/ClientModel.cpp
  71. 2
      mix/CodeModel.cpp
  72. 44
      mix/MixClient.cpp
  73. 2
      mix/MixClient.h
  74. BIN
      mix/qml/img/addblock.png
  75. BIN
      mix/qml/img/addblock@2x.png
  76. BIN
      mix/qml/img/duplicateicon.png
  77. BIN
      mix/qml/img/duplicateicon@2x.png
  78. BIN
      mix/qml/img/leftarrow.png
  79. BIN
      mix/qml/img/leftarrow@2x.png
  80. BIN
      mix/qml/img/newaccounticon.png
  81. BIN
      mix/qml/img/newaccounticon@2x.png
  82. BIN
      mix/qml/img/recyclediscard.png
  83. BIN
      mix/qml/img/recyclediscard@2x.png
  84. BIN
      mix/qml/img/recycleicon.png
  85. BIN
      mix/qml/img/recycleicon@2x.png
  86. BIN
      mix/qml/img/recyclekeep.png
  87. BIN
      mix/qml/img/recyclekeep@2x.png
  88. BIN
      mix/qml/img/restoreicon.png
  89. BIN
      mix/qml/img/restoreicon@2x.png
  90. BIN
      mix/qml/img/rightarrow.png
  91. BIN
      mix/qml/img/rightarrow@2x.png
  92. BIN
      mix/qml/img/saveicon.png
  93. BIN
      mix/qml/img/saveicon@2x.png
  94. BIN
      mix/qml/img/sendtransactionicon.png
  95. BIN
      mix/qml/img/sendtransactionicon@2x.png
  96. 2384
      test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json
  97. 38
      test/libethereum/StateTestsFiller/stSpecialTestFiller.json
  98. 15
      test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json
  99. 2
      test/libp2p/net.cpp
  100. 4
      test/libwhisper/whisperMessage.cpp

4
alethzero/MainWin.cpp

@ -1240,7 +1240,9 @@ void Main::refreshBlockCount()
{ {
auto d = ethereum()->blockChain().details(); auto d = ethereum()->blockChain().details();
BlockQueueStatus b = ethereum()->blockQueueStatus(); BlockQueueStatus b = ethereum()->blockQueueStatus();
ui->chainStatus->setText(QString("%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)); 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));
} }
void Main::on_turboMining_triggered() void Main::on_turboMining_triggered()

2
alethzero/MainWin.h

@ -238,7 +238,7 @@ private:
void installNameRegWatch(); void installNameRegWatch();
void installBalancesWatch(); void installBalancesWatch();
virtual void timerEvent(QTimerEvent*); virtual void timerEvent(QTimerEvent*) override;
void refreshNetwork(); void refreshNetwork();
void refreshMining(); void refreshMining();

6
alethzero/NatspecHandler.h

@ -39,17 +39,17 @@ class NatspecHandler: public NatSpecFace
~NatspecHandler(); ~NatspecHandler();
/// Stores locally in a levelDB a key value pair of contract code hash to natspec documentation /// Stores locally in a levelDB a key value pair of contract code hash to natspec documentation
void add(dev::h256 const& _contractHash, std::string const& _doc); virtual void add(dev::h256 const& _contractHash, std::string const& _doc) override;
/// Retrieves the natspec documentation as a string given a contract code hash /// Retrieves the natspec documentation as a string given a contract code hash
std::string retrieve(dev::h256 const& _contractHash) const override; std::string retrieve(dev::h256 const& _contractHash) const override;
/// Given a json natspec string and the transaction data return the user notice /// Given a json natspec string and the transaction data return the user notice
std::string getUserNotice(std::string const& json, const dev::bytes& _transactionData); virtual std::string getUserNotice(std::string const& json, const dev::bytes& _transactionData) override;
/// Given a contract code hash and the transaction's data retrieve the natspec documention's /// Given a contract code hash and the transaction's data retrieve the natspec documention's
/// user notice for that transaction. /// user notice for that transaction.
/// @returns The user notice or an empty string if no natspec for the contract exists /// @returns The user notice or an empty string if no natspec for the contract exists
/// or if the existing natspec does not document the @c _methodName /// or if the existing natspec does not document the @c _methodName
std::string getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionDacta); virtual std::string getUserNotice(dev::h256 const& _contractHash, dev::bytes const& _transactionDacta) override;
private: private:
ldb::ReadOptions m_readOptions; ldb::ReadOptions m_readOptions;

195
eth/main.cpp

@ -84,15 +84,24 @@ void interactiveHelp()
<< " minestop Stops mining." << endl << " minestop Stops mining." << endl
<< " mineforce <enable> Forces mining, even when there are no transactions." << endl << " mineforce <enable> Forces mining, even when there are no transactions." << endl
<< " block Gives the current block height." << 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 << " 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 << " newaccount <name> Creates a new account with the given name." << endl
<< " transact Execute a given transaction." << endl << " transact Execute a given transaction." << endl
<< " txcreate Execute a given contract creation transaction." << endl
<< " send Execute a given transaction with current secret." << endl << " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl << " contract Create a new contract with current secret." << endl
<< " peers List the peers that are connected" << endl << " peers List the peers that are connected" << endl
#if ETH_FATDB || !ETH_TRUE #if ETH_FATDB || !ETH_TRUE
<< " listaccounts List the accounts on the network." << endl << " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts 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 #endif
<< " setsigningkey <addr> Set the address with which to sign transactions." << endl << " setsigningkey <addr> Set the address with which to sign transactions." << endl
<< " setaddress <addr> Set the coinbase (mining payout) address." << endl << " setaddress <addr> Set the coinbase (mining payout) address." << endl
@ -125,6 +134,7 @@ void help()
<< " --session-sign-key <address> Sign all transactions with the key of the given address for this session only." << endl << " --session-sign-key <address> Sign all transactions with the key of the given address for this session only." << endl
<< " --master <password> Give the master password for the key store." << endl << " --master <password> Give the master password for the key store." << endl
<< " --password <password> Give a password for a private key." << endl << " --password <password> Give a password for a private key." << endl
<< " --sentinel <server> Set the sentinel for reporting bad blocks or chain issues." << endl
<< endl << endl
<< "Client transacting:" << endl << "Client transacting:" << endl
/*<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl /*<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl
@ -137,6 +147,7 @@ void help()
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl << " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (default: off)" << endl << " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (default: off)" << endl
<< " -f,--force-mining Mine even when there are no transactions to mine (default: off)" << endl << " -f,--force-mining Mine even when there are no transactions to mine (default: off)" << endl
<< " --mine-on-wrong-chain Mine even when we know it's the wrong chain (default: off)" << endl
<< " -C,--cpu When mining, use the CPU." << endl << " -C,--cpu When mining, use the CPU." << endl
<< " -G,--opencl When mining use the GPU via OpenCL." << endl << " -G,--opencl When mining use the GPU via OpenCL." << endl
<< " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl << " --opencl-platform <n> When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl
@ -278,6 +289,7 @@ int main(int argc, char** argv)
bool upnp = true; bool upnp = true;
WithExisting killChain = WithExisting::Trust; WithExisting killChain = WithExisting::Trust;
bool jit = false; bool jit = false;
string sentinel;
/// Networking params. /// Networking params.
string clientName; string clientName;
@ -293,6 +305,7 @@ int main(int argc, char** argv)
/// Mining params /// Mining params
unsigned mining = 0; unsigned mining = 0;
bool forceMining = false; bool forceMining = false;
bool mineOnWrongChain = false;
Address signingKey; Address signingKey;
Address sessionKey; Address sessionKey;
Address beneficiary = signingKey; Address beneficiary = signingKey;
@ -375,6 +388,10 @@ int main(int argc, char** argv)
mode = OperationMode::Export; mode = OperationMode::Export;
filename = argv[++i]; filename = argv[++i];
} }
else if (arg == "--sentinel" && i + 1 < argc)
sentinel = argv[++i];
else if (arg == "--mine-on-wrong-chain")
mineOnWrongChain = true;
else if (arg == "--format" && i + 1 < argc) else if (arg == "--format" && i + 1 < argc)
{ {
string m = argv[++i]; string m = argv[++i];
@ -670,6 +687,8 @@ int main(int argc, char** argv)
nodeMode == NodeMode::Full ? set<string>{"eth"/*, "shh"*/} : set<string>(), nodeMode == NodeMode::Full ? set<string>{"eth"/*, "shh"*/} : set<string>(),
netPrefs, netPrefs,
&nodesState); &nodesState);
web3.ethereum()->setMineOnBadChain(mineOnWrongChain);
web3.ethereum()->setSentinel(sentinel);
auto toNumber = [&](string const& s) -> unsigned { auto toNumber = [&](string const& s) -> unsigned {
if (s == "latest") if (s == "latest")
@ -961,9 +980,88 @@ int main(int argc, char** argv)
cout << "Current mining beneficiary:" << endl << beneficiary << endl; cout << "Current mining beneficiary:" << endl << beneficiary << endl;
cout << "Current signing account:" << endl << signingKey << 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") else if (c && cmd == "block")
{ {
cout << "Current block: " <<c->blockChain().details().number << endl; 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") else if (cmd == "peers")
{ {
@ -1077,6 +1175,64 @@ int main(int argc, char** argv)
else else
cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA"; 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 #if ETH_FATDB
else if (c && cmd == "listcontracts") else if (c && cmd == "listcontracts")
{ {
@ -1100,6 +1256,43 @@ int main(int argc, char** argv)
cout << ss << endl; 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 #endif
else if (c && cmd == "send") else if (c && cmd == "send")
{ {

7
ethminer/CMakeLists.txt

@ -5,7 +5,10 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
if (JSONRPC)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
endif()
set(EXECUTABLE ethminer) set(EXECUTABLE ethminer)
@ -19,10 +22,6 @@ target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
if (JSONRPC) if (JSONRPC)
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES}) 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() endif()
target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethcore)

7
ethminer/MinerAux.h

@ -127,6 +127,11 @@ public:
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); throw BadArgument();
} }
else if (arg == "--list-devices")
{
ProofOfWork::GPUMiner::listDevices();
exit(0);
}
else if (arg == "--use-chunks") else if (arg == "--use-chunks")
{ {
dagChunks = 4; dagChunks = 4;
@ -175,7 +180,7 @@ public:
m_minerType = MinerType::CPU; m_minerType = MinerType::CPU;
else if (arg == "-G" || arg == "--opencl") else if (arg == "-G" || arg == "--opencl")
{ {
if (!ProofOfWork::GPUMiner::haveSufficientGPUMemory()) if (!ProofOfWork::GPUMiner::haveSufficientMemory())
{ {
cout << "No GPU device with sufficient memory was found. Defaulting to CPU" << endl; cout << "No GPU device with sufficient memory was found. Defaulting to CPU" << endl;
m_minerType = MinerType::CPU; m_minerType = MinerType::CPU;

5
json_spirit/json_spirit_writer_template.h

@ -25,13 +25,9 @@ namespace json_spirit
return 'A' - 10 + ch; return 'A' - 10 + ch;
} }
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs")
template< class String_type > template< class String_type >
String_type non_printable_to_string( unsigned int c ) String_type non_printable_to_string( unsigned int c )
{ {
typedef typename String_type::value_type Char_type;
String_type result( 6, '\\' ); String_type result( 6, '\\' );
result[1] = 'u'; result[1] = 'u';
@ -43,7 +39,6 @@ namespace json_spirit
return result; return result;
} }
#pragma GCC diagnostic pop
template< typename Char_type, class String_type > template< typename Char_type, class String_type >
bool add_esc_char( Char_type c, String_type& s ) bool add_esc_char( Char_type c, String_type& s )

39
libdevcore/Exceptions.h

@ -30,7 +30,8 @@
namespace dev namespace dev
{ {
// base class for all exceptions
/// Base class for all exceptions.
struct Exception: virtual std::exception, virtual boost::exception struct Exception: virtual std::exception, virtual boost::exception
{ {
Exception(std::string _message = std::string()): m_message(std::move(_message)) {} Exception(std::string _message = std::string()): m_message(std::move(_message)) {}
@ -40,20 +41,26 @@ private:
std::string m_message; std::string m_message;
}; };
struct BadHexCharacter: virtual Exception {}; #define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { public: X(): Exception(#X) {} }
struct RLPException: virtual Exception {};
struct BadCast: virtual RLPException {}; /// Base class for all RLP exceptions.
struct BadRLP: virtual RLPException {}; struct RLPException: virtual Exception { RLPException(std::string _message = std::string()): Exception(_message) {} };
struct OversizeRLP: virtual RLPException {}; #define DEV_SIMPLE_EXCEPTION_RLP(X) struct X: virtual RLPException { public: X(): RLPException(#X) {} }
struct UndersizeRLP: virtual RLPException {};
struct NoNetworking: virtual Exception {}; DEV_SIMPLE_EXCEPTION_RLP(BadCast);
struct NoUPnPDevice: virtual Exception {}; DEV_SIMPLE_EXCEPTION_RLP(BadRLP);
struct RootNotFound: virtual Exception {}; DEV_SIMPLE_EXCEPTION_RLP(OversizeRLP);
struct BadRoot: virtual Exception {}; DEV_SIMPLE_EXCEPTION_RLP(UndersizeRLP);
struct FileError: virtual Exception {};
struct Overflow: virtual Exception {}; DEV_SIMPLE_EXCEPTION(BadHexCharacter);
DEV_SIMPLE_EXCEPTION(NoNetworking);
DEV_SIMPLE_EXCEPTION(NoUPnPDevice);
DEV_SIMPLE_EXCEPTION(RootNotFound);
DEV_SIMPLE_EXCEPTION(BadRoot);
DEV_SIMPLE_EXCEPTION(FileError);
DEV_SIMPLE_EXCEPTION(Overflow);
DEV_SIMPLE_EXCEPTION(FailedInvariant);
struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): Exception("Interface " + _f + " not supported.") {} }; struct InterfaceNotSupported: virtual Exception { public: InterfaceNotSupported(std::string _f): Exception("Interface " + _f + " not supported.") {} };
struct FailedInvariant: virtual Exception {};
struct ExternalFunctionFailure: virtual Exception { public: ExternalFunctionFailure(std::string _f): Exception("Function " + _f + "() failed.") {} }; struct ExternalFunctionFailure: virtual Exception { public: ExternalFunctionFailure(std::string _f): Exception("Function " + _f + "() failed.") {} };
// error information to be added to exceptions // error information to be added to exceptions
@ -66,5 +73,7 @@ using errinfo_min = boost::error_info<struct tag_min, bigint>;
using errinfo_max = boost::error_info<struct tag_max, bigint>; using errinfo_max = boost::error_info<struct tag_max, bigint>;
using RequirementError = boost::tuple<errinfo_required, errinfo_got>; using RequirementError = boost::tuple<errinfo_required, errinfo_got>;
using errinfo_hash256 = boost::error_info<struct tag_hash, h256>; using errinfo_hash256 = boost::error_info<struct tag_hash, h256>;
using HashMismatchError = boost::tuple<errinfo_hash256, errinfo_hash256>; using errinfo_required_h256 = boost::error_info<struct tag_required_h256, h256>;
using errinfo_got_h256 = boost::error_info<struct tag_get_h256, h256>;
using Hash256RequirementError = boost::tuple<errinfo_required_h256, errinfo_got_h256>;
} }

2
libdevcore/FixedHash.h

@ -113,7 +113,7 @@ public:
/// @returns an abridged version of the hash as a user-readable hex string. /// @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"; } 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()); } std::string hex() const { return toHex(ref()); }
/// @returns a mutable byte vector_ref to the object's data. /// @returns a mutable byte vector_ref to the object's data.

8
libdevcore/Log.cpp

@ -40,6 +40,14 @@ mutex x_logOverride;
/// or equal to the currently output verbosity (g_logVerbosity). /// or equal to the currently output verbosity (g_logVerbosity).
static map<type_info const*, bool> s_logOverride; static map<type_info const*, bool> s_logOverride;
bool isLogVisible(std::type_info const* _ch, bool _default)
{
Guard l(x_logOverride);
if (s_logOverride.count(_ch))
return s_logOverride[_ch];
return _default;
}
LogOverrideAux::LogOverrideAux(std::type_info const* _ch, bool _value): LogOverrideAux::LogOverrideAux(std::type_info const* _ch, bool _value):
m_ch(_ch) m_ch(_ch)
{ {

3
libdevcore/Log.h

@ -73,6 +73,9 @@ public:
LogOverride(bool _value): LogOverrideAux(&typeid(Channel), _value) {} LogOverride(bool _value): LogOverrideAux(&typeid(Channel), _value) {}
}; };
bool isChannelVisible(std::type_info const* _ch, bool _default);
template <class Channel> bool isChannelVisible() { return isChannelVisible(&typeid(Channel), Channel::verbosity <= g_logVerbosity); }
/// Temporary changes system's verbosity for specific function. Restores the old verbosity when function returns. /// Temporary changes system's verbosity for specific function. Restores the old verbosity when function returns.
/// Not thread-safe, use with caution! /// Not thread-safe, use with caution!
struct VerbosityHolder struct VerbosityHolder

8
libdevcore/RangeMask.h

@ -219,6 +219,14 @@ public:
return uit == m_ranges.end() ? m_all.second : uit->first; return uit == m_ranges.end() ? m_all.second : uit->first;
} }
size_t size() const
{
size_t c = 0;
for (auto const& r: this->m_ranges)
c += r.second - r.first;
return c;
}
private: private:
UnsignedRange m_all; UnsignedRange m_all;
std::map<T, T> m_ranges; std::map<T, T> m_ranges;

4
libdevcrypto/Common.cpp

@ -54,7 +54,7 @@ Public dev::toPublic(Secret const& _secret)
{ {
Public p; Public p;
s_secp256k1.toPublic(_secret, p); s_secp256k1.toPublic(_secret, p);
return std::move(p); return p;
} }
Address dev::toAddress(Public const& _public) Address dev::toAddress(Public const& _public)
@ -230,7 +230,7 @@ h256 crypto::kdf(Secret const& _priv, h256 const& _hash)
if (!s || !_hash || !_priv) if (!s || !_hash || !_priv)
BOOST_THROW_EXCEPTION(InvalidState()); BOOST_THROW_EXCEPTION(InvalidState());
return std::move(s); return s;
} }
h256 Nonce::get(bool _commit) h256 Nonce::get(bool _commit)

2
libdevcrypto/CryptoPP.cpp

@ -61,7 +61,7 @@ bytes Secp256k1::eciesKDF(Secret _z, bytes _s1, unsigned kdByteLen)
} }
k.resize(kdByteLen); k.resize(kdByteLen);
return move(k); return k;
} }
void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher) void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher)

2
libdevcrypto/CryptoPP.h

@ -59,7 +59,7 @@ namespace crypto
using namespace CryptoPP; using namespace CryptoPP;
inline ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data() + 32, 32); return std::move(ECP::Point(x,y)); } inline ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data() + 32, 32); return ECP::Point(x,y); }
inline Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.data(), Secret::size)); } inline Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.data(), Secret::size)); }

4
libdevcrypto/OverlayDB.cpp

@ -95,7 +95,7 @@ bytes OverlayDB::lookupAux(h256 const& _h) const
{ {
bytes ret = MemoryDB::lookupAux(_h); bytes ret = MemoryDB::lookupAux(_h);
if (!ret.empty() || !m_db) if (!ret.empty() || !m_db)
return move(ret); return ret;
std::string v; std::string v;
bytes b = _h.asBytes(); bytes b = _h.asBytes();
b.push_back(255); // for aux b.push_back(255); // for aux
@ -116,7 +116,7 @@ std::string OverlayDB::lookup(h256 const& _h) const
std::string ret = MemoryDB::lookup(_h); std::string ret = MemoryDB::lookup(_h);
if (ret.empty() && m_db) if (ret.empty() && m_db)
m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret); m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret);
return move(ret); return ret;
} }
bool OverlayDB::exists(h256 const& _h) const bool OverlayDB::exists(h256 const& _h) const

51
libethash-cl/ethash_cl_miner.cpp

@ -127,7 +127,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
return devices.size(); return devices.size();
} }
bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId) bool ethash_cl_miner::haveSufficientGPUMemory()
{ {
std::vector<cl::Platform> platforms; std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms); cl::Platform::get(&platforms);
@ -136,15 +136,25 @@ bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId)
ETHCL_LOG("No OpenCL platforms found."); ETHCL_LOG("No OpenCL platforms found.");
return false; return false;
} }
for (unsigned i = 0; i < platforms.size(); ++i)
if (haveSufficientGPUMemory(i))
return true;
return false;
}
bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId)
{
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (_platformId >= platforms.size())
return false;
std::vector<cl::Device> devices; std::vector<cl::Device> devices;
unsigned platform_num = std::min<unsigned>(_platformId, platforms.size() - 1); unsigned platform_num = std::min<unsigned>(_platformId, platforms.size() - 1);
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty()) if (devices.empty())
{
ETHCL_LOG("No OpenCL devices found.");
return false; return false;
}
for (cl::Device const& device: devices) for (cl::Device const& device: devices)
{ {
@ -168,6 +178,39 @@ bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId)
return false; return false;
} }
void ethash_cl_miner::listDevices()
{
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
{
ETHCL_LOG("No OpenCL platforms found.");
return;
}
for (unsigned i = 0; i < platforms.size(); ++i)
listDevices(i);
}
void ethash_cl_miner::listDevices(unsigned _platformId)
{
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (_platformId >= platforms.size())
return;
std::string outString ="Listing OpenCL devices for platform " + to_string(_platformId) + "\n[deviceID] deviceName\n";
std::vector<cl::Device> devices;
platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices);
unsigned i = 0;
std::string deviceString;
for (cl::Device const& device: devices)
{
outString += "[" + to_string(i) + "] " + device.getInfo<CL_DEVICE_NAME>() + "\n";
++i;
}
ETHCL_LOG(outString);
}
void ethash_cl_miner::finish() void ethash_cl_miner::finish()
{ {
if (m_queue()) if (m_queue())

5
libethash-cl/ethash_cl_miner.h

@ -35,7 +35,10 @@ public:
static unsigned get_num_platforms(); static unsigned get_num_platforms();
static unsigned get_num_devices(unsigned _platformId = 0); static unsigned get_num_devices(unsigned _platformId = 0);
static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0);
static bool haveSufficientGPUMemory(unsigned _platformId = 0); static bool haveSufficientGPUMemory();
static bool haveSufficientGPUMemory(unsigned _platformId);
static void listDevices();
static void listDevices(unsigned _platformId);
bool init( bool init(
uint8_t const* _dag, uint8_t const* _dag,

24
libethcore/BlockInfo.cpp

@ -139,7 +139,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
mixHash = _header[field = 13].toHash<h256>(RLP::VeryStrict); mixHash = _header[field = 13].toHash<h256>(RLP::VeryStrict);
nonce = _header[field = 14].toHash<Nonce>(RLP::VeryStrict); nonce = _header[field = 14].toHash<Nonce>(RLP::VeryStrict);
} }
catch (Exception const& _e) catch (Exception const& _e)
{ {
_e << errinfo_name("invalid block header format") << BadFieldError(field, toHex(_header[field].data().toBytes())); _e << errinfo_name("invalid block header format") << BadFieldError(field, toHex(_header[field].data().toBytes()));
@ -151,9 +150,26 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
// check it hashes according to proof of work or that it's the genesis block. // check it hashes according to proof of work or that it's the genesis block.
if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this))
BOOST_THROW_EXCEPTION(InvalidBlockNonce() << errinfo_hash256(headerHash(WithoutNonce)) << errinfo_nonce(nonce) << errinfo_difficulty(difficulty)); {
InvalidBlockNonce ex;
ex << errinfo_hash256(headerHash(WithoutNonce));
ex << errinfo_nonce(nonce);
ex << errinfo_difficulty(difficulty);
ex << errinfo_seedHash(seedHash());
ex << errinfo_target(boundary());
ex << errinfo_mixHash(mixHash);
Ethash::Result er = EthashAux::eval(seedHash(), headerHash(WithoutNonce), nonce);
ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash));
BOOST_THROW_EXCEPTION(ex);
}
else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this))
BOOST_THROW_EXCEPTION(InvalidBlockNonce() << errinfo_hash256(headerHash(WithoutNonce)) << errinfo_nonce(nonce) << errinfo_difficulty(difficulty)); {
InvalidBlockNonce ex;
ex << errinfo_hash256(headerHash(WithoutNonce));
ex << errinfo_nonce(nonce);
ex << errinfo_difficulty(difficulty);
BOOST_THROW_EXCEPTION(ex);
}
if (_s != CheckNothing) if (_s != CheckNothing)
{ {
@ -224,7 +240,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
for (auto const& t: txs) for (auto const& t: txs)
cdebug << toHex(t); cdebug << toHex(t);
BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(expectedRoot, transactionsRoot)); BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, transactionsRoot));
} }
clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data())); clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data()));
if (sha3Uncles != sha3(root[2].data())) if (sha3Uncles != sha3(root[2].data()))

15
libethcore/Ethash.cpp

@ -364,11 +364,6 @@ void Ethash::GPUMiner::pause()
stopWorking(); stopWorking();
} }
bool Ethash::GPUMiner::haveSufficientGPUMemory()
{
return ethash_cl_miner::haveSufficientGPUMemory(s_platformId);
}
std::string Ethash::GPUMiner::platformInfo() std::string Ethash::GPUMiner::platformInfo()
{ {
return ethash_cl_miner::platform_info(s_platformId, s_deviceId); return ethash_cl_miner::platform_info(s_platformId, s_deviceId);
@ -379,6 +374,16 @@ unsigned Ethash::GPUMiner::getNumDevices()
return ethash_cl_miner::get_num_devices(s_platformId); return ethash_cl_miner::get_num_devices(s_platformId);
} }
void Ethash::GPUMiner::listDevices()
{
return ethash_cl_miner::listDevices();
}
bool Ethash::GPUMiner::haveSufficientMemory()
{
return ethash_cl_miner::haveSufficientGPUMemory();
}
#endif #endif
} }

6
libethcore/Ethash.h

@ -87,10 +87,11 @@ public:
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); }
static std::string platformInfo(); static std::string platformInfo();
static bool haveSufficientGPUMemory() { return false; }
static void setDefaultPlatform(unsigned) {} static void setDefaultPlatform(unsigned) {}
static void setDagChunks(unsigned) {} static void setDagChunks(unsigned) {}
static void setDefaultDevice(unsigned) {} static void setDefaultDevice(unsigned) {}
static void listDevices() {}
static bool haveSufficientMemory() { return false; }
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, std::thread::hardware_concurrency()); } static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, std::thread::hardware_concurrency()); }
protected: protected:
void kickOff() override void kickOff() override
@ -117,8 +118,9 @@ public:
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; }
static std::string platformInfo(); static std::string platformInfo();
static bool haveSufficientGPUMemory();
static unsigned getNumDevices(); static unsigned getNumDevices();
static void listDevices();
static bool haveSufficientMemory();
static void setDefaultPlatform(unsigned _id) { s_platformId = _id; } static void setDefaultPlatform(unsigned _id) { s_platformId = _id; }
static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } static void setDefaultDevice(unsigned _id) { s_deviceId = _id; }
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, getNumDevices()); } static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, getNumDevices()); }

77
libethcore/Exceptions.h

@ -35,46 +35,45 @@ using errinfo_field = boost::error_info<struct tag_field, int>;
using errinfo_data = boost::error_info<struct tag_data, std::string>; using errinfo_data = boost::error_info<struct tag_data, std::string>;
using errinfo_nonce = boost::error_info<struct tag_nonce, h64>; using errinfo_nonce = boost::error_info<struct tag_nonce, h64>;
using errinfo_difficulty = boost::error_info<struct tag_difficulty, u256>; using errinfo_difficulty = boost::error_info<struct tag_difficulty, u256>;
using errinfo_target = boost::error_info<struct tag_target, h256>;
using errinfo_seedHash = boost::error_info<struct tag_seedHash, h256>;
using errinfo_mixHash = boost::error_info<struct tag_mixHash, h256>;
using errinfo_ethashResult = boost::error_info<struct tag_ethashResult, std::tuple<h256, h256>>;
using BadFieldError = boost::tuple<errinfo_field, errinfo_data>; using BadFieldError = boost::tuple<errinfo_field, errinfo_data>;
struct DatabaseAlreadyOpen: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(OutOfGasBase);
struct OutOfGasBase: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(OutOfGasIntrinsic);
struct NotEnoughAvailableSpace: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(NotEnoughAvailableSpace);
struct NotEnoughCash: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(NotEnoughCash);
struct GasPriceTooLow: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(GasPriceTooLow);
struct BlockGasLimitReached: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(BlockGasLimitReached);
struct NoSuchContract: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(FeeTooSmall);
struct ContractAddressCollision: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(TooMuchGasUsed);
struct FeeTooSmall: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(ExtraDataTooBig);
struct TooMuchGasUsed: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidSignature);
struct ExtraDataTooBig: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidBlockFormat);
struct InvalidSignature: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidUnclesHash);
struct InvalidBlockFormat: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(TooManyUncles);
struct InvalidUnclesHash: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(UncleTooOld);
struct InvalidUncle: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(UncleIsBrother);
struct TooManyUncles: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(UncleInChain);
struct UncleTooOld: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidStateRoot);
struct UncleIsBrother: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidGasUsed);
struct UncleInChain: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidTransactionsRoot);
struct DuplicateUncleNonce: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidDifficulty);
struct InvalidStateRoot: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidGasLimit);
struct InvalidGasUsed: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidReceiptsStateRoot);
struct InvalidTransactionsHash: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidTimestamp);
struct InvalidTransaction: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidLogBloom);
struct InvalidDifficulty: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidNonce);
struct InvalidGasLimit: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidBlockHeaderItemCount);
struct InvalidTransactionGasUsed: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidBlockNonce);
struct InvalidTransactionsStateRoot: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidParentHash);
struct InvalidReceiptsStateRoot: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(InvalidNumber);
struct InvalidTimestamp: virtual dev::Exception {};
struct InvalidLogBloom: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(DatabaseAlreadyOpen);
struct InvalidNonce: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(DAGCreationFailure);
struct InvalidBlockHeaderItemCount: virtual dev::Exception {}; DEV_SIMPLE_EXCEPTION(DAGComputeFailure);
struct InvalidBlockNonce: virtual dev::Exception {};
struct InvalidParentHash: virtual dev::Exception {};
struct InvalidNumber: virtual dev::Exception {};
struct InvalidContractAddress: virtual public dev::Exception {};
struct DAGCreationFailure: virtual public dev::Exception {};
struct DAGComputeFailure: virtual public dev::Exception {};
} }
} }

48
libethereum/BlockChain.cpp

@ -331,9 +331,18 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
// Can't continue - chain bad. // Can't continue - chain bad.
badBlocks.push_back(block.first.hash()); badBlocks.push_back(block.first.hash());
} }
catch (Exception const& _e) catch (dev::eth::FutureTime)
{ {
cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << LogTag::Error << diagnostic_information(_e); cwarn << "ODD: Import queue contains a block with future time." << LogTag::Error << boost::current_exception_diagnostic_information();
// NOTE: don't reimport since the queue should guarantee everything in the past.
// Can't continue - chain bad.
badBlocks.push_back(block.first.hash());
}
catch (Exception& ex)
{
cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << LogTag::Error << diagnostic_information(ex);
if (m_onBad)
m_onBad(ex);
// NOTE: don't reimport since the queue should guarantee everything in the right order. // NOTE: don't reimport since the queue should guarantee everything in the right order.
// Can't continue - chain bad. // Can't continue - chain bad.
badBlocks.push_back(block.first.hash()); badBlocks.push_back(block.first.hash());
@ -360,8 +369,10 @@ pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, O
{ {
return make_pair(ImportResult::FutureTime, make_pair(h256s(), h256s())); return make_pair(ImportResult::FutureTime, make_pair(h256s(), h256s()));
} }
catch (...) catch (Exception& ex)
{ {
if (m_onBad)
m_onBad(ex);
return make_pair(ImportResult::Malformed, make_pair(h256s(), h256s())); return make_pair(ImportResult::Malformed, make_pair(h256s(), h256s()));
} }
} }
@ -379,10 +390,11 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
bi.verifyInternals(&_block); bi.verifyInternals(&_block);
} }
#if ETH_CATCH #if ETH_CATCH
catch (Exception const& _e) catch (Exception& ex)
{ {
clog(BlockChainNote) << " Malformed block: " << diagnostic_information(_e); clog(BlockChainNote) << " Malformed block: " << diagnostic_information(ex);
_e << errinfo_comment("Malformed block "); ex << errinfo_now(time(0));
ex << errinfo_block(_block);
throw; throw;
} }
#endif #endif
@ -470,14 +482,8 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla
blb.blooms.push_back(s.receipt(i).bloom()); blb.blooms.push_back(s.receipt(i).bloom());
br.receipts.push_back(s.receipt(i)); br.receipts.push_back(s.receipt(i));
} }
try {
s.cleanup(true); s.cleanup(true);
}
catch (BadRoot)
{
cwarn << "BadRoot error. Retrying import later.";
BOOST_THROW_EXCEPTION(FutureTime());
}
td = pd.totalDifficulty + tdIncrease; td = pd.totalDifficulty + tdIncrease;
@ -520,20 +526,20 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla
#endif #endif
} }
#if ETH_CATCH #if ETH_CATCH
catch (InvalidNonce const& _e) catch (BadRoot& ex)
{ {
clog(BlockChainNote) << " Malformed block: " << diagnostic_information(_e); cwarn << "BadRoot error. Retrying import later.";
_e << errinfo_comment("Malformed block "); BOOST_THROW_EXCEPTION(FutureTime());
throw;
} }
catch (Exception const& _e) catch (Exception& ex)
{ {
clog(BlockChainWarn) << " Malformed block: " << diagnostic_information(_e); clog(BlockChainWarn) << " Malformed block: " << diagnostic_information(ex);
_e << errinfo_comment("Malformed block ");
clog(BlockChainWarn) << "Block: " << _bi.hash(); clog(BlockChainWarn) << "Block: " << _bi.hash();
clog(BlockChainWarn) << _bi; clog(BlockChainWarn) << _bi;
clog(BlockChainWarn) << "Block parent: " << _bi.parentHash; clog(BlockChainWarn) << "Block parent: " << _bi.parentHash;
clog(BlockChainWarn) << BlockInfo(block(_bi.parentHash)); clog(BlockChainWarn) << BlockInfo(block(_bi.parentHash));
ex << errinfo_now(time(0));
ex << errinfo_block(_block);
throw; throw;
} }
#endif #endif

5
libethereum/BlockChain.h

@ -257,6 +257,9 @@ public:
/// Deallocate unused data. /// Deallocate unused data.
void garbageCollect(bool _force = false); void garbageCollect(bool _force = false);
/// Change the function that is called with a bad block.
template <class T> void setOnBad(T const& _t) { m_onBad = _t; }
private: private:
static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); }
@ -336,6 +339,8 @@ private:
ldb::ReadOptions m_readOptions; ldb::ReadOptions m_readOptions;
ldb::WriteOptions m_writeOptions; ldb::WriteOptions m_writeOptions;
std::function<void(Exception&)> m_onBad; ///< Called if we have a block that doesn't verify.
friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc);
}; };

55
libethereum/BlockQueue.cpp

@ -26,6 +26,7 @@
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include "BlockChain.h" #include "BlockChain.h"
#include "State.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
@ -76,56 +77,44 @@ void BlockQueue::verifierBody()
std::pair<BlockInfo, bytes> res; std::pair<BlockInfo, bytes> res;
swap(work.second, res.second); swap(work.second, res.second);
try { try
try { {
try
{
res.first.populate(res.second, CheckEverything, work.first); res.first.populate(res.second, CheckEverything, work.first);
res.first.verifyInternals(&res.second); res.first.verifyInternals(&res.second);
} }
catch (InvalidBlockNonce&) catch (Exception& ex)
{
badBlock(res.second, "Invalid block nonce");
cwarn << " Nonce:" << res.first.nonce.hex();
cwarn << " PoWHash:" << res.first.headerHash(WithoutNonce).hex();
cwarn << " SeedHash:" << res.first.seedHash().hex();
cwarn << " Target:" << res.first.boundary().hex();
cwarn << " MixHash:" << res.first.mixHash.hex();
Ethash::Result er = EthashAux::eval(res.first.seedHash(), res.first.headerHash(WithoutNonce), res.first.nonce);
cwarn << " Ethash v:" << er.value.hex();
cwarn << " Ethash mH:" << er.mixHash.hex();
throw;
}
catch (Exception& _e)
{ {
badBlock(res.second, _e.what()); clog(BlockChainNote) << " Malformed block: " << diagnostic_information(ex);
badBlock(res.second, ex.what());
ex << errinfo_now(time(0));
ex << errinfo_block(res.second);
if (m_onBad)
m_onBad(ex);
throw; throw;
} }
RLP r(&res.second); RLP r(&res.second);
unsigned ii = 0;
for (auto const& uncle: r[2]) for (auto const& uncle: r[2])
{ {
try try
{ {
BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything);
} }
catch (InvalidNonce&) catch (Exception& ex)
{
badBlockHeader(uncle.data(), "Invalid uncle nonce");
BlockInfo bi = BlockInfo::fromHeader(uncle.data(), CheckNothing);
cwarn << " Nonce:" << bi.nonce.hex();
cwarn << " PoWHash:" << bi.headerHash(WithoutNonce).hex();
cwarn << " SeedHash:" << bi.seedHash().hex();
cwarn << " Target:" << bi.boundary().hex();
cwarn << " MixHash:" << bi.mixHash.hex();
Ethash::Result er = EthashAux::eval(bi.seedHash(), bi.headerHash(WithoutNonce), bi.nonce);
cwarn << " Ethash v:" << er.value.hex();
cwarn << " Ethash mH:" << er.mixHash.hex();
throw;
}
catch (Exception& _e)
{ {
badBlockHeader(uncle.data(), _e.what()); clog(BlockChainNote) << " Malformed block header: " << diagnostic_information(ex);
badBlockHeader(uncle.data(), ex.what());
ex << errinfo_uncleIndex(ii);
ex << errinfo_now(time(0));
ex << errinfo_block(res.second);
if (m_onBad)
m_onBad(ex);
throw; throw;
} }
++ii;
} }
} }
catch (...) catch (...)

4
libethereum/BlockQueue.h

@ -110,6 +110,8 @@ public:
template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); } template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); }
template <class T> void setOnBad(T const& _t) { m_onBad = _t; }
private: private:
void noteReady_WITH_LOCK(h256 const& _b); void noteReady_WITH_LOCK(h256 const& _b);
@ -134,6 +136,8 @@ private:
std::vector<std::thread> m_verifiers; ///< Threads who only verify. std::vector<std::thread> m_verifiers; ///< Threads who only verify.
bool m_deleting = false; ///< Exit condition for verifiers. bool m_deleting = false; ///< Exit condition for verifiers.
std::function<void(Exception&)> m_onBad; ///< Called if we have a block that doesn't verify.
}; };
std::ostream& operator<<(std::ostream& _out, BlockQueueStatus const& _s); std::ostream& operator<<(std::ostream& _out, BlockQueueStatus const& _s);

7
libethereum/CMakeLists.txt

@ -14,6 +14,10 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..) include_directories(BEFORE ..)
include_directories(${LEVELDB_INCLUDE_DIRS}) include_directories(${LEVELDB_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
if (JSONRPC)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
endif()
set(EXECUTABLE ethereum) set(EXECUTABLE ethereum)
@ -30,6 +34,9 @@ target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} secp256k1)
if (JSONRPC)
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES})
endif()
if (CMAKE_COMPILER_IS_MINGW) if (CMAKE_COMPILER_IS_MINGW)
target_link_libraries(${EXECUTABLE} ssp shlwapi) target_link_libraries(${EXECUTABLE} ssp shlwapi)

167
libethereum/Client.cpp

@ -25,9 +25,16 @@
#include <thread> #include <thread>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/math/distributions/normal.hpp> #include <boost/math/distributions/normal.hpp>
#if ETH_JSONRPC || !ETH_TRUE
#include <jsonrpccpp/client.h>
#include <jsonrpccpp/client/connectors/httpclient.h>
#endif
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/StructuredLogger.h> #include <libdevcore/StructuredLogger.h>
#include <libp2p/Host.h> #include <libp2p/Host.h>
#if ETH_JSONRPC || !ETH_TRUE
#include "Sentinel.h"
#endif
#include "Defaults.h" #include "Defaults.h"
#include "Executive.h" #include "Executive.h"
#include "EthereumHost.h" #include "EthereumHost.h"
@ -80,6 +87,101 @@ void VersionChecker::setOk()
} }
} }
void Client::onBadBlock(Exception& _ex)
{
// BAD 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);
#if ETH_JSONRPC || !ETH_TRUE
if (!m_sentinel.empty())
{
Json::Value report;
report["client"] = "cpp";
report["version"] = Version;
report["protocolVersion"] = c_protocolVersion;
report["databaseVersion"] = c_databaseVersion;
report["errortype"] = _ex.what();
report["block"] = toHex(block);
report["hint"] = Json::Value(Json::objectValue);
// add the various hints.
if (unsigned const* uncleIndex = boost::get_error_info<errinfo_uncleIndex>(_ex))
{
// uncle that failed.
report["hints"]["uncleIndex"] = *uncleIndex;
}
else if (unsigned const* txIndex = boost::get_error_info<errinfo_transactionIndex>(_ex))
{
// transaction that failed.
report["hints"]["transactionIndex"] = *txIndex;
}
else
{
// general block failure.
}
if (string const* vmtraceJson = boost::get_error_info<errinfo_vmtrace>(_ex))
Json::Reader().parse(*vmtraceJson, report["hints"]["vmtrace"]);
if (vector<bytes> const* receipts = boost::get_error_info<errinfo_receipts>(_ex))
{
report["hints"]["receipts"] = Json::arrayValue;
for (auto const& r: *receipts)
report["hints"]["receipts"].append(toHex(r));
}
if (h256Hash const* excluded = boost::get_error_info<errinfo_unclesExcluded>(_ex))
{
report["hints"]["unclesExcluded"] = Json::arrayValue;
for (auto const& r: h256Set() + *excluded)
report["hints"]["unclesExcluded"].append(Json::Value(r.hex()));
}
#define DEV_HINT_ERRINFO(X) \
if (auto const* n = boost::get_error_info<errinfo_ ## X>(_ex)) \
report["hints"][#X] = toString(*n)
#define DEV_HINT_ERRINFO_HASH(X) \
if (auto const* n = boost::get_error_info<errinfo_ ## X>(_ex)) \
report["hints"][#X] = n->hex()
DEV_HINT_ERRINFO_HASH(hash256);
DEV_HINT_ERRINFO(uncleNumber);
DEV_HINT_ERRINFO(currentNumber);
DEV_HINT_ERRINFO(now);
DEV_HINT_ERRINFO(invalidSymbol);
DEV_HINT_ERRINFO(wrongAddress);
DEV_HINT_ERRINFO(comment);
DEV_HINT_ERRINFO(min);
DEV_HINT_ERRINFO(max);
DEV_HINT_ERRINFO(required);
DEV_HINT_ERRINFO(got);
DEV_HINT_ERRINFO_HASH(required_LogBloom);
DEV_HINT_ERRINFO_HASH(got_LogBloom);
DEV_HINT_ERRINFO_HASH(required_h256);
DEV_HINT_ERRINFO_HASH(got_h256);
jsonrpc::HttpClient client(m_sentinel);
Sentinel rpc(client);
try
{
rpc.eth_badBlock(report);
}
catch (...)
{
cwarn << "Error reporting to sentinel. Sure the address" << m_sentinel << "is correct?";
}
}
#endif
}
void BasicGasPricer::update(BlockChain const& _bc) void BasicGasPricer::update(BlockChain const& _bc)
{ {
unsigned c = 0; unsigned c = 0;
@ -185,6 +287,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string c
m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30);
m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue);
m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);
m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); });
m_gp->update(m_bc); m_gp->update(m_bc);
@ -206,6 +310,18 @@ Client::~Client()
stopWorking(); stopWorking();
} }
static const Address c_canary("0x");
bool Client::isChainBad() const
{
return stateAt(c_canary, 0) != 0;
}
bool Client::isUpgradeNeeded() const
{
return stateAt(c_canary, 0) == 2;
}
void Client::setNetworkId(u256 _n) void Client::setNetworkId(u256 _n)
{ {
if (auto h = m_host.lock()) if (auto h = m_host.lock())
@ -450,6 +566,9 @@ ProofOfWork::WorkPackage Client::getWork()
bool oldShould = shouldServeWork(); bool oldShould = shouldServeWork();
m_lastGetWork = chrono::system_clock::now(); m_lastGetWork = chrono::system_clock::now();
if (!m_mineOnBadChain && isChainBad())
return ProofOfWork::WorkPackage();
// if this request has made us bother to serve work, prep it now. // if this request has made us bother to serve work, prep it now.
if (!oldShould && shouldServeWork()) if (!oldShould && shouldServeWork())
onPostStateChanged(); onPostStateChanged();
@ -606,11 +725,22 @@ bool Client::remoteActive() const
void Client::onPostStateChanged() void Client::onPostStateChanged()
{ {
cnote << "Post state changed"; cnote << "Post state changed.";
rejigMining();
m_remoteWorking = false;
}
if (m_bq.items().first == 0 && (isMining() || remoteActive())) void Client::startMining()
{
m_wouldMine = true;
rejigMining();
}
void Client::rejigMining()
{
if ((wouldMine() || remoteActive()) && !m_bq.items().first && (!isChainBad() || mineOnBadChain()) /*&& (forceMining() || transactionsWaiting())*/)
{ {
cnote << "Restarting mining..."; cnote << "Rejigging mining...";
DEV_WRITE_GUARDED(x_working) DEV_WRITE_GUARDED(x_working)
m_working.commitToMine(m_bc); m_working.commitToMine(m_bc);
DEV_READ_GUARDED(x_working) DEV_READ_GUARDED(x_working)
@ -619,20 +749,21 @@ void Client::onPostStateChanged()
m_postMine = m_working; m_postMine = m_working;
m_miningInfo = m_postMine.info(); m_miningInfo = m_postMine.info();
} }
m_farm.setWork(m_miningInfo);
Ethash::ensurePrecomputed(m_bc.number()); if (m_wouldMine)
{
m_farm.setWork(m_miningInfo);
if (m_turboMining)
m_farm.startGPU();
else
m_farm.startCPU();
m_farm.setWork(m_miningInfo);
Ethash::ensurePrecomputed(m_bc.number());
}
} }
m_remoteWorking = false; if (!m_wouldMine)
} m_farm.stop();
void Client::startMining()
{
if (m_turboMining)
m_farm.startGPU();
else
m_farm.startCPU();
onPostStateChanged();
} }
void Client::noteChanged(h256Hash const& _filters) void Client::noteChanged(h256Hash const& _filters)
@ -750,3 +881,9 @@ void Client::flushTransactions()
{ {
doWork(); doWork();
} }
HashChainStatus Client::hashChainStatus() const
{
auto h = m_host.lock();
return h ? h->status() : HashChainStatus { 0, 0, false };
}

35
libethereum/Client.h

@ -143,7 +143,7 @@ public:
ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether, Address const& _from = Address()); ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether, Address const& _from = Address());
/// Get the remaining gas limit in this block. /// Get the remaining gas limit in this block.
virtual u256 gasLimitRemaining() const { return m_postMine.gasLimitRemaining(); } virtual u256 gasLimitRemaining() const override { return m_postMine.gasLimitRemaining(); }
// [PRIVATE API - only relevant for base clients, not available in general] // [PRIVATE API - only relevant for base clients, not available in general]
dev::eth::State state(unsigned _txi, h256 _block) const; dev::eth::State state(unsigned _txi, h256 _block) const;
@ -156,10 +156,14 @@ public:
CanonBlockChain const& blockChain() const { return m_bc; } CanonBlockChain const& blockChain() const { return m_bc; }
/// Get some information on the block queue. /// Get some information on the block queue.
BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } 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: // Mining stuff:
void setAddress(Address _us) { WriteGuard l(x_preMine); m_preMine.setAddress(_us); } virtual void setAddress(Address _us) override { WriteGuard l(x_preMine); m_preMine.setAddress(_us); }
/// Check block validity prior to mining. /// Check block validity prior to mining.
bool miningParanoia() const { return m_paranoia; } bool miningParanoia() const { return m_paranoia; }
@ -174,14 +178,26 @@ public:
/// Enable/disable GPU mining. /// Enable/disable GPU mining.
void setTurboMining(bool _enable = true) { m_turboMining = _enable; if (isMining()) startMining(); } void setTurboMining(bool _enable = true) { m_turboMining = _enable; if (isMining()) startMining(); }
/// Check to see if we'd mine on an apparently bad chain.
bool mineOnBadChain() const { return m_mineOnBadChain; }
/// Set true if you want to mine even when the canary says you're on the wrong chain.
void setMineOnBadChain(bool _v) { m_mineOnBadChain = _v; }
/// @returns true if the canary says that the chain is bad.
bool isChainBad() const;
/// @returns true if the canary says that the client should be upgraded.
bool isUpgradeNeeded() const;
/// Start mining. /// Start mining.
/// NOT thread-safe - call it & stopMining only from a single thread /// NOT thread-safe - call it & stopMining only from a single thread
void startMining() override; void startMining() override;
/// Stop mining. /// Stop mining.
/// NOT thread-safe /// NOT thread-safe
void stopMining() override { m_farm.stop(); } void stopMining() override { m_wouldMine = false; rejigMining(); }
/// Are we mining now? /// Are we mining now?
bool isMining() const override { return m_farm.isMining(); } bool isMining() const override { return m_farm.isMining(); }
/// Are we mining now?
bool wouldMine() const override { return m_wouldMine; }
/// The hashrate... /// The hashrate...
uint64_t hashrate() const override; uint64_t hashrate() const override;
/// Check the progress of the mining. /// Check the progress of the mining.
@ -213,6 +229,8 @@ public:
void retryUnkonwn() { m_bq.retryAllUnknown(); } void retryUnkonwn() { m_bq.retryAllUnknown(); }
/// Get a report of activity. /// Get a report of activity.
ActivityReport activityReport() { ActivityReport ret; std::swap(m_report, ret); return ret; } ActivityReport activityReport() { ActivityReport ret; std::swap(m_report, ret); return ret; }
/// Set a JSONRPC server to which we can report bad blocks.
void setSentinel(std::string const& _server) { m_sentinel = _server; }
protected: protected:
/// InterfaceStub methods /// InterfaceStub methods
@ -249,6 +267,9 @@ private:
/// Called when Worker is exiting. /// Called when Worker is exiting.
void doneWorking() override; void doneWorking() override;
/// Called when wouldMine(), turboMining(), isChainBad(), forceMining(), pendingTransactions() have changed.
void rejigMining();
/// Magically called when the chain has changed. An import route is provided. /// Magically called when the chain has changed. An import route is provided.
/// Called by either submitWork() or in our main thread through syncBlockQueue(). /// Called by either submitWork() or in our main thread through syncBlockQueue().
void onChainChanged(ImportRoute const& _ir); void onChainChanged(ImportRoute const& _ir);
@ -278,6 +299,10 @@ private:
/// @returns true only if it's worth bothering to prep the mining block. /// @returns true only if it's worth bothering to prep the mining block.
bool shouldServeWork() const { return m_bq.items().first == 0 && (isMining() || remoteActive()); } bool shouldServeWork() const { return m_bq.items().first == 0 && (isMining() || remoteActive()); }
/// Called when we have attempted to import a bad block.
/// @warning May be called from any thread.
void onBadBlock(Exception& _ex);
VersionChecker m_vc; ///< Dummy object to check & update the protocol version. VersionChecker m_vc; ///< Dummy object to check & update the protocol version.
CanonBlockChain m_bc; ///< Maintains block database. CanonBlockChain m_bc; ///< Maintains block database.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
@ -302,8 +327,10 @@ private:
Handler m_tqReady; Handler m_tqReady;
Handler m_bqReady; Handler m_bqReady;
bool m_wouldMine = false; ///< True if we /should/ be mining.
bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping. bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping.
bool m_forceMining = false; ///< Mine even when there are no transactions pending? bool m_forceMining = false; ///< Mine even when there are no transactions pending?
bool m_mineOnBadChain = false; ///< Mine even when the canary says it's a bad chain.
bool m_paranoia = false; ///< Should we be paranoid about our state? bool m_paranoia = false; ///< Should we be paranoid about our state?
mutable std::chrono::system_clock::time_point m_lastGarbageCollection; mutable std::chrono::system_clock::time_point m_lastGarbageCollection;
@ -317,6 +344,8 @@ private:
Mutex x_signalled; Mutex x_signalled;
std::atomic<bool> m_syncTransactionQueue = {false}; std::atomic<bool> m_syncTransactionQueue = {false};
std::atomic<bool> m_syncBlockQueue = {false}; std::atomic<bool> m_syncBlockQueue = {false};
std::string m_sentinel;
}; };
} }

5
libethereum/ClientBase.cpp

@ -401,17 +401,16 @@ h256s ClientBase::pendingHashes() const
return h256s() + postMine().pendingHashes(); return h256s() + postMine().pendingHashes();
} }
StateDiff ClientBase::diff(unsigned _txi, h256 _block) const StateDiff ClientBase::diff(unsigned _txi, h256 _block) const
{ {
State st = asOf(_block); State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); return st.fromPending(_txi).diff(st.fromPending(_txi + 1), true);
} }
StateDiff ClientBase::diff(unsigned _txi, BlockNumber _block) const StateDiff ClientBase::diff(unsigned _txi, BlockNumber _block) const
{ {
State st = asOf(_block); State st = asOf(_block);
return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); return st.fromPending(_txi).diff(st.fromPending(_txi + 1), true);
} }
Addresses ClientBase::addresses(BlockNumber _block) const Addresses ClientBase::addresses(BlockNumber _block) const

8
libethereum/ClientBase.h

@ -134,8 +134,8 @@ public:
virtual Transactions pending() const override; virtual Transactions pending() const override;
virtual h256s pendingHashes() const override; virtual h256s pendingHashes() const override;
ImportResult injectTransaction(bytes const& _rlp) override { prepareForTransaction(); return m_tq.import(_rlp); } virtual ImportResult injectTransaction(bytes const& _rlp) override { prepareForTransaction(); return m_tq.import(_rlp); }
ImportResult injectBlock(bytes const& _block); virtual ImportResult injectBlock(bytes const& _block) override;
using Interface::diff; using Interface::diff;
virtual StateDiff diff(unsigned _txi, h256 _block) const override; virtual StateDiff diff(unsigned _txi, h256 _block) const override;
@ -145,9 +145,6 @@ public:
virtual Addresses addresses(BlockNumber _block) const override; virtual Addresses addresses(BlockNumber _block) const override;
virtual u256 gasLimitRemaining() const override; virtual u256 gasLimitRemaining() const override;
/// Set the coinbase address
virtual void setAddress(Address _us) = 0;
/// Get the coinbase address /// Get the coinbase address
virtual Address address() const override; virtual Address address() const override;
@ -156,6 +153,7 @@ public:
virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::startMining")); } virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::startMining")); }
virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::stopMining")); } virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::stopMining")); }
virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); }
virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); }
virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); }
virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); }
virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); }

7
libethereum/CommonNet.h

@ -84,5 +84,12 @@ enum class Syncing
Done Done
}; };
struct HashChainStatus
{
unsigned total;
unsigned received;
bool estimated;
};
} }
} }

7
libethereum/DownloadMan.cpp

@ -80,7 +80,6 @@ HashDownloadSub::HashDownloadSub(HashDownloadMan& _man): m_man(&_man)
{ {
WriteGuard l(m_man->x_subs); WriteGuard l(m_man->x_subs);
m_asked = RangeMask<unsigned>(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount); m_asked = RangeMask<unsigned>(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount);
m_attempted = RangeMask<unsigned>(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount);
m_man->m_subs.insert(this); m_man->m_subs.insert(this);
} }
@ -98,7 +97,6 @@ void HashDownloadSub::resetFetch()
Guard l(m_fetch); Guard l(m_fetch);
m_remaining = 0; m_remaining = 0;
m_asked = RangeMask<unsigned>(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount); m_asked = RangeMask<unsigned>(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount);
m_attempted = RangeMask<unsigned>(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount);
} }
unsigned HashDownloadSub::nextFetch(unsigned _n) unsigned HashDownloadSub::nextFetch(unsigned _n)
@ -110,10 +108,9 @@ unsigned HashDownloadSub::nextFetch(unsigned _n)
if (!m_man || m_man->chainEmpty()) if (!m_man || m_man->chainEmpty())
return 0; return 0;
m_asked = (~(m_man->taken() + m_attempted)).lowest(_n); m_asked = (~(m_man->taken())).lowest(_n);
if (m_asked.empty()) if (m_asked.empty())
m_asked = (~(m_man->taken(true) + m_attempted)).lowest(_n); m_asked = (~(m_man->taken(true))).lowest(_n);
m_attempted += m_asked;
return *m_asked.begin(); return *m_asked.begin();
} }

8
libethereum/DownloadMan.h

@ -187,7 +187,6 @@ public:
bool askedContains(unsigned _i) const { Guard l(m_fetch); return m_asked.contains(_i); } bool askedContains(unsigned _i) const { Guard l(m_fetch); return m_asked.contains(_i); }
RangeMask<unsigned> const& asked() const { return m_asked; } RangeMask<unsigned> const& asked() const { return m_asked; }
RangeMask<unsigned> const& attemped() const { return m_attempted; }
private: private:
void resetFetch(); // Called by DownloadMan when we need to reset the download. void resetFetch(); // Called by DownloadMan when we need to reset the download.
@ -196,7 +195,6 @@ private:
mutable Mutex m_fetch; mutable Mutex m_fetch;
unsigned m_remaining; unsigned m_remaining;
RangeMask<unsigned> m_asked; RangeMask<unsigned> m_asked;
RangeMask<unsigned> m_attempted;
}; };
class HashDownloadMan class HashDownloadMan
@ -255,6 +253,11 @@ public:
return m_got.full(); return m_got.full();
} }
unsigned gotCount() const
{
return m_got.size();
}
size_t chainSize() const { ReadGuard l(m_lock); return m_chainCount; } size_t chainSize() const { ReadGuard l(m_lock); return m_chainCount; }
size_t chainEmpty() const { ReadGuard l(m_lock); return m_chainCount == 0; } size_t chainEmpty() const { ReadGuard l(m_lock); return m_chainCount == 0; }
void foreachSub(std::function<void(HashDownloadSub const&)> const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); } void foreachSub(std::function<void(HashDownloadSub const&)> const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); }
@ -274,3 +277,4 @@ private:
} }
} }

113
libethereum/EthereumHost.cpp

@ -237,7 +237,7 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash)
void EthereumHost::onPeerStatus(EthereumPeer* _peer) void EthereumHost::onPeerStatus(EthereumPeer* _peer)
{ {
Guard l(x_sync); RecursiveGuard l(x_sync);
if (_peer->m_genesisHash != m_chain.genesisHash()) if (_peer->m_genesisHash != m_chain.genesisHash())
_peer->disable("Invalid genesis hash"); _peer->disable("Invalid genesis hash");
else if (_peer->m_protocolVersion != protocolVersion() && _peer->m_protocolVersion != c_oldProtocolVersion) else if (_peer->m_protocolVersion != protocolVersion() && _peer->m_protocolVersion != c_oldProtocolVersion)
@ -252,12 +252,13 @@ void EthereumHost::onPeerStatus(EthereumPeer* _peer)
{ {
if (_peer->m_protocolVersion != protocolVersion()) if (_peer->m_protocolVersion != protocolVersion())
estimatePeerHashes(_peer); estimatePeerHashes(_peer);
else if (_peer->m_latestBlockNumber > m_chain.number())
_peer->m_expectedHashes = (unsigned)_peer->m_latestBlockNumber - m_chain.number() + 1000;
else else
_peer->m_expectedHashes = 1000; {
if (m_hashMan.chainSize() < _peer->m_expectedHashes) if (_peer->m_latestBlockNumber > m_chain.number())
m_hashMan.resetToRange(m_chain.number() + 1, _peer->m_expectedHashes); _peer->m_expectedHashes = (unsigned)_peer->m_latestBlockNumber - m_chain.number();
if (m_hashMan.chainSize() < _peer->m_expectedHashes)
m_hashMan.resetToRange(m_chain.number() + 1, _peer->m_expectedHashes);
}
continueSync(_peer); continueSync(_peer);
} }
} }
@ -267,7 +268,7 @@ void EthereumHost::estimatePeerHashes(EthereumPeer* _peer)
BlockInfo block = m_chain.info(); BlockInfo block = m_chain.info();
time_t lastBlockTime = (block.hash() == m_chain.genesisHash()) ? 1428192000 : (time_t)block.timestamp; time_t lastBlockTime = (block.hash() == m_chain.genesisHash()) ? 1428192000 : (time_t)block.timestamp;
time_t now = time(0); time_t now = time(0);
unsigned blockCount = 1000; unsigned blockCount = 30000;
if (lastBlockTime > now) if (lastBlockTime > now)
clog(NetWarn) << "Clock skew? Latest block is in the future"; clog(NetWarn) << "Clock skew? Latest block is in the future";
else else
@ -276,9 +277,16 @@ void EthereumHost::estimatePeerHashes(EthereumPeer* _peer)
_peer->m_expectedHashes = blockCount; _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) void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes)
{ {
Guard l(x_sync); RecursiveGuard l(x_sync);
assert(_peer->m_asking == Asking::Nothing); assert(_peer->m_asking == Asking::Nothing);
onPeerHashes(_peer, _hashes, false); onPeerHashes(_peer, _hashes, false);
} }
@ -287,13 +295,23 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool
{ {
if (_hashes.empty()) if (_hashes.empty())
{ {
onPeerDoneHashes(_peer, true); _peer->m_hashSub.doneFetch();
continueSync();
return;
}
bool syncByNumber = _peer->m_syncHashNumber;
if (!syncByNumber && _peer->m_syncHash != m_syncingLatestHash)
{
// Obsolete hashes, discard
continueSync(_peer);
return; return;
} }
unsigned knowns = 0; unsigned knowns = 0;
unsigned unknowns = 0; unsigned unknowns = 0;
h256s neededBlocks; h256s neededBlocks;
bool syncByNumber = !m_syncingLatestHash; unsigned firstNumber = _peer->m_syncHashNumber - _hashes.size();
for (unsigned i = 0; i < _hashes.size(); ++i) for (unsigned i = 0; i < _hashes.size(); ++i)
{ {
_peer->addRating(1); _peer->addRating(1);
@ -323,8 +341,11 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool
} }
else else
knowns++; knowns++;
if (!syncByNumber) if (!syncByNumber)
m_syncingLatestHash = h; m_syncingLatestHash = h;
else
_peer->m_hashSub.noteHash(firstNumber + i, 1);
} }
if (syncByNumber) if (syncByNumber)
{ {
@ -370,13 +391,14 @@ void EthereumHost::onPeerDoneHashes(EthereumPeer* _peer, bool _localChain)
{ {
m_man.resetToChain(m_hashes); m_man.resetToChain(m_hashes);
m_hashes.clear(); m_hashes.clear();
m_hashMan.reset(m_chain.number() + 1);
} }
continueSync(); continueSync();
} }
void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
{ {
Guard l(x_sync); RecursiveGuard l(x_sync);
assert(_peer->m_asking == Asking::Nothing); assert(_peer->m_asking == Asking::Nothing);
unsigned itemCount = _r.itemCount(); unsigned itemCount = _r.itemCount();
clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks");
@ -386,6 +408,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
// Got to this peer's latest block - just give up. // Got to this peer's latest block - just give up.
clog(NetNote) << "Finishing blocks fetch..."; clog(NetNote) << "Finishing blocks fetch...";
// NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary. // NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary.
_peer->m_sub.doneFetch();
_peer->setIdle(); _peer->setIdle();
return; return;
} }
@ -452,7 +475,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r)
void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes)
{ {
Guard l(x_sync); RecursiveGuard l(x_sync);
if (isSyncing_UNSAFE()) if (isSyncing_UNSAFE())
{ {
clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading."; clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading.";
@ -464,7 +487,7 @@ void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes)
void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r)
{ {
Guard l(x_sync); RecursiveGuard l(x_sync);
if (isSyncing_UNSAFE()) if (isSyncing_UNSAFE())
{ {
clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading.";
@ -551,6 +574,17 @@ void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r)
} }
} }
void EthereumHost::onPeerAborting(EthereumPeer* _peer)
{
RecursiveGuard l(x_sync);
if (_peer->isSyncing())
{
_peer->setIdle();
_peer->setRude();
continueSync();
}
}
void EthereumHost::continueSync() void EthereumHost::continueSync()
{ {
clog(NetAllDetail) << "Getting help with downloading hashes and blocks"; clog(NetAllDetail) << "Getting help with downloading hashes and blocks";
@ -564,22 +598,37 @@ void EthereumHost::continueSync()
void EthereumHost::continueSync(EthereumPeer* _peer) void EthereumHost::continueSync(EthereumPeer* _peer)
{ {
assert(_peer->m_asking == Asking::Nothing); assert(_peer->m_asking == Asking::Nothing);
bool otherPeerSync = false; bool otherPeerV60Sync = false;
bool otherPeerV61Sync = false;
if (m_needSyncHashes && peerShouldGrabChain(_peer)) if (m_needSyncHashes && peerShouldGrabChain(_peer))
{ {
foreachPeer([&](EthereumPeer* _p) foreachPeer([&](EthereumPeer* _p)
{ {
if (_p != _peer && _p->m_asking == Asking::Hashes && _p->m_protocolVersion != protocolVersion()) if (_p != _peer && _p->m_asking == Asking::Hashes)
otherPeerSync = true; // Already have a peer downloading hash chain with old protocol, do nothing {
if (_p->m_protocolVersion != protocolVersion())
otherPeerV60Sync = true; // Already have a peer downloading hash chain with old protocol, do nothing
else
otherPeerV61Sync = true; // Already have a peer downloading hash chain with V61+ protocol, join if supported
}
}); });
if (otherPeerSync) if (otherPeerV60Sync && !m_hashes.empty())
{
/// Downloading from other peer with v60 protocol, nothing else we can do
_peer->setIdle();
return;
}
if (otherPeerV61Sync && _peer->m_protocolVersion != protocolVersion())
{ {
/// Downloading from other peer with v60 protocol, nothing ese we can do /// Downloading from other peer with v61+ protocol which this peer does not support,
_peer->setIdle(); _peer->setIdle();
return; return;
} }
if (_peer->m_protocolVersion == protocolVersion() && !m_syncingLatestHash) if (_peer->m_protocolVersion == protocolVersion() && !m_hashMan.isComplete())
{
m_syncingV61 = true;
_peer->requestHashes(); /// v61+ and not catching up to a particular hash _peer->requestHashes(); /// v61+ and not catching up to a particular hash
}
else else
{ {
// Restart/continue sync in single peer mode // Restart/continue sync in single peer mode
@ -588,7 +637,14 @@ void EthereumHost::continueSync(EthereumPeer* _peer)
m_syncingLatestHash =_peer->m_latestHash; m_syncingLatestHash =_peer->m_latestHash;
m_syncingTotalDifficulty = _peer->m_totalDifficulty; m_syncingTotalDifficulty = _peer->m_totalDifficulty;
} }
_peer->requestHashes(m_syncingLatestHash); if (_peer->m_totalDifficulty >= m_syncingTotalDifficulty)
{
_peer->requestHashes(m_syncingLatestHash);
m_syncingV61 = false;
m_estimatedHashes = _peer->m_expectedHashes;
}
else
_peer->setIdle();
} }
} }
else if (m_needSyncBlocks && peerShouldGrabBlocks(_peer)) // Check if this peer can help with downloading blocks else if (m_needSyncBlocks && peerShouldGrabBlocks(_peer)) // Check if this peer can help with downloading blocks
@ -599,6 +655,10 @@ void EthereumHost::continueSync(EthereumPeer* _peer)
bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const
{ {
// Early exit if this peer has proved unreliable.
if (_peer->isRude())
return false;
auto td = _peer->m_totalDifficulty; auto td = _peer->m_totalDifficulty;
auto lh = m_syncingLatestHash; auto lh = m_syncingLatestHash;
auto ctd = m_chain.details().totalDifficulty; auto ctd = m_chain.details().totalDifficulty;
@ -611,6 +671,10 @@ bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const
bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const
{ {
// Early exit if this peer has proved unreliable.
if (_peer->isRude())
return false;
h256 c = m_chain.currentHash(); h256 c = m_chain.currentHash();
unsigned n = m_chain.number(); unsigned n = m_chain.number();
u256 td = m_chain.details().totalDifficulty; u256 td = m_chain.details().totalDifficulty;
@ -640,3 +704,12 @@ bool EthereumHost::isSyncing_UNSAFE() const
}); });
return syncing; return syncing;
} }
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 };
}

16
libethereum/EthereumHost.h

@ -70,8 +70,10 @@ public:
void reset(); void reset();
DownloadMan const& downloadMan() const { return m_man; } DownloadMan const& downloadMan() const { return m_man; }
bool isSyncing() const { Guard l(x_sync); return isSyncing_UNSAFE(); } bool isSyncing() const { RecursiveGuard l(x_sync); return isSyncing_UNSAFE(); }
bool isBanned(p2p::NodeId _id) const { return !!m_banned.count(_id); } 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 noteNewTransactions() { m_newTransactions = true; }
void noteNewBlocks() { m_newBlocks = true; } void noteNewBlocks() { m_newBlocks = true; }
@ -82,10 +84,12 @@ public:
void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has new hashes void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has new hashes
void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has another sequential block of hashes during sync void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has another sequential block of hashes during sync
void onPeerTransactions(EthereumPeer* _peer, RLP const& _r); ///< Called by peer when it has new transactions void onPeerTransactions(EthereumPeer* _peer, RLP const& _r); ///< Called by peer when it has new transactions
void onPeerAborting(EthereumPeer* _peer); ///< Called by peer when it is disconnecting
DownloadMan& downloadMan() { return m_man; } DownloadMan& downloadMan() { return m_man; }
HashDownloadMan& hashDownloadMan() { return m_hashMan; } HashDownloadMan& hashDownloadMan() { return m_hashMan; }
BlockChain const& chain() { return m_chain; } BlockChain const& chain() { return m_chain; }
HashChainStatus status();
static unsigned const c_oldProtocolVersion; static unsigned const c_oldProtocolVersion;
@ -141,12 +145,16 @@ private:
bool m_newTransactions = false; bool m_newTransactions = false;
bool m_newBlocks = false; bool m_newBlocks = false;
mutable Mutex x_sync; mutable RecursiveMutex x_sync;
bool m_needSyncHashes = true; ///< Indicates if need to downlad hashes bool m_needSyncHashes = true; ///< Indicates if need to downlad hashes
bool m_needSyncBlocks = true; ///< Indicates if we still need to download some blocks bool m_needSyncBlocks = true; ///< Indicates if we still need to download some blocks
h256 m_syncingLatestHash; ///< Latest block's hash, as of the current sync. h256 m_syncingLatestHash; ///< Latest block's hash, as of the current sync.
u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty, as of the current sync. u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty, as of the current sync.
h256s m_hashes; ///< List of hashes with unknown block numbers. Used for v60 chain downloading and catching up to a particular unknown 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.
}; };
} }

33
libethereum/EthereumPeer.cpp

@ -40,6 +40,8 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, Cap
m_hashSub(host()->hashDownloadMan()), m_hashSub(host()->hashDownloadMan()),
m_peerCapabilityVersion(_cap.second) m_peerCapabilityVersion(_cap.second)
{ {
m_isRude = host()->isRude(session()->id(), session()->info().clientVersion);
session()->addNote("manners", m_isRude ? "RUDE" : "nice");
m_syncHashNumber = host()->chain().number() + 1; m_syncHashNumber = host()->chain().number() + 1;
requestStatus(); requestStatus();
} }
@ -52,8 +54,14 @@ EthereumPeer::~EthereumPeer()
void EthereumPeer::abortSync() void EthereumPeer::abortSync()
{ {
if (isSyncing()) host()->onPeerAborting(this);
setIdle(); }
void EthereumPeer::setRude()
{
m_isRude = true;
host()->noteRude(session()->id(), session()->info().clientVersion);
session()->addNote("manners", m_isRude ? "RUDE" : "nice");
} }
EthereumHost* EthereumPeer::host() const EthereumHost* EthereumPeer::host() const
@ -105,6 +113,7 @@ void EthereumPeer::requestHashes()
{ {
assert(m_asking == Asking::Nothing); assert(m_asking == Asking::Nothing);
m_syncHashNumber = m_hashSub.nextFetch(c_maxHashesAsk); m_syncHashNumber = m_hashSub.nextFetch(c_maxHashesAsk);
m_syncHash = h256();
setAsking(Asking::Hashes); setAsking(Asking::Hashes);
RLPStream s; RLPStream s;
prep(s, GetBlockHashesByNumberPacket, 2) << m_syncHashNumber << c_maxHashesAsk; prep(s, GetBlockHashesByNumberPacket, 2) << m_syncHashNumber << c_maxHashesAsk;
@ -119,6 +128,8 @@ void EthereumPeer::requestHashes(h256 const& _lastHash)
RLPStream s; RLPStream s;
prep(s, GetBlockHashesPacket, 2) << _lastHash << c_maxHashesAsk; prep(s, GetBlockHashesPacket, 2) << _lastHash << c_maxHashesAsk;
clog(NetMessageDetail) << "Requesting block hashes staring from " << _lastHash; clog(NetMessageDetail) << "Requesting block hashes staring from " << _lastHash;
m_syncHash = _lastHash;
m_syncHashNumber = 0;
sealAndSend(s); sealAndSend(s);
} }
@ -175,8 +186,16 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
m_genesisHash = _r[4].toHash<h256>(); m_genesisHash = _r[4].toHash<h256>();
if (m_peerCapabilityVersion == host()->protocolVersion()) if (m_peerCapabilityVersion == host()->protocolVersion())
{ {
m_protocolVersion = host()->protocolVersion(); if (_r.itemCount() != 6)
m_latestBlockNumber = _r[5].toInt<u256>(); {
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; clog(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << m_genesisHash << "/" << m_latestBlockNumber << ", TD:" << m_totalDifficulty << "=" << m_latestHash;
@ -240,12 +259,10 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
setAsking(Asking::Nothing); setAsking(Asking::Nothing);
h256s hashes(itemCount); h256s hashes(itemCount);
for (unsigned i = 0; i < itemCount; ++i) for (unsigned i = 0; i < itemCount; ++i)
{
hashes[i] = _r[i].toHash<h256>(); hashes[i] = _r[i].toHash<h256>();
m_hashSub.noteHash(m_syncHashNumber + i, 1);
}
m_syncHashNumber += itemCount; if (m_syncHashNumber > 0)
m_syncHashNumber += itemCount;
host()->onPeerHashes(this, hashes); host()->onPeerHashes(this, hashes);
break; break;
} }

15
libethereum/EthereumPeer.h

@ -82,6 +82,12 @@ public:
/// Request blocks. Uses block download manager. /// Request blocks. Uses block download manager.
void requestBlocks(); void requestBlocks();
/// Check if this node is rude.
bool isRude() const { return m_isRude; }
/// Set that it's a rude node.
void setRude();
private: private:
using p2p::Capability::sealAndSend; using p2p::Capability::sealAndSend;
@ -101,7 +107,7 @@ private:
void setAsking(Asking _g); void setAsking(Asking _g);
/// Do we presently need syncing with this peer? /// Do we presently need syncing with this peer?
bool needsSyncing() const { return !!m_latestHash; } bool needsSyncing() const { return !isRude() && !!m_latestHash; }
/// Are we presently syncing with this peer? /// Are we presently syncing with this peer?
bool isSyncing() const; bool isSyncing() const;
@ -128,8 +134,9 @@ private:
/// This is built as we ask for hashes. Once no more hashes are given, we present this to the /// 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. /// host who initialises the DownloadMan and m_sub becomes active for us to begin asking for blocks.
unsigned m_expectedHashes = 0; ///< Estimated upper bound of hashes to expect from this peer. unsigned m_expectedHashes = 0; ///< Estimated upper bound of hashes to expect from this peer.
unsigned m_syncHashNumber = 0; ///< Number of latest hash we sync to unsigned m_syncHashNumber = 0; ///< Number of latest hash we sync to (PV61+)
h256 m_syncHash; ///< Latest hash we sync to (PV60)
/// Once we're asking for blocks, this becomes in use. /// Once we're asking for blocks, this becomes in use.
DownloadSub m_sub; DownloadSub m_sub;
@ -145,6 +152,8 @@ private:
h256Hash m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them). h256Hash m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them).
Mutex x_knownTransactions; Mutex x_knownTransactions;
h256Hash m_knownTransactions; ///< Transactions that the peer already knows of. h256Hash m_knownTransactions; ///< Transactions that the peer already knows of.
bool m_isRude; ///< True if this node has been rude in the past.
}; };
} }

118
libethereum/Executive.cpp

@ -19,6 +19,9 @@
#include "Executive.h" #include "Executive.h"
#include <boost/timer.hpp> #include <boost/timer.hpp>
#if ETH_JSONRPC || !ETH_TRUE
#include <json/json.h>
#endif
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include <libevm/VM.h> #include <libevm/VM.h>
@ -34,6 +37,101 @@ using namespace dev::eth;
const char* VMTraceChannel::name() { return "EVM"; } const char* VMTraceChannel::name() { return "EVM"; }
const char* ExecutiveWarnChannel::name() { return WarnChannel::name(); } const char* ExecutiveWarnChannel::name() { return WarnChannel::name(); }
StandardTrace::StandardTrace():
m_trace(new Json::Value(Json::arrayValue))
{}
bool changesMemory(Instruction _inst)
{
return
_inst == Instruction::MSTORE ||
_inst == Instruction::MSTORE8 ||
_inst == Instruction::CALL ||
_inst == Instruction::CALLCODE ||
_inst == Instruction::SHA3 ||
_inst == Instruction::CALLDATACOPY ||
_inst == Instruction::CODECOPY ||
_inst == Instruction::EXTCODECOPY;
}
bool changesStorage(Instruction _inst)
{
return _inst == Instruction::SSTORE;
}
void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, VM* voidVM, ExtVMFace const* voidExt)
{
ExtVM const& ext = *static_cast<ExtVM const*>(voidExt);
VM& vm = *voidVM;
Json::Value r(Json::objectValue);
Json::Value stack(Json::arrayValue);
for (auto const& i: vm.stack())
stack.append(toHex(toCompactBigEndian(i), 1));
r["stack"] = stack;
bool newContext = false;
Instruction lastInst = Instruction::STOP;
if (m_lastInst.size() == ext.depth)
{
// starting a new context
assert(m_lastInst.size() == ext.depth);
m_lastInst.push_back(inst);
newContext = true;
}
else if (m_lastInst.size() == ext.depth + 2)
{
// returned from old context
m_lastInst.pop_back();
lastInst = m_lastInst.back();
}
else if (m_lastInst.size() == ext.depth + 1)
{
// continuing in previous context
lastInst = m_lastInst.back();
}
else
{
cwarn << "GAA!!! Tracing VM and more than one new/deleted stack frame between steps!";
cwarn << "Attmepting naive recovery...";
m_lastInst.resize(ext.depth + 1);
}
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 (changesStorage(lastInst) || newContext)
{
Json::Value storage(Json::objectValue);
for (auto const& i: ext.state().storage(ext.myAddress))
storage[toHex(toCompactBigEndian(i.first), 1)] = toHex(toCompactBigEndian(i.second), 1);
r["storage"] = storage;
}
r["depth"] = ext.depth;
r["address"] = ext.myAddress.hex();
r["steps"] = (unsigned)_steps;
r["inst"] = (unsigned)inst;
r["pc"] = toString(vm.curPC());
r["gas"] = toString(gas);
r["gascost"] = toString(gasCost);
r["memexpand"] = toString(newMemSize);
m_trace->append(r);
}
string StandardTrace::json() const
{
return Json::FastWriter().write(*m_trace);
}
Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level):
m_s(_s), m_s(_s),
m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)), m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)),
@ -68,7 +166,7 @@ void Executive::initialize(Transaction const& _transaction)
if (!m_t.checkPayment()) if (!m_t.checkPayment())
{ {
clog(ExecutiveWarnChannel) << "Not enough gas to pay for the transaction: Require >" << m_t.gasRequired() << " Got" << m_t.gas(); clog(ExecutiveWarnChannel) << "Not enough gas to pay for the transaction: Require >" << m_t.gasRequired() << " Got" << m_t.gas();
m_excepted = TransactionException::OutOfGas; m_excepted = TransactionException::OutOfGasBase;
BOOST_THROW_EXCEPTION(OutOfGasBase() << RequirementError(m_t.gasRequired(), (bigint)m_t.gas())); BOOST_THROW_EXCEPTION(OutOfGasBase() << RequirementError(m_t.gasRequired(), (bigint)m_t.gas()));
} }
@ -202,24 +300,6 @@ OnOpFunc Executive::simpleTrace()
}; };
} }
OnOpFunc Executive::standardTrace(ostream& o_output)
{
return [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, VM* voidVM, ExtVMFace const* voidExt)
{
ExtVM const& ext = *static_cast<ExtVM const*>(voidExt);
VM& vm = *voidVM;
o_output << endl << " STACK" << endl;
for (auto i: vm.stack())
o_output << (h256)i << endl;
o_output << " MEMORY" << endl << ((vm.memory().size() > 1000) ? " mem size greater than 1000 bytes " : memDump(vm.memory()));
o_output << " STORAGE" << endl;
for (auto const& i: ext.state().storage(ext.myAddress))
o_output << showbase << hex << i.first << ": " << i.second << endl;
o_output << " < " << dec << ext.depth << " : " << ext.myAddress << " : #" << steps << " : " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " : " << dec << gas << " : -" << dec << gasCost << " : " << newMemSize << "x32" << " >";
};
}
bool Executive::go(OnOpFunc const& _onOp) bool Executive::go(OnOpFunc const& _onOp)
{ {
if (m_ext) if (m_ext)

18
libethereum/Executive.h

@ -25,6 +25,11 @@
#include <libevm/VMFace.h> #include <libevm/VMFace.h>
#include "Transaction.h" #include "Transaction.h"
namespace Json
{
class Value;
}
namespace dev namespace dev
{ {
namespace eth namespace eth
@ -38,6 +43,19 @@ struct Manifest;
struct VMTraceChannel: public LogChannel { static const char* name(); static const int verbosity = 11; }; struct VMTraceChannel: public LogChannel { static const char* name(); static const int verbosity = 11; };
struct ExecutiveWarnChannel: public LogChannel { static const char* name(); static const int verbosity = 6; }; struct ExecutiveWarnChannel: public LogChannel { static const char* name(); static const int verbosity = 6; };
class StandardTrace
{
public:
StandardTrace();
void operator()(uint64_t _steps, Instruction _inst, bigint _newMemSize, bigint _gasCost, bigint _gas, VM* _vm, ExtVMFace const* _extVM);
std::string json() const;
private:
std::vector<Instruction> m_lastInst;
std::shared_ptr<Json::Value> m_trace;
};
/** /**
* @brief Message-call/contract-creation executor; useful for executing transactions. * @brief Message-call/contract-creation executor; useful for executing transactions.
* *

2
libethereum/Interface.h

@ -198,6 +198,8 @@ public:
virtual void stopMining() = 0; virtual void stopMining() = 0;
/// Are we mining now? /// Are we mining now?
virtual bool isMining() const = 0; virtual bool isMining() const = 0;
/// Would we like to mine now?
virtual bool wouldMine() const = 0;
/// Current hash rate. /// Current hash rate.
virtual uint64_t hashrate() const = 0; virtual uint64_t hashrate() const = 0;

8
libethereum/Precompiled.cpp

@ -55,9 +55,13 @@ void ecrecoverCode(bytesConstRef _in, bytesRef _out)
{ {
try try
{ {
ret = sha3(recover(sig, in.hash)); Public rec = recover(sig, in.hash);
if (rec)
ret = dev::sha3(rec);
else
return;
} }
catch (...) {} catch (...) { return; }
} }
} }

31
libethereum/Sentinel.h

@ -0,0 +1,31 @@
/**
* This file is generated by jsonrpcstub, DO NOT CHANGE IT MANUALLY!
*/
#ifndef JSONRPC_CPP_STUB_DEV_ETH_SENTINEL_H_
#define JSONRPC_CPP_STUB_DEV_ETH_SENTINEL_H_
#include <jsonrpccpp/client.h>
namespace dev {
namespace eth {
class Sentinel : public jsonrpc::Client
{
public:
Sentinel(jsonrpc::IClientConnector &conn, jsonrpc::clientVersion_t type = jsonrpc::JSONRPC_CLIENT_V2) : jsonrpc::Client(conn, type) {}
int eth_badBlock(const Json::Value& param1) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
Json::Value result = this->CallMethod("eth_badBlock",p);
if (result.isInt())
return result.asInt();
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
};
}
}
#endif //JSONRPC_CPP_STUB_DEV_ETH_SENTINEL_H_

3
libethereum/Sentinel.json

@ -0,0 +1,3 @@
[
{ "name": "eth_badBlock", "params": [ {} ], "order": [], "returns": 0 }
]

157
libethereum/State.cpp

@ -158,6 +158,7 @@ State::State(State const& _s):
m_transactions(_s.m_transactions), m_transactions(_s.m_transactions),
m_receipts(_s.m_receipts), m_receipts(_s.m_receipts),
m_transactionSet(_s.m_transactionSet), m_transactionSet(_s.m_transactionSet),
m_touched(_s.m_touched),
m_cache(_s.m_cache), m_cache(_s.m_cache),
m_previousBlock(_s.m_previousBlock), m_previousBlock(_s.m_previousBlock),
m_currentBlock(_s.m_currentBlock), m_currentBlock(_s.m_currentBlock),
@ -206,7 +207,7 @@ State::~State()
{ {
} }
StateDiff State::diff(State const& _c) const StateDiff State::diff(State const& _c, bool _quick) const
{ {
StateDiff ret; StateDiff ret;
@ -217,19 +218,29 @@ StateDiff State::diff(State const& _c) const
auto trie = SecureTrieDB<Address, OverlayDB>(const_cast<OverlayDB*>(&m_db), rootHash()); auto trie = SecureTrieDB<Address, OverlayDB>(const_cast<OverlayDB*>(&m_db), rootHash());
auto trieD = SecureTrieDB<Address, OverlayDB>(const_cast<OverlayDB*>(&_c.m_db), _c.rootHash()); auto trieD = SecureTrieDB<Address, OverlayDB>(const_cast<OverlayDB*>(&_c.m_db), _c.rootHash());
for (auto i: trie) if (_quick)
ads.insert(i.first), trieAds.insert(i.first); {
for (auto i: trieD) trieAds = m_touched;
ads.insert(i.first), trieAdsD.insert(i.first); trieAdsD = _c.m_touched;
for (auto i: m_cache) (ads += m_touched) += _c.m_touched;
}
else
{
for (auto const& i: trie)
ads.insert(i.first), trieAds.insert(i.first);
for (auto const& i: trieD)
ads.insert(i.first), trieAdsD.insert(i.first);
}
for (auto const& i: m_cache)
ads.insert(i.first); ads.insert(i.first);
for (auto i: _c.m_cache) for (auto const& i: _c.m_cache)
ads.insert(i.first); ads.insert(i.first);
// cnote << *this; // cnote << *this;
// cnote << _c; // cnote << _c;
for (auto i: ads) for (auto const& i: ads)
{ {
auto it = m_cache.find(i); auto it = m_cache.find(i);
auto itD = _c.m_cache.find(i); auto itD = _c.m_cache.find(i);
@ -272,7 +283,7 @@ void State::ensureCached(std::unordered_map<Address, Account>& _cache, Address _
void State::commit() void State::commit()
{ {
dev::eth::commit(m_cache, m_db, m_state); m_touched += dev::eth::commit(m_cache, m_db, m_state);
m_cache.clear(); m_cache.clear();
} }
@ -450,6 +461,7 @@ void State::resetCurrent()
m_receipts.clear(); m_receipts.clear();
m_transactionSet.clear(); m_transactionSet.clear();
m_cache.clear(); m_cache.clear();
m_touched.clear();
m_currentBlock = BlockInfo(); m_currentBlock = BlockInfo();
m_currentBlock.coinbaseAddress = m_ourAddress; m_currentBlock.coinbaseAddress = m_ourAddress;
m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0)); m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0));
@ -577,19 +589,20 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire
LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number);
vector<bytes> receipts; vector<bytes> receipts;
ostringstream ss; string ret;
unsigned i = 0; unsigned i = 0;
for (auto const& tr: rlp[1]) for (auto const& tr: rlp[1])
{ {
ss << " VM Execution of transaction" << i << ":" << endl; StandardTrace st;
execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, Executive::standardTrace(ss)); execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, [&](uint64_t _steps, Instruction _inst, bigint _newMemSize, bigint _gasCost, bigint _gas, VM* _vm, ExtVMFace const* _extVM) { st(_steps, _inst, _newMemSize, _gasCost, _gas, _vm, _extVM); });
ret += (ret.empty() ? "[" : ",") + st.json();
RLPStream receiptRLP; RLPStream receiptRLP;
m_receipts.back().streamRLP(receiptRLP); m_receipts.back().streamRLP(receiptRLP);
receipts.push_back(receiptRLP.out()); receipts.push_back(receiptRLP.out());
++i; ++i;
ss << endl;
} }
return ss.str(); return ret.empty() ? "[]" : (ret + "]");
} }
u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir) u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir)
@ -605,6 +618,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
#endif #endif
if (m_currentBlock.parentHash != m_previousBlock.hash()) if (m_currentBlock.parentHash != m_previousBlock.hash())
// Internal client error.
BOOST_THROW_EXCEPTION(InvalidParentHash()); BOOST_THROW_EXCEPTION(InvalidParentHash());
// Populate m_currentBlock with the correct values. // Populate m_currentBlock with the correct values.
@ -624,16 +638,19 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
unsigned i = 0; unsigned i = 0;
for (auto const& tr: rlp[1]) for (auto const& tr: rlp[1])
{ {
try { try
{
LogOverride<ExecutiveWarnChannel> o(false); LogOverride<ExecutiveWarnChannel> o(false);
execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); execute(lh, Transaction(tr.data(), CheckTransaction::Everything));
} }
catch (...) catch (Exception& ex)
{ {
badBlock(_block, "Invalid transaction"); badBlock(_block, "Invalid transaction: " + toString(toTransactionException(ex)));
cwarn << " Transaction Index:" << i; cwarn << " Transaction Index:" << i;
LogOverride<ExecutiveWarnChannel> o(true); LogOverride<ExecutiveWarnChannel> o(true);
execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); DEV_IGNORE_EXCEPTIONS(execute(lh, Transaction(tr.data(), CheckTransaction::Everything)));
ex << errinfo_transactionIndex(i);
throw; throw;
} }
@ -658,7 +675,12 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
cwarn << " " << TransactionReceipt(&b); cwarn << " " << TransactionReceipt(&b);
} }
cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir); cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir);
BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot());
InvalidReceiptsStateRoot ex;
ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot);
ex << errinfo_receipts(receipts);
ex << errinfo_vmtrace(vmTrace(_block, _bc, _ir));
BOOST_THROW_EXCEPTION(ex);
} }
if (m_currentBlock.logBloom != logBloom()) if (m_currentBlock.logBloom != logBloom())
@ -671,7 +693,10 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
cwarn << " " << j << ":" << TransactionReceipt(&b).bloom().hex(); cwarn << " " << j << ":" << TransactionReceipt(&b).bloom().hex();
} }
cwarn << " Final bloom:" << m_currentBlock.logBloom.hex(); cwarn << " Final bloom:" << m_currentBlock.logBloom.hex();
BOOST_THROW_EXCEPTION(InvalidLogBloom()); InvalidLogBloom ex;
ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom);
ex << errinfo_receipts(receipts);
BOOST_THROW_EXCEPTION(ex);
} }
// Initialise total difficulty calculation. // Initialise total difficulty calculation.
@ -681,45 +706,70 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
if (rlp[2].itemCount() > 2) if (rlp[2].itemCount() > 2)
{ {
badBlock(_block, "Too many uncles"); badBlock(_block, "Too many uncles");
BOOST_THROW_EXCEPTION(TooManyUncles()); BOOST_THROW_EXCEPTION(TooManyUncles() << errinfo_max(2) << errinfo_got(rlp[2].itemCount()));
} }
vector<BlockInfo> rewarded; vector<BlockInfo> rewarded;
h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6);
excluded.insert(m_currentBlock.hash()); excluded.insert(m_currentBlock.hash());
unsigned ii = 0;
for (auto const& i: rlp[2]) for (auto const& i: rlp[2])
{ {
auto h = sha3(i.data()); try
if (excluded.count(h))
{ {
badBlock(_block, "Invalid uncle included"); auto h = sha3(i.data());
BOOST_THROW_EXCEPTION(UncleInChain() << errinfo_comment("Uncle in block already mentioned") << errinfo_data(toString(excluded)) << errinfo_hash256(sha3(i.data()))); if (excluded.count(h))
} {
excluded.insert(h); badBlock(_block, "Invalid uncle included");
UncleInChain ex;
ex << errinfo_comment("Uncle in block already mentioned");
ex << errinfo_unclesExcluded(excluded);
ex << errinfo_hash256(sha3(i.data()));
BOOST_THROW_EXCEPTION(ex);
}
excluded.insert(h);
BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); BlockInfo uncle;
BlockInfo uncleParent(_bc.block(uncle.parentHash)); BlockInfo uncleParent;
if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h);
{ if (!_bc.isKnown(uncle.parentHash))
badBlock(_block, "Uncle too old"); BOOST_THROW_EXCEPTION(UnknownParent());
cwarn << " Uncle number: " << uncle.number;
cwarn << " Uncle parent number: " << uncleParent.number; uncleParent = BlockInfo(_bc.block(uncle.parentHash));
cwarn << " Block number: " << m_currentBlock.number; if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7)
BOOST_THROW_EXCEPTION(UncleTooOld()); {
badBlock(_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);
BOOST_THROW_EXCEPTION(ex);
}
else if (uncle.number == m_currentBlock.number)
{
badBlock(_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);
BOOST_THROW_EXCEPTION(ex);
}
uncle.verifyParent(uncleParent);
// tdIncrease += uncle.difficulty;
rewarded.push_back(uncle);
++ii;
} }
else if (uncle.number == m_currentBlock.number) catch (Exception& ex)
{ {
badBlock(_block, "Uncle is brother"); ex << errinfo_uncleIndex(ii);
cwarn << " Uncle number: " << uncle.number; throw;
cwarn << " Uncle parent number: " << uncleParent.number;
cwarn << " Block number: " << m_currentBlock.number;
BOOST_THROW_EXCEPTION(UncleIsBrother());
} }
uncle.verifyParent(uncleParent);
// tdIncrease += uncle.difficulty;
rewarded.push_back(uncle);
} }
applyRewards(rewarded); applyRewards(rewarded);
@ -731,15 +781,8 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement
if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash())
{ {
badBlock(_block, "Bad state root"); badBlock(_block, "Bad state root");
cnote << " Given to be:" << m_currentBlock.stateRoot;
// TODO: Fix
// cnote << SecureTrieDB<Address, OverlayDB>(&m_db, m_currentBlock.stateRoot);
cnote << " Calculated to be:" << rootHash();
cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir);
// cnote << m_state;
// Rollback the trie.
m_db.rollback(); m_db.rollback();
BOOST_THROW_EXCEPTION(InvalidStateRoot()); BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot));
} }
if (m_currentBlock.gasUsed != gasUsed()) if (m_currentBlock.gasUsed != gasUsed())
@ -1188,8 +1231,10 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
if (!e.execute()) if (!e.execute())
#if ETH_VMTRACE #if ETH_VMTRACE
{ {
(void)_onOp; if (isChannelVisible<VMTraceChannel>())
e.go(e.simpleTrace()); e.go(e.simpleTrace());
else
e.go(_onOp);
} }
#else #else
e.go(_onOp); e.go(_onOp);

28
libethereum/State.h

@ -46,6 +46,22 @@ namespace test { class ImportTest; class StateLoader; }
namespace eth namespace eth
{ {
// Import-specific errinfos
using errinfo_uncleIndex = boost::error_info<struct tag_uncleIndex, unsigned>;
using errinfo_currentNumber = boost::error_info<struct tag_currentNumber, u256>;
using errinfo_uncleNumber = boost::error_info<struct tag_uncleNumber, u256>;
using errinfo_unclesExcluded = boost::error_info<struct tag_unclesExcluded, h256Hash>;
using errinfo_block = boost::error_info<struct tag_block, bytes>;
using errinfo_now = boost::error_info<struct tag_now, unsigned>;
using errinfo_transactionIndex = boost::error_info<struct tag_transactionIndex, unsigned>;
using errinfo_vmtrace = boost::error_info<struct tag_vmtrace, std::string>;
using errinfo_receipts = boost::error_info<struct tag_receipts, std::vector<bytes>>;
using errinfo_required_LogBloom = boost::error_info<struct tag_required_LogBloom, LogBloom>;
using errinfo_got_LogBloom = boost::error_info<struct tag_get_LogBloom, LogBloom>;
using LogBloomRequirementError = boost::tuple<errinfo_required_LogBloom, errinfo_got_LogBloom>;
class BlockChain; class BlockChain;
class State; class State;
@ -294,10 +310,12 @@ public:
State fromPending(unsigned _i) const; State fromPending(unsigned _i) const;
/// @returns the StateDiff caused by the pending transaction of index @a _i. /// @returns the StateDiff caused by the pending transaction of index @a _i.
StateDiff pendingDiff(unsigned _i) const { return fromPending(_i).diff(fromPending(_i + 1)); } StateDiff pendingDiff(unsigned _i) const { return fromPending(_i).diff(fromPending(_i + 1), true); }
/// @return the difference between this state (origin) and @a _c (destination). /// @return the difference between this state (origin) and @a _c (destination).
StateDiff diff(State const& _c) const; /// @param _quick if true doesn't check all addresses possible (/very/ slow for a full chain)
/// but rather only those touched by the transactions in creating the two States.
StateDiff diff(State const& _c, bool _quick = false) const;
/// Sync our state with the block chain. /// Sync our state with the block chain.
/// This basically involves wiping ourselves if we've been superceded and rebuilding from the transaction queue. /// This basically involves wiping ourselves if we've been superceded and rebuilding from the transaction queue.
@ -371,6 +389,7 @@ private:
TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts. TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts.
h256Hash m_transactionSet; ///< The set of transaction hashes that we've included in the state. h256Hash m_transactionSet; ///< The set of transaction hashes that we've included in the state.
OverlayDB m_lastTx; OverlayDB m_lastTx;
AddressHash m_touched; ///< Tracks all addresses touched by transactions so far.
mutable std::unordered_map<Address, Account> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed. mutable std::unordered_map<Address, Account> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed.
@ -394,8 +413,9 @@ private:
std::ostream& operator<<(std::ostream& _out, State const& _s); std::ostream& operator<<(std::ostream& _out, State const& _s);
template <class DB> template <class DB>
void commit(std::unordered_map<Address, Account> const& _cache, DB& _db, SecureTrieDB<Address, DB>& _state) AddressHash commit(std::unordered_map<Address, Account> const& _cache, DB& _db, SecureTrieDB<Address, DB>& _state)
{ {
AddressHash ret;
for (auto const& i: _cache) for (auto const& i: _cache)
if (i.second.isDirty()) if (i.second.isDirty())
{ {
@ -434,7 +454,9 @@ void commit(std::unordered_map<Address, Account> const& _cache, DB& _db, SecureT
_state.insert(i.first, &s.out()); _state.insert(i.first, &s.out());
} }
ret.insert(i.first);
} }
return ret;
} }
} }

43
libethereum/Transaction.cpp

@ -60,8 +60,25 @@ std::string badTransaction(bytesConstRef _tx, string const& _err)
return ret.str(); return ret.str();
} }
TransactionException dev::eth::toTransactionException(VMException const& _e) TransactionException dev::eth::toTransactionException(Exception const& _e)
{ {
// Basic Transaction exceptions
if (!!dynamic_cast<BadRLP const*>(&_e))
return TransactionException::BadRLP;
if (!!dynamic_cast<OutOfGasIntrinsic const*>(&_e))
return TransactionException::OutOfGasIntrinsic;
if (!!dynamic_cast<InvalidSignature const*>(&_e))
return TransactionException::InvalidSignature;
// Executive exceptions
if (!!dynamic_cast<OutOfGasBase const*>(&_e))
return TransactionException::OutOfGasBase;
if (!!dynamic_cast<InvalidNonce const*>(&_e))
return TransactionException::InvalidNonce;
if (!!dynamic_cast<NotEnoughCash const*>(&_e))
return TransactionException::NotEnoughCash;
if (!!dynamic_cast<BlockGasLimitReached const*>(&_e))
return TransactionException::BlockGasLimitReached;
// VM execution exceptions
if (!!dynamic_cast<BadInstruction const*>(&_e)) if (!!dynamic_cast<BadInstruction const*>(&_e))
return TransactionException::BadInstruction; return TransactionException::BadInstruction;
if (!!dynamic_cast<BadJumpDestination const*>(&_e)) if (!!dynamic_cast<BadJumpDestination const*>(&_e))
@ -75,6 +92,28 @@ TransactionException dev::eth::toTransactionException(VMException const& _e)
return TransactionException::Unknown; return TransactionException::Unknown;
} }
std::ostream& dev::eth::operator<<(std::ostream& _out, TransactionException const& _er)
{
switch (_er)
{
case TransactionException::None: _out << "None"; break;
case TransactionException::BadRLP: _out << "BadRLP"; break;
case TransactionException::OutOfGasIntrinsic: _out << "OutOfGasIntrinsic"; break;
case TransactionException::InvalidSignature: _out << "InvalidSignature"; break;
case TransactionException::InvalidNonce: _out << "InvalidNonce"; break;
case TransactionException::NotEnoughCash: _out << "NotEnoughCash"; break;
case TransactionException::OutOfGasBase: _out << "OutOfGasBase"; break;
case TransactionException::BlockGasLimitReached: _out << "BlockGasLimitReached"; break;
case TransactionException::BadInstruction: _out << "BadInstruction"; break;
case TransactionException::BadJumpDestination: _out << "BadJumpDestination"; break;
case TransactionException::OutOfGas: _out << "OutOfGas"; break;
case TransactionException::OutOfStack: _out << "OutOfStack"; break;
case TransactionException::StackUnderflow: _out << "StackUnderflow"; break;
default: _out << "Unknown"; break;
}
return _out;
}
Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig) Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig)
{ {
int field = 0; int field = 0;
@ -114,7 +153,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig)
throw; throw;
} }
if (_checkSig >= CheckTransaction::Cheap && !checkPayment()) if (_checkSig >= CheckTransaction::Cheap && !checkPayment())
BOOST_THROW_EXCEPTION(OutOfGasBase() << RequirementError(gasRequired(), (bigint)gas())); BOOST_THROW_EXCEPTION(OutOfGasIntrinsic() << RequirementError(gasRequired(), (bigint)gas()));
} }
Address const& Transaction::safeSender() const noexcept Address const& Transaction::safeSender() const noexcept

6
libethereum/Transaction.h

@ -25,6 +25,7 @@
#include <libdevcore/SHA3.h> #include <libdevcore/SHA3.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libevmcore/Params.h> #include <libevmcore/Params.h>
namespace dev namespace dev
{ {
namespace eth namespace eth
@ -48,6 +49,8 @@ enum class TransactionException
{ {
None = 0, None = 0,
Unknown, Unknown,
BadRLP,
OutOfGasIntrinsic, ///< Too little gas to pay for the base transaction cost.
InvalidSignature, InvalidSignature,
InvalidNonce, InvalidNonce,
NotEnoughCash, NotEnoughCash,
@ -69,7 +72,8 @@ enum class CodeDeposit
struct VMException; struct VMException;
TransactionException toTransactionException(VMException const& _e); TransactionException toTransactionException(Exception const& _e);
std::ostream& operator<<(std::ostream& _out, TransactionException const& _er);
/// Description of the result of executing a transaction. /// Description of the result of executing a transaction.
struct ExecutionResult struct ExecutionResult

322
libevm/VM.cpp

@ -45,165 +45,169 @@ static array<InstructionMetric, 256> metrics()
return s_ret; return s_ret;
} }
bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) void VM::checkRequirements(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, Instruction _inst)
{ {
// Reset leftovers from possible previous run static const auto c_metrics = metrics();
m_curPC = 0; auto& metric = c_metrics[static_cast<size_t>(_inst)];
m_jumpDests.clear();
m_stack.reserve((unsigned)c_stackLimit); if (metric.gasPriceTier == InvalidTier)
BOOST_THROW_EXCEPTION(BadInstruction());
unique_ptr<CallParameters> callParams; // FEES...
bigint runGas = c_tierStepGas[metric.gasPriceTier];
bigint newTempSize = m_temp.size();
bigint copySize = 0;
static const array<InstructionMetric, 256> c_metrics = metrics(); // should work, but just seems to result in immediate errorless exit on initial execution. yeah. weird.
//m_onFail = std::function<void()>(onOperation);
auto memNeed = [](u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; require(metric.args, metric.ret);
auto gasForMem = [](bigint _size) -> bigint
auto onOperation = [&]()
{ {
bigint s = _size / 32; if (_onOp)
return (bigint)c_memoryGas * s + s * s / c_quadCoeffDiv; _onOp(m_steps, _inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, io_gas, this, &_ext);
}; };
if (m_jumpDests.empty()) auto memNeed = [](u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; };
for (unsigned i = 0; i < _ext.code.size(); ++i)
switch (_inst)
{
case Instruction::SSTORE:
if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2])
runGas = c_sstoreSetGas;
else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2])
{ {
if (_ext.code[i] == (byte)Instruction::JUMPDEST) runGas = c_sstoreResetGas;
m_jumpDests.push_back(i); _ext.sub.refunds += c_sstoreRefundGas;
else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32)
i += _ext.code[i] - (unsigned)Instruction::PUSH1 + 1;
} }
u256 nextPC = m_curPC + 1; else
for (uint64_t steps = 0; true; m_curPC = nextPC, nextPC = m_curPC + 1, ++steps) runGas = c_sstoreResetGas;
break;
case Instruction::SLOAD:
runGas = c_sloadGas;
break;
// These all operate on memory and therefore potentially expand it:
case Instruction::MSTORE:
newTempSize = (bigint)m_stack.back() + 32;
break;
case Instruction::MSTORE8:
newTempSize = (bigint)m_stack.back() + 1;
break;
case Instruction::MLOAD:
newTempSize = (bigint)m_stack.back() + 32;
break;
case Instruction::RETURN:
newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]);
break;
case Instruction::SHA3:
runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas;
newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]);
break;
case Instruction::CALLDATACOPY:
copySize = m_stack[m_stack.size() - 3];
newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]);
break;
case Instruction::CODECOPY:
copySize = m_stack[m_stack.size() - 3];
newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]);
break;
case Instruction::EXTCODECOPY:
copySize = m_stack[m_stack.size() - 4];
newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]);
break;
case Instruction::JUMPDEST:
runGas = 1;
break;
case Instruction::LOG0:
case Instruction::LOG1:
case Instruction::LOG2:
case Instruction::LOG3:
case Instruction::LOG4:
{ {
// INSTRUCTION... unsigned n = (unsigned)_inst - (unsigned)Instruction::LOG0;
Instruction inst = (Instruction)_ext.getCode(m_curPC); runGas = c_logGas + c_logTopicGas * n + (bigint)c_logDataGas * m_stack[m_stack.size() - 2];
auto metric = c_metrics[(int)inst]; newTempSize = memNeed(m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]);
int gasPriceTier = metric.gasPriceTier; break;
}
if (gasPriceTier == InvalidTier)
BOOST_THROW_EXCEPTION(BadInstruction());
// FEES...
bigint runGas = c_tierStepGas[metric.gasPriceTier];
bigint newTempSize = m_temp.size();
bigint copySize = 0;
// should work, but just seems to result in immediate errorless exit on initial execution. yeah. weird.
//m_onFail = std::function<void()>(onOperation);
require(metric.args, metric.ret);
auto onOperation = [&]()
{
if (_onOp)
_onOp(steps, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, io_gas, this, &_ext);
};
switch (inst)
{
case Instruction::SSTORE:
if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2])
runGas = c_sstoreSetGas;
else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2])
{
runGas = c_sstoreResetGas;
_ext.sub.refunds += c_sstoreRefundGas;
}
else
runGas = c_sstoreResetGas;
break;
case Instruction::SLOAD: case Instruction::CALL:
runGas = c_sloadGas; case Instruction::CALLCODE:
break; runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1];
if (_inst != Instruction::CALLCODE && !_ext.exists(asAddress(m_stack[m_stack.size() - 2])))
runGas += c_callNewAccountGas;
if (m_stack[m_stack.size() - 3] > 0)
runGas += c_callValueTransferGas;
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::CREATE:
{
newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]);
runGas = c_createGas;
break;
}
case Instruction::EXP:
{
auto expon = m_stack[m_stack.size() - 2];
runGas = c_expGas + c_expByteGas * (32 - (h256(expon).firstBitSet() / 8));
break;
}
default:;
}
// These all operate on memory and therefore potentially expand it: auto gasForMem = [](bigint _size) -> bigint
case Instruction::MSTORE: {
newTempSize = (bigint)m_stack.back() + 32; bigint s = _size / 32;
break; return (bigint)c_memoryGas * s + s * s / c_quadCoeffDiv;
case Instruction::MSTORE8: };
newTempSize = (bigint)m_stack.back() + 1;
break;
case Instruction::MLOAD:
newTempSize = (bigint)m_stack.back() + 32;
break;
case Instruction::RETURN:
newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]);
break;
case Instruction::SHA3:
runGas = c_sha3Gas + (m_stack[m_stack.size() - 2] + 31) / 32 * c_sha3WordGas;
newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 2]);
break;
case Instruction::CALLDATACOPY:
copySize = m_stack[m_stack.size() - 3];
newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]);
break;
case Instruction::CODECOPY:
copySize = m_stack[m_stack.size() - 3];
newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]);
break;
case Instruction::EXTCODECOPY:
copySize = m_stack[m_stack.size() - 4];
newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]);
break;
case Instruction::JUMPDEST: newTempSize = (newTempSize + 31) / 32 * 32;
runGas = 1; if (newTempSize > m_temp.size())
break; runGas += gasForMem(newTempSize) - gasForMem(m_temp.size());
runGas += c_copyGas * ((copySize + 31) / 32);
case Instruction::LOG0: onOperation();
case Instruction::LOG1:
case Instruction::LOG2:
case Instruction::LOG3:
case Instruction::LOG4:
{
unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0;
runGas = c_logGas + c_logTopicGas * n + (bigint)c_logDataGas * m_stack[m_stack.size() - 2];
newTempSize = memNeed(m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]);
break;
}
case Instruction::CALL: if (io_gas < runGas)
case Instruction::CALLCODE: BOOST_THROW_EXCEPTION(OutOfGas());
runGas = (bigint)c_callGas + m_stack[m_stack.size() - 1];
if (inst != Instruction::CALLCODE && !_ext.exists(asAddress(m_stack[m_stack.size() - 2])))
runGas += c_callNewAccountGas;
if (m_stack[m_stack.size() - 3] > 0)
runGas += c_callValueTransferGas;
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::CREATE: io_gas -= (u256)runGas;
{
newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]);
runGas = c_createGas;
break;
}
case Instruction::EXP:
{
auto expon = m_stack[m_stack.size() - 2];
runGas = c_expGas + c_expByteGas * (32 - (h256(expon).firstBitSet() / 8));
break;
}
default:;
}
newTempSize = (newTempSize + 31) / 32 * 32; if (newTempSize > m_temp.size())
if (newTempSize > m_temp.size()) m_temp.resize((size_t)newTempSize);
runGas += gasForMem(newTempSize) - gasForMem(m_temp.size()); }
runGas += c_copyGas * ((copySize + 31) / 32);
onOperation(); bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
{
m_stack.reserve((unsigned)c_stackLimit);
if (io_gas < runGas) for (size_t i = 0; i < _ext.code.size(); ++i)
BOOST_THROW_EXCEPTION(OutOfGas()); {
if (_ext.code[i] == (byte)Instruction::JUMPDEST)
m_jumpDests.push_back(i);
else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32)
i += _ext.code[i] - (size_t)Instruction::PUSH1 + 1;
}
io_gas -= (u256)runGas; auto verifyJumpDest = [](u256 const& _dest, std::vector<uint64_t> const& _validDests)
{
auto nextPC = static_cast<uint64_t>(_dest);
if (!std::binary_search(_validDests.begin(), _validDests.end(), nextPC) || _dest > std::numeric_limits<uint64_t>::max())
BOOST_THROW_EXCEPTION(BadJumpDestination());
return nextPC;
};
if (newTempSize > m_temp.size()) m_steps = 0;
m_temp.resize((size_t)newTempSize); for (auto nextPC = m_curPC + 1; true; m_curPC = nextPC, nextPC = m_curPC + 1, ++m_steps)
{
Instruction inst = (Instruction)_ext.getCode(m_curPC);
checkRequirements(io_gas, _ext, _onOp, inst);
// EXECUTE...
switch (inst) switch (inst)
{ {
case Instruction::ADD: case Instruction::ADD:
@ -299,7 +303,7 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
case Instruction::SIGNEXTEND: case Instruction::SIGNEXTEND:
if (m_stack.back() < 31) if (m_stack.back() < 31)
{ {
unsigned const testBit(m_stack.back() * 8 + 7); auto testBit = static_cast<unsigned>(m_stack.back()) * 8 + 7;
u256& number = m_stack[m_stack.size() - 2]; u256& number = m_stack[m_stack.size() - 2];
u256 mask = ((u256(1) << testBit) - 1); u256 mask = ((u256(1) << testBit) - 1);
if (boost::multiprecision::bit_test(number, testBit)) if (boost::multiprecision::bit_test(number, testBit))
@ -480,7 +484,7 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
case Instruction::DUP15: case Instruction::DUP15:
case Instruction::DUP16: case Instruction::DUP16:
{ {
auto n = 1 + (int)inst - (int)Instruction::DUP1; auto n = 1 + (unsigned)inst - (unsigned)Instruction::DUP1;
m_stack.push_back(m_stack[m_stack.size() - n]); m_stack.push_back(m_stack[m_stack.size() - n]);
break; break;
} }
@ -501,7 +505,7 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
case Instruction::SWAP15: case Instruction::SWAP15:
case Instruction::SWAP16: case Instruction::SWAP16:
{ {
unsigned n = (int)inst - (int)Instruction::SWAP1 + 2; auto n = (unsigned)inst - (unsigned)Instruction::SWAP1 + 2;
auto d = m_stack.back(); auto d = m_stack.back();
m_stack.back() = m_stack[m_stack.size() - n]; m_stack.back() = m_stack[m_stack.size() - n];
m_stack[m_stack.size() - n] = d; m_stack[m_stack.size() - n] = d;
@ -535,18 +539,12 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::JUMP: case Instruction::JUMP:
nextPC = m_stack.back(); nextPC = verifyJumpDest(m_stack.back(), m_jumpDests);
if (find(m_jumpDests.begin(), m_jumpDests.end(), (uint64_t)nextPC) == m_jumpDests.end() || nextPC > numeric_limits<uint64_t>::max() )
BOOST_THROW_EXCEPTION(BadJumpDestination());
m_stack.pop_back(); m_stack.pop_back();
break; break;
case Instruction::JUMPI: case Instruction::JUMPI:
if (m_stack[m_stack.size() - 2]) if (m_stack[m_stack.size() - 2])
{ nextPC = verifyJumpDest(m_stack.back(), m_jumpDests);
nextPC = m_stack.back();
if (find(m_jumpDests.begin(), m_jumpDests.end(), (uint64_t)nextPC) == m_jumpDests.end() || nextPC > numeric_limits<uint64_t>::max() )
BOOST_THROW_EXCEPTION(BadJumpDestination());
}
m_stack.pop_back(); m_stack.pop_back();
m_stack.pop_back(); m_stack.pop_back();
break; break;
@ -598,7 +596,7 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
break; break;
case Instruction::CREATE: case Instruction::CREATE:
{ {
u256 endowment = m_stack.back(); auto endowment = m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned initOff = (unsigned)m_stack.back(); unsigned initOff = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
@ -614,16 +612,14 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
case Instruction::CALL: case Instruction::CALL:
case Instruction::CALLCODE: case Instruction::CALLCODE:
{ {
if (!callParams) CallParameters callParams;
callParams.reset(new CallParameters); callParams.gas = m_stack.back();
callParams->gas = m_stack.back();
if (m_stack[m_stack.size() - 3] > 0) if (m_stack[m_stack.size() - 3] > 0)
callParams->gas += c_callStipend; callParams.gas += c_callStipend;
m_stack.pop_back(); m_stack.pop_back();
callParams->codeAddress = asAddress(m_stack.back()); callParams.codeAddress = asAddress(m_stack.back());
m_stack.pop_back(); m_stack.pop_back();
callParams->value = m_stack.back(); callParams.value = m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
unsigned inOff = (unsigned)m_stack.back(); unsigned inOff = (unsigned)m_stack.back();
@ -635,19 +631,19 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
unsigned outSize = (unsigned)m_stack.back(); unsigned outSize = (unsigned)m_stack.back();
m_stack.pop_back(); m_stack.pop_back();
if (_ext.balance(_ext.myAddress) >= callParams->value && _ext.depth < 1024) if (_ext.balance(_ext.myAddress) >= callParams.value && _ext.depth < 1024)
{ {
callParams->onOp = _onOp; callParams.onOp = _onOp;
callParams->senderAddress = _ext.myAddress; callParams.senderAddress = _ext.myAddress;
callParams->receiveAddress = inst == Instruction::CALL ? callParams->codeAddress : callParams->senderAddress; callParams.receiveAddress = inst == Instruction::CALL ? callParams.codeAddress : callParams.senderAddress;
callParams->data = bytesConstRef(m_temp.data() + inOff, inSize); callParams.data = bytesConstRef(m_temp.data() + inOff, inSize);
callParams->out = bytesRef(m_temp.data() + outOff, outSize); callParams.out = bytesRef(m_temp.data() + outOff, outSize);
m_stack.push_back(_ext.call(*callParams)); m_stack.push_back(_ext.call(callParams));
} }
else else
m_stack.push_back(0); m_stack.push_back(0);
io_gas += callParams->gas; io_gas += callParams.gas;
break; break;
} }
case Instruction::RETURN: case Instruction::RETURN:

6
libevm/VM.h

@ -54,16 +54,18 @@ class VM: public VMFace
public: public:
virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) override final; virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) override final;
u256 curPC() const { return m_curPC; } uint64_t curPC() const { return m_curPC; }
bytes const& memory() const { return m_temp; } bytes const& memory() const { return m_temp; }
u256s const& stack() const { return m_stack; } u256s const& stack() const { return m_stack; }
private: private:
void checkRequirements(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, Instruction _inst);
void require(u256 _n, u256 _d) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackUnderflow() << RequirementError((bigint)_n, (bigint)m_stack.size())); } if (m_stack.size() - _n + _d > c_stackLimit) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(OutOfStack() << RequirementError((bigint)(_d - _n), (bigint)m_stack.size())); } } void require(u256 _n, u256 _d) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackUnderflow() << RequirementError((bigint)_n, (bigint)m_stack.size())); } if (m_stack.size() - _n + _d > c_stackLimit) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(OutOfStack() << RequirementError((bigint)(_d - _n), (bigint)m_stack.size())); } }
void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } }
u256 m_curPC = 0; uint64_t m_curPC = 0;
uint64_t m_steps = 0;
bytes m_temp; bytes m_temp;
u256s m_stack; u256s m_stack;
std::vector<uint64_t> m_jumpDests; std::vector<uint64_t> m_jumpDests;

1
libevm/VMFace.h

@ -25,6 +25,7 @@ namespace dev
namespace eth namespace eth
{ {
#define ETH_SIMPLE_EXCEPTION_VM(X) struct X: virtual VMException { public X(): VMException(#X) {} };
struct VMException: virtual Exception {}; struct VMException: virtual Exception {};
struct BreakPointHit: virtual VMException {}; struct BreakPointHit: virtual VMException {};
struct BadInstruction: virtual VMException {}; struct BadInstruction: virtual VMException {};

2
libevmasm/Assembly.cpp

@ -109,7 +109,7 @@ string Assembly::getLocationFromSources(StringMap const& _sourceCodes, SourceLoc
if (newLinePos != string::npos) if (newLinePos != string::npos)
cut = cut.substr(0, newLinePos) + "..."; cut = cut.substr(0, newLinePos) + "...";
return move(cut); return cut;
} }
ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const

4
libevmcore/Exceptions.h

@ -28,8 +28,8 @@ namespace dev
namespace eth namespace eth
{ {
struct InvalidDeposit: virtual Exception {}; DEV_SIMPLE_EXCEPTION(InvalidDeposit);
struct InvalidOpcode: virtual Exception {}; DEV_SIMPLE_EXCEPTION(InvalidOpcode);
} }
} }

4
libp2p/Common.h

@ -183,8 +183,8 @@ struct NodeIPEndpoint
uint16_t udpPort = 0; uint16_t udpPort = 0;
uint16_t tcpPort = 0; uint16_t tcpPort = 0;
operator bi::udp::endpoint() const { return std::move(bi::udp::endpoint(address, udpPort)); } operator bi::udp::endpoint() const { return bi::udp::endpoint(address, udpPort); }
operator bi::tcp::endpoint() const { return std::move(bi::tcp::endpoint(address, tcpPort)); } operator bi::tcp::endpoint() const { return bi::tcp::endpoint(address, tcpPort); }
operator bool() const { return !address.is_unspecified() && udpPort > 0 && tcpPort > 0; } operator bool() const { return !address.is_unspecified() && udpPort > 0 && tcpPort > 0; }

4
libp2p/Host.cpp

@ -834,7 +834,7 @@ KeyPair Host::networkAlias(bytesConstRef _b)
{ {
RLP r(_b); RLP r(_b);
if (r.itemCount() == 3 && r[0].isInt() && r[0].toInt<unsigned>() >= 3) if (r.itemCount() == 3 && r[0].isInt() && r[0].toInt<unsigned>() >= 3)
return move(KeyPair(move(Secret(r[1].toBytes())))); return KeyPair(Secret(r[1].toBytes()));
else else
return move(KeyPair::create()); return KeyPair::create();
} }

2
libp2p/Network.cpp

@ -111,7 +111,7 @@ std::set<bi::address> Network::getInterfaceAddresses()
#endif #endif
return std::move(addresses); return addresses;
} }
int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs) int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs)

12
libp2p/NodeTable.cpp

@ -88,7 +88,7 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node, NodeRelation _relati
} }
if (!_node.endpoint) if (!_node.endpoint)
return move(shared_ptr<NodeEntry>()); return shared_ptr<NodeEntry>();
// ping address to recover nodeid if nodeid is empty // ping address to recover nodeid if nodeid is empty
if (!_node.id) if (!_node.id)
@ -98,7 +98,7 @@ shared_ptr<NodeEntry> NodeTable::addNode(Node const& _node, NodeRelation _relati
DEV_GUARDED(x_pubkDiscoverPings) DEV_GUARDED(x_pubkDiscoverPings)
m_pubkDiscoverPings[_node.endpoint.address] = std::chrono::steady_clock::now(); m_pubkDiscoverPings[_node.endpoint.address] = std::chrono::steady_clock::now();
ping(_node.endpoint); ping(_node.endpoint);
return move(shared_ptr<NodeEntry>()); return shared_ptr<NodeEntry>();
} }
DEV_GUARDED(x_nodes) DEV_GUARDED(x_nodes)
@ -129,7 +129,7 @@ list<NodeId> NodeTable::nodes() const
DEV_GUARDED(x_nodes) DEV_GUARDED(x_nodes)
for (auto& i: m_nodes) for (auto& i: m_nodes)
nodes.push_back(i.second->id); nodes.push_back(i.second->id);
return move(nodes); return nodes;
} }
list<NodeEntry> NodeTable::snapshot() const list<NodeEntry> NodeTable::snapshot() const
@ -140,7 +140,7 @@ list<NodeEntry> NodeTable::snapshot() const
for (auto const& np: s.nodes) for (auto const& np: s.nodes)
if (auto n = np.lock()) if (auto n = np.lock())
ret.push_back(*n); ret.push_back(*n);
return move(ret); return ret;
} }
Node NodeTable::node(NodeId const& _id) Node NodeTable::node(NodeId const& _id)
@ -282,7 +282,7 @@ vector<shared_ptr<NodeEntry>> NodeTable::nearestNodeEntries(NodeId _target)
for (auto const& n: nodes.second) for (auto const& n: nodes.second)
if (ret.size() < s_bucketSize && !!n->endpoint && n->endpoint.isAllowed()) if (ret.size() < s_bucketSize && !!n->endpoint && n->endpoint.isAllowed())
ret.push_back(n); ret.push_back(n);
return move(ret); return ret;
} }
void NodeTable::ping(NodeIPEndpoint _to) const void NodeTable::ping(NodeIPEndpoint _to) const
@ -422,8 +422,8 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes
unsigned packetType = signedBytes[0]; unsigned packetType = signedBytes[0];
bytesConstRef rlpBytes(_packet.cropped(h256::size + Signature::size + 1)); bytesConstRef rlpBytes(_packet.cropped(h256::size + Signature::size + 1));
RLP rlp(rlpBytes);
try { try {
RLP rlp(rlpBytes);
switch (packetType) switch (packetType)
{ {
case Pong::type: case Pong::type:

4
libp2p/RLPxFrameIO.cpp

@ -154,7 +154,7 @@ h128 RLPXFrameIO::egressDigest()
SHA3_256 h(m_egressMac); SHA3_256 h(m_egressMac);
h128 digest; h128 digest;
h.TruncatedFinal(digest.data(), h128::size); h.TruncatedFinal(digest.data(), h128::size);
return move(digest); return digest;
} }
h128 RLPXFrameIO::ingressDigest() h128 RLPXFrameIO::ingressDigest()
@ -162,7 +162,7 @@ h128 RLPXFrameIO::ingressDigest()
SHA3_256 h(m_ingressMac); SHA3_256 h(m_ingressMac);
h128 digest; h128 digest;
h.TruncatedFinal(digest.data(), h128::size); h.TruncatedFinal(digest.data(), h128::size);
return move(digest); return digest;
} }
void RLPXFrameIO::updateEgressMACWithHeader(bytesConstRef _headerCipher) void RLPXFrameIO::updateEgressMACWithHeader(bytesConstRef _headerCipher)

4
libp2p/UDP.cpp

@ -52,12 +52,12 @@ h256 RLPXDatagramFace::sign(Secret const& _k)
bytesConstRef signedRLPx(&data[h256::size], data.size() - h256::size); bytesConstRef signedRLPx(&data[h256::size], data.size() - h256::size);
dev::sha3(signedRLPx).ref().copyTo(rlpxHash); dev::sha3(signedRLPx).ref().copyTo(rlpxHash);
return std::move(sighash); return sighash;
} }
Public RLPXDatagramFace::authenticate(bytesConstRef _sig, bytesConstRef _rlp) Public RLPXDatagramFace::authenticate(bytesConstRef _sig, bytesConstRef _rlp)
{ {
Signature const& sig = *(Signature const*)_sig.data(); Signature const& sig = *(Signature const*)_sig.data();
return std::move(dev::recover(sig, sha3(_rlp))); return dev::recover(sig, sha3(_rlp));
} }

2
libp2p/UDP.h

@ -81,7 +81,7 @@ template <class T>
struct RLPXDatagram: public RLPXDatagramFace struct RLPXDatagram: public RLPXDatagramFace
{ {
RLPXDatagram(bi::udp::endpoint const& _ep): RLPXDatagramFace(_ep) {} RLPXDatagram(bi::udp::endpoint const& _ep): RLPXDatagramFace(_ep) {}
static T fromBytesConstRef(bi::udp::endpoint const& _ep, bytesConstRef _bytes) { try { T t(_ep); t.interpretRLP(_bytes); return std::move(t); } catch(...) { T t(_ep); return std::move(t); } } static T fromBytesConstRef(bi::udp::endpoint const& _ep, bytesConstRef _bytes) { try { T t(_ep); t.interpretRLP(_bytes); return t; } catch(...) { return T{_ep}; } }
uint8_t packetType() { return T::type; } uint8_t packetType() { return T::type; }
}; };

42
libsolidity/AST.cpp

@ -410,7 +410,14 @@ void InheritanceSpecifier::checkTypeRequirements()
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call.")); BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call."));
for (size_t i = 0; i < m_arguments.size(); ++i) for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in constructer call.")); BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError(
"Invalid type for argument in constructor call. "
"Invalid implicit conversion from " +
m_arguments[i]->getType()->toString() +
" to " +
parameterTypes[i]->toString() +
" requested."
));
} }
TypePointer StructDefinition::getType(ContractDefinition const*) const TypePointer StructDefinition::getType(ContractDefinition const*) const
@ -592,7 +599,14 @@ void ModifierInvocation::checkTypeRequirements(vector<ContractDefinition const*>
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for modifier invocation.")); BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for modifier invocation."));
for (size_t i = 0; i < m_arguments.size(); ++i) for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*(*parameters)[i]->getType())) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*(*parameters)[i]->getType()))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in modifier invocation.")); BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError(
"Invalid type for argument in modifier invocation. "
"Invalid implicit conversion from " +
m_arguments[i]->getType()->toString() +
" to " +
(*parameters)[i]->getType()->toString() +
" requested."
));
} }
void EventDefinition::checkTypeRequirements() void EventDefinition::checkTypeRequirements()
@ -782,9 +796,18 @@ void FunctionCall::checkTypeRequirements(TypePointers const*)
{ {
// call by positional arguments // call by positional arguments
for (size_t i = 0; i < m_arguments.size(); ++i) for (size_t i = 0; i < m_arguments.size(); ++i)
if (!functionType->takesArbitraryParameters() && if (
!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) !functionType->takesArbitraryParameters() &&
BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError("Invalid type for argument in function call.")); !m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])
)
BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError(
"Invalid type for argument in function call. "
"Invalid implicit conversion from " +
m_arguments[i]->getType()->toString() +
" to " +
parameterTypes[i]->toString() +
" requested."
));
} }
else else
{ {
@ -808,7 +831,14 @@ void FunctionCall::checkTypeRequirements(TypePointers const*)
if (parameterNames[j] == *m_names[i]) { if (parameterNames[j] == *m_names[i]) {
// check type convertible // check type convertible
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[j])) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[j]))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError(
"Invalid type for argument in function call. "
"Invalid implicit conversion from " +
m_arguments[i]->getType()->toString() +
" to " +
parameterTypes[i]->toString() +
" requested."
));
found = true; found = true;
break; break;

2
libsolidity/AST.h

@ -503,7 +503,7 @@ public:
/// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly /// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly
/// declared and there is no assignment to the variable that fixes the type. /// declared and there is no assignment to the variable that fixes the type.
TypePointer getType(ContractDefinition const* = nullptr) const { return m_type; } TypePointer getType(ContractDefinition const* = nullptr) const override { return m_type; }
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; } void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
virtual bool isLValue() const override; virtual bool isLValue() const override;

2
libsolidity/CompilerContext.cpp

@ -133,7 +133,7 @@ set<Declaration const*> CompilerContext::getFunctionsWithoutCode()
for (auto const& it: m_functionEntryLabels) for (auto const& it: m_functionEntryLabels)
if (m_functionsWithCode.count(it.first) == 0) if (m_functionsWithCode.count(it.first) == 0)
functions.insert(it.first); functions.insert(it.first);
return move(functions); return functions;
} }
ModifierDefinition const& CompilerContext::getFunctionModifier(string const& _name) const ModifierDefinition const& CompilerContext::getFunctionModifier(string const& _name) const

2
libsolidity/LValue.h

@ -109,7 +109,7 @@ public:
StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration); StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration);
/// Constructs the LValue and assumes that the storage reference is already on the stack. /// Constructs the LValue and assumes that the storage reference is already on the stack.
StorageItem(CompilerContext& _compilerContext, Type const& _type); StorageItem(CompilerContext& _compilerContext, Type const& _type);
virtual unsigned sizeOnStack() const { return 2; } virtual unsigned sizeOnStack() const override { return 2; }
virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override; virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue( virtual void storeValue(
Type const& _sourceType, Type const& _sourceType,

12
libsolidity/Types.cpp

@ -1459,29 +1459,29 @@ MagicType::MagicType(MagicType::Kind _kind):
switch (m_kind) switch (m_kind)
{ {
case Kind::Block: case Kind::Block:
m_members = move(MemberList({ m_members = MemberList({
{"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::Address)}, {"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
{"timestamp", make_shared<IntegerType>(256)}, {"timestamp", make_shared<IntegerType>(256)},
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Location::BlockHash)}, {"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Location::BlockHash)},
{"difficulty", make_shared<IntegerType>(256)}, {"difficulty", make_shared<IntegerType>(256)},
{"number", make_shared<IntegerType>(256)}, {"number", make_shared<IntegerType>(256)},
{"gaslimit", make_shared<IntegerType>(256)} {"gaslimit", make_shared<IntegerType>(256)}
})); });
break; break;
case Kind::Message: case Kind::Message:
m_members = move(MemberList({ m_members = MemberList({
{"sender", make_shared<IntegerType>(0, IntegerType::Modifier::Address)}, {"sender", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
{"gas", make_shared<IntegerType>(256)}, {"gas", make_shared<IntegerType>(256)},
{"value", make_shared<IntegerType>(256)}, {"value", make_shared<IntegerType>(256)},
{"data", make_shared<ArrayType>(ReferenceType::Location::CallData)}, {"data", make_shared<ArrayType>(ReferenceType::Location::CallData)},
{"sig", make_shared<FixedBytesType>(4)} {"sig", make_shared<FixedBytesType>(4)}
})); });
break; break;
case Kind::Transaction: case Kind::Transaction:
m_members = move(MemberList({ m_members = MemberList({
{"origin", make_shared<IntegerType>(0, IntegerType::Modifier::Address)}, {"origin", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
{"gasprice", make_shared<IntegerType>(256)} {"gasprice", make_shared<IntegerType>(256)}
})); });
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic."));

4
libsolidity/Types.h

@ -407,7 +407,7 @@ public:
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(const Type& _other) const override; virtual bool operator==(const Type& _other) const override;
virtual unsigned getCalldataEncodedSize(bool _padded) const override; virtual unsigned getCalldataEncodedSize(bool _padded) const override;
virtual bool isDynamicallySized() const { return m_hasDynamicLength; } virtual bool isDynamicallySized() const override { return m_hasDynamicLength; }
virtual u256 getStorageSize() const override; virtual u256 getStorageSize() const override;
virtual unsigned getSizeOnStack() const override; virtual unsigned getSizeOnStack() const override;
virtual std::string toString() const override; virtual std::string toString() const override;
@ -820,7 +820,7 @@ public:
return TypePointer(); return TypePointer();
} }
virtual bool operator==(Type const& _other) const; virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; } virtual bool canBeStored() const override { return false; }
virtual bool canLiveOutsideStorage() const override { return true; } virtual bool canLiveOutsideStorage() const override { return true; }
virtual unsigned getSizeOnStack() const override { return 0; } virtual unsigned getSizeOnStack() const override { return 0; }

2
libtestutils/FixedClient.h

@ -48,7 +48,7 @@ public:
virtual eth::State asOf(h256 const& _h) const override; virtual eth::State asOf(h256 const& _h) const override;
virtual eth::State preMine() const override { ReadGuard l(x_stateDB); return m_state; } virtual eth::State preMine() const override { ReadGuard l(x_stateDB); return m_state; }
virtual eth::State postMine() const override { ReadGuard l(x_stateDB); return m_state; } virtual eth::State postMine() const override { ReadGuard l(x_stateDB); return m_state; }
virtual void setAddress(Address _us) { WriteGuard l(x_stateDB); m_state.setAddress(_us); } virtual void setAddress(Address _us) override { WriteGuard l(x_stateDB); m_state.setAddress(_us); }
virtual void prepareForTransaction() override {} virtual void prepareForTransaction() override {}
private: private:

2
libweb3jsonrpc/WebThreeStubServer.h

@ -43,7 +43,7 @@ class WebThreeStubServer: public dev::WebThreeStubServerBase, public dev::WebThr
public: public:
WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::shared_ptr<dev::eth::AccountHolder> const& _ethAccounts, std::vector<dev::KeyPair> const& _shhAccounts); WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::shared_ptr<dev::eth::AccountHolder> const& _ethAccounts, std::vector<dev::KeyPair> const& _shhAccounts);
virtual std::string web3_clientVersion(); virtual std::string web3_clientVersion() override;
private: private:
virtual dev::eth::Interface* client() override; virtual dev::eth::Interface* client() override;

8
libwhisper/WhisperHost.h

@ -54,7 +54,7 @@ public:
virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override; virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override;
virtual Topics const& fullTopics(unsigned _id) const { try { return m_filters.at(m_watches.at(_id).id).full; } catch (...) { return EmptyTopics; } } virtual Topics const& fullTopics(unsigned _id) const override { try { return m_filters.at(m_watches.at(_id).id).full; } catch (...) { return EmptyTopics; } }
virtual unsigned installWatch(Topics const& _filter) override; virtual unsigned installWatch(Topics const& _filter) override;
virtual unsigned installWatchOnId(h256 _filterId) override; virtual unsigned installWatchOnId(h256 _filterId) override;
virtual void uninstallWatch(unsigned _watchId) override; virtual void uninstallWatch(unsigned _watchId) override;
@ -69,11 +69,11 @@ public:
void cleanup(); void cleanup();
protected: protected:
void doWork(); virtual void doWork() override;
private: private:
virtual void onStarting() { startWorking(); } virtual void onStarting() override { startWorking(); }
virtual void onStopping() { stopWorking(); } virtual void onStopping() override { stopWorking(); }
void streamMessage(h256 _m, RLPStream& _s) const; void streamMessage(h256 _m, RLPStream& _s) const;

4
mix/ClientModel.cpp

@ -539,7 +539,9 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
// filter out locations that match whole function or contract // filter out locations that match whole function or contract
SourceLocation location = instruction.getLocation(); SourceLocation location = instruction.getLocation();
QString source = QString::fromUtf8(location.sourceName->c_str()); QString source;
if (location.sourceName)
source = QString::fromUtf8(location.sourceName->c_str());
if (m_codeModel->isContractOrFunctionLocation(location)) if (m_codeModel->isContractOrFunctionLocation(location))
location = dev::SourceLocation(-1, -1, location.sourceName); location = dev::SourceLocation(-1, -1, location.sourceName);

2
mix/CodeModel.cpp

@ -67,7 +67,7 @@ private:
return LocationPair(_node.getLocation().start, _node.getLocation().end); return LocationPair(_node.getLocation().start, _node.getLocation().end);
} }
virtual bool visit(FunctionDefinition const&) virtual bool visit(FunctionDefinition const&) override
{ {
m_functionScope = true; m_functionScope = true;
return true; return true;

44
mix/MixClient.cpp

@ -205,27 +205,29 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
switch (er.excepted) switch (er.excepted)
{ {
case TransactionException::None: case TransactionException::None:
break; break;
case TransactionException::NotEnoughCash: case TransactionException::NotEnoughCash:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment")); BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment"));
case TransactionException::OutOfGasBase: case TransactionException::OutOfGasIntrinsic:
case TransactionException::OutOfGas: case TransactionException::OutOfGasBase:
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas")); case TransactionException::OutOfGas:
case TransactionException::BlockGasLimitReached: BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas"));
BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached")); case TransactionException::BlockGasLimitReached:
case TransactionException::OutOfStack: BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached"));
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack")); case TransactionException::OutOfStack:
case TransactionException::StackUnderflow: BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack"));
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow")); case TransactionException::StackUnderflow:
//these should not happen in mix BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow"));
case TransactionException::Unknown: //these should not happen in mix
case TransactionException::BadInstruction: case TransactionException::Unknown:
case TransactionException::BadJumpDestination: case TransactionException::BadInstruction:
case TransactionException::InvalidSignature: case TransactionException::BadJumpDestination:
case TransactionException::InvalidNonce: case TransactionException::InvalidSignature:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error")); case TransactionException::InvalidNonce:
}; case TransactionException::BadRLP:
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error"));
}
ExecutionResult d; ExecutionResult d;
d.result = er; d.result = er;

2
mix/MixClient.h

@ -80,7 +80,7 @@ protected:
/// ClientBase methods /// ClientBase methods
using ClientBase::asOf; using ClientBase::asOf;
virtual dev::eth::State asOf(h256 const& _block) const override; virtual dev::eth::State asOf(h256 const& _block) const override;
virtual dev::eth::BlockChain& bc() { return *m_bc; } virtual dev::eth::BlockChain& bc() override { return *m_bc; }
virtual dev::eth::BlockChain const& bc() const override { return *m_bc; } virtual dev::eth::BlockChain const& bc() const override { return *m_bc; }
virtual dev::eth::State preMine() const override { ReadGuard l(x_state); return m_startState; } virtual dev::eth::State preMine() const override { ReadGuard l(x_state); return m_startState; }
virtual dev::eth::State postMine() const override { ReadGuard l(x_state); return m_state; } virtual dev::eth::State postMine() const override { ReadGuard l(x_state); return m_state; }

BIN
mix/qml/img/addblock.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 B

BIN
mix/qml/img/addblock@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
mix/qml/img/duplicateicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

BIN
mix/qml/img/duplicateicon@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
mix/qml/img/leftarrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

BIN
mix/qml/img/leftarrow@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 B

BIN
mix/qml/img/newaccounticon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

BIN
mix/qml/img/newaccounticon@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

BIN
mix/qml/img/recyclediscard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

BIN
mix/qml/img/recyclediscard@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
mix/qml/img/recycleicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

BIN
mix/qml/img/recycleicon@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
mix/qml/img/recyclekeep.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

BIN
mix/qml/img/recyclekeep@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
mix/qml/img/restoreicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
mix/qml/img/restoreicon@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
mix/qml/img/rightarrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

BIN
mix/qml/img/rightarrow@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

BIN
mix/qml/img/saveicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
mix/qml/img/saveicon@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
mix/qml/img/sendtransactionicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

BIN
mix/qml/img/sendtransactionicon@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

2384
test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json

File diff suppressed because it is too large

38
test/libethereum/StateTestsFiller/stSpecialTestFiller.json

@ -194,44 +194,6 @@
} }
}, },
"txfrom0_deja" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "256",
"currentGasLimit" : "1000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"code" : "0x6042601f53600064ffffffffff2080",
"nonce" : "0",
"storage" : {
}
},
"0000000000000000000000000000000000000000" : {
"balance" : "1000000000000000000",
"code" : "0x",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" : {
"data" : "",
"gasLimit" : "1000000",
"gasPrice" : "0",
"nonce" : "0",
"r" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"s" : "0xbadf00d70ec28c94a3b55ec771bcbc70778d6ee0b51ca7ea9514594c861b1884",
"v": "27",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000"
}
},
"JUMPDEST_Attack" : { "JUMPDEST_Attack" : {
"env" : { "env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",

15
test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json

@ -15,6 +15,21 @@
} }
}, },
"invalidSignature" : {
"expect" : "invalid",
"transaction" : {
"data" : "",
"gasLimit" : "1000000",
"gasPrice" : "0",
"nonce" : "0",
"r" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"s" : "0xbadf00d70ec28c94a3b55ec771bcbc70778d6ee0b51ca7ea9514594c861b1884",
"v": "27",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000"
}
},
"NotEnoughGasLimit" : { "NotEnoughGasLimit" : {
"expect" : "invalid", "expect" : "invalid",
"transaction" : "transaction" :

2
test/libp2p/net.cpp

@ -74,7 +74,7 @@ struct TestNodeTable: public NodeTable
ret.push_back(make_pair(k,s_basePort+i)); ret.push_back(make_pair(k,s_basePort+i));
} }
return std::move(ret); return ret;
} }
void pingTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes) void pingTestNodes(std::vector<std::pair<KeyPair,unsigned>> const& _testNodes)

4
test/libwhisper/whisperMessage.cpp

@ -37,7 +37,7 @@ Topics createRandomTopics(unsigned int i)
ret.push_back(t); ret.push_back(t);
} }
return move(ret); return ret;
} }
bytes createRandomPayload(unsigned int i) bytes createRandomPayload(unsigned int i)
@ -48,7 +48,7 @@ bytes createRandomPayload(unsigned int i)
for (int j = 0; j < sz; ++j) for (int j = 0; j < sz; ++j)
ret.push_back(rand() % 256); ret.push_back(rand() % 256);
return move(ret); return ret;
} }
void comparePayloads(Message const& m1, Message const& m2) void comparePayloads(Message const& m1, Message const& m2)

Loading…
Cancel
Save