diff --git a/abi/main.cpp b/abi/main.cpp index 7bb00e390..34187acc7 100644 --- a/abi/main.cpp +++ b/abi/main.cpp @@ -39,8 +39,10 @@ void help() << " abi dec -a [ | ]" << endl << "Options:" << endl << " -a,--abi-file Specify the JSON ABI file." << endl + << "Input options (enc mode):" << endl + << " -p,--prefix Require all arguments to be prefixed 0x (hex), . (decimal), # (binary)." << endl << "Output options (dec mode):" << endl - << " -i,--index When decoding, output only the nth (counting from 0) return value." << endl + << " -i,--index Output only the nth (counting from 0) return value." << endl << " -d,--decimal All data should be displayed as decimal." << endl << " -x,--hex Display all data as hex." << endl << " -b,--binary Display all data as binary." << endl @@ -72,16 +74,57 @@ enum class Encoding { Binary, }; +struct InvalidUserString: public Exception {}; + +pair fromUser(std::string const& _arg, bool _requirePrefix) +{ + if (_requirePrefix) + { + if (_arg.substr(0, 2) == "0x") + return make_pair(fromHex(_arg), false); + if (_arg.substr(0, 1) == ".") + return make_pair(toCompactBigEndian(bigint(_arg.substr(1))), false); + if (_arg.substr(0, 1) == "#") + return make_pair(asBytes(_arg.substr(1)), true); + throw InvalidUserString(); + } + else + { + if (_arg.substr(0, 2) == "0x") + return make_pair(fromHex(_arg), false); + if (_arg.find_first_not_of("0123456789")) + return make_pair(toCompactBigEndian(bigint(_arg)), false); + return make_pair(asBytes(_arg), true); + } +} + +bytes aligned(bytes const& _b, bool _left, unsigned _length) +{ + bytes ret = _b; + while (ret.size() < _length) + if (_left) + ret.push_back(0); + else + ret.insert(ret.begin(), 0); + while (ret.size() > _length) + if (_left) + ret.pop_back(); + else + ret.erase(ret.begin()); + return ret; +} + int main(int argc, char** argv) { Encoding encoding = Encoding::Auto; Mode mode = Mode::Encode; string abiFile; - string methodName; - bool outputPrefix = false; + string method; + bool prefix = false; bool clearZeroes = false; bool clearNulls = false; int outputIndex = -1; + vector> args; for (int i = 1; i < argc; ++i) { @@ -97,7 +140,7 @@ int main(int argc, char** argv) else if ((arg == "-i" || arg == "--index") && argc > i) outputIndex = atoi(argv[++i]); else if (arg == "-p" || arg == "--prefix") - outputPrefix = true; + prefix = true; else if (arg == "-z" || arg == "--no-zeroes") clearZeroes = true; else if (arg == "-n" || arg == "--no-nulls") @@ -110,8 +153,10 @@ int main(int argc, char** argv) encoding = Encoding::Binary; else if (arg == "-V" || arg == "--version") version(); + else if (method.empty()) + method = arg; else - methodName = arg; + args.push_back(fromUser(arg, prefix)); } string abi; @@ -122,16 +167,28 @@ int main(int argc, char** argv) abi = contentsString(abiFile); if (mode == Mode::Encode) + { + if (abi.empty()) + { + bytes ret; + if (!method.empty()) + ret = FixedHash<32>(sha3(method)).asBytes(); + if (method.empty()) + for (pair const& arg: args) + ret += aligned(arg.first, arg.second, 32); + } + else + { + // TODO: read abi. + } + } + else if (mode == Mode::Decode) { (void)encoding; - (void)outputPrefix; (void)clearZeroes; (void)clearNulls; (void)outputIndex; } - else if (mode == Mode::Decode) - { - } return 0; } diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4b9af1666..0ee2961a1 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -169,7 +169,7 @@ Main::Main(QWidget *parent) : bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), false, {"eth", "shh"}, p2p::NetworkPreferences(), network)); - m_httpConnector.reset(new jsonrpc::HttpServer(8080)); + m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), keysAsVector(m_myKeys), this)); connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); m_server->setIdentities(keysAsVector(owned())); diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index 7248ee4a6..534f18a69 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -328,8 +328,8 @@ void Transact::rejigData() to = m_context->fromString(ui->destination->currentText()); er = ethereum()->call(s, value(), to, m_data, ethereum()->gasLimitRemaining(), gasPrice()); } - gasNeeded = (qint64)er.gasUsed; - htmlInfo = QString("
INFO Gas required: %1 total = %2 base, %3 exec
").arg(gasNeeded).arg(baseGas).arg(gasNeeded - baseGas) + htmlInfo; + gasNeeded = (qint64)(er.gasUsed + er.gasRefunded); + htmlInfo = QString("
INFO Gas required: %1 total = %2 base, %3 exec [%4 refunded later]
").arg(gasNeeded).arg(baseGas).arg(gasNeeded - baseGas).arg((qint64)er.gasRefunded) + htmlInfo; if (er.excepted != TransactionException::None) { diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index a0d5a50c1..dd14b0650 100755 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -38,12 +38,14 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # disable decorated name length exceeded, name was truncated (4503) # disable warning C4535: calling _set_se_translator() requires /EHa (for boost tests) # declare Windows XP requirement - add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501) + # undefine windows.h MAX && MIN macros cause it cause conflicts with std::min && std::max functions + add_compile_options(/MP /EHsc /wd4068 /wd4996 /wd4503 -D_WIN32_WINNT=0x0501 /DNOMINMAX) # disable empty object file warning set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") # warning LNK4075: ignoring '/EDITANDCONTINUE' due to '/SAFESEH' specification # warning LNK4099: pdb was not found with lib - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075") + # stack size 16MB + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4099,4075 /STACK:16777216") # windows likes static set(ETH_STATIC 1) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index ea272da56..05893715e 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -30,6 +30,9 @@ if (APPLE) set (CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/local/opt/qt5") endif() +find_program(CTEST_COMMAND ctest) +message(STATUS "ctest path: ${CTEST_COMMAND}") + # Dependencies must have a version number, to ensure reproducible build. The version provided here is the one that is in the extdep repository. If you use system libraries, version numbers may be different. find_package (CryptoPP 5.6.2 EXACT REQUIRED) diff --git a/cmake/EthUtils.cmake b/cmake/EthUtils.cmake index c6fd43ed4..69690156a 100644 --- a/cmake/EthUtils.cmake +++ b/cmake/EthUtils.cmake @@ -22,3 +22,43 @@ macro(replace_if_different SOURCE DST) endif() endmacro() +macro(eth_add_test NAME) + + # parse arguments here + set(commands) + set(current_command "") + foreach (arg ${ARGN}) + if (arg STREQUAL "ARGS") + if (current_command) + list(APPEND commands ${current_command}) + endif() + set(current_command "") + else () + set(current_command "${current_command} ${arg}") + endif() + endforeach(arg) + list(APPEND commands ${current_command}) + + message(STATUS "test: ${NAME} | ${commands}") + + # create tests + set(index 0) + list(LENGTH commands count) + while (index LESS count) + list(GET commands ${index} test_arguments) + + set(run_test "--run_test=${NAME}") + add_test(NAME "${NAME}.${index}" COMMAND testeth ${run_test} ${test_arguments}) + + math(EXPR index "${index} + 1") + endwhile(index LESS count) + + # add target to run them + add_custom_target("test.${NAME}" + DEPENDS testeth + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -DETH_TEST_NAME="${NAME}" -DCTEST_COMMAND="${CTEST_COMMAND}" -P "${ETH_SCRIPTS_DIR}/runtest.cmake" + ) + +endmacro() + diff --git a/cmake/scripts/runtest.cmake b/cmake/scripts/runtest.cmake new file mode 100644 index 000000000..15f7409ef --- /dev/null +++ b/cmake/scripts/runtest.cmake @@ -0,0 +1,15 @@ +# Should be used to run ctest +# +# example usage: +# cmake -DETH_TEST_NAME=TestInterfaceStub -DCTEST_COMMAND=/path/to/ctest -P scripts/runtest.cmake + +if (NOT CTEST_COMMAND) + message(FATAL_ERROR "ctest could not be found!") +endif() + +# verbosity is off, cause BOOST_MESSAGE is not thread safe and output is a trash +# see https://codecrafter.wordpress.com/2012/11/01/c-unit-test-framework-adapter-part-3/ +# +# output might not be usefull cause of thread safety issue +execute_process(COMMAND ${CTEST_COMMAND} --force-new-ctest-process -C Debug --output-on-failure -j 4 -R "${ETH_TEST_NAME}[.].*") + diff --git a/eth/main.cpp b/eth/main.cpp index eda6e12ae..03c54a5b1 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -117,7 +117,7 @@ void help() << " -i,--interactive Enter interactive mode (default: non-interactive)." << endl #if ETH_JSONRPC << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl - << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl + << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl #endif << " -K,--kill-blockchain First kill the blockchain." << endl << " -l,--listen Listen on the given port for incoming connected (default: 30303)." << endl @@ -370,7 +370,7 @@ int main(int argc, char** argv) interactive = true; #if ETH_JSONRPC else if ((arg == "-j" || arg == "--json-rpc")) - jsonrpc = jsonrpc == -1 ? 8080 : jsonrpc; + jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc; else if (arg == "--json-rpc-port" && i + 1 < argc) jsonrpc = atoi(argv[++i]); #endif @@ -457,7 +457,7 @@ int main(int argc, char** argv) unique_ptr jsonrpcConnector; if (jsonrpc > -1) { - jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc)); + jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); jsonrpcServer->setIdentities({us}); jsonrpcServer->StartListening(); @@ -582,8 +582,8 @@ int main(int argc, char** argv) else if (cmd == "jsonstart") { if (jsonrpc < 0) - jsonrpc = 8080; - jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc)); + jsonrpc = SensibleHttpPort; + jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); jsonrpcServer->setIdentities({us}); jsonrpcServer->StartListening(); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 9676b4a78..235a39267 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -65,6 +65,7 @@ ldb::Slice toSlice(h256 _h, unsigned _sub = 0); using BlocksHash = std::map; using TransactionHashes = h256s; +using UncleHashes = h256s; enum { ExtraDetails = 0, @@ -130,7 +131,10 @@ public: TransactionHashes transactionHashes(h256 _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; } TransactionHashes transactionHashes() const { return transactionHashes(currentHash()); } - /// Get a list of transaction hashes for a given block. Thread-safe. + /// Get a list of uncle hashes for a given block. Thread-safe. + UncleHashes uncleHashes(h256 _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[2]) ret.push_back(sha3(t.data())); return ret; } + UncleHashes uncleHashes() const { return uncleHashes(currentHash()); } + h256 numberHash(u256 _index) const { if (!_index) return genesisHash(); return queryExtras(h256(_index), m_blockHashes, x_blockHashes, NullBlockHash).value; } /** Get the block blooms for a number of blocks. Thread-safe. diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 9e8a611c6..5af2bebd3 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -186,11 +186,6 @@ void Client::doneWorking() m_postMine = m_preMine; } -void Client::flushTransactions() -{ - doWork(); -} - void Client::killChain() { bool wasMining = isMining(); @@ -249,64 +244,9 @@ void Client::clearPending() noteChanged(changeds); } -unsigned Client::installWatch(h256 _h, Reaping _r) -{ - unsigned ret; - { - Guard l(m_filterLock); - ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0; - m_watches[ret] = ClientWatch(_h, _r); - cwatch << "+++" << ret << _h.abridged(); - } - auto ch = logs(ret); - if (ch.empty()) - ch.push_back(InitialChange); - { - Guard l(m_filterLock); - swap(m_watches[ret].changes, ch); - } - return ret; -} - -unsigned Client::installWatch(LogFilter const& _f, Reaping _r) -{ - h256 h = _f.sha3(); - { - Guard l(m_filterLock); - if (!m_filters.count(h)) - { - cwatch << "FFF" << _f << h.abridged(); - m_filters.insert(make_pair(h, _f)); - } - } - return installWatch(h, _r); -} - -bool Client::uninstallWatch(unsigned _i) -{ - cwatch << "XXX" << _i; - - Guard l(m_filterLock); - - auto it = m_watches.find(_i); - if (it == m_watches.end()) - return false; - auto id = it->second.id; - m_watches.erase(it); - - auto fit = m_filters.find(id); - if (fit != m_filters.end()) - if (!--fit->second.refCount) - { - cwatch << "*X*" << fit->first << ":" << fit->second.filter; - m_filters.erase(fit); - } - return true; -} - void Client::noteChanged(h256Set const& _filters) { - Guard l(m_filterLock); + Guard l(x_filtersWatches); if (_filters.size()) cnote << "noteChanged(" << _filters << ")"; // accrue all changes left in each filter into the watches. @@ -324,42 +264,9 @@ void Client::noteChanged(h256Set const& _filters) i.second.changes.clear(); } -LocalisedLogEntries Client::peekWatch(unsigned _watchId) const -{ - Guard l(m_filterLock); - -#if ETH_DEBUG - cdebug << "peekWatch" << _watchId; -#endif - auto& w = m_watches.at(_watchId); -#if ETH_DEBUG - cdebug << "lastPoll updated to " << chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); -#endif - w.lastPoll = chrono::system_clock::now(); - return w.changes; -} - -LocalisedLogEntries Client::checkWatch(unsigned _watchId) -{ - Guard l(m_filterLock); - LocalisedLogEntries ret; - -#if ETH_DEBUG && 0 - cdebug << "checkWatch" << _watchId; -#endif - auto& w = m_watches.at(_watchId); -#if ETH_DEBUG && 0 - cdebug << "lastPoll updated to " << chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); -#endif - std::swap(ret, w.changes); - w.lastPoll = chrono::system_clock::now(); - - return ret; -} - void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _transactionHash) { - Guard l(m_filterLock); + Guard l(x_filtersWatches); for (pair& i: m_filters) if (i.second.filter.envelops(RelativeBlock::Pending, m_bc.number() + 1)) { @@ -381,7 +288,7 @@ void Client::appendFromNewBlock(h256 const& _block, h256Set& io_changed) auto d = m_bc.info(_block); auto br = m_bc.receipts(_block); - Guard l(m_filterLock); + Guard l(x_filtersWatches); for (pair& i: m_filters) if (i.second.filter.envelops(RelativeBlock::Latest, d.number) && i.second.filter.matches(d.logBloom)) // acceptable number & looks like block may contain a matching log entry. @@ -475,68 +382,6 @@ void Client::setupState(State& _s) _s.commitToMine(m_bc); } -void Client::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) -{ - startWorking(); - - u256 n; - { - ReadGuard l(x_stateDB); - n = m_postMine.transactionsFrom(toAddress(_secret)); - } - Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); -// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); - StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged()); - cnote << "New transaction " << t; - m_tq.attemptImport(t.rlp()); -} - -ExecutionResult Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) -{ - ExecutionResult ret; - try - { - u256 n; - State temp; - // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); - { - ReadGuard l(x_stateDB); - temp = asOf(_blockNumber); - n = temp.transactionsFrom(toAddress(_secret)); - } - Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); - ret = temp.execute(m_bc, t.rlp(), Permanence::Reverted); - } - catch (...) - { - // TODO: Some sort of notification of failure. - } - return ret; -} - -ExecutionResult Client::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) -{ - ExecutionResult ret; - try - { - u256 n; - State temp; - // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); - { - ReadGuard l(x_stateDB); - temp = asOf(_blockNumber); - n = temp.transactionsFrom(toAddress(_secret)); - } - Transaction t(_value, _gasPrice, _gas, _data, n, _secret); - ret = temp.execute(m_bc, t.rlp(), Permanence::Reverted); - } - catch (...) - { - // TODO: Some sort of notification of failure. - } - return ret; -} - ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 _value, u256 _gasPrice) { ExecutionResult ret; @@ -561,28 +406,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 return ret; } -Address Client::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) -{ - startWorking(); - - u256 n; - { - ReadGuard l(x_stateDB); - n = m_postMine.transactionsFrom(toAddress(_secret)); - } - Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); - cnote << "New transaction " << t; - m_tq.attemptImport(t.rlp()); - return right160(sha3(rlpList(t.sender(), t.nonce()))); -} - -void Client::inject(bytesConstRef _rlp) -{ - startWorking(); - - m_tq.attemptImport(_rlp); -} - pair Client::getWork() { Guard l(x_remoteMiner); @@ -712,7 +535,7 @@ void Client::doWork() // watches garbage collection vector toUninstall; { - Guard l(m_filterLock); + Guard l(x_filtersWatches); for (auto key: keysOf(m_watches)) if (m_watches[key].lastPoll != chrono::system_clock::time_point::max() && chrono::system_clock::now() - m_watches[key].lastPoll > chrono::seconds(20)) { @@ -730,15 +553,15 @@ void Client::doWork() } } -State Client::asOf(unsigned _h) const +State Client::asOf(h256 const& _block) const { ReadGuard l(x_stateDB); - if (_h == PendingBlock) - return m_postMine; - else if (_h == LatestBlock) - return m_preMine; - else - return State(m_stateDB, m_bc, m_bc.numberHash(_h)); + return State(m_stateDB, bc(), _block); +} + +void Client::prepareForTransaction() +{ + startWorking(); } State Client::state(unsigned _txi, h256 _block) const @@ -759,183 +582,14 @@ eth::State Client::state(unsigned _txi) const return m_postMine.fromPending(_txi); } -StateDiff Client::diff(unsigned _txi, BlockNumber _block) const -{ - State st = asOf(_block); - return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); -} - -StateDiff Client::diff(unsigned _txi, h256 _block) const -{ - State st = state(_block); - return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); -} - -std::vector
Client::addresses(BlockNumber _block) const -{ - vector
ret; - for (auto const& i: asOf(_block).addresses()) - ret.push_back(i.first); - return ret; -} - -u256 Client::balanceAt(Address _a, BlockNumber _block) const -{ - return asOf(_block).balance(_a); -} - -std::map Client::storageAt(Address _a, BlockNumber _block) const -{ - return asOf(_block).storage(_a); -} - -u256 Client::countAt(Address _a, BlockNumber _block) const -{ - return asOf(_block).transactionsFrom(_a); -} - -u256 Client::stateAt(Address _a, u256 _l, BlockNumber _block) const -{ - return asOf(_block).storage(_a, _l); -} - -bytes Client::codeAt(Address _a, BlockNumber _block) const -{ - return asOf(_block).code(_a); -} - -Transaction Client::transaction(h256 _transactionHash) const -{ - return Transaction(m_bc.transaction(_transactionHash), CheckSignature::Range); -} - -Transaction Client::transaction(h256 _blockHash, unsigned _i) const -{ - auto bl = m_bc.block(_blockHash); - RLP b(bl); - if (_i < b[1].itemCount()) - return Transaction(b[1][_i].data(), CheckSignature::Range); - else - return Transaction(); -} - -BlockInfo Client::uncle(h256 _blockHash, unsigned _i) const -{ - auto bl = m_bc.block(_blockHash); - RLP b(bl); - if (_i < b[2].itemCount()) - return BlockInfo::fromHeader(b[2][_i].data()); - else - return BlockInfo(); -} - -unsigned Client::transactionCount(h256 _blockHash) const -{ - auto bl = m_bc.block(_blockHash); - RLP b(bl); - return b[1].itemCount(); -} - -unsigned Client::uncleCount(h256 _blockHash) const -{ - auto bl = m_bc.block(_blockHash); - RLP b(bl); - return b[2].itemCount(); -} - -Transactions Client::transactions(h256 _blockHash) const -{ - auto bl = m_bc.block(_blockHash); - RLP b(bl); - Transactions res; - for (unsigned i = 0; i < b[1].itemCount(); i++) - res.emplace_back(b[1][i].data(), CheckSignature::Range); - return res; -} - -TransactionHashes Client::transactionHashes(h256 _blockHash) const -{ - return m_bc.transactionHashes(_blockHash); -} - -LocalisedLogEntries Client::logs(unsigned _watchId) const +void Client::inject(bytesConstRef _rlp) { - LogFilter f; - try - { - Guard l(m_filterLock); - f = m_filters.at(m_watches.at(_watchId).id).filter; - } - catch (...) - { - return LocalisedLogEntries(); - } - return logs(f); + startWorking(); + + m_tq.attemptImport(_rlp); } -LocalisedLogEntries Client::logs(LogFilter const& _f) const +void Client::flushTransactions() { - LocalisedLogEntries ret; - unsigned begin = min(m_bc.number() + 1, (unsigned)_f.latest()); - unsigned end = min(m_bc.number(), min(begin, (unsigned)_f.earliest())); - - // Handle pending transactions differently as they're not on the block chain. - if (begin > m_bc.number()) - { - ReadGuard l(x_stateDB); - for (unsigned i = 0; i < m_postMine.pending().size(); ++i) - { - // Might have a transaction that contains a matching log. - TransactionReceipt const& tr = m_postMine.receipt(i); - auto sha3 = m_postMine.pending()[i].sha3(); - LogEntries le = _f.matches(tr); - if (le.size()) - for (unsigned j = 0; j < le.size(); ++j) - ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin, sha3)); - } - begin = m_bc.number(); - } - - set matchingBlocks; - for (auto const& i: _f.bloomPossibilities()) - for (auto u: m_bc.withBlockBloom(i, end, begin)) - matchingBlocks.insert(u); - -#if ETH_DEBUG - unsigned falsePos = 0; -#endif - for (auto n: matchingBlocks) - { -#if ETH_DEBUG - int total = 0; -#endif - auto h = m_bc.numberHash(n); - auto receipts = m_bc.receipts(h).receipts; - for (size_t i = 0; i < receipts.size(); i++) - { - TransactionReceipt receipt = receipts[i]; - if (_f.matches(receipt.bloom())) - { - auto info = m_bc.info(h); - auto h = transaction(info.hash, i).sha3(); - LogEntries le = _f.matches(receipt); - if (le.size()) - { -#if ETH_DEBUG - total += le.size(); -#endif - for (unsigned j = 0; j < le.size(); ++j) - ret.insert(ret.begin(), LocalisedLogEntry(le[j], n, h)); - } - } -#if ETH_DEBUG - if (!total) - falsePos++; -#endif - } - } -#if ETH_DEBUG - cdebug << matchingBlocks.size() << "searched from" << (end - begin) << "skipped; " << falsePos << "false +ves"; -#endif - return ret; + doWork(); } diff --git a/libethereum/Client.h b/libethereum/Client.h index 6e34dc925..dad0ca664 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -40,9 +40,8 @@ #include "TransactionQueue.h" #include "State.h" #include "CommonNet.h" -#include "LogFilter.h" #include "Miner.h" -#include "Interface.h" +#include "ClientBase.h" namespace dev { @@ -74,40 +73,6 @@ private: static const int GenesisBlock = INT_MIN; -struct InstalledFilter -{ - InstalledFilter(LogFilter const& _f): filter(_f) {} - - LogFilter filter; - unsigned refCount = 1; - LocalisedLogEntries changes; -}; - -static const h256 PendingChangedFilter = u256(0); -static const h256 ChainChangedFilter = u256(1); - -static const LogEntry SpecialLogEntry = LogEntry(Address(), h256s(), bytes()); -static const LocalisedLogEntry InitialChange(SpecialLogEntry, 0); - -struct ClientWatch -{ - ClientWatch(): lastPoll(std::chrono::system_clock::now()) {} - explicit ClientWatch(h256 _id, Reaping _r): id(_id), lastPoll(_r == Reaping::Automatic ? std::chrono::system_clock::now() : std::chrono::system_clock::time_point::max()) {} - - h256 id; - LocalisedLogEntries changes = LocalisedLogEntries{ InitialChange }; - mutable std::chrono::system_clock::time_point lastPoll = std::chrono::system_clock::now(); -}; - -struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; }; -#define cwatch dev::LogOutputStream() -struct WorkInChannel: public LogChannel { static const char* name() { return ">W>"; } static const int verbosity = 16; }; -struct WorkOutChannel: public LogChannel { static const char* name() { return "() -#define cworkin dev::LogOutputStream() -#define cworkout dev::LogOutputStream() - template struct ABISerialiser {}; template struct ABISerialiser> { static bytes serialise(FixedHash const& _t) { static_assert(N <= 32, "Cannot serialise hash > 32 bytes."); static_assert(N > 0, "Cannot serialise zero-length hash."); return bytes(32 - N, 0) + _t.asBytes(); } }; template <> struct ABISerialiser { static bytes serialise(u256 const& _t) { return h256(_t).asBytes(); } }; @@ -182,7 +147,7 @@ private: /** * @brief Main API hub for interfacing with Ethereum. */ -class Client: public MinerHost, public Interface, Worker +class Client: public MinerHost, public ClientBase, Worker { friend class Miner; @@ -211,88 +176,20 @@ public: /// Resets the gas pricer to some other object. void setGasPricer(std::shared_ptr _gp) { m_gp = _gp; } - /// Submits the given message-call transaction. - virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; - - /// Submits a new contract-creation transaction. - /// @returns the new contract's address (assuming it all goes through). - virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; - /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. - virtual void inject(bytesConstRef _rlp) override; + virtual void inject(bytesConstRef _rlp); /// Blocks until all pending transactions have been processed. virtual void flushTransactions() override; - /// Makes the given call. Nothing is recorded into the state. - virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override; - - /// Does the given creation. Nothing is recorded into the state. - /// @returns the pair of the Address of the created contract together with its code. - virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override; - + using Interface::call; // to remove warning about hiding virtual function /// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH. ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether); - // Informational stuff - - // [NEW API] - - using Interface::balanceAt; - using Interface::countAt; - using Interface::stateAt; - using Interface::codeAt; - using Interface::storageAt; - - virtual u256 balanceAt(Address _a, BlockNumber _block) const; - virtual u256 countAt(Address _a, BlockNumber _block) const; - virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const; - virtual bytes codeAt(Address _a, BlockNumber _block) const; - virtual std::map storageAt(Address _a, BlockNumber _block) const; - - virtual unsigned installWatch(LogFilter const& _filter, Reaping _r = Reaping::Automatic) override; - virtual unsigned installWatch(h256 _filterId, Reaping _r = Reaping::Automatic) override; - virtual bool uninstallWatch(unsigned _watchId) override; - virtual LocalisedLogEntries peekWatch(unsigned _watchId) const; - virtual LocalisedLogEntries checkWatch(unsigned _watchId); - - virtual LocalisedLogEntries logs(unsigned _watchId) const; - virtual LocalisedLogEntries logs(LogFilter const& _filter) const; - - // [EXTRA API]: - - /// @returns the length of the chain. - virtual unsigned number() const { return m_bc.number(); } - - /// Get the list of pending transactions. - /// @TODO: Remove in favour of transactions(). - virtual Transactions pending() const { return m_postMine.pending(); } - - virtual h256 hashFromNumber(unsigned _number) const { return m_bc.numberHash(_number); } - virtual BlockInfo blockInfo(h256 _hash) const { return BlockInfo(m_bc.block(_hash)); } - virtual BlockDetails blockDetails(h256 _hash) const { return m_bc.details(_hash); } - virtual Transaction transaction(h256 _transactionHash) const; - virtual Transaction transaction(h256 _blockHash, unsigned _i) const; - virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const; - virtual unsigned transactionCount(h256 _blockHash) const; - virtual unsigned uncleCount(h256 _blockHash) const; - virtual Transactions transactions(h256 _blockHash) const; - virtual TransactionHashes transactionHashes(h256 _blockHash) const; - - /// Differences between transactions. - using Interface::diff; - virtual StateDiff diff(unsigned _txi, h256 _block) const; - virtual StateDiff diff(unsigned _txi, BlockNumber _block) const; - - /// Get a list of all active addresses. - using Interface::addresses; - virtual std::vector
addresses(BlockNumber _block) const; - /// Get the remaining gas limit in this block. virtual u256 gasLimitRemaining() const { return m_postMine.gasLimitRemaining(); } // [PRIVATE API - only relevant for base clients, not available in general] - dev::eth::State state(unsigned _txi, h256 _block) const; dev::eth::State state(h256 _block) const; dev::eth::State state(unsigned _txi) const; @@ -317,10 +214,6 @@ public: /// Enable/disable fast mining. void setTurboMining(bool _enable = true) { m_turboMining = _enable; } - /// Set the coinbase address. - virtual void setAddress(Address _us) { m_preMine.setAddress(_us); } - /// Get the coinbase address. - virtual Address address() const { return m_preMine.address(); } /// Stops mining and sets the number of mining threads (0 for automatic). virtual void setMiningThreads(unsigned _threads = 0); /// Get the effective number of mining threads. @@ -356,6 +249,17 @@ public: void killChain(); protected: + /// InterfaceStub methods + virtual BlockChain const& bc() const override { return m_bc; } + + /// Returns the state object for the full block (i.e. the terminal state) for index _h. + /// Works properly with LatestBlock and PendingBlock. + using ClientBase::asOf; + virtual State asOf(h256 const& _block) const override; + virtual State preMine() const override { ReadGuard l(x_stateDB); return m_preMine; } + virtual State postMine() const override { ReadGuard l(x_stateDB); return m_postMine; } + virtual void prepareForTransaction() override; + /// Collate the changed filters for the bloom filter of the given pending transaction. /// Insert any filters that are activated into @a o_changed. void appendFromNewPending(TransactionReceipt const& _receipt, h256Set& io_changed, h256 _sha3); @@ -380,13 +284,8 @@ private: virtual bool turbo() const { return m_turboMining; } virtual bool force() const { return m_forceMining; } - /// Returns the state object for the full block (i.e. the terminal state) for index _h. - /// Works properly with LatestBlock and PendingBlock. - State asOf(unsigned _h) const; - VersionChecker m_vc; ///< Dummy object to check & update the protocol version. CanonBlockChain m_bc; ///< Maintains block database. - TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). std::shared_ptr m_gp; ///< The gas pricer. @@ -407,10 +306,6 @@ private: bool m_forceMining = false; ///< Mine even when there are no transactions pending? bool m_verifyOwnBlocks = true; ///< Should be verify blocks that we mined? - mutable Mutex m_filterLock; - std::map m_filters; - std::map m_watches; - mutable std::chrono::system_clock::time_point m_lastGarbageCollection; }; diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp new file mode 100644 index 000000000..f9caf98ac --- /dev/null +++ b/libethereum/ClientBase.cpp @@ -0,0 +1,402 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file ClientBase.cpp + * @author Gav Wood + * @author Marek Kotewicz + * @date 2015 + */ + +#include +#include "ClientBase.h" +#include "BlockChain.h" +#include "Executive.h" + +using namespace std; +using namespace dev; +using namespace dev::eth; + +State ClientBase::asOf(BlockNumber _h) const +{ + if (_h == PendingBlock) + return postMine(); + else if (_h == LatestBlock) + return preMine(); + return asOf(bc().numberHash(_h)); +} + +void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +{ + prepareForTransaction(); + + u256 n = postMine().transactionsFrom(toAddress(_secret)); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + m_tq.attemptImport(t.rlp()); + + StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged()); + cnote << "New transaction " << t; +} + +Address ClientBase::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) +{ + prepareForTransaction(); + + u256 n = postMine().transactionsFrom(toAddress(_secret)); + Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); + m_tq.attemptImport(t.rlp()); + + StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged()); + cnote << "New transaction " << t; + + return right160(sha3(rlpList(t.sender(), t.nonce()))); +} + +// TODO: remove try/catch, allow exceptions +ExecutionResult ClientBase::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) +{ + ExecutionResult ret; + try + { + State temp = asOf(_blockNumber); + u256 n = temp.transactionsFrom(toAddress(_secret)); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + ret = temp.execute(bc(), t.rlp(), Permanence::Reverted); + } + catch (...) + { + // TODO: Some sort of notification of failure. + } + return ret; +} + +ExecutionResult ClientBase::create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) +{ + ExecutionResult ret; + try + { + State temp = asOf(_blockNumber); + u256 n = temp.transactionsFrom(toAddress(_secret)); + // cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); + + Transaction t(_value, _gasPrice, _gas, _data, n, _secret); + ret = temp.execute(bc(), t.rlp(), Permanence::Reverted); + } + catch (...) + { + // TODO: Some sort of notification of failure. + } + return ret; +} + +u256 ClientBase::balanceAt(Address _a, BlockNumber _block) const +{ + return asOf(_block).balance(_a); +} + +u256 ClientBase::countAt(Address _a, BlockNumber _block) const +{ + return asOf(_block).transactionsFrom(_a); +} + +u256 ClientBase::stateAt(Address _a, u256 _l, BlockNumber _block) const +{ + return asOf(_block).storage(_a, _l); +} + +bytes ClientBase::codeAt(Address _a, BlockNumber _block) const +{ + return asOf(_block).code(_a); +} + +map ClientBase::storageAt(Address _a, BlockNumber _block) const +{ + return asOf(_block).storage(_a); +} + +// TODO: remove try/catch, allow exceptions +LocalisedLogEntries ClientBase::logs(unsigned _watchId) const +{ + LogFilter f; + try + { + Guard l(x_filtersWatches); + f = m_filters.at(m_watches.at(_watchId).id).filter; + } + catch (...) + { + return LocalisedLogEntries(); + } + return logs(f); +} + +LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const +{ + LocalisedLogEntries ret; + unsigned begin = min(bc().number() + 1, (unsigned)_f.latest()); + unsigned end = min(bc().number(), min(begin, (unsigned)_f.earliest())); + + // Handle pending transactions differently as they're not on the block chain. + if (begin > bc().number()) + { + State temp = postMine(); + for (unsigned i = 0; i < temp.pending().size(); ++i) + { + // Might have a transaction that contains a matching log. + TransactionReceipt const& tr = temp.receipt(i); + auto th = temp.pending()[i].sha3(); + LogEntries le = _f.matches(tr); + if (le.size()) + for (unsigned j = 0; j < le.size(); ++j) + ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin, th)); + } + begin = bc().number(); + } + + set matchingBlocks; + for (auto const& i: _f.bloomPossibilities()) + for (auto u: bc().withBlockBloom(i, end, begin)) + matchingBlocks.insert(u); + + unsigned falsePos = 0; + for (auto n: matchingBlocks) + { + int total = 0; + auto h = bc().numberHash(n); + auto receipts = bc().receipts(h).receipts; + for (size_t i = 0; i < receipts.size(); i++) + { + TransactionReceipt receipt = receipts[i]; + if (_f.matches(receipt.bloom())) + { + auto info = bc().info(h); + auto th = transaction(info.hash, i).sha3(); + LogEntries le = _f.matches(receipt); + if (le.size()) + { + total += le.size(); + for (unsigned j = 0; j < le.size(); ++j) + ret.insert(ret.begin(), LocalisedLogEntry(le[j], n, th)); + } + } + + if (!total) + falsePos++; + } + } + + cdebug << matchingBlocks.size() << "searched from" << (end - begin) << "skipped; " << falsePos << "false +ves"; + return ret; +} + +unsigned ClientBase::installWatch(LogFilter const& _f, Reaping _r) +{ + h256 h = _f.sha3(); + { + Guard l(x_filtersWatches); + if (!m_filters.count(h)) + { + cwatch << "FFF" << _f << h.abridged(); + m_filters.insert(make_pair(h, _f)); + } + } + return installWatch(h, _r); +} + +unsigned ClientBase::installWatch(h256 _h, Reaping _r) +{ + unsigned ret; + { + Guard l(x_filtersWatches); + ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0; + m_watches[ret] = ClientWatch(_h, _r); + cwatch << "+++" << ret << _h.abridged(); + } + auto ch = logs(ret); + if (ch.empty()) + ch.push_back(InitialChange); + { + Guard l(x_filtersWatches); + swap(m_watches[ret].changes, ch); + } + return ret; +} + +bool ClientBase::uninstallWatch(unsigned _i) +{ + cwatch << "XXX" << _i; + + Guard l(x_filtersWatches); + + auto it = m_watches.find(_i); + if (it == m_watches.end()) + return false; + auto id = it->second.id; + m_watches.erase(it); + + auto fit = m_filters.find(id); + if (fit != m_filters.end()) + if (!--fit->second.refCount) + { + cwatch << "*X*" << fit->first << ":" << fit->second.filter; + m_filters.erase(fit); + } + return true; +} + +LocalisedLogEntries ClientBase::peekWatch(unsigned _watchId) const +{ + Guard l(x_filtersWatches); + + cwatch << "peekWatch" << _watchId; + auto& w = m_watches.at(_watchId); + cwatch << "lastPoll updated to " << chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); + w.lastPoll = chrono::system_clock::now(); + return w.changes; +} + +LocalisedLogEntries ClientBase::checkWatch(unsigned _watchId) +{ + Guard l(x_filtersWatches); + LocalisedLogEntries ret; + + cwatch << "checkWatch" << _watchId; + auto& w = m_watches.at(_watchId); + cwatch << "lastPoll updated to " << chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); + std::swap(ret, w.changes); + w.lastPoll = chrono::system_clock::now(); + + return ret; +} + +h256 ClientBase::hashFromNumber(unsigned _number) const +{ + return bc().numberHash(_number); +} + +BlockInfo ClientBase::blockInfo(h256 _hash) const +{ + return BlockInfo(bc().block(_hash)); +} + +BlockDetails ClientBase::blockDetails(h256 _hash) const +{ + return bc().details(_hash); +} + +Transaction ClientBase::transaction(h256 _transactionHash) const +{ + return Transaction(bc().transaction(_transactionHash), CheckSignature::Range); +} + +Transaction ClientBase::transaction(h256 _blockHash, unsigned _i) const +{ + auto bl = bc().block(_blockHash); + RLP b(bl); + if (_i < b[1].itemCount()) + return Transaction(b[1][_i].data(), CheckSignature::Range); + else + return Transaction(); +} + +Transactions ClientBase::transactions(h256 _blockHash) const +{ + auto bl = bc().block(_blockHash); + RLP b(bl); + Transactions res; + for (unsigned i = 0; i < b[1].itemCount(); i++) + res.emplace_back(b[1][i].data(), CheckSignature::Range); + return res; +} + +TransactionHashes ClientBase::transactionHashes(h256 _blockHash) const +{ + return bc().transactionHashes(_blockHash); +} + +BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const +{ + auto bl = bc().block(_blockHash); + RLP b(bl); + if (_i < b[2].itemCount()) + return BlockInfo::fromHeader(b[2][_i].data()); + else + return BlockInfo(); +} + +UncleHashes ClientBase::uncleHashes(h256 _blockHash) const +{ + return bc().uncleHashes(_blockHash); +} + +unsigned ClientBase::transactionCount(h256 _blockHash) const +{ + auto bl = bc().block(_blockHash); + RLP b(bl); + return b[1].itemCount(); +} + +unsigned ClientBase::uncleCount(h256 _blockHash) const +{ + auto bl = bc().block(_blockHash); + RLP b(bl); + return b[2].itemCount(); +} + +unsigned ClientBase::number() const +{ + return bc().number(); +} + +Transactions ClientBase::pending() const +{ + return postMine().pending(); +} + + +StateDiff ClientBase::diff(unsigned _txi, h256 _block) const +{ + State st = asOf(_block); + return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); +} + +StateDiff ClientBase::diff(unsigned _txi, BlockNumber _block) const +{ + State st = asOf(_block); + return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); +} + +Addresses ClientBase::addresses(BlockNumber _block) const +{ + Addresses ret; + for (auto const& i: asOf(_block).addresses()) + ret.push_back(i.first); + return ret; +} + +u256 ClientBase::gasLimitRemaining() const +{ + return postMine().gasLimitRemaining(); +} + +void ClientBase::setAddress(Address _us) +{ + preMine().setAddress(_us); +} + +Address ClientBase::address() const +{ + return preMine().address(); +} diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h new file mode 100644 index 000000000..9d9482277 --- /dev/null +++ b/libethereum/ClientBase.h @@ -0,0 +1,167 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file ClientBase.h + * @author Gav Wood + * @author Marek Kotewicz + * @date 2015 + */ + +#pragma once + +#include +#include "Interface.h" +#include "LogFilter.h" + +namespace dev { + +namespace eth { + +struct InstalledFilter +{ + InstalledFilter(LogFilter const& _f): filter(_f) {} + + LogFilter filter; + unsigned refCount = 1; + LocalisedLogEntries changes; +}; + +static const h256 PendingChangedFilter = u256(0); +static const h256 ChainChangedFilter = u256(1); + +static const LogEntry SpecialLogEntry = LogEntry(Address(), h256s(), bytes()); +static const LocalisedLogEntry InitialChange(SpecialLogEntry, 0); + +struct ClientWatch +{ + ClientWatch(): lastPoll(std::chrono::system_clock::now()) {} + explicit ClientWatch(h256 _id, Reaping _r): id(_id), lastPoll(_r == Reaping::Automatic ? std::chrono::system_clock::now() : std::chrono::system_clock::time_point::max()) {} + + h256 id; + LocalisedLogEntries changes = LocalisedLogEntries{ InitialChange }; + mutable std::chrono::system_clock::time_point lastPoll = std::chrono::system_clock::now(); +}; + +struct WatchChannel: public LogChannel { static const char* name() { return "(o)"; } static const int verbosity = 7; }; +#define cwatch dev::LogOutputStream() +struct WorkInChannel: public LogChannel { static const char* name() { return ">W>"; } static const int verbosity = 16; }; +struct WorkOutChannel: public LogChannel { static const char* name() { return "() +#define cworkin dev::LogOutputStream() +#define cworkout dev::LogOutputStream() + +class ClientBase: public dev::eth::Interface +{ +public: + ClientBase() {} + virtual ~ClientBase() {} + + /// Submits the given message-call transaction. + virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; + + /// Submits a new contract-creation transaction. + /// @returns the new contract's address (assuming it all goes through). + virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; + + /// Makes the given call. Nothing is recorded into the state. + virtual ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override; + + virtual ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo, BlockNumber _blockNumber = PendingBlock) override; + + using Interface::balanceAt; + using Interface::countAt; + using Interface::stateAt; + using Interface::codeAt; + using Interface::storageAt; + + virtual u256 balanceAt(Address _a, BlockNumber _block) const override; + virtual u256 countAt(Address _a, BlockNumber _block) const override; + virtual u256 stateAt(Address _a, u256 _l, BlockNumber _block) const override; + virtual bytes codeAt(Address _a, BlockNumber _block) const override; + virtual std::map storageAt(Address _a, BlockNumber _block) const override; + + virtual LocalisedLogEntries logs(unsigned _watchId) const override; + virtual LocalisedLogEntries logs(LogFilter const& _filter) const override; + + /// Install, uninstall and query watches. + virtual unsigned installWatch(LogFilter const& _filter, Reaping _r = Reaping::Automatic) override; + virtual unsigned installWatch(h256 _filterId, Reaping _r = Reaping::Automatic) override; + virtual bool uninstallWatch(unsigned _watchId) override; + virtual LocalisedLogEntries peekWatch(unsigned _watchId) const override; + virtual LocalisedLogEntries checkWatch(unsigned _watchId) override; + + virtual h256 hashFromNumber(unsigned _number) const override; + virtual eth::BlockInfo blockInfo(h256 _hash) const override; + virtual eth::BlockDetails blockDetails(h256 _hash) const override; + virtual eth::Transaction transaction(h256 _transactionHash) const override; + virtual eth::Transaction transaction(h256 _blockHash, unsigned _i) const override; + virtual eth::Transactions transactions(h256 _blockHash) const override; + virtual eth::TransactionHashes transactionHashes(h256 _blockHash) const override; + virtual eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override; + virtual eth::UncleHashes uncleHashes(h256 _blockHash) const override; + virtual unsigned transactionCount(h256 _blockHash) const override; + virtual unsigned uncleCount(h256 _blockHash) const override; + virtual unsigned number() const override; + virtual eth::Transactions pending() const override; + + using Interface::diff; + virtual StateDiff diff(unsigned _txi, h256 _block) const override; + virtual StateDiff diff(unsigned _txi, BlockNumber _block) const override; + + using Interface::addresses; + virtual Addresses addresses(BlockNumber _block) const override; + virtual u256 gasLimitRemaining() const override; + + /// Set the coinbase address + virtual void setAddress(Address _us) override; + + /// Get the coinbase address + virtual Address address() const override; + + /// TODO: consider moving it to a separate interface + + virtual void setMiningThreads(unsigned _threads) override { (void)_threads; BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::setMiningThreads")); } + virtual unsigned miningThreads() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningThreads")); } + virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::startMining")); } + virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::stopMining")); } + virtual bool isMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::isMining")); } + virtual eth::MineProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::miningProgress")); } + virtual std::pair getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::getWork")); } + virtual bool submitWork(eth::ProofOfWork::Proof const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("dev::eth::ClientBase::submitWork")); } + + State asOf(BlockNumber _h) const; + +protected: + /// The interface that must be implemented in any class deriving this. + /// { + virtual BlockChain const& bc() const = 0; + virtual State asOf(h256 const& _h) const = 0; + virtual State preMine() const = 0; + virtual State postMine() const = 0; + virtual void prepareForTransaction() = 0; + /// } + + TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain. + + // filters + mutable Mutex x_filtersWatches; ///< Our lock. + std::map m_filters; ///< The dictionary of filters that are active. + std::map m_watches; ///< Each and every watch - these reference a filter. + +}; + +}} diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 597506821..c574fa650 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -44,6 +44,11 @@ u256 Executive::gasUsed() const return m_t.gas() - m_endGas; } +ExecutionResult Executive::executionResult() const +{ + return ExecutionResult(gasUsed(), m_excepted, m_newAddress, m_out, m_codeDeposit, m_ext ? m_ext->sub.refunds : 0); +} + void Executive::accrueSubState(SubState& _parentContext) { if (m_ext) diff --git a/libethereum/Executive.h b/libethereum/Executive.h index d04a39da8..eb0c27ad2 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -104,7 +104,7 @@ public: bool excepted() const { return m_excepted != TransactionException::None; } /// Get the above in an amalgamated fashion. - ExecutionResult executionResult() const { return ExecutionResult(gasUsed(), m_excepted, m_newAddress, m_out, m_codeDeposit); } + ExecutionResult executionResult() const; private: bool setup(); diff --git a/libethereum/Interface.h b/libethereum/Interface.h index b78106ae1..47fdb7250 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -38,6 +38,7 @@ namespace eth { using TransactionHashes = h256s; +using UncleHashes = h256s; enum class Reaping { @@ -66,9 +67,6 @@ public: /// @returns the new contract's address (assuming it all goes through). virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) = 0; - /// Injects the RLP-encoded transaction given by the _rlp into the transaction queue directly. - virtual void inject(bytesConstRef _rlp) = 0; - /// Blocks until all pending transactions have been processed. virtual void flushTransactions() = 0; @@ -118,6 +116,7 @@ public: virtual Transaction transaction(h256 _transactionHash) const = 0; virtual Transaction transaction(h256 _blockHash, unsigned _i) const = 0; virtual BlockInfo uncle(h256 _blockHash, unsigned _i) const = 0; + virtual UncleHashes uncleHashes(h256 _blockHash) const = 0; virtual unsigned transactionCount(h256 _blockHash) const = 0; virtual unsigned uncleCount(h256 _blockHash) const = 0; virtual Transactions transactions(h256 _blockHash) const = 0; diff --git a/libethereum/State.h b/libethereum/State.h index 3883a4897..ee88f443e 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -41,7 +41,7 @@ namespace dev { -namespace test { class ImportTest; } +namespace test { class ImportTest; class StateLoader; } namespace eth { @@ -99,6 +99,7 @@ class State { friend class ExtVM; friend class dev::test::ImportTest; + friend class dev::test::StateLoader; friend class Executive; public: diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 31a7f74a9..502f089fb 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -68,6 +68,10 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig) m_type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall; m_receiveAddress = rlp[field = 3].isEmpty() ? Address() : rlp[field = 3].toHash
(RLP::VeryStrict); m_value = rlp[field = 4].toInt(); + + if (!rlp[field = 5].isData()) + BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("transaction data RLP must be an array")); + m_data = rlp[field = 5].toBytes(); byte v = rlp[field = 6].toInt() - 27; h256 r = rlp[field = 7].toInt(); diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 1287be64e..bed291868 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -75,12 +75,13 @@ TransactionException toTransactionException(VMException const& _e); struct ExecutionResult { ExecutionResult() = default; - ExecutionResult(u256 _gasUsed, TransactionException _excepted, Address _newAddress, bytesConstRef _output, CodeDeposit _codeDeposit): gasUsed(_gasUsed), excepted(_excepted), newAddress(_newAddress), output(_output.toBytes()), codeDeposit(_codeDeposit) {} + ExecutionResult(u256 _gasUsed, TransactionException _excepted, Address _newAddress, bytesConstRef _output, CodeDeposit _codeDeposit, u256 _gasRefund): gasUsed(_gasUsed), excepted(_excepted), newAddress(_newAddress), output(_output.toBytes()), codeDeposit(_codeDeposit), gasRefunded(_gasRefund) {} u256 gasUsed = 0; TransactionException excepted = TransactionException::Unknown; Address newAddress; bytes output; CodeDeposit codeDeposit = CodeDeposit::None; + u256 gasRefunded = 0; }; std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 9e4ffe174..806df6b30 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -47,6 +47,13 @@ using namespace jsonrpc; using namespace dev; using namespace dev::eth; +#if ETH_DEBUG +const unsigned dev::SensibleHttpThreads = 1; +#else +const unsigned dev::SensibleHttpThreads = 4; +#endif +const unsigned dev::SensibleHttpPort = 8080; + static Json::Value toJson(dev::eth::BlockInfo const& _bi) { Json::Value res; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 214573e0d..40265ac10 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -48,6 +48,9 @@ namespace shh class Interface; } +extern const unsigned SensibleHttpThreads; +extern const unsigned SensibleHttpPort; + class WebThreeStubDatabaseFace { public: diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index fd7b2263d..0a2464b65 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -44,30 +44,21 @@ namespace mix const Secret c_defaultUserAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074"); const u256 c_mixGenesisDifficulty = c_minimumDifficulty; //TODO: make it lower for Mix somehow - -class MixBlockChain: public dev::eth::BlockChain + +bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) { -public: - MixBlockChain(std::string const& _path, h256 _stateRoot): - BlockChain(createGenesisBlock(_stateRoot), _path, true) - { - } - - static bytes createGenesisBlock(h256 _stateRoot) - { - RLPStream block(3); - block.appendList(15) - << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie - << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 - << std::string() << h256() << h64(u64(42)); - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - return block.out(); - } -}; + RLPStream block(3); + block.appendList(15) + << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie + << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 + << std::string() << h256() << h64(u64(42)); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); +} MixClient::MixClient(std::string const& _dbPath): - m_dbPath(_dbPath), m_minigThreads(0) + m_dbPath(_dbPath), m_miningThreads(0) { std::map account; account.insert(std::make_pair(c_defaultUserAccountSecret, 1000000 * ether)); @@ -81,7 +72,7 @@ MixClient::~MixClient() void MixClient::resetState(std::map _accounts) { WriteGuard l(x_state); - Guard fl(m_filterLock); + Guard fl(x_filtersWatches); m_filters.clear(); m_watches.clear(); @@ -197,7 +188,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); // collect watches h256Set changed; - Guard l(m_filterLock); + Guard l(x_filtersWatches); for (std::pair& i: m_filters) if ((unsigned)i.second.filter.latest() > bc().number()) { @@ -243,15 +234,10 @@ ExecutionResult MixClient::execution(unsigned _index) const return m_executions.at(_index); } -State MixClient::asOf(int _block) const +State MixClient::asOf(h256 const& _block) const { ReadGuard l(x_state); - if (_block == 0) - return m_state; - else if (_block == -1) - return m_startState; - else - return State(m_stateDB, bc(), bc().numberHash(_block)); + return State(m_stateDB, bc(), _block); } void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) @@ -272,26 +258,11 @@ Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes cons return address; } -void MixClient::inject(bytesConstRef _rlp) -{ - WriteGuard l(x_state); - eth::Transaction t(_rlp, CheckSignature::None); - executeTransaction(t, m_state, false); -} - -void MixClient::flushTransactions() -{ -} - dev::eth::ExecutionResult MixClient::call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber) { - u256 n; - State temp; - { - ReadGuard lr(x_state); - temp = asOf(_blockNumber); - n = temp.transactionsFrom(toAddress(_secret)); - } + + State temp = asOf(_blockNumber); + u256 n = temp.transactionsFrom(toAddress(_secret)); Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); bytes rlp = t.rlp(); WriteGuard lw(x_state); //TODO: lock is required only for last execution state @@ -315,122 +286,6 @@ dev::eth::ExecutionResult MixClient::create(Secret _secret, u256 _value, bytes c return lastExecution().result; } -u256 MixClient::balanceAt(Address _a, BlockNumber _block) const -{ - return asOf(_block).balance(_a); -} - -u256 MixClient::countAt(Address _a, BlockNumber _block) const -{ - return asOf(_block).transactionsFrom(_a); -} - -u256 MixClient::stateAt(Address _a, u256 _l, BlockNumber _block) const -{ - return asOf(_block).storage(_a, _l); -} - -bytes MixClient::codeAt(Address _a, BlockNumber _block) const -{ - return asOf(_block).code(_a); -} - -std::map MixClient::storageAt(Address _a, BlockNumber _block) const -{ - return asOf(_block).storage(_a); -} - -eth::LocalisedLogEntries MixClient::logs(unsigned _watchId) const -{ - Guard l(m_filterLock); - h256 h = m_watches.at(_watchId).id; - auto filterIter = m_filters.find(h); - if (filterIter != m_filters.end()) - return logs(filterIter->second.filter); - return eth::LocalisedLogEntries(); -} - -eth::LocalisedLogEntries MixClient::logs(eth::LogFilter const& _f) const -{ - LocalisedLogEntries ret; - unsigned lastBlock = bc().number(); - unsigned block = std::min(lastBlock, (unsigned)_f.latest()); - unsigned end = std::min(lastBlock, std::min(block, (unsigned)_f.earliest())); - // Pending transactions - if (block > bc().number()) - { - ReadGuard l(x_state); - for (unsigned i = 0; i < m_state.pending().size(); ++i) - { - // Might have a transaction that contains a matching log. - TransactionReceipt const& tr = m_state.receipt(i); - LogEntries logEntries = _f.matches(tr); - for (unsigned entry = 0; entry < logEntries.size(); ++entry) - ret.insert(ret.begin(), LocalisedLogEntry(logEntries[entry], block)); - } - block = bc().number(); - } - - // The rest - auto h = bc().numberHash(block); - for (; ret.size() != block && block != end; block--) - { - if (_f.matches(bc().info(h).logBloom)) - for (TransactionReceipt receipt: bc().receipts(h).receipts) - if (_f.matches(receipt.bloom())) - for (auto const& e: _f.matches(receipt)) - ret.insert(ret.begin(), LocalisedLogEntry(e, block)); - h = bc().details(h).parent; - } - return ret; -} - -unsigned MixClient::installWatch(h256 _h, eth::Reaping _r) -{ - unsigned ret; - { - Guard l(m_filterLock); - ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0; - m_watches[ret] = ClientWatch(_h, _r); - } - auto ch = logs(ret); - if (ch.empty()) - ch.push_back(eth::InitialChange); - { - Guard l(m_filterLock); - swap(m_watches[ret].changes, ch); - } - return ret; -} - -unsigned MixClient::installWatch(eth::LogFilter const& _f, eth::Reaping _r) -{ - h256 h = _f.sha3(); - { - Guard l(m_filterLock); - m_filters.insert(std::make_pair(h, _f)); - } - return installWatch(h, _r); -} - -bool MixClient::uninstallWatch(unsigned _i) -{ - Guard l(m_filterLock); - - auto it = m_watches.find(_i); - if (it == m_watches.end()) - return false; - auto id = it->second.id; - m_watches.erase(it); - - auto fit = m_filters.find(id); - if (fit != m_filters.end()) - if (!--fit->second.refCount) - m_filters.erase(fit); - - return true; -} - void MixClient::noteChanged(h256Set const& _filters) { for (auto& i: m_watches) @@ -445,168 +300,26 @@ void MixClient::noteChanged(h256Set const& _filters) i.second.changes.clear(); } -LocalisedLogEntries MixClient::peekWatch(unsigned _watchId) const -{ - Guard l(m_filterLock); - if (_watchId < m_watches.size()) - return m_watches.at(_watchId).changes; - return LocalisedLogEntries(); -} - -LocalisedLogEntries MixClient::checkWatch(unsigned _watchId) -{ - Guard l(m_filterLock); - LocalisedLogEntries ret; - if (_watchId < m_watches.size()) - std::swap(ret, m_watches.at(_watchId).changes); - return ret; -} - -h256 MixClient::hashFromNumber(unsigned _number) const -{ - ReadGuard l(x_state); - return bc().numberHash(_number); -} - -eth::BlockInfo MixClient::blockInfo(h256 _hash) const -{ - ReadGuard l(x_state); - return BlockInfo(bc().block(_hash)); - -} - eth::BlockInfo MixClient::blockInfo() const { ReadGuard l(x_state); return BlockInfo(bc().block()); } -eth::BlockDetails MixClient::blockDetails(h256 _hash) const -{ - ReadGuard l(x_state); - return bc().details(_hash); -} - -Transaction MixClient::transaction(h256 _transactionHash) const -{ - ReadGuard l(x_state); - return Transaction(bc().transaction(_transactionHash), CheckSignature::Range); -} - -eth::Transaction MixClient::transaction(h256 _blockHash, unsigned _i) const -{ - ReadGuard l(x_state); - auto bl = bc().block(_blockHash); - RLP b(bl); - if (_i < b[1].itemCount()) - return Transaction(b[1][_i].data(), CheckSignature::Range); - else - return Transaction(); -} - -eth::BlockInfo MixClient::uncle(h256 _blockHash, unsigned _i) const -{ - ReadGuard l(x_state); - auto bl = bc().block(_blockHash); - RLP b(bl); - if (_i < b[2].itemCount()) - return BlockInfo::fromHeader(b[2][_i].data()); - else - return BlockInfo(); -} - -unsigned MixClient::transactionCount(h256 _blockHash) const -{ - ReadGuard l(x_state); - auto bl = bc().block(_blockHash); - RLP b(bl); - return b[1].itemCount(); -} - -unsigned MixClient::uncleCount(h256 _blockHash) const -{ - ReadGuard l(x_state); - auto bl = bc().block(_blockHash); - RLP b(bl); - return b[2].itemCount(); -} - -Transactions MixClient::transactions(h256 _blockHash) const -{ - ReadGuard l(x_state); - auto bl = bc().block(_blockHash); - RLP b(bl); - Transactions res; - for (unsigned i = 0; i < b[1].itemCount(); i++) - res.emplace_back(b[1][i].data(), CheckSignature::Range); - return res; -} - -TransactionHashes MixClient::transactionHashes(h256 _blockHash) const -{ - ReadGuard l(x_state); - return bc().transactionHashes(_blockHash); -} - -unsigned MixClient::number() const -{ - ReadGuard l(x_state); - return bc().number(); -} - -eth::Transactions MixClient::pending() const -{ - ReadGuard l(x_state); - return m_state.pending(); -} - -eth::StateDiff MixClient::diff(unsigned _txi, h256 _block) const -{ - ReadGuard l(x_state); - State st(m_stateDB, bc(), _block); - return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); -} - -eth::StateDiff MixClient::diff(unsigned _txi, BlockNumber _block) const -{ - State st = asOf(_block); - return st.fromPending(_txi).diff(st.fromPending(_txi + 1)); -} - -Addresses MixClient::addresses(BlockNumber _block) const -{ - Addresses ret; - for (auto const& i: asOf(_block).addresses()) - ret.push_back(i.first); - return ret; -} - -u256 MixClient::gasLimitRemaining() const -{ - ReadGuard l(x_state); - return m_state.gasLimitRemaining(); -} - void MixClient::setAddress(Address _us) { WriteGuard l(x_state); m_state.setAddress(_us); } -Address MixClient::address() const -{ - ReadGuard l(x_state); - return m_state.address(); -} - void MixClient::setMiningThreads(unsigned _threads) { - m_minigThreads = _threads; + m_miningThreads = _threads; } unsigned MixClient::miningThreads() const { - return m_minigThreads; + return m_miningThreads; } void MixClient::startMining() diff --git a/mix/MixClient.h b/mix/MixClient.h index e1085a20e..179b445ac 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,8 +25,7 @@ #include #include -#include -#include +#include #include #include "MachineStates.h" @@ -35,9 +34,15 @@ namespace dev namespace mix { -class MixBlockChain; +class MixBlockChain: public dev::eth::BlockChain +{ +public: + MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, true) {} + + static bytes createGenesisBlock(h256 _stateRoot); +}; -class MixClient: public dev::eth::Interface +class MixClient: public dev::eth::ClientBase { public: MixClient(std::string const& _dbPath); @@ -48,43 +53,12 @@ public: ExecutionResult lastExecution() const; ExecutionResult execution(unsigned _index) const; - //dev::eth::Interface void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) override; Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) override; - void inject(bytesConstRef _rlp) override; - void flushTransactions() override; - dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber) override; - dev::eth::ExecutionResult create(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber) override; - u256 balanceAt(Address _a, eth::BlockNumber _block) const override; - u256 countAt(Address _a, eth::BlockNumber _block) const override; - u256 stateAt(Address _a, u256 _l, eth::BlockNumber _block) const override; - bytes codeAt(Address _a, eth::BlockNumber _block) const override; - std::map storageAt(Address _a, eth::BlockNumber _block) const override; - eth::LocalisedLogEntries logs(unsigned _watchId) const override; - eth::LocalisedLogEntries logs(eth::LogFilter const& _filter) const override; - unsigned installWatch(eth::LogFilter const& _filter, eth::Reaping _r = eth::Reaping::Automatic) override; - unsigned installWatch(h256 _filterId, eth::Reaping _r = eth::Reaping::Automatic) override; - bool uninstallWatch(unsigned _watchId) override; - eth::LocalisedLogEntries peekWatch(unsigned _watchId) const override; - eth::LocalisedLogEntries checkWatch(unsigned _watchId) override; - h256 hashFromNumber(unsigned _number) const override; - eth::BlockInfo blockInfo(h256 _hash) const override; - eth::BlockDetails blockDetails(h256 _hash) const override; - eth::Transaction transaction(h256 _transactionHash) const override; - eth::Transaction transaction(h256 _blockHash, unsigned _i) const override; - eth::BlockInfo uncle(h256 _blockHash, unsigned _i) const override; - unsigned transactionCount(h256 _blockHash) const override; - unsigned uncleCount(h256 _blockHash) const override; - eth::Transactions transactions(h256 _blockHash) const override; - eth::TransactionHashes transactionHashes(h256 _blockHash) const override; - unsigned number() const override; - eth::Transactions pending() const override; - eth::StateDiff diff(unsigned _txi, h256 _block) const override; - eth::StateDiff diff(unsigned _txi, eth::BlockNumber _block) const override; - Addresses addresses(eth::BlockNumber _block) const override; - u256 gasLimitRemaining() const override; + dev::eth::ExecutionResult call(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, eth::BlockNumber _blockNumber = eth::PendingBlock) override; + dev::eth::ExecutionResult create(Secret _secret, u256 _value, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * eth::szabo, eth::BlockNumber _blockNumber = eth::PendingBlock) override; + void setAddress(Address _us) override; - Address address() const override; void setMiningThreads(unsigned _threads) override; unsigned miningThreads() const override; void startMining() override; @@ -93,16 +67,27 @@ public: eth::MineProgress miningProgress() const override; std::pair getWork() override { return std::pair(); } bool submitWork(eth::ProofOfWork::Proof const&) override { return false; } + virtual void flushTransactions() override {} + /// @returns the last mined block information + using Interface::blockInfo; // to remove warning about hiding virtual function eth::BlockInfo blockInfo() const; std::vector userAccounts() { return m_userAccounts; } +protected: + virtual dev::eth::BlockChain& bc() { return *m_bc; } + + /// InterfaceStub methods + virtual dev::eth::State asOf(h256 const& _block) const override; + using ClientBase::asOf; + 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 postMine() const override { ReadGuard l(x_state); return m_state; } + virtual void prepareForTransaction() override {} + private: void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call); void noteChanged(h256Set const& _filters); - dev::eth::State asOf(int _block) const; - MixBlockChain& bc() { return *m_bc; } - MixBlockChain const& bc() const { return *m_bc; } std::vector m_userAccounts; eth::State m_state; @@ -111,12 +96,9 @@ private: std::auto_ptr m_bc; mutable boost::shared_mutex x_state; mutable boost::shared_mutex x_executions; - mutable std::mutex m_filterLock; - std::map m_filters; - std::map m_watches; ExecutionResults m_executions; std::string m_dbPath; - unsigned m_minigThreads; + unsigned m_miningThreads; }; } diff --git a/neth/main.cpp b/neth/main.cpp index 4888f784d..fc4c8c9c6 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -474,7 +474,11 @@ int main(int argc, char** argv) unique_ptr jsonrpcConnector; if (jsonrpc > -1) { - jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc)); +#if ETH_DEBUG + jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", 1)); +#else + jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", 4)); +#endif jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); jsonrpcServer->setIdentities({us}); jsonrpcServer->StartListening(); @@ -625,7 +629,11 @@ int main(int argc, char** argv) { if (jsonrpc < 0) jsonrpc = 8080; - jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc)); +#if ETH_DEBUG + jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", 1)); +#else + jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", 4)); +#endif jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, vector({us}))); jsonrpcServer->setIdentities({us}); jsonrpcServer->StartListening(); diff --git a/test/transaction.cpp b/test/transaction.cpp index 77f6ecdaf..4c57326ba 100644 --- a/test/transaction.cpp +++ b/test/transaction.cpp @@ -48,6 +48,13 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) if (!txFromRlp.signature().isValid()) BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); } + catch(Exception const& _e) + { + cnote << i.first; + cnote << "Transaction Exception: " << diagnostic_information(_e); + BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!"); + continue; + } catch(...) { BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!"); diff --git a/test/ttTransactionTestFiller.json b/test/ttTransactionTestFiller.json index 0058feac1..c04b76848 100644 --- a/test/ttTransactionTestFiller.json +++ b/test/ttTransactionTestFiller.json @@ -571,6 +571,7 @@ "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" } }, + "unpadedRValue": { "transaction": { "nonce": "13", @@ -583,5 +584,19 @@ "v": "28", "value": "" } + }, + + "libsecp256k1test": { + "transaction": { + "nonce": "", + "gasPrice": "0x09184e72a000", + "gasLimit": "0x1388", + "to": "", + "data": "", + "r": "44", + "s": "4", + "v": "27", + "value": "" + } } }